fix: update performance.now() when calling in a busy loop (#35435)

This commit is contained in:
Max Schmitt 2025-04-07 21:40:58 +01:00 committed by GitHub
parent 9cb05c56f5
commit 76d5b8778c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 5 deletions

View File

@ -99,6 +99,7 @@ export class ClockController {
now(): number {
this._replayLogOnce();
this._syncRealTime();
return this._now.time;
}
@ -119,9 +120,21 @@ export class ClockController {
performanceNow(): DOMHighResTimeStamp {
this._replayLogOnce();
this._syncRealTime();
return this._now.ticks;
}
private _syncRealTime() {
if (!this._realTime)
return;
const now = this._embedder.performanceNow();
const sinceLastSync = now - this._realTime.lastSyncTicks;
if (sinceLastSync > 0) {
this._advanceNow(shiftTicks(this._now.ticks, sinceLastSync));
this._realTime.lastSyncTicks = now;
}
}
private _innerSetTime(time: WallTime) {
this._now.time = time;
this._now.isFixedTime = false;
@ -216,12 +229,10 @@ export class ClockController {
this._currentRealTimeTimer = {
callAt,
dispose: this._embedder.setTimeout(() => {
const now = this._embedder.performanceNow();
this._currentRealTimeTimer = undefined;
const sinceLastSync = now - this._realTime!.lastSyncTicks;
this._realTime!.lastSyncTicks = now;
this._syncRealTime();
// eslint-disable-next-line no-console
void this._runTo(shiftTicks(this._now.ticks, sinceLastSync)).catch(e => console.error(e)).then(() => this._updateRealTimeTimer());
void this._runTo(this._now.ticks).catch(e => console.error(e)).then(() => this._updateRealTimeTimer());
}, callAt - this._now.ticks),
};
}
@ -231,7 +242,6 @@ export class ClockController {
await this._innerFastForwardTo(shiftTicks(this._now.ticks, ticks | 0));
}
private async _innerFastForwardTo(to: Ticks) {
if (to < this._now.ticks)
throw new Error('Cannot fast-forward to the past');

View File

@ -533,3 +533,35 @@ it.describe('Date.now', () => {
expect(dateValue).toBe(1001);
});
});
it('correctly increments Date.now()/performance.now() during blocking execution', {
annotation: {
type: 'issue',
description: 'https://github.com/microsoft/playwright/issues/35362',
}
}, async ({ page, server }) => {
await page.clock.setSystemTime(new Date('2026-01-01'));
server.setRoute('/repro.html', (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(`
<html>
<body>
<script>
{
const start = performance.now();
while (performance.now() - start < 100) { }
}
{
const start = Date.now();
while (Date.now() - start < 100) { }
}
console.log('done');
</script>
</body>
</html>
`);
});
const waitForDone = page.waitForEvent('console', msg => msg.text() === 'done');
await page.goto(server.PREFIX + '/repro.html');
await waitForDone;
});