如何用 jest 和 react-testing-library 测试 react-toastify
How to test react-toastify with jest and react-testing-library
我有一个带有某种形式的屏幕,在提交时,我使用 axios 将请求发送到后端。成功收到响应后,我用 react-toastify 祝酒。非常简单的屏幕。但是,当我尝试使用 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-testing-library 填写表格,按下提交按钮,然后等待 toast 出现。我正在使用 mock service worker 来模拟响应。我确认响应返回正常,但由于某种原因,toast 拒绝显示。我目前的测试如下:
expect(await screen.findByRole("alert")).toBeInTheDocument();
我正在寻找具有角色警报的元素。但这似乎不起作用。
另外,我尝试做这样的事情:
...
beforeAll(() => {
jest.useFakeTimers();
}
...
it("test", () => {
...
act(() =>
jest.runAllTimers();
)
expect(await screen.findByRole("alert")).toBeInTheDocument();
}
我是 JS 的新手,问题可能是由于 axios 和 react-toastify 的异步性质造成的,但我不知道如何测试这种行为。我尝试了很多东西,包括模拟计时器和 运行 它们,模拟计时器并推进它们,而不是模拟它们并等待等。我什至尝试模拟 toast 的调用,但我无法让它正常工作.另外,这似乎是一个实现细节,所以我不认为我应该嘲笑它。
我认为问题是我在 axios promise 解决后展示了 toast,所以计时器不知何故变得混乱。
找了很多地方都没有找到答案。
提前致谢。
谢谢@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 似乎不起作用,但我太累了,无法深入挖掘:)
我不必使用任何假计时器或兑现承诺。显然,当您使用 await 和 finBy* 查询时,RTL 已经执行了这些操作,只是渲染顺序错误。
我要做的是模拟 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()
})
我有一个带有某种形式的屏幕,在提交时,我使用 axios 将请求发送到后端。成功收到响应后,我用 react-toastify 祝酒。非常简单的屏幕。但是,当我尝试使用 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-testing-library 填写表格,按下提交按钮,然后等待 toast 出现。我正在使用 mock service worker 来模拟响应。我确认响应返回正常,但由于某种原因,toast 拒绝显示。我目前的测试如下:
expect(await screen.findByRole("alert")).toBeInTheDocument();
我正在寻找具有角色警报的元素。但这似乎不起作用。 另外,我尝试做这样的事情:
...
beforeAll(() => {
jest.useFakeTimers();
}
...
it("test", () => {
...
act(() =>
jest.runAllTimers();
)
expect(await screen.findByRole("alert")).toBeInTheDocument();
}
我是 JS 的新手,问题可能是由于 axios 和 react-toastify 的异步性质造成的,但我不知道如何测试这种行为。我尝试了很多东西,包括模拟计时器和 运行 它们,模拟计时器并推进它们,而不是模拟它们并等待等。我什至尝试模拟 toast 的调用,但我无法让它正常工作.另外,这似乎是一个实现细节,所以我不认为我应该嘲笑它。
我认为问题是我在 axios promise 解决后展示了 toast,所以计时器不知何故变得混乱。
找了很多地方都没有找到答案。
提前致谢。
谢谢@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 似乎不起作用,但我太累了,无法深入挖掘:) 我不必使用任何假计时器或兑现承诺。显然,当您使用 await 和 finBy* 查询时,RTL 已经执行了这些操作,只是渲染顺序错误。
我要做的是模拟 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()
})