如何使用react-testing-library和jest与mock自定义react钩子更新? &g



看下面的自定义钩子。前提是当query发生变化时,它会更新自己的状态。

export function UseCustomHook() {
const { query } = useRouter()
const [state, setState] = useState({})
useEffect(() => {
const updatedState = helperFunction(query)
setState(updatedState)
}, [query])
return state
}

目标是模拟useRouter,但同时也更新它来专门测试"助手函数被调用n次,当查询更新n次">

我们可以用

模拟模块useRouter
jest.mock('next/router', () => ({
useRouter() {
return {
route: '/',
pathname: '',
query: {...},
asPath: '',
}
},
}))

但是这只是把它当作一个普通的模块。我想把它模拟成一个钩子,然后在

下面的测试中更新它
describe('useCustomHook', () => {
it('should call helperFunction when query updates', () => {
const query = {...}
jest.spyOn(Router, 'useRouter' as any).mockImplementation(() => ({ query }))

const { result } = renderHook(() => useCustomHook())
expect(...)  
})
})

您可以使用jest.mock()模拟next/router模块,useRouter钩子及其返回值。在我们改变了query的值之后,我们应该调用renderer函数来重新渲染自定义钩子,这样useEffect钩子就会使用新的query作为它的依赖项。

此外,我使用jest.spyOn()添加spy onconsole.count()方法来检查effect函数调用的次数。

useCustomHook.ts:

import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
export function useCustomHook() {
const { query } = useRouter();
const [state, setState] = useState({});
useEffect(() => {
console.count('effect');
setState({ id: query.id });
}, [query]);
return state;
}

useCustomHook.test.ts:

import { useRouter } from 'next/router';
import { renderHook } from '@testing-library/react-hooks';
import { useCustomHook } from './useCustomHook';
import { mocked } from 'ts-jest/utils';
import { NextRouter } from 'next/dist/next-server/lib/router/router';
jest.mock('next/router');
const useMockRouter = mocked(useRouter);
describe('68660313', () => {
test('should pass', () => {
const countSpy = jest.spyOn(console, 'count');
const query1 = ({ query: { id: '1' } } as unknown) as NextRouter;
const query2 = ({ query: { id: '2' } } as unknown) as NextRouter;
useMockRouter.mockReturnValue(query1);
const { result, rerender } = renderHook(() => useCustomHook());
expect(result.current).toEqual({ id: '1' });
useMockRouter.mockReturnValue(query2);
rerender();
expect(result.current).toEqual({ id: '2' });
expect(countSpy).toBeCalledTimes(2);
});
});

测试结果:

PASS  examples/68660313/useCustomHook.test.ts (7.664 s)
68660313
✓ should pass (32 ms)
console.count
effect: 1
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
console.count
effect: 2
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
------------------|---------|----------|---------|---------|-------------------
File              | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------------|---------|----------|---------|---------|-------------------
All files         |     100 |      100 |     100 |     100 |                   
useCustomHook.ts |     100 |      100 |     100 |     100 |                   
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        8.184 s

包的版本:

"next": "^11.0.1",
"jest": "^26.6.3",
"ts-jest": "^26.4.4",
"react": "^16.14.0",

最新更新