简体   繁体   English

使用 useEffect 和 jest.useFakeTimer() 进行测试

[英]Testing with useEffect and jest.useFakeTimer()

I'm trying to create simple refresher component here我正在尝试在这里创建简单的复习组件

Refresher.js复习.js

import { useEffect } from 'react';

const Refresher = ({ onRefresh }) => {
  useEffect(() => {
    const id = setInterval(onRefresh, 60000);
    return () => {
      clearInterval(id);
    };
  }, [onRefresh]);

  return null;
};

export default Refresher;

However, when i try to test it using jest.useFakeTimers() , somehow it's didn't work.但是,当我尝试使用jest.useFakeTimers()对其进行测试时,不知何故它不起作用。 The stub is not called even after jest.runOnlyPendingTimers()即使在jest.runOnlyPendingTimers()之后也不调用存根

import React from 'react';
import renderer from 'react-test-renderer';
import Refresher from '../Refresher';

describe('Refresher', () => {
  test('should refresh the result every 60 seconds', () => {
    jest.useFakeTimers();

    const onRefreshSpy = jest.fn();

    const refresher = renderer.create(<Refresher onRefresh={onRefreshSpy} />);

    expect(onRefreshSpy).not.toHaveBeenCalled();
    jest.runOnlyPendingTimers();
    refresher.update(); // Trying force update here

    expect(onRefreshSpy).toHaveBeenCalled();
  });
});

If not mistaken, the interval will not run if the component are not update, so i tried to use refresher.update() , but seems like it's not really work.如果没记错的话,如果组件没有更新,间隔将不会运行,所以我尝试使用refresher.update() ,但似乎它并不是真的有效。

Anyone know how to fix the test here?有人知道如何在这里修复测试吗?

You just need to mock useLayoutEffect instead of useEffect.您只需要模拟 useLayoutEffect 而不是 useEffect。 See issue here 在此处查看问题

describe('Refresher', () => {
  beforeAll(() => jest.spyOn(React, 'useEffect').mockImplementation(React.useLayoutEffect))
  test('should refresh the result every 60 seconds', () => {
    jest.useFakeTimers();
    const onRefreshSpy = jest.fn();
    const refresher = renderer.create(<Refresher onRefresh={onRefreshSpy} />);
    expect(onRefreshSpy).not.toHaveBeenCalled();
    jest.runOnlyPendingTimers();
    expect(onRefreshSpy).toHaveBeenCalled();
  });
});

You have better control with the modern fake timers.您可以更好地控制modern假定时器。

import React from 'react';
import renderer from 'react-test-renderer';
import Refresher from '../Refresher';

describe('Refresher', () => {
  test('should refresh the result every 60 seconds', () => {
    jest.useFakeTimers('modern'); // default for Jest 27+

    const onRefreshSpy = jest.fn();

    const refresher = renderer.create(<Refresher onRefresh={onRefreshSpy} />);

    expect(onRefreshSpy).not.toHaveBeenCalled();

    jest.advanceTimersByTime(60000);
    expect(onRefreshSpy).toHaveBeenCalledTimes(1);

    jest.advanceTimersByTime(60000);
    expect(onRefreshSpy).toHaveBeenCalledTimes(2);
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM