Playwright 测试中如何 mock 日期时间

Playwright 1.45+ 用 page.clock.setFixedTime 固定 Date,或 install/pauseAt/runFor 控制时钟与定时器。说明时区、旧版 addInitScript 的局限和服务端时间边界。

最佳实践
测试检测与质量验证插画

一句话回答:Playwright 1.45+ 优先用 page.clock。只固定 Date 用 setFixedTime();要推进计时器则用 install()、pauseAt() 和 runFor()。不存在 clock.tick(),时间字符串 01:30 表示 1 分 30 秒,不是 1.5 小时。旧版 addInitScript 仅适合受限的 Date 模拟。

官方时钟 API(Playwright ≥ 1.45,推荐)

以下为 Playwright Test 示例,目标页面需换成自有测试页面:

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

test('固定页面日期', 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('推进页面计时器', 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 固定 Date,但不推进时间;runFor 推进虚拟时钟并触发期间计时器。大量定时器可能使长时间快进很慢,fastForward 的回调触发语义不同,不能随意替换。显式写 Z 或时区偏移避免依赖执行机时区。

兼容写法:addInitScript 注入(老版本)

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};
  }`);
});

原理:页面加载前把全局 Date 换成继承版——无参构造固定返回假时间,显式传参的行为不变;Date.now() 同样固定。它不完整模拟 Date 作为函数调用等行为,也不控制服务端、worker 或原生时钟;复杂测试应升级使用官方 Clock。

注意事项

  1. 必须在页面加载前注入:addInitScript 天然满足;时钟 API 先 install() 再 goto()
  2. 服务端时间不受影响:mock 只改浏览器端——后端接口返回的时间照样真实,端到端测试"时间一致性"要服务端配合
  3. 定时器:addInitScript 方案不动 setTimeout;要快进定时器必须用 page.clock.runFor()
  4. 性能/动画:rAF 动画与假时钟可能互相干扰,必要时配合禁用动画

常见问题(FAQ)

Q:为什么不在测试里直接改系统时间?

A:改系统时间影响整台机器(其他进程、证书校验、日志全乱),且 CI 无权限。浏览器内 mock 只影响当前页面,随测试隔离。

Q:page.clock 和 Sinon 的 fake timers 冲突吗?

A:页面里如果已加载 Sinon fake timers,再装 Playwright clock 会互相覆盖。选一个:E2E 层面统一用 page.clock,组件内单测用 Sinon。

Q:怎么测试"限时优惠已过期"这类状态?

A:两个测试分别设固定时间在截止前/截止后断言 UI;或者用 clock.runFor() 在一个测试里连续快进。


参考资料

本文依据官方资料核对,未进行现场运行测试;代码与配置示例需结合实际版本、权限和环境验证。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台