Testing Intl.NumberFormat in Vitest

Removing the whitespace character

I was writing a test for a currency formatter function:

const currencyFormat = new Intl.NumberFormat('sv-SE', {
  'maximumFractionDigits': 0, 'style': 'currency', 'currency': 'SEK',
});

export function formatAsCurrency(sum: number): string {
  if (sum === undefined || isNaN(sum)) {
    return currencyFormat.format(0);
  }

  return currencyFormat.format(sum);
}

And the test looked like this:

test('formatAsCurrency', () => {
  const value = 1337;
  const currency = formatAsCurrency(value);
  expect(currency).toBe('1 337 kr');
});

It would not pass in Vitest though the output looked exactly as expected. One reason could have been Node support for internationalization, but I was on Node 21 so that wasn’t the problem.

Turns out Node produces the result with a whitespace character instead of a “regular space”. Hard to spot by just looking at the code, but pasting it in Sublime Text revealed the character difference.

Screenshot of whitespace character

This GitHub Discussion provided a solution for the replacement: replace(/\u00a0/g, ' ');

I changed the test because the output was OK in the browser, so assuming it’s a Node thing.

export function formatAsCurrency(sum: number): string {
  if (sum === undefined || isNaN(sum)) {
    return currencyFormat.format(0).replace(/\u00a0/g, ' ');
  }

  return currencyFormat.format(sum).replace(/\u00a0/g, ' ');
}

And for decimals, I had the following formatter:

const currencyFormatWithDecimals = new Intl.NumberFormat('sv-SE', {
  'style': 'currency', 'currency': 'SEK',
});

And the following test:

test('format as currency with decimals', () => {
  const value = 123456.789;

  const currency = formatAsCurrency(value, true).replace(/\u00a0/g, ' ');
  expect(currency).toBe('123 456,79 kr');
});