From d0c840f6390e3693fce199507981716be3df62f9 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Fri, 2 Aug 2024 15:27:54 +0200 Subject: [PATCH] fix(clock): mock time in Event.prototype.timeStamp (#31986) Ideally we generate the timestamp when the Event gets created. This patch adds a best-effort logic, since we can't override the constructor of natively created events, e.g. `MouseEvent`. Fixes https://github.com/microsoft/playwright/issues/31924 --- docs/src/clock.md | 1 + .../playwright-core/src/server/injected/clock.ts | 8 ++++++++ tests/library/clock.spec.ts | 12 ++++++++++++ 3 files changed, 21 insertions(+) diff --git a/docs/src/clock.md b/docs/src/clock.md index a515d46d50..ea14941d82 100644 --- a/docs/src/clock.md +++ b/docs/src/clock.md @@ -31,6 +31,7 @@ The recommended approach is to use `setFixedTime` to set the time to a specific - `requestIdleCallback` - `cancelIdleCallback` - `performance` + - `Event.timeStamp` ::: ## Test with predefined time diff --git a/packages/playwright-core/src/server/injected/clock.ts b/packages/playwright-core/src/server/injected/clock.ts index afce525be1..48cc9276a2 100644 --- a/packages/playwright-core/src/server/injected/clock.ts +++ b/packages/playwright-core/src/server/injected/clock.ts @@ -697,6 +697,14 @@ export function install(globalObject: WindowOrWorkerGlobalScope, config: Install (globalObject as any).Intl = api[method]!; } else if (method === 'performance') { (globalObject as any).performance = api[method]!; + const kEventTimeStamp = Symbol('playwrightEventTimeStamp'); + Object.defineProperty(Event.prototype, 'timeStamp', { + get() { + if (!this[kEventTimeStamp]) + this[kEventTimeStamp] = api.performance?.now(); + return this[kEventTimeStamp]; + } + }); } else { (globalObject as any)[method] = (...args: any[]) => { return (api[method] as any).apply(api, args); diff --git a/tests/library/clock.spec.ts b/tests/library/clock.spec.ts index 9fd8426a92..90279fd893 100644 --- a/tests/library/clock.spec.ts +++ b/tests/library/clock.spec.ts @@ -1060,6 +1060,18 @@ it.describe('stubTimers', () => { expect(prev).toBe(0); }); + it('replace Event.prototype.timeStamp', async ({ install }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/31924' }); + const clock = install(); + await clock.runFor(1000); + const event1 = new Event('foo'); + expect(event1.timeStamp).toBe(1000); + await clock.runFor(1000); + const event2 = new Event('foo'); + expect(event2.timeStamp).toBe(2000); + expect(event1.timeStamp).toBe(1000); + }); + it('uninstalls global performance.now', async ({ install }) => { const oldNow = performance.now; const clock = install();