DEV Community

Cover image for Mock Intl and Date globals in Jest (easily!)
Jeff Sheets
Jeff Sheets

Posted on • Originally published at sheetsj.com

3

Mock Intl and Date globals in Jest (easily!)

In Javascript land, mocking the browser global objects can be a bit of a pain for tests. Searching StackOverflow gives plenty of complicated answers. Some suggesting using 3rd party mock libraries. Some that overwrite the global object itself.... But Jest already has this capability built-in and it isn't so bad:

So let's say you have a method that gets the user's timezone or the timezone offset. (the timezone offset is used sometimes since IE11 doesn't support easily reading the timezone, but I digress)

/**
 * Useful when passing the browser timezone to a backend Java API that reads a timezone in using ZoneId.of(tz),
 *  as both 'America/Chicago' and '-0600' are valid values when passed to the Java API.
 *  The Offset is used to handle IE11 and other older browsers.
 */
export const getUserTimeZoneOrOffset = () => {
  let timeZone;
  try {
    timeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone;
  } catch (error) {
    // Ignore if this happens, and just use the fallback
  }

  if (!timeZone) {
    //Could not get a browser timezone, maybe IE11, so instead use timezoneOffset formatted for Java
    // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/ZoneOffset.html#of(java.lang.String)
    const offset = new Date().getTimezoneOffset();

    //Yeah this offset +/- seems backwards,
    // but JS actually returns a positive when local tz is behind UTC (like for US tzs)
    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
    // e.g. offset = 300, timeZone='-0500'
    const plusMinus = offset <= 0 ? '+' : '-';
    //leftpad a 0 when needed for two digits
    const hours = ('0' + Math.floor(Math.abs(offset) / 60)).slice(-2);
    const minutes = ('0' + (offset % 60)).slice(-2);
    timeZone = `${plusMinus}${hours}${minutes}`;
  }

  return timeZone;
};
Enter fullscreen mode Exit fullscreen mode

Now to test this, we'll need to mock out both the Intl and Date Javascript globals. We can do this using Jest's spyOn method to temporarily replace the global method with our own implementation. Notice that we setup the spy in the beforeEach and reset everything in the afterEach. The setup works something like this:

import { getUserTimeZoneOrOffset } from './timeZoneUtils.js';  
describe('getUserTimeZoneOrOffset', () => {
    let mockOffset;
    let mockTimezone;

    beforeEach(() => {
      mockTimezone = undefined;
      jest.spyOn(Intl, 'DateTimeFormat').mockImplementation(() => ({
        resolvedOptions: () => ({
          timeZone: mockTimezone
        })
      }));

      mockOffset = undefined;
      jest
        .spyOn(Date.prototype, 'getTimezoneOffset')
        .mockImplementation(() => mockOffset);
    });

    afterEach(() => {
      jest.restoreAllMocks();
    });

    test('returns timezone name when found', () => {
      mockTimezone = 'America/Chicago';
      const result = getUserTimeZoneOrOffset();
      expect(result).toBe('America/Chicago');
    });

    test.each([
      [300, '-0500'],
      [150, '-0230'],
      [-60, '+0100'],
      [-330, '+0530'],
      [0, '+0000'],
      [-765, '+1245']
    ])('timezoneOffset for %i is %s', (offset, expected) => {
      mockOffset = offset;
      const result = getUserTimeZoneOrOffset();
      expect(result).toBe(expected);
    });
  });
Enter fullscreen mode Exit fullscreen mode

But that's it! No need to import an extra library. This is all supplied directly in Jest itself!

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay