reactjs - 使用 React 和 jest 将状态钩子传递给子组件时如何测试副作用?
问题描述
我想测试一个子组件,但它依赖于父组件的状态(挂钩)。
孩子接收isModalOpen
和setIsModalOpen
作为属性。每次isModalOpen
变化,useEffect
里面Child
都会触发。但是,当我尝试自行测试Child
组件时,我无法强制更改触发useEffect
钩子的状态。如何在无需Parent
在测试环境中渲染的情况下实现这一点?
在下面的示例中,我可以通过 render 使测试通过Parent
。我只想渲染Child
,并且仍然通过测试。
function Child({ isModalOpen, setIsModalOpen }) {
useEffect(() => {
console.log("is the modal open?", isModalOpen);
}, [isModalOpen]);
return (
<button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
Click to {isModalOpen ? "close" : "open"} modal
</button>
);
}
function Parent() {
const [isModalOpen, setIsModalOpen] = useState(false);
return <Child isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} />;
}
测试:
it("React test", () => {
let isModalOpen = false;
const mockFunction = jest.fn((val) => (isModalOpen = val));
const { queryByTestId } = render(
<Child isModalOpen={isModalOpen} setIsModalOpen={mockFunction} />
);
const btnEl = queryByTestId("myBtn");
btnEl.click();
expect(btnEl.innerHTML).toEqual("Click to close modal");
// -----
// -----
// -----
// ----- The below code works
// const { queryByTestId } = render(<Parent />);
// const btnEl = queryByTestId("myBtn");
// btnEl.click();
// expect(btnEl.innerHTML).toEqual("Click to close modal");
});
这是上述代码片段的一个工作示例: https ://codesandbox.io/s/jest-test-forked-cjm3r?file=/index.test.js
解决方案
实际上总结一下,如果钩子传递给孩子,你试图测试的内容与钩子无关。把孩子想象成你的测试对象;换句话说,它是您要测试的唯一内容。根据定义,“钩子”是无关紧要的。您传入一个函数,您可以断言已使用正确值调用的函数。
总结一下,你有两种情况
- 当模态打开并单击“单击以关闭模态”按钮时,模态将关闭或以其他方式已知正在使用false调用您的模拟函数。
- 当模态关闭并单击“单击以关闭模态”按钮时,模态将打开或以其他方式已知正在调用您的模拟函数true。
我对您上面的测试进行了少量编辑以证明这一点。随意复制并粘贴它并自己检查,如果您有任何问题,请告诉我。
注意:从沙箱链接复制并粘贴,稍作修改,以免与原始代码有太大差异。
it("closes the modal when clicking on the button", () => {
function Child({ isModalOpen, setIsModalOpen }) {
useEffect(() => {
console.log("is the modal open?", isModalOpen);
}, [isModalOpen]);
return (
<button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
Click to {isModalOpen ? "close" : "open"} modal
</button>
);
}
// notice the mock here doesn't take arguments
const mockFunction = jest.fn();
const { queryByTestId } = render(
// notice that I've set the initial value for isModal to true
<Child isModalOpen={true} setIsModalOpen={mockFunction} />
);
const btnEl = queryByTestId("myBtn");
btnEl.click();
expect(btnEl.innerHTML).toEqual("Click to close modal");
// the assertion here
expect(mockFunction).toHaveBeenCalledWith(false);
});
it("opens the modal when clicking on the bottom", () => {
function Child({ isModalOpen, setIsModalOpen }) {
useEffect(() => {
console.log("is the modal open?", isModalOpen);
}, [isModalOpen]);
return (
<button data-testId="myBtn" onClick={() => setIsModalOpen(!isModalOpen)}>
Click to {isModalOpen ? "close" : "open"} modal
</button>
);
}
const mockFunction = jest.fn();
const { queryByTestId } = render(
// notice that I've set the initial value for isModal to false
<Child isModalOpen={false} setIsModalOpen={mockFunction} />
);
const btnEl = queryByTestId("myBtn");
btnEl.click();
expect(btnEl.innerHTML).toEqual("Click to open modal");
// the assertion here
expect(mockFunction).toHaveBeenCalledWith(true);
});
推荐阅读
- git - 当签出和推送回购的不同分支时,您计算机上的明显文件如何变化?
- python - set_camera_info 在 ubuntu 16.04 上不适用于 ROS
- python - 迁移学习 - 尝试在 RTX 2070 上重新训练efficientnet-B07 内存不足
- odoo - 在向导中显示模型的 one2many 值
- django - Django Machina 模板面临的问题
- typescript - 可以在 Typescript 中导出导入的合并命名空间吗?
- python - 难以让我的代码正确运行
- python - 混洗字符串的输出打印在 2 行输出中
- reactjs - 如何在反应自动建议中仅呈现 5 个项目?
- javascript - 快速服务器 POST 方法和登录时获取未定义值的问题