调度自定义事件并测试它是不是被正确触发(React TypeScript,Jest)
Posted
技术标签:
【中文标题】调度自定义事件并测试它是不是被正确触发(React TypeScript,Jest)【英文标题】:Dispatch a Custom Event and test if it was correctly triggered (React TypeScript, Jest)调度自定义事件并测试它是否被正确触发(React TypeScript,Jest) 【发布时间】:2022-01-20 19:32:42 【问题描述】:我正在尝试验证位于反应函数 useEffect 挂钩内的自定义事件侦听器,如下所示:
export interface specialEvent extends Event
detail?: string
function Example()
React.useEffect(()=>
document.addEventListener('specialEvent', handleChange)
return () =>
document.removeEventListener('specialEvent',handleChange)
)
const handleChange = (event:SpecialEvent) =>
...
我想触发这个自定义事件监听器并开玩笑地测试它:
it('should trigger "specialEvent" event Listener Properly', async () =>
const specialEvent = new CustomEvent('specialEvent')
const handleChange = jest.fn()
render(<Example />)
await waitFor(() =>
window.document.dispatchEvent(specialEvent)
expect(window.document.dispatchEvent).toHaveBeenNthCalledWith(1, 'specialEvent')
expect(specialEvent).toHaveBeenCalledTimes(1)
)
)
这段代码给了我以下错误:
expect(received).toHaveBeenNthCalledWith(n, ...expected)
Matcher error: received value must be a mock or spy function
Received has type: function
Received has value: [Function dispatchEvent]
按照其中一个答案的建议,我尝试了这个:
//Assert Statements
const specialEvent = new CustomEvent('specialEvent');
const handleSelect = jest.fn();
act(() =>
render(<Example />)
);
await waitFor(() =>
window.document.dispatchEvent(specialEvent)
expect(handleSelect).toHaveBeenCalledTimes(1)
);
但这一次它说预期的呼叫是 1 但收到的是 0。
谁能帮我解决这个问题?
【问题讨论】:
【参考方案1】:在测试时,导致 React 状态更新的代码应该包装到 act(...)
中。如果 handleChange
不会导致 React 状态更新,则不需要使用 act
。
此外,最好不要测试实现细节,对于您的情况,测试实现细节语句是:
expect(window.document.dispatchEvent).toHaveBeenNthCalledWith(1, 'specialEvent')
expect(specialEvent).toHaveBeenCalledTimes(1)
对实现细节的每一个小改动都会导致需要修改测试用例。我们应该从用户的角度来测试 UI,用户并不关心 UI 的实现细节,只关心 UI 的正确渲染。
您应该测试的是:当触发自定义事件并且在事件处理程序中更改状态时,组件的输出会发生什么。
例如
index.tsx
:
import React, useState from 'react';
export interface SpecialEvent extends Event
detail?: string;
export function Example()
const [changed, setChanged] = useState(false);
React.useEffect(() =>
document.addEventListener('specialEvent', handleChange);
return () =>
document.removeEventListener('specialEvent', handleChange);
;
);
const handleChange = (event: SpecialEvent) =>
console.log(event);
setChanged((pre) => !pre);
;
return <div>changed ? 'a' : 'b'</div>;
index.test.tsx
:
import render, screen, act from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import Example from './';
describe('70400540', () =>
test('should pass', () =>
const specialEvent = new CustomEvent('specialEvent');
render(<Example />);
expect(screen.getByText('b')).toBeInTheDocument();
act(() =>
window.document.dispatchEvent(specialEvent);
);
expect(screen.getByText('a')).toBeInTheDocument();
);
);
window.document.dispatchEvent(specialEvent)
会导致 React 状态发生变化,所以我们将其包装成 act(...)
。
测试结果:
PASS examples/70400540/index.test.tsx (11.259 s)
70400540
✓ should pass (59 ms)
console.log
CustomEvent isTrusted: [Getter]
at Document.handleChange (examples/70400540/index.tsx:16:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 12.655 s
软件包版本:
"@testing-library/react": "^11.2.2",
"react": "^16.14.0",
"jest": "^26.6.3",
【讨论】:
【参考方案2】:正如错误消息所述,toHaveBeenNthCalledWith
匹配器需要将mock 或间谍传递给expect
。
但是,您可能不需要对 window.document.dispatchEvent
被调用做出任何断言,因为您知道您在测试中的上述行中调用了它。
有关更多信息,请在此处查看toHaveBeenNthCalledWith
上的文档:https://jestjs.io/docs/expect#tohavebeennthcalledwithnthcall-arg1-arg2-
【讨论】:
我将代码更新为:expect(specialEvent).toHaveBeenCalledTimes(1)
,但它显示预期:1 调用:0。你知道可能出了什么问题:``` const specialEvent = new CustomEvent('specialEvent') const handleSelect = jest.fn() act(() => render(以上是关于调度自定义事件并测试它是不是被正确触发(React TypeScript,Jest)的主要内容,如果未能解决你的问题,请参考以下文章