带有setTimeout的Jest测试挂钩状态更新

问题描述 投票:1回答:1

我正在尝试使用点击处理程序测试自毁组件的卸载。点击处理程序使用setTimeout更新useState。

但是,我的测试失败了,但我希望它能通过。我尝试使用诸如jacktimeTimesByTime()之类的开玩笑的模拟计时器,但是它不起作用。如果我在setTimeout之外调用setState,则测试通过。

component.js

const DangerMsg = ({ duration, onAnimDurationEnd, children }) => {
const [isVisible, setVisible] = useState(false);
const [sectionClass, setSectionClass] = useState(classes.container);

function handleAnimation() {
    setSectionClass(classes.containerAnimated);
    let timer = setTimeout(() => {
        setVisible(false);
    }, 300);
    return clearTimeout(timer);
}

useEffect(() => {
    let timer1;
    let timer2;
    function animate() {
        if (onAnimDurationEnd) {
            setSectionClass(classes.containerAnimated);
            timer2 = setTimeout(() => {
                setVisible(false);
            }, 300);
        } else {
            setVisible(false);
        }
    }

    if (children) {
        setVisible(true);
    }
    if (duration) {
        timer1 = setTimeout(() => {
            animate();
        }, duration);
    }
    return () => {
        clearTimeout(timer1);
        clearTimeout(timer2);
    };
}, [children, duration, onAnimDurationEnd]);

return (
    <>
        {isVisible ? (
            <section className={sectionClass} data-test="danger-msg">
                <div className={classes.inner}>
                    {children}
                    <button
                        className={classes.btn}
                        onClick={() => handleAnimation()}
                        data-test="btn"
                    >
                        &times;
                    </button>
                </div>
            </section>
        ) : null}
    </>
);

};

导出默认DangerMsg;

test.js

it("should NOT render on click", async () => {
    jest.useFakeTimers();
    const { useState } = jest.requireActual("react");
    useStateMock.mockImplementation(useState);
    // useEffect not called on shallow
    component = mount(
        <DangerMsg>
            <div></div>
        </DangerMsg>
    );
    const btn = findByTestAttr(component, "btn");
    btn.simulate("click");
    jest.advanceTimersByTime(400);
    const wrapper = findByTestAttr(component, "danger-msg");
    expect(wrapper).toHaveLength(0);
});

Note,我在实际中模拟useState实现,因为在其他测试中,我使用了自定义useState模拟。

reactjs jestjs settimeout enzyme
1个回答
0
投票

不是使用酶,而是使用testing-library/react,因此是部分解决方案。以下测试按预期通过:

  test("display loader after 1 second", () => {
    jest.useFakeTimers(); // mock timers
    const { queryByRole } = render(
      <AssetsMap {...defaultProps} isLoading={true} />
    );
    act(() => {
      jest.runAllTimers(); // trigger setTimeout
    });
    const loader = queryByRole("progressbar");
    expect(loader).toBeTruthy();
  });

我直接运行计时器,但按时间前进应该得到相似的结果。

© www.soinside.com 2019 - 2024. All rights reserved.