cre*_*lus 7 javascript reactjs jestjs react-testing-library react-hooks
我正在渲染一个元素,该元素利用 setTimeout 将内部文本从加载状态更改为所需的消息:
function Message({ message }: any) {
const [showMessage, setShowMessage] = useState(false);
useEffect(() => {
const CTATimer = setTimeout(() => {
setShowMessage(true);
}, 1500);
return () => {
clearTimeout(CTATimer);
};
}, []);
if (!showMessage) {
return <p>Loading...</p>;
}
return (
<>
<div>{message.text}</div>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
相应的测试渲染,然后将时间提前 1500 毫秒,然后应该显示消息。然而,目前测试失败,终端显示文本仍然是Loading...
。测试是这样写的:
const mockMessage = {
text: "this is a message",
answers: [],
id: 1,
};
afterEach(() => {
jest.useRealTimers();
});
it("should show message after setTimeout", () => {
jest.useFakeTimers();
jest.advanceTimersByTime(1500);
customRender(<Message message={mockMessage} />); // my customRender is just the default render but with a ThemeProvider wrapper.
const message = screen.getByText(/this is a message/i);
expect(message).toBeInTheDocument();
});
Run Code Online (Sandbox Code Playgroud)
为什么我的测试在 1500 毫秒过去后仍然呈现加载状态?
如果使用异步测试,因为您需要用于userEvent
打字等。我在此博客上找到了一个解决方案:https ://onestepcode.com/testing-library-user-event-with-fake-timers/
诀窍是将delay
选项设置userEvent
为null
。
const user = userEvent.setup({ delay: null });
Run Code Online (Sandbox Code Playgroud)
这是一个完整的测试用例
test("Pressing the button hides the text (fake timers)", async () => {
const user = userEvent.setup({ delay: null });
jest.useFakeTimers();
render(<Demo />);
const button = screen.getByRole("button");
await user.click(button);
act(() => {
jest.runAllTimers();
});
const text = screen.queryByText("Hello World!");
expect(text).not.toBeInTheDocument();
jest.useRealTimers();
});
Run Code Online (Sandbox Code Playgroud)
您应该在渲染组件后提前计时器。此外,您应该调用jest.advanceTimersByTime()
内部act函数。否则,它会抛出警告:Warning: An update to Message inside a test was not wrapped in act(...).
index.tsx
:
import React from \'react\';\nimport { useEffect, useState } from \'react\';\n\nexport function Message({ message }: any) {\n const [showMessage, setShowMessage] = useState(false);\n\n useEffect(() => {\n const CTATimer = setTimeout(() => {\n setShowMessage(true);\n }, 1500);\n return () => {\n clearTimeout(CTATimer);\n };\n }, []);\n\n if (!showMessage) {\n return <p>Loading...</p>;\n }\n\n return (\n <>\n <div>{message.text}</div>\n </>\n );\n}\n
Run Code Online (Sandbox Code Playgroud)\nindex.test.tsx
:
import React from \'react\';\nimport { render, screen, act } from \'@testing-library/react\';\nimport \'@testing-library/jest-dom/extend-expect\';\nimport { Message } from \'./\';\n\ndescribe(\'Message\', () => {\n const mockMessage = {\n text: \'this is a message\',\n answers: [],\n id: 1,\n };\n\n afterEach(() => {\n jest.useRealTimers();\n });\n\n it(\'should show message after setTimeout\', () => {\n jest.useFakeTimers();\n render(<Message message={mockMessage} />);\n act(() => {\n jest.advanceTimersByTime(1500);\n });\n const message = screen.getByText(/this is a message/i);\n expect(message).toBeInTheDocument();\n });\n});\n
Run Code Online (Sandbox Code Playgroud)\n测试结果:
\nimport React from \'react\';\nimport { useEffect, useState } from \'react\';\n\nexport function Message({ message }: any) {\n const [showMessage, setShowMessage] = useState(false);\n\n useEffect(() => {\n const CTATimer = setTimeout(() => {\n setShowMessage(true);\n }, 1500);\n return () => {\n clearTimeout(CTATimer);\n };\n }, []);\n\n if (!showMessage) {\n return <p>Loading...</p>;\n }\n\n return (\n <>\n <div>{message.text}</div>\n </>\n );\n}\n
Run Code Online (Sandbox Code Playgroud)\n
归档时间: |
|
查看次数: |
13537 次 |
最近记录: |