Introduction
We have code in our class that basically formats a number by transforming for example 1000000 to 1 M and 1500000 to 1.5 M respectively.
To achieve this we are using the following code
export const shortNumberString = (number: number) => {
if (!number) {
return number === 0 ? '0' : '';
}
const i = Math.floor(Math.log(number) / Math.log(1000));
return (
Number((number / Math.pow(1000, i)).toFixed(1)).toLocaleString() +
' ' +
['', 'K', 'M', 'B'][i]
).trim();
};
The code works as expected and does what we want them to do, but we have developers from all over the world so based on the locale of the user this test fails.
Normally we just ignore these failed tests, but they are super annoying because you always see these tests failing but have to activiely check to ignore them.
The tests basically fail because for some users it gets formatted to 1.5 M and for others to 1,5 M.
Attempted Solutions
Add NODE_ICU
Some users have recommended to use NODE_ICU package, which I added using
yarn add -D NODE_ICU
Afterwards I have added this to our test script
"test": "NODE_ICU_DATA=node_modules/full-icu craco test",
However, running yarn test does still result in errors. I have also tried to run this via command line but the same error appears
Mock Number().toLocaleString()
I have tried to mock Number.toLocaleString but without success. I have tried the following methods
Ignore the return values as I just wanted it to fail with the given input so I’m sure it works with mocking
(global as any).Number.toLocaleString = jest.fn(() => ({
...(global as any).Number,
toLocaleString: jest.fn(() => '12.3.2019 13.47.47'),
}));
However, this does not work. It is not mockin anything
Same applies for this code
(global as any).Number.toLocaleString = jest.fn(() => new Date('2019-04-07T10:20:30Z'));
(global as any).Number = jest.fn(() => ({
toLocaleString: jest.fn(() => '12.3.2019 13.47.47'),
}));
This also fails, because of the following error
Cannot read properties of undefined (reading ‘toLocaleString’)
TypeError: Cannot read properties of undefined (reading ‘toLocaleString’)
jest.mock('Number', () => ({
...jest.requireActual('Number'),
// eslint-disable-next-line @typescript-eslint/no-unused-vars
toLocaleString: () => {
return Promise.resolve('yolo');
},
}));
This does not work as there is no module named Number jest can mock. I have not found a way to mock
jest
.spyOn(global.Number, 'toLocaleString')
.mockImplementation((number: string) => 10);
This also does not work as it tells me I cannot call the method spyOn like .spyOn(global.Number, 'toLocaleString')
Set env.LL etc
I have also tried to set the locales of env manually
const env: any = process.env;
env.LANG = 'en-GB';
env.LANGUAGE = 'en-GB';
env.LC_ALL = 'en-GB';
env.LC_MESSAGES = 'en-GB';
const language = env.LANG || env.LANGUAGE || env.LC_ALL || env.LC_MESSAGES;
console.log(language);
in the console.log it returns en-GB but the tests are still failing even though en-GB should return the correct format
I am out of ideas but cannot believe that it is impossible to mock this. However, everything I find on Google is mostly for Date mocking but not for Number mocking and I cannot apply these suggestions to Number formatting to get them working.
Any help would be appreciated