Mock dates and timers in Playwright

Use the Clock API to fix Date values or advance timers, with explicit time zones and clear browser-context boundaries.

Best practices
Illustration of software development and testing

In Playwright 1.45 and later, use page.clock for browser time control. setFixedTime() fixes the value returned by Date; install(), pauseAt(), and runFor() let you control timers as well. There is no clock.tick() method, and a duration string such as 01:30 means one minute and thirty seconds.

Although the API is reached through a page, the installed clock applies to the entire browser context, including its pages and iframes. It does not change the backend's clock.

Use the Clock API

These Playwright Test examples use an example page. Replace it with the application whose time-dependent behavior you need to verify:

import { test, expect } from '@playwright/test';

test('fixed browser date', async ({ page }) => {
  await page.clock.setFixedTime(new Date('2026-06-21T13:00:00Z'));
  await page.goto('https://example.com');
  expect(await page.evaluate(() => Date.now()))
    .toBe(Date.parse('2026-06-21T13:00:00Z'));
});

test('advance browser timers', async ({ page }) => {
  await page.clock.install({ time: new Date('2026-06-21T12:00:00Z') });
  await page.goto('https://example.com');
  await page.clock.pauseAt(new Date('2026-06-21T13:00:00Z'));
  await page.clock.runFor(90 * 60 * 1000);
});

setFixedTime() fixes Date values while ordinary timers continue running. runFor() advances the controlled clock and runs callbacks during that interval. fastForward() has different semantics: due timers fire at most once during the jump. With many timers, a long runFor() can take substantial time, but replacing it with fastForward() changes what you test.

Use an explicit Z or UTC offset so parsing does not depend on the machine's time zone. Date formatting may also depend on the browser context's configured time zone.

Older versions: a limited Date override

For a legacy suite, an initialization script can replace part of Date behavior before the page's scripts run:

test.beforeEach(async ({ page }) => {
  const fakeNow = new Date('2026-06-21T13:00:00Z').valueOf();

  await page.addInitScript(`{
    Date = class extends Date {
      constructor(...args) {
        if (args.length === 0) { super(${fakeNow}); }
        else { super(...args); }
      }
    }
    Date.now = () => ${fakeNow};
  }`);
});

The no-argument constructor and Date.now() return the fixed time; explicit constructor arguments are forwarded. This is not a complete Date replacement: calling Date() as a function no longer behaves normally. It does not control timers, backend time, worker time, or native clocks. Upgrade to the supported Clock API for more demanding scenarios.

Boundaries to account for

  1. Register the initialization script before navigation. For Clock-based timer control, call install() before goto() so the page creates timers against the controlled implementation.
  2. Backend timestamps remain real unless the server provides its own test-time mechanism. Coordinate both sides when testing time consistency across an API.
  3. The legacy override does not change setTimeout(). Timer progression requires an installed clock and methods such as runFor().
  4. Animation callbacks and a controlled clock can interact. Stabilize animations when they are irrelevant to the behavior under test.

Frequently asked questions

Why not change the operating system clock?

That affects unrelated processes, certificate validation, and logs, and may require privileges unavailable in CI. Clock emulation stays within a browser context. Playwright Test normally gives each test its own isolated context.

Can I combine Playwright Clock with Sinon fake timers?

Avoid installing both in the same page; the replacements can overwrite or interfere with each other. Choose one owner of time for that test layer.

How do I test an offer expiring?

Use separate tests with a fixed date before and after the deadline, or install a clock and advance it within one test. Assert the UI outcome, and remember that server-enforced expiry needs matching backend test data or time control.

References

Related reading

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting