close
close

jest usefaketimers donotfake

2 min read 03-10-2024
jest usefaketimers donotfake

Mastering Time with Jest's useFakeTimers and donotfake

Jest's useFakeTimers is a powerful tool for testing asynchronous code that relies on timers, such as setTimeout, setInterval, and Date.now. It allows you to control the passage of time within your tests, making them more predictable and reliable. However, sometimes you might want to specifically exclude certain timers from being faked. This is where the donotfake option comes in handy.

Let's consider a scenario where you have a function that schedules a task using setTimeout but also relies on the actual current time for some internal logic:

function scheduleTask(delay) {
  const startTime = Date.now(); // Get current time
  setTimeout(() => {
    const elapsedTime = Date.now() - startTime;
    console.log(`Task completed after ${elapsedTime} milliseconds`);
  }, delay);
}

Now, if we directly use jest.useFakeTimers() in our test without any modifications, the Date.now() calls inside the function will be mocked, leading to unexpected results:

test('scheduleTask with fake timers', () => {
  jest.useFakeTimers();
  scheduleTask(1000);
  // Advance the fake timer
  jest.advanceTimersByTime(1000);
  // This will always log "Task completed after 0 milliseconds"
});

To fix this, we can use the donotfake option within useFakeTimers to exclude Date.now from being mocked:

test('scheduleTask with fake timers and donotfake', () => {
  jest.useFakeTimers({ doNotFake: ['Date.now'] });
  scheduleTask(1000);
  jest.advanceTimersByTime(1000);
  // This will log "Task completed after 1000 milliseconds" as expected
});

By adding doNotFake: ['Date.now'], we ensure that the Date.now function remains untouched, allowing the actual time to be used within our test.

Understanding donotfake:

The donotfake option is a powerful feature that allows you to fine-tune Jest's fake timers behavior. It accepts an array of strings representing the functions or methods you want to exclude from being mocked. This can be especially helpful when dealing with complex code that interacts with multiple timers and external dependencies.

Practical Example:

Imagine you have a function that triggers an API call using setTimeout after a certain delay but also needs to check the current time to ensure it's within a specific time window. Here's how you can test this function effectively using donotfake:

function makeAPICall(delay) {
  const now = Date.now();
  setTimeout(() => {
    if (now + delay < new Date().getTime()) {
      // Make API call only if still within the time window
      console.log('Making API call');
    } else {
      console.log('Time window expired');
    }
  }, delay);
}

test('makeAPICall with fake timers and donotfake', () => {
  jest.useFakeTimers({ doNotFake: ['Date.now'] });
  const now = Date.now();
  makeAPICall(1000);
  jest.advanceTimersByTime(500);
  expect(now + 500).toBeLessThan(new Date().getTime());
  jest.advanceTimersByTime(500);
  expect(now + 1000).toBeGreaterThanOrEqual(new Date().getTime());
});

In this example, we explicitly exclude Date.now from being mocked using donotfake. This ensures that the actual time is used for the time window checks within the makeAPICall function, allowing for accurate testing of the logic.

Key Points:

  • Use donotfake to exclude specific timer functions from being mocked when using jest.useFakeTimers().
  • Carefully consider which functions need to be mocked and which need to be left untouched for your tests to be accurate and meaningful.
  • donotfake provides fine-grained control over Jest's fake timers behavior, allowing you to tailor them to your specific testing needs.

By understanding and leveraging the power of useFakeTimers and donotfake, you can write more effective and reliable tests for your asynchronous code.

Latest Posts