您可以将useUser
钩子放在组件内。将一些道具传递给这个组件并检查。稍后,传递新的 props 以重新渲染组件并再次检查是否getUserSpy
被多次调用。
此外,我们使用MemoryRouter
with initial entries 而不是 mockinguseParams
来提供 URL 参数。
我们测试的预期结果是:无论组件渲染多少次,由于dispatch
和user
参数是稳定的,钩子中的useEffect
inuseUser
只会执行一次。
例如
useUser.ts
:
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { useParams } from 'react-router-dom';
import * as slice from './slice';
export const useUser = (): void => {
const dispatch = useDispatch();
const { user } = useParams<{ user: string }>();
useEffect(() => {
dispatch(slice.getUser(user));
}, [dispatch, user]);
};
slice.ts
:
export const getUser = (user) => ({ type: 'GET_USER', payload: user });
useUser.test.tsx
:
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import React from 'react';
import { Provider } from 'react-redux';
import { MemoryRouter, Route } from 'react-router-dom';
import { createStore } from 'redux';
import * as slice from './slice';
import { useUser } from './useUser';
describe('useUser', () => {
test('should pass', () => {
const getUserSpy = jest.spyOn(slice, 'getUser');
function TestComp(props) {
console.log(props);
useUser();
return null;
}
const store = createStore(() => ({}));
const { rerender } = renderHook(TestComp, {
initialProps: { data: '1' },
wrapper: ({ children }) => (
<Provider store={store}>
<MemoryRouter initialEntries={['/test']}>
<Route path="/:user">{children}</Route>
</MemoryRouter>
</Provider>
),
});
expect(getUserSpy).toBeCalledWith('test');
rerender({ data: '2' });
expect(getUserSpy).toBeCalledTimes(1);
});
});
测试结果:
PASS stackoverflow/70928091/useUser.test.tsx (7.748 s)
useUser
✓ should pass (39 ms)
console.log
{ data: '1' }
at TestComp (stackoverflow/70928091/useUser.test.tsx:14:15)
console.log
{ data: '2' }
at TestComp (stackoverflow/70928091/useUser.test.tsx:14:15)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
slice.ts | 100 | 100 | 100 | 100 |
useUser.ts | 100 | 100 | 100 | 100 |
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.253 s, estimated 9 s