Tom*_*Tom 11 javascript unit-testing settimeout jestjs user-event
我正在为 React 组件编写 Jest 测试,并使用该@testing-library/user-event库来模拟用户交互。除了使用 Jest 的假计时器的测试之外,这非常有效。
这是一个示例测试:
\nit(`fires onClick prop function when the button is clicked`, async () => {\n // jest.useFakeTimers()\n\n let propFn = jest.fn()\n\n let app = RTL.render(\n <SampleComp onClick={propFn} />\n )\n\n await userEvent.click(app.queryByText(\'Test button\')!)\n\n expect(propFn).toHaveBeenCalled()\n\n // jest.useRealTimers()\n})\nRun Code Online (Sandbox Code Playgroud)\n这是组件:
\nfunction SampleComp({ onClick }) {\n // a simple bridge for debugging\n function _onClick(e) {\n console.log(`_onClick invoked`)\n return onClick(e)\n }\n\n return (\n <button onClick={_onClick}>\n Test button\n </button>\n )\n}\nRun Code Online (Sandbox Code Playgroud)\n如果没有假计时器,测试将在不到一秒的时间内运行并通过。使用假计时器,测试会超时然后失败:
\n \xe2\x97\x8f fires onClick prop function when the button is clicked\n\n thrown: "Exceeded timeout of 5000 ms for a test.\n Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."\nRun Code Online (Sandbox Code Playgroud)\n它也无法发出调试行,因此显然单击事件从未被触发。
\n我已经完成了大量调试,并确定根本原因是用户事件库依赖于setTimeout内部在事件之间创建短暂的延迟。
是的,“事件”复数——回想一下用户事件库的价值主张是:
\n\n\n\n
fireEvent调度 DOM 事件,而user-event模拟完整的交互,这可能会触发多个事件并在此过程中进行额外的检查。
\n--用户事件文档
在本例中,用户事件为我创建了两个事件:
\n1虽然第一个事件的用户事件的内部事件对象只有 atarget和 no type,但对我来说,第一个事件是鼠标移动或鼠标悬停在按钮上是有意义的。无论如何:我已经验证用户事件内部创建的操作列表确实有 2 项,第二项明确标记为“[MouseLeft]”。
通过用户事件pointerAction函数在事件之间插入延迟在事件之间插入延迟。就我而言,用户事件在事件 1 和 2 之间的延迟期间停止。
超时是在用户事件的wait模块中创建的:
\xe2\x97\x8f fires onClick prop function when the button is clicked\n\n thrown: "Exceeded timeout of 5000 ms for a test.\n Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."\nRun Code Online (Sandbox Code Playgroud)\n我已经通过在我的 node_modules 中对该行进行猴子修补来验证这是问题所在,以便在没有计时器的情况下立即解决,如下所示:
\nnew Promise<void>(resolve => globalThis.setTimeout(() => resolve(), delay))\nRun Code Online (Sandbox Code Playgroud)\n不幸的是,我的应用程序代码有一些重要的计时器,它无法让测试套件实时等待它们。即使我可以,我怀疑后来发现这个问题的人可能也没有这种自由。
\n运行 Jest 的假计时器来允许用户事件继续进行是行不通的,如下所示:
\nnew Promise<void>(resolve => resolve())\nRun Code Online (Sandbox Code Playgroud)\n那么,如何将 Jest 的假定时器与用户事件库结合使用呢?
\n在这种情况下,版本似乎确实很重要:这个测试对于 React、Jest 和 user-event 的早期版本非常有效。以下是我现在正在使用的版本(其中有问题),以及我正在使用的版本(其中有效):
\n| 图书馆 | 电流 (断路) | 上一个 (工作过) |
|---|---|---|
| 笑话 | v27.5.1 | v26.6.3 |
| 反应 | v18.1.0 | v16.13.1 |
| @testing-library/用户事件 | v14.3.0 | v12.8.3 |
我应该注意的是,不可能更改正在使用的软件包版本。我需要一个适用于“当前”列中列出的特定版本的解决方案。
\n注意:我认为这个问题并不是 React 特有的,使用 Vue 或 Svelte 或其他任何东西的人只要使用 Jest 的假计时器 + 用户事件(它们都是与框架无关的)就会遇到相同的问题)。所以,我不会将其标记为 React。
\n小智 6
你尝试过这个吗:
const ue = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
Run Code Online (Sandbox Code Playgroud)
就我而言,如果没有设置它就不起作用。更多这里用 Jest 模拟 setTimeout
您可以使用设置功能禁用延迟user-event:
const user = userEvent.setup({ delay: null })
Run Code Online (Sandbox Code Playgroud)
确保使用返回的实例setup():
await user.click(app.queryByText('Test button')!)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2878 次 |
| 最近记录: |