I have a test file and am testing for the formatCurrency function. The problem, even though I've mocked window.navigator.language to be en-GB my function in test doesn't format the currency in £. In the UI it works as expected, but in jest looks like you can't change window.navigator.language. Any suggestions?

const languageCurrency = {
  "en-GB": "GBP",
  "en-US": "USD",
};

const userLanguage = window.navigator.language

export const formatCurrency = (value) => 
  Intl.NumberFormat(userLanguage, {
    style: "currency",
    currency: languageCurrency[userLanguage],
  }).format(value);

and here is my test file

import { formatCurrency } from "./formatCurrency";

describe("given formatCurrency fucntion", () => {
  let windowSpy;

  beforeEach(() => {
    windowSpy = jest.spyOn(window, "window", "get");
  });

  afterEach(() => {
    windowSpy.mockRestore();
  });

  it("should set the user language to `en-GB`", () => {
    windowSpy.mockImplementation(() => ({
      navigator: {
        language: "en-GB",
      },
    }));

    expect(window.navigator.language).toBe("en-GB"); //this will pass
    expect(formatCurrency(1000)).toBe("£1000.00"); // this fails 
  });
});

enter image description here

1

There are 1 best solutions below

2
On

Since the userLanguage variable is assigned in the module scope. You should mock window.navigator.language first, then import the module. So that the userLanguage variable will be assigned with the mock value.

Note: The code defined in the module scope will be executed immediately when you import the module.

Besides, the formatted currency should be '£1,000.00'

Intl.NumberFormat('en-GB', {style: 'currency', currency: 'GBP'}).format(1000) 
// '£1,000.00'

E.g.

formatCurrency.ts:

const languageCurrency = {
  'en-GB': 'GBP',
  'en-US': 'USD',
};

const userLanguage = window.navigator.language;

export const formatCurrency = (value) => {
  console.debug('languageCurrency[userLanguage]: %s userLanguage: %s', languageCurrency[userLanguage], userLanguage);
  return Intl.NumberFormat(userLanguage, {
    style: 'currency',
    currency: languageCurrency[userLanguage],
  }).format(value);
};

formatCurrency.test.ts:

// import { formatCurrency } from './formatCurrency';

describe('given formatCurrency fucntion', () => {
  let windowSpy;

  beforeEach(() => {
    windowSpy = jest.spyOn(window, 'window', 'get');
    jest.resetModuleRegistry();
  });

  afterEach(() => {
    windowSpy.mockRestore();
  });

  it('should set the user language to `en-GB`', async () => {
    windowSpy.mockImplementation(() => ({
      navigator: {
        language: 'en-GB',
      },
    }));

    const { formatCurrency } = await import('./formatCurrency');

    expect(window.navigator.language).toBe('en-GB');
    expect(formatCurrency(1000)).toBe('£1,000.00');
  });

  it('should set the user language to `en-US`', async () => {
    windowSpy.mockImplementation(() => ({
      navigator: {
        language: 'en-US',
      },
    }));

    const { formatCurrency } = await import('./formatCurrency');

    expect(window.navigator.language).toBe('en-US');
    expect(formatCurrency(1000)).toBe('$1,000.00');
  });
});

Test result:

 PASS  stackoverflow/75399792/formatCurrency.test.ts (11.303 s)
  given formatCurrency fucntion
    ✓ should set the user language to `en-GB` (41 ms)
    ✓ should set the user language to `en-US` (3 ms)

  console.debug
    languageCurrency[userLanguage]: GBP userLanguage: en-GB

      at formatCurrency (stackoverflow/75399792/formatCurrency.ts:9:11)

  console.debug
    languageCurrency[userLanguage]: USD userLanguage: en-US

      at formatCurrency (stackoverflow/75399792/formatCurrency.ts:9:11)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        12.209 s