Обновление состояния ловушки Jest с помощью setTimeout - PullRequest
1 голос
/ 15 марта 2020

Я пытаюсь протестировать демонтирование самоуничтожающегося компонента с помощью обработчика щелчков. Обработчик щелчков обновляет useState с помощью setTimeout.

Однако мой тест не пройден, хотя я ожидаю, что он пройдет. Я пытался использовать шутливые таймеры, такие как advanceTimersByTime (), но он не работает. Если я вызываю setState вне setTimeout, тест проходит.

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}
    </>
);

};

export default 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);
});

Примечание , я издеваюсь над реализацией useState с фактической, потому что в других тестах я использовал пользовательский useState mock .

1 Ответ

0 голосов
/ 30 марта 2020

Не использовать фермент, а 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();
  });

Я запускаю таймеры напрямую, но продвижение по времени должно давать аналогичные результаты.

...