如何使用 Jest 使用新的 React Router Hooks 模拟 history.push
How to mock history.push with the new React Router Hooks using Jest
我正在尝试在 react-router
上的新 useHistory
挂钩中模拟 history.push
并使用 @testing-library/react
。我只是像这里的第一个答案一样嘲笑模块:
所以我在做:
//NotFound.js
import * as React from 'react';
import { useHistory } from 'react-router-dom';
const RouteNotFound = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/help')} />
</div>
);
};
export default RouteNotFound;
//NotFound.test.js
describe('RouteNotFound', () => {
it('Redirects to correct URL on click', () => {
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
const { getByRole } = render(
<MemoryRouter>
<RouteNotFound />
</MemoryRouter>
);
fireEvent.click(getByRole('button'));
expect(mockHistoryPush).toHaveBeenCalledWith('/help');
});
})
但是mockHistoryPush
没有被调用...我做错了什么?
在模块范围内使用jest.mock
会自动提升到代码块的顶部。这样您就可以在 NotFound.jsx
文件和您的测试文件中获得模拟版本 react-router-dom
。
此外,我们只想mock useHistory
hook,所以我们应该使用jest.requireActual()
获取原始模块,其他方法保持原始版本。
解决方法如下:
NotFound.jsx
:
import React from 'react';
import { useHistory } from 'react-router-dom';
const RouteNotFound = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/help')} />
</div>
);
};
export default RouteNotFound;
NotFound.test.jsx
:
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, fireEvent } from '@testing-library/react';
import RouteNotFound from './NotFound';
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
describe('RouteNotFound', () => {
it('Redirects to correct URL on click', () => {
const { getByRole } = render(
<MemoryRouter>
<RouteNotFound />
</MemoryRouter>,
);
fireEvent.click(getByRole('button'));
expect(mockHistoryPush).toHaveBeenCalledWith('/help');
});
});
100% 覆盖率的单元测试结果:
PASS src/Whosebug/58524183/NotFound.test.jsx
RouteNotFound
✓ Redirects to correct URL on click (66ms)
--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
NotFound.jsx | 100 | 100 | 100 | 100 | |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.133s, estimated 11s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/Whosebug/58524183
您实际上不需要模拟 react-router-dom
(至少对于 v5),因为它提供了一堆测试工具:https://v5.reactrouter.com/web/guides/testing
要检查您的历史记录是否实际更改,您可以使用 createMemoryHistory
并检查其内容:
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Menu } from './Menu';
import { createMemoryHistory } from 'history'
import { Router } from 'react-router-dom';
test('triggers path change', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
<Menu />
</Router>
);
const aboutItem = screen.getByText('About');
expect(aboutItem).toBeInTheDocument();
userEvent.click(aboutItem);
expect(history.length).toBe(2);
expect(history.location.pathname).toBe('/about');
});
这可能会有帮助。您可以使用 jest.fn() 来模拟 history.push().
const historyMock = { push: jest.fn() }
expect(historyMock.push.mock.calls[0]).toEqual([
{
pathname: "/profile", // URL
search: , // search-data
},
]);
我正在尝试在 react-router
上的新 useHistory
挂钩中模拟 history.push
并使用 @testing-library/react
。我只是像这里的第一个答案一样嘲笑模块:
所以我在做:
//NotFound.js
import * as React from 'react';
import { useHistory } from 'react-router-dom';
const RouteNotFound = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/help')} />
</div>
);
};
export default RouteNotFound;
//NotFound.test.js
describe('RouteNotFound', () => {
it('Redirects to correct URL on click', () => {
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
const { getByRole } = render(
<MemoryRouter>
<RouteNotFound />
</MemoryRouter>
);
fireEvent.click(getByRole('button'));
expect(mockHistoryPush).toHaveBeenCalledWith('/help');
});
})
但是mockHistoryPush
没有被调用...我做错了什么?
在模块范围内使用jest.mock
会自动提升到代码块的顶部。这样您就可以在 NotFound.jsx
文件和您的测试文件中获得模拟版本 react-router-dom
。
此外,我们只想mock useHistory
hook,所以我们应该使用jest.requireActual()
获取原始模块,其他方法保持原始版本。
解决方法如下:
NotFound.jsx
:
import React from 'react';
import { useHistory } from 'react-router-dom';
const RouteNotFound = () => {
const history = useHistory();
return (
<div>
<button onClick={() => history.push('/help')} />
</div>
);
};
export default RouteNotFound;
NotFound.test.jsx
:
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, fireEvent } from '@testing-library/react';
import RouteNotFound from './NotFound';
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockHistoryPush,
}),
}));
describe('RouteNotFound', () => {
it('Redirects to correct URL on click', () => {
const { getByRole } = render(
<MemoryRouter>
<RouteNotFound />
</MemoryRouter>,
);
fireEvent.click(getByRole('button'));
expect(mockHistoryPush).toHaveBeenCalledWith('/help');
});
});
100% 覆盖率的单元测试结果:
PASS src/Whosebug/58524183/NotFound.test.jsx
RouteNotFound
✓ Redirects to correct URL on click (66ms)
--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
NotFound.jsx | 100 | 100 | 100 | 100 | |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 5.133s, estimated 11s
源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/Whosebug/58524183
您实际上不需要模拟 react-router-dom
(至少对于 v5),因为它提供了一堆测试工具:https://v5.reactrouter.com/web/guides/testing
要检查您的历史记录是否实际更改,您可以使用 createMemoryHistory
并检查其内容:
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Menu } from './Menu';
import { createMemoryHistory } from 'history'
import { Router } from 'react-router-dom';
test('triggers path change', () => {
const history = createMemoryHistory();
render(
<Router history={history}>
<Menu />
</Router>
);
const aboutItem = screen.getByText('About');
expect(aboutItem).toBeInTheDocument();
userEvent.click(aboutItem);
expect(history.length).toBe(2);
expect(history.location.pathname).toBe('/about');
});
这可能会有帮助。您可以使用 jest.fn() 来模拟 history.push().
const historyMock = { push: jest.fn() }
expect(historyMock.push.mock.calls[0]).toEqual([
{
pathname: "/profile", // URL
search: , // search-data
},
]);