异步事件处理程序中未调用模拟的 useHistory
Mocked useHistory is not called in async event handler
总结
我正在为我的 React 应用程序编写测试代码,但不知何故,它总是失败。
我的应用程序代码非常简单,只有一个按钮,如果单击它,就会触发一个函数handleSubmit
。
处理程序的作用是
- 正在从后端获取数据(这是异步函数)
- 移至
/complete
页。
我做了什么
- 我在测试代码
中模拟了从API获取数据的函数
- 我在测试代码中嘲笑了
useHistory
备注
我意识到如果从 API 获取数据的行被注释掉,测试就会通过。
代码
- 我的主要应用程序代码
import { useFetchDataFromAPI } from '@/usecase/useFetchDataFromAPI';
:
const { fetchDataFromAPI } = useFetchDataFromAPI();
:
const handleSubmit = async () => {
// If the line below is not commented out, test will fail
// const { id } = await fetchDataFromAPI();
history.push(`/complete`);
};
return (
<>
<button onClick={handleSubmit}>Button</button>
</>
- 我的测试代码
:
jest.mock('@/usecase/useFetchDataFromAPI', () => ({
useFetchDataFromAPI: () => {
return { fetchDataFromAPI: jest.fn((): number => {
return 1;
})}
}
}));
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom') as any,
useHistory: () => ({
push: mockHistoryPush,
}),
}));
:
const renderApplicationWithRouterHistory = () => {
const history = createMemoryHistory();
const wrapper = render(
<Router history={history}>
<Application />
</Router>
);
return { ...wrapper, history };
};
:
describe('Test onClick handler', async () => {
test('Submit', () => {
const { getByText, getByRole } = renderApplication();
const elementSubmit = getByText('Button');
expect(elementSubmit).toBeInTheDocument();
fireEvent.click(elementSubmit);
expect(mockHistoryPush).toHaveBeenCalled();
});
});
您的事件处理程序在单击按钮时被调用,但由于它是异步的,因此直到您的测试运行 之后才会评估其结果。在这种特殊情况下,您不需要异步行为,因此只需使用:
const handleSubmit = () => {
history.push(`/complete`)
}
testing-library
提供了一个方法 waitFor 如果你的处理程序确实需要 await
一些东西:
await waitFor(() => expect(mockHistoryPush).toHaveBeenCalled())
尽管另一种简单的方法是在测试中简单地等待一个承诺,这样期望就会延迟一个滴答声:
fireEvent.click(elementSubmit);
await Promise.resolve();
expect(mockHistoryPush).toHaveBeenCalled();
总结
我正在为我的 React 应用程序编写测试代码,但不知何故,它总是失败。
我的应用程序代码非常简单,只有一个按钮,如果单击它,就会触发一个函数handleSubmit
。
处理程序的作用是
- 正在从后端获取数据(这是异步函数)
- 移至
/complete
页。
我做了什么
- 我在测试代码 中模拟了从API获取数据的函数
- 我在测试代码中嘲笑了
useHistory
备注
我意识到如果从 API 获取数据的行被注释掉,测试就会通过。
代码
- 我的主要应用程序代码
import { useFetchDataFromAPI } from '@/usecase/useFetchDataFromAPI';
:
const { fetchDataFromAPI } = useFetchDataFromAPI();
:
const handleSubmit = async () => {
// If the line below is not commented out, test will fail
// const { id } = await fetchDataFromAPI();
history.push(`/complete`);
};
return (
<>
<button onClick={handleSubmit}>Button</button>
</>
- 我的测试代码
:
jest.mock('@/usecase/useFetchDataFromAPI', () => ({
useFetchDataFromAPI: () => {
return { fetchDataFromAPI: jest.fn((): number => {
return 1;
})}
}
}));
const mockHistoryPush = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom') as any,
useHistory: () => ({
push: mockHistoryPush,
}),
}));
:
const renderApplicationWithRouterHistory = () => {
const history = createMemoryHistory();
const wrapper = render(
<Router history={history}>
<Application />
</Router>
);
return { ...wrapper, history };
};
:
describe('Test onClick handler', async () => {
test('Submit', () => {
const { getByText, getByRole } = renderApplication();
const elementSubmit = getByText('Button');
expect(elementSubmit).toBeInTheDocument();
fireEvent.click(elementSubmit);
expect(mockHistoryPush).toHaveBeenCalled();
});
});
您的事件处理程序在单击按钮时被调用,但由于它是异步的,因此直到您的测试运行 之后才会评估其结果。在这种特殊情况下,您不需要异步行为,因此只需使用:
const handleSubmit = () => {
history.push(`/complete`)
}
testing-library
提供了一个方法 waitFor 如果你的处理程序确实需要 await
一些东西:
await waitFor(() => expect(mockHistoryPush).toHaveBeenCalled())
尽管另一种简单的方法是在测试中简单地等待一个承诺,这样期望就会延迟一个滴答声:
fireEvent.click(elementSubmit);
await Promise.resolve();
expect(mockHistoryPush).toHaveBeenCalled();