我正在为一个React组件编写Jest测试,并使用@testing-library/user-event
库来模拟用户交互。
下面是一个示例测试:
it(`fires onClick prop function when the button is clicked`, async () => {
// jest.useFakeTimers()
let propFn = jest.fn()
let app = RTL.render(
<SampleComp onClick={propFn} />
)
await userEvent.click(app.queryByText('Test button')!)
expect(propFn).toHaveBeenCalled()
// jest.useRealTimers()
})
这是组件:
function SampleComp({ onClick }) {
// a simple bridge for debugging
function _onClick(e) {
console.log(`_onClick invoked`)
return onClick(e)
}
return (
<button onClick={_onClick}>
Test button
</button>
)
}
如果没有假计时器,测试会在几分之一秒内运行并通过。如果有假计时器,测试会超时并失败:
● fires onClick prop function when the button is clicked
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
它也无法发出调试行,因此显然不会触发click事件。
我已经做了大量的调试,并确定根本原因是用户事件库在内部依赖于setTimeout
来创建事件之间的短暂延迟。
是的,"事件"* 复数 *--回想一下用户事件库的价值主张是:fireEvent
调度DOM事件,而user-event
模拟完整的 * 交互 *,这可能会触发多个事件并在过程中执行其他检查。
- -用户事件文档
在本例中,user-event为我创建了两个事件:
1.鼠标移动1
1.实际点击
1尽管user-event的内部事件对象中的第一个事件只有一个target
而没有type
,但我认为第一个事件应该是鼠标移动或鼠标悬停在按钮上。我已经验证了用户事件在内部创建的操作列表确实有2个项目,第二个项目明确标记为"[MouseLeft]"。
延迟是由user-event的pointerAction
函数插入到事件之间的。在我的例子中,user-event在事件1和2之间的延迟期间停止。
超时在user-event的wait
模块中创建:
new Promise<void>(resolve => globalThis.setTimeout(() => resolve(), delay))
我已经通过monkeypatch我的node_modules中的那一行来验证了这是一个问题,这样就可以在没有计时器的情况下立即解决问题,如下所示:
new Promise<void>(resolve => resolve())
不幸的是,我的应用程序代码有一些重要的计时器,让测试套件实时等待它们是不可行的。即使我可以,我怀疑那些后来发现这个问题的人可能没有这样的自由。
运行Jest的假计时器以允许用户事件继续进行是不起作用的,如下所示:
it(`fires onClick prop function when the button is clicked`, async () => {
jest.useFakeTimers()
let propFn = jest.fn()
let app = RTL.render(
<SampleComp onClick={propFn} />
)
let userAction = userEvent.click(app.queryByText('Test button')!)
jest.runOnlyPendingTimers() // no good
jest.runAllTimers() // also no good
await userAction
expect(propFn).toHaveBeenCalled()
jest.useRealTimers()
})
那么,如何将Jest的假计时器与用户事件库结合使用呢?
在这种情况下,版本似乎确实很重要:这个测试在早期版本的React、Jest和user-event上运行得很好。下面是我现在使用的版本(在这里中断),以及我正在使用的版本(在这里正常工作):
| 图书馆|电流(休息)|上一个(已完成)|
| - -| - -| - -|
| 开玩笑|v27.5.1|v26.6.3|
| React了|v18.1.0|v16.13.1|
| @测试库/用户事件|v14.3.0|v12.8.3|
我需要注意的是,它是不可能改变正在使用的软件包版本。我需要一个解决方案,工作与特定版本中列出的"当前"列。
注意:我认为这个问题并不是React特有的,使用Vue或Svelte或其他任何东西的人,只要他们使用Jest的假定时器+用户事件(两者都是框架不可知的),就会有同样的问题。
2条答案
按热度按时间guicsvcw1#
您可以使用
user-event
设置功能禁用延迟:然后确保使用
setup()
返回的示例:mkh04yzy2#
您是否尝试过以下操作:
在我的情况下,如果没有设置它就不工作。更多这里Mocking setTimeout with Jest