ค้นหาเว็บไซต์

typescript - ทำไมพฤติกรรมของ `jest.useFakeTimers` ถึงแตกต่างเมื่อเรียกใช้ภายในกับภายนอก `beforeEach` ใน React Native


ภาพรวม

ฉันพบพฤติกรรมที่แตกต่างกันของ jest.useFakeTimers เมื่อเรียกใช้ภายใน beforeEach เทียบกับเรียกใช้ภายนอก

ตัวอย่างที่สามารถทำซ้ำได้

// Foo.tsx

import * as React from 'react';
import {View} from 'react-native';

const Foo: React.FC = () => {
  const [timePassed, setTimePassed] = React.useState<number>(0);
  const [flag, setFlag] = React.useState(true);

  console.log(`timePassed: ${timePassed}, flag: ${flag}`);
  React.useEffect(() => {
    if (flag) {
      setTimeout(() => {
        if (timePassed > 1) {
          setFlag(false);
        }
        setTimePassed(timePassed + 1);
      }, 1);
    }
  }, [flag, timePassed]);

  return <View />;
};

export default Foo;
// foo.outside.test.tsx
import * as React from 'react';
import {render} from '@testing-library/react-native';
import Foo from '../Foo';

jest.useFakeTimers();

describe('Test Foo', () => {
  test('1', () => {
    render(<Foo />);
    jest.runAllTimers();
  });

  test('2', () => {
    render(<Foo />);
    jest.runAllTimers();
  });
});
// foo.inside.test.tsx
import * as React from 'react';
import {render} from '@testing-library/react-native';
import Foo from '../Foo';

describe('Test Foo', () => {
  // fake timer usage follows: https://testing-library.com/docs/using-fake-timers/
  beforeEach(() => {
    jest.useFakeTimers();
  });

  afterEach(() => {
    jest.runOnlyPendingTimers();
    jest.useRealTimers();
  });

  test('1', () => {
    render(<Foo />);
    jest.runAllTimers();
  });

  test('2', () => {
    render(<Foo />);
    jest.runAllTimers();
  });
});

ผลการทดสอบ

ข้างนอก

npx jest __tests__/foo.outside.test.tsx
  console.log
    timePassed: 0, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 1, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: false

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 3, flag: false

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 0, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 1, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: false

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 3, flag: false

      at log (Foo.tsx:8:11)

 PASS  __tests__/foo.outside.test.tsx
  Test Foo
    ✓ 1 (58 ms)
    ✓ 2 (21 ms)

ข้างใน

npx jest __tests__/foo.inside.test.tsx                      1 ↵
  console.log
    timePassed: 0, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 1, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 2, flag: false

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 3, flag: false

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 0, flag: true

      at log (Foo.tsx:8:11)

  console.log
    timePassed: 1, flag: true

      at log (Foo.tsx:8:11)

 PASS  __tests__/foo.inside.test.tsx
  Test Foo
    ✓ 1 (62 ms)
    ✓ 2 (14 ms)

การสังเกต

ดูเหมือนว่าในการตั้งค่า ภายนอก jest.runAllTimers จะทำให้ตัวจับเวลาทำงานจนจบในทั้งสองกรณีทดสอบ อย่างไรก็ตาม ในการตั้งค่า ภายใน มีเพียงตัวจับเวลาในกรณีทดสอบแรกที่ทำงานจนจบ; ตัวจับเวลาในกรณีทดสอบที่สองจะสิ้นสุดก่อนเวลา

คำถาม

ทำไมพฤติกรรมของตัวจับเวลาปลอมถึงต่างกันเมื่อเรียกใช้ jest.useFakeTimers ภายในและภายนอก beforeEach? ฉันคาดว่าการตั้งค่าทั้งสองแบบจะรันตัวจับเวลาไปจนจบ ดังนั้นพฤติกรรมปัจจุบันของการตั้งค่า ภายใน จึงเป็นเรื่องน่าประหลาดใจในเชิงลบ

ข้อมูลเครื่องและซอฟต์แวร์

  • macOS Big Sur v11.6.5
  • รีแอ็กต์: 17.0.2
  • react-native: 0.65.1
  • เจสต์: 28.1.2
  • @testing-library/react-native: 10.1.1
  • ไทป์สคริปต์: 4.5.2