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。
注意事项
- 必须在页面加载前注入:addInitScript 天然满足;时钟 API 先
install()再goto() - 服务端时间不受影响:mock 只改浏览器端——后端接口返回的时间照样真实,端到端测试"时间一致性"要服务端配合
- 定时器:addInitScript 方案不动 setTimeout;要快进定时器必须用
page.clock.runFor() - 性能/动画: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() 在一个测试里连续快进。
参考资料
本文依据官方资料核对,未进行现场运行测试;代码与配置示例需结合实际版本、权限和环境验证。