我有一个带有一些表单的屏幕,在提交时,我用axios将请求发送到后端。在成功收到回复后,我展示了一个带有react toast ify的吐司。相当直接的屏幕。然而,当我尝试使用jest和react测试库进行集成测试来测试这种行为时,我似乎无法使toast出现在DOM上。
我有一个像这样的实用程序渲染器来渲染我正在用toast容器测试的组件:
import {render} from "@testing-library/react";
import React from "react";
import {ToastContainer} from "react-toastify";
export const renderWithToastify = (component) => (
render(
<div>
{component}
<ToastContainer/>
</div>
)
);
在测试本身中,我用react测试库填充表单,按下提交按钮,等待toast出现。我使用模拟服务人员来模拟响应。我确认回复正常,但由于某种原因,祝酒词拒绝出现。我目前的测试如下:
expect(await screen.findByRole("alert")).toBeInTheDocument();
我正在寻找一个具有角色警报的元素。但这似乎不起作用。此外,我试着做这样的事情:
...
beforeAll(() => {
jest.useFakeTimers();
}
...
it("test", () => {
...
act(() =>
jest.runAllTimers();
)
expect(await screen.findByRole("alert")).toBeInTheDocument();
}
我对JS有点陌生,这个问题可能是由于axios和react toast ify的异步性质造成的,但我不知道如何测试这种行为。我尝试了很多事情,包括嘲笑计时器并运行它们,嘲笑计时器并推进它们,而不是嘲笑它们并等待等等。我甚至试图嘲笑祝酒词,但我无法正常工作。另外,这似乎是一个实现细节,所以我不认为我应该嘲笑它。
我认为问题是,我在axios承诺得到解决后展示了祝酒词,所以计时器不知何故会感到困惑。
我试着找了很多地方,但都没找到答案。
提前谢谢。
谢谢@Estus Flask,但问题要愚蠢得多:(我必须在组件之前渲染ToastContainer,如下所示:
import {render} from "@testing-library/react";
import React from "react";
import {ToastContainer} from "react-toastify";
export const renderWithToastify = (component) => {
return (
render(
<div>
<ToastContainer/>
{component}
</div>
)
);
};
然后,测试非常简单,我只需要等待吐司的标题:
expect(await screen.findByText("alert text")).toBeInTheDocument();
findByRole似乎由于某种原因不起作用,但我太累了,无法深入挖掘:(我不必使用任何假计时器或兑现承诺。有趣的是,RTL已经在使用wait和finBy*查询时执行了这些操作,只是渲染顺序错误。
当您无法访问DOM时(如Redux副作用(,为了使用mock,您可以执行以下操作:
import { toast } from 'react-toastify'
jest.mock('react-toastify', () => ({
toast: {
success: jest.fn(),
},
}))
expect(toast.success).toHaveBeenCalled()
我要做的是模拟react-toastify
中的方法来监视该方法,看看它被称为什么,但不是屏幕上出现的实际组件:
// setupTests.js
jest.mock('react-toastify', () => {
const actual = jest.requireActual('react-toastify');
Object.assign(actual, {toast: jest.fn()});
return actual;
});
然后在实际测试中:
// test.spec.js
import {toast} from 'react-toastify';
const toastCalls = []
const spy = toast.mockImplementation((...args) => {
toastCalls.push(args)
}
)
describe('...', () => {
it('should ...', () => {
// do something that calls the toast
...
// then
expect(toastCalls).toEqual(...)
}
}
)
另一个建议是将这个mockImplementation
放入一个单独的助手函数中,您可以很容易地调用它来进行所需的测试这是一种熊骨头的方法:
function startMonitoring() {
const monitor = {toast: [], log: [], api: [], navigation: []};
toast.mockImplementation((...args) => {
monitor.toast.push(args);
});
log.mockImplementation((...args) => {
monitor.log.push(args);
});
api.mockImplementation((...args) => {
monitor.api.push(args);
});
navigation.mockImplementation((...args) => {
monitor.navigation.push(args);
});
return () => monitor;
}
it('should...', () => {
const getSpyCalls = startMonitoring();
// do something
expect(getSpyCalls()).toEqual({
toast: [...],
log: [...],
api: [...],
navigation: [...]
});
});
这里,解决方案是使用getByText:
await waitFor(() => {
expect(screen.getByText(/Logged!/i)).toBeTruthy()
})