我想测试一个子组件,但是它依赖于父组件的状态(钩子)。
子节点接收isModalOpen和setIsModalOpen作为属性。每次isModalOpen发生变化时,Child内部的useEffect都会触发。但是,当我试图单独测试Child组件时,我无法强制状态更改触发useEffect挂钩。我如何实现这一点而不必在测试环境中呈现Parent?
在下面的示例中,我可以通过呈现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
发布于 2021-04-19 03:52:37
实际上,总结一下,如果将钩子传递给孩子,那么您要测试的内容与钩子无关。把孩子想象成被测试的subject;换句话说,它是您唯一想要测试的东西。顾名思义,“钩子”是无关紧要的。传入一个函数,就可以断言调用了一个具有适当值的函数。
总之,你有两个案子
当
为了演示这一点,我对上面的测试做了一些小编辑。请随意复制和粘贴它,并为自己检查,并让我知道,如果你有问题。
注意:从沙箱链接中复制和粘贴,只需稍作修改,以避免与原始代码产生太大差异。
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);
});https://stackoverflow.com/questions/67155636
复制相似问题