Intl.NumberFormat space character does not match
Asked Answered
W

4

44

I'm running into an issue where Intl.NumberFormat is formatting the space character in some way that is different from what Jest is expecting. Tests against the same function with values that do not yield spaces as separators pass fine. Jest is considering the space between the 4 and the 5 characters to be different. I am using the intl polyfill for fr_CA both in my app and in my test.

Here is my function, but the only really relevant part is the Intl.NumberFormat output. How can I reconcile the formatting for the space character so that my test passes?

  export function formatCurrency( num, locale = 'en_US', showFractionDigits = false) {
    const options = {
        style: locale === 'fr_CA' ? 'decimal' : 'currency',
        currency: locale.length && locale.indexOf('CA') > -1 ? 'CAD' : 'USD'
    };

    const final = new Intl.NumberFormat(locale.replace('_', '-'), options).format(num);

    if (locale === 'fr_CA') {
        return `${final} $`;
    } else {
        return final;
    }
  }

My assertion:

expect(formatCurrency(24555.55, 'fr_CA', true)).toBe('24 555,55 $');

Result:

Expected value to be:
  "24 555,55 $"
Received:
  "24 555,55 $"
Wideranging answered 17/1, 2019 at 18:21 Comment(2)
I don't see difference in your expected and received. Do you have typo there?Atilt
There is no typo. That's the whole point of this question.Wideranging
W
61
'11 111.11'.split('').map(x => console.log((x.charCodeAt(0))))

Yields "32" for the space character which is a normal space.

new Intl.NumberFormat('fr-CA').format(11111.11).split('').map(x => console.log((x.charCodeAt(0))))

Yields "160" for the space character, which is a non-breaking space.

To make these tests pass, you need to add the non-breaking space UTF-16 (\xa0) character code into the assertion.

expect(formatCurrency(24555.55, 'fr_CA', true)).toBe('24\xa0555,55 $');
Wideranging answered 17/1, 2019 at 19:6 Comment(3)
Wow, I spent way too much time banging my head trying to solve this. Glad I landed here later than never.Patinous
What is the reason for this? Is there a way to tell Intl to use the normal \x20 space character?Chipboard
@Chipboard This is the desired/correct behavior. Dollars and cents should never be on to two different lines. It's just something you don't think about until you go to test it.Wideranging
B
29

NumberFormat use small non-breaking space (\u202f) for thousand separator and normal non-breaking space beforece currency (\xa0)

  expect(new Intl.NumberFormat("fr-FR", {
    style: "currency",
    currency: "EUR",
  }).format(126126)).toBe("126\u202f126,00\xa0€")
Bayle answered 19/11, 2020 at 10:19 Comment(2)
Thanks a lot for sharing the \u202f character !Falkirk
expect(actualResult.replace(/\xa0/g, ' ').replace(/\u202f/g, ' ')).toEqual(expectedResult)Unthoughtof
W
2

Because every jest-fails-on-whitespace question points here, I feel it's necessary to say many cases might be served by checking for whitespace rather than specific characters. Using .toMatch() with a regex containing the \W character will match either space or non-breaking space:

expect(formatCurrency(24555.55, 'fr_CA', true)).toMatch(/24\W555,55\W$/);

It also matches a small non-breaking space:

expect(new Intl.NumberFormat("fr-FR", {
  style: "currency",
  currency: "EUR",
}).format(126126)).toMatch(/126\W126,00\W€/)
Whop answered 17/2, 2023 at 22:17 Comment(0)
U
0

If you need the character for the thousand separator that Intl.NumberFormat uses (for example in case you using locale: 'fr_US') this is what you are looking for:

\u202f

Example:

    const numberToFormat = '1000000.012345678912345678';
    const expectedFR = '1\u202f000\u202f000,012345678912345678';
    expect(Intl.NumberFormat('fr-US').format(numberToFormat).toBe(expectedFR);
Undeceive answered 3/5, 2023 at 19:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.