React 测试库文档说不需要在每次测试后进行清理,但是对于
renderHook
文档,如果在测试结束后调用 unmount 则不会说什么。
那么在使用
unmount
的测试中是否有必要调用 renderHook
呢?
cleanup
时不需要调用 RTL renderHook()
函数,从源码中我们知道它底层是通过 render
来调用
<TestComponent/>
函数的。所以
如果您使用的测试框架支持
cleanup
全局(如 mocha、Jest 和 Jasmine),则默认情况下会在每次测试后自动调用。afterEach
function renderHook(renderCallback, options = {}) {
const {initialProps, ...renderOptions} = options
if (renderOptions.legacyRoot && typeof ReactDOM.render !== 'function') {
const error = new Error(
'`legacyRoot: true` is not supported in this version of React. ' +
'If your app runs React 19 or later, you should remove this flag. ' +
'If your app runs React 18 or earlier, visit https://react.dev/blog/2022/03/08/react-18-upgrade-guide for upgrade instructions.',
)
Error.captureStackTrace(error, renderHook)
throw error
}
const result = React.createRef()
function TestComponent({renderCallbackProps}) {
const pendingResult = renderCallback(renderCallbackProps)
React.useEffect(() => {
result.current = pendingResult
})
return null
}
const {rerender: baseRerender, unmount} = render(
<TestComponent renderCallbackProps={initialProps} />,
renderOptions,
)
function rerender(rerenderCallbackProps) {
return baseRerender(
<TestComponent renderCallbackProps={rerenderCallbackProps} />,
)
}
return {result, rerender, unmount}
}
如果你想测试
cleanup
钩子的useEffect()
函数中的代码逻辑,你应该调用ummount()
函数。请看下面的例子:
import { renderHook, screen } from '@testing-library/react';
import React, { useEffect } from 'react';
describe('78435539', () => {
test('should pass', () => {
const Context = React.createContext('default');
function Wrapper({ children }) {
return (
<Context.Provider value="provided">
<h1>Provider 1</h1>
{children}
</Context.Provider>
);
}
const { result } = renderHook(() => React.useContext(Context), { wrapper: Wrapper });
expect(result.current).toEqual('provided');
screen.debug();
});
test('should pass 2', () => {
const Context = React.createContext('default');
function Wrapper({ children }) {
return (
<Context.Provider value="provided">
<h1>Provider 2</h1>
{children}
</Context.Provider>
);
}
const { result } = renderHook(() => React.useContext(Context), { wrapper: Wrapper });
expect(result.current).toEqual('provided');
screen.debug();
});
test('should pass 3', () => {
let count = 0;
const { unmount } = renderHook(() => {
useEffect(() => {
const onClick = () => {
count++;
};
document.body.addEventListener('click', onClick);
return () => {
document.body.removeEventListener('click', onClick);
};
}, []);
});
document.body.click();
expect(count).toBe(1);
unmount();
document.body.click();
expect(count).toBe(1);
});
});
测试结果:
> jest -o
console.log
<body>
<div>
<h1>
Provider 1
</h1>
</div>
</body>
at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:87:13)
console.log
<body>
<div>
<h1>
Provider 2
</h1>
</div>
</body>
at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:87:13)
PASS stackoverflow/78435539/index.test.tsx
78435539
√ should pass (32 ms)
√ should pass 2 (5 ms)
√ should pass 3 (2 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.044 s
Ran all test suites related to changed files.