-
Notifications
You must be signed in to change notification settings - Fork 19
Description
Hello EpicWeb team!
I'm going through the testing-fundamentals workshop (liked the idea of building my own assertion library to really understand how they work under the hoods). While going through the exercises, I faced an issue where some tests were failing due to timezones differences
One of those was the greet function:
export function greet(name: string) {
const weekday = new Date().toLocaleDateString('en-US', { weekday: 'long' })
return `Hello, ${name}! Happy, ${weekday}.`
}Where in the test we override the globalThis.Date on the greet.test.ts file:
beforeAll(() => {
globalThis.Date = new Proxy(globalThis.Date, {
construct: () => new OriginalDate('2024-01-01'),
})
})However, when executing npx tsx --import ./setup.ts greet.test.ts, I got the test fails with the message: Error: Expected Hello, John! Happy, Sunday. to equal to Hello, John! Happy, Monday.
Full error:
npx tsx --import ./setup.ts greet.test.ts
✗ returns a greeting message for the given name
Error: Expected Hello, John! Happy, Sunday. to equal to Hello, John! Happy, Monday.
at Object.toBe (testing-fundamentals/exercises/02.test-structure/04.solution.hooks/setup.ts:16:11)
at <anonymous> (testing-fundamentals/exercises/02.test-structure/04.solution.hooks/greet.test.ts:21:24)
at globalThis.test testing-fundamentals/exercises/02.test-structure/04.solution.hooks/setup.ts:24:3)
at <anonymous> (testing-fundamentals/exercises/02.test-structure/04.solution.hooks/greet.test.ts:20:1)
at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:123:5)
✓ returns a congratulation message for the given name
When executing new Date('2024-01-01') in the console, it indeed returns Sunday
After digging it a little bit, I found out that was because the given date format (YYYY-MM-DD), makes javaScript's Date object interpret the date as UTC time, so basically the problem was that in the test we set the date in UTC but the greet function displays it in local time, so it might lead to a test falling depending on the timezone where it was executed.
I found a couple of different solutions for this issue, but I would like to ask what could be the best way to handle it?
One solution was to set the timezone to UTC when overriding
beforeAll(() => {
globalThis.Date = new Proxy(globalThis.Date, {
construct: (target, args) => {
const instance = new OriginalDate('2024-01-01')
// Override the toLocaleDateString method to always return UTC or it will fail when running in different timezones
instance.toLocaleDateString = function (locale?: any, options?: any) {
return OriginalDate.prototype.toLocaleDateString.call(this, locale, {
...options,
timeZone: 'UTC',
})
}
return instance
},
})
})But that sounds overkill to me, as the test setup became far more complex this way.
Another solution I found was to set the timezone to UTC with the TZ Node environment variable.
TZ=UTC npx tsx --import ./setup.ts greet.test.ts
That looks like an efficient approach to me, but I didn't find a mention of this in the workshop, would it be a good practice to have the timezone overridden like this?
Then, in a real-world project, to have everyone using the project to run the tests in the same timezone, the environment override could be added to the package.json as in the example below:
"scripts": {
"test": "TZ=UTC vitest"
}