# Dates and Randomness — Jest, Vitest & Testing Library

Source: https://www.skillbyai.com/en/javascript-testing/a-dates

> Pin the clock and control random values.

## Make non-deterministic inputs deterministic

Code that calls `new Date()`, `Date.now()` or `Math.random()` gives different results on each run, and date logic often breaks only at midnight, month ends or in another time zone. Options, from simplest: pass **the current time or a random source in as a parameter** (easiest to test, cleaner design); use **`vi.setSystemTime(date)` / `jest.setSystemTime(date)`** with fake timers to pin `Date`; and **spy on `Math.random`** with `mockReturnValue` for a fixed sequence. Also pin the **time zone** for the test process, for example by setting the `TZ` environment variable in the test script, so date formatting tests behave the same on every laptop and CI machine.

## Pinned date and fixed random values

Vitest; Jest has jest.setSystemTime and jest.spyOn.

```typescript
import { afterEach, expect, it, vi } from 'vitest';
import { isTrialExpired, pickWinner } from './promo';

afterEach(() => {
  vi.useRealTimers();
  vi.restoreAllMocks();
});

it('expires the trial after 14 days', () => {
  vi.useFakeTimers();
  vi.setSystemTime(new Date('2025-03-15T12:00:00Z'));

  expect(isTrialExpired(new Date('2025-03-01T12:00:00Z'))).toBe(true);
  expect(isTrialExpired(new Date('2025-03-02T12:00:00Z'))).toBe(false);
});

it('picks the entry at the random index', () => {
  vi.spyOn(Math, 'random').mockReturnValue(0.5);
  expect(pickWinner(['a', 'b', 'c', 'd'])).toBe('c');   // floor(0.5 * 4) = 2
});

// package.json: "test": "TZ=UTC vitest"   (bash syntax; on Windows use a tool such as cross-env)
```

## Inject the clock in new code

A function like `isExpired(start, now = new Date())` needs no fakes at all in tests: pass the `now` you want. Reserve global time mocking for code you cannot easily change.

**Quiz:** Which approach makes a date-dependent function easiest to test?

- [ ] Use real timers and retry on failure
- [ ] Run the tests only at midnight
- [x] Pass the current time in as a parameter with a sensible default
- [ ] Snapshot the output of new Date()

*Answer:* Pass the current time in as a parameter with a sensible default. Injected time needs no global mocks.
