Vitest timezone mocking: inconsistent Date behavior across environments
0 reputation · 03 Feb 2025, 13:01 UTC
0 reputation · 03 Feb 2025, 13:01 UTC
Vitest uses the Node.js Date implementation, which follows the process.env.TZ setting. When tests involve date‑manipulation libraries such as date‑fns‑tz, the output can vary between a developer’s machine and CI runners that have different default time zones.
process.env.TZ affects all subsequent Date calls and can interfere with other tests or parallel workers.Teams must decide whether to rely on manual TZ manipulation, adopt external libraries, or push for a first‑party Vitest API that standardizes timezone mocking. The lack of a documented approach leaves uncertainty about how to achieve consistent, repeatable test results across environments.
30275 reputation · 03 Feb 2025, 19:34 UTC
Vitest does not ship a dedicated timezone‑mock API. The safest, most repeatable way to control Date behaviour across all environments is to explicitly set process.env.TZ for the duration of each test (or test file) and, when necessary, pair it with vi.setSystemTime(). This guarantees that both Node’s Date and libraries that rely on the process timezone (e.g., date‑fns‑tz) produce identical results regardless of the host’s default zone.
vi.setSystemTime() freezes the epoch value but leaves the timezone unchanged.process.env.TZ globally can leak between parallel workers unless we reset it after each test.Date internally honour the current process.env.TZ at import time, so the mock must be in place before the module loads.// test/setup.ts
const ORIGINAL_TZ = process.env.TZ;
export { ORIGINAL_TZ };
// test/example.test.ts
import { vi } from 'vitest';
import { ORIGINAL_TZ } from './setup';
beforeEach(() => {
process.env.TZ = 'UTC'; // or any zone you need
vi.setSystemTime(new Date('2024-01-01T12:00:00Z'));
});
afterEach(() => {
process.env.TZ = ORIGINAL_TZ;
vi.useRealTimers();
});
test('date‑fns‑tz works in UTC', async () => {
const { utcToZonedTime, format } = await import('date-fns-tz');
const zoned = utcToZonedTime('2024-01-01T12:00:00Z', 'America/New_York');
expect(format(zoned, 'yyyy-MM-dd HH:mm')).toBe('2024-01-01 07:00');
});
vitest --run --worker=1
TZ=UTC vitest
vitest --reporter=verbose locally and on CI; the output of new Date().toISOString() should match the mocked timezone.process.env.TZ is restored after each test by adding a console log in afterEach.process.env.TZ each time.Do your tests run with Vitest’s default parallel workers (multiple workers) or a single worker? This determines whether you need to isolate the process.env.TZ change per worker or can rely on a global reset after each test file.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.