chore: add clock.next() (#31097)
This commit is contained in:
parent
a617dd0df8
commit
76e977a934
|
|
@ -4,6 +4,7 @@
|
|||
Playwright uses [@sinonjs/fake-timers](https://github.com/sinonjs/fake-timers) for clock emulation. Clock is installed for the entire [BrowserContext], so the time
|
||||
in all the pages and iframes is controlled by the same clock.
|
||||
|
||||
|
||||
## async method: Clock.install
|
||||
* since: v1.45
|
||||
|
||||
|
|
@ -42,6 +43,14 @@ Tells `@sinonjs/fake-timers` to increment mocked time automatically based on the
|
|||
Relevant only when using with [`option: shouldAdvanceTime`]. Increment mocked time by advanceTimeDelta ms every advanceTimeDelta ms change
|
||||
in the real system time (default: 20).
|
||||
|
||||
|
||||
## async method: Clock.next
|
||||
* since: v1.45
|
||||
- returns: <[int]> Fake milliseconds since the unix epoch.
|
||||
|
||||
Advances the clock to the the moment of the first scheduled timer, firing it.
|
||||
|
||||
|
||||
## async method: Clock.jump
|
||||
* since: v1.45
|
||||
|
||||
|
|
@ -54,7 +63,6 @@ This can be used to simulate the JS engine (such as a browser) being put to slee
|
|||
|
||||
Time may be the number of milliseconds to advance the clock by or a human-readable string. Valid string formats are "08" for eight seconds, "01:00" for one minute and "02:34:10" for two hours, 34 minutes and ten seconds.
|
||||
|
||||
|
||||
## async method: Clock.runAll
|
||||
* since: v1.45
|
||||
- returns: <[int]> Fake milliseconds since the unix epoch.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ export class Clock implements api.Clock {
|
|||
});
|
||||
}
|
||||
|
||||
async next(): Promise<number> {
|
||||
const result = await this._browserContext._channel.clockNext();
|
||||
return result.fakeTime;
|
||||
}
|
||||
|
||||
async runAll(): Promise<number> {
|
||||
const result = await this._browserContext._channel.clockRunAll();
|
||||
return result.fakeTime;
|
||||
|
|
|
|||
|
|
@ -976,6 +976,10 @@ scheme.BrowserContextClockJumpParams = tObject({
|
|||
timeString: tOptional(tString),
|
||||
});
|
||||
scheme.BrowserContextClockJumpResult = tOptional(tObject({}));
|
||||
scheme.BrowserContextClockNextParams = tOptional(tObject({}));
|
||||
scheme.BrowserContextClockNextResult = tObject({
|
||||
fakeTime: tNumber,
|
||||
});
|
||||
scheme.BrowserContextClockRunAllParams = tOptional(tObject({}));
|
||||
scheme.BrowserContextClockRunAllResult = tObject({
|
||||
fakeTime: tNumber,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,13 @@ export class Clock {
|
|||
|
||||
async jump(time: number | string) {
|
||||
this._assertInstalled();
|
||||
await this._addAndEvaluate(`globalThis.__pwFakeTimers.jump(${JSON.stringify(time)}); 0`);
|
||||
await this._addAndEvaluate(`globalThis.__pwFakeTimers.jump(${JSON.stringify(time)})`);
|
||||
}
|
||||
|
||||
async next(): Promise<number> {
|
||||
this._assertInstalled();
|
||||
await this._browserContext.addInitScript(`globalThis.__pwFakeTimers.next()`);
|
||||
return await this._evaluateInFrames(`globalThis.__pwFakeTimers.nextAsync()`);
|
||||
}
|
||||
|
||||
async runAll(): Promise<number> {
|
||||
|
|
|
|||
|
|
@ -320,6 +320,10 @@ export class BrowserContextDispatcher extends Dispatcher<BrowserContext, channel
|
|||
await this._context.clock.jump(params.timeString || params.timeNumber || 0);
|
||||
}
|
||||
|
||||
async clockNext(params: channels.BrowserContextClockNextParams, metadata?: CallMetadata | undefined): Promise<channels.BrowserContextClockNextResult> {
|
||||
return { fakeTime: await this._context.clock.next() };
|
||||
}
|
||||
|
||||
async clockRunAll(params: channels.BrowserContextClockRunAllParams, metadata?: CallMetadata | undefined): Promise<channels.BrowserContextClockRunAllResult> {
|
||||
return { fakeTime: await this._context.clock.runAll() };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1654,7 +1654,6 @@ function withGlobal(_global) {
|
|||
* @returns {Clock}
|
||||
*/
|
||||
function install(config) {
|
||||
console.log('INSTALL', config);
|
||||
if (
|
||||
arguments.length > 1 ||
|
||||
config instanceof Date ||
|
||||
|
|
|
|||
5
packages/playwright-core/types/types.d.ts
vendored
5
packages/playwright-core/types/types.d.ts
vendored
|
|
@ -17289,6 +17289,11 @@ export interface Clock {
|
|||
*/
|
||||
jump(time: number|string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Advances the clock to the the moment of the first scheduled timer, firing it.
|
||||
*/
|
||||
next(): Promise<number>;
|
||||
|
||||
/**
|
||||
* Runs all pending timers until there are none remaining. If new timers are added while it is executing they will be
|
||||
* run as well. This makes it easier to run asynchronous tests to completion without worrying about the number of
|
||||
|
|
|
|||
|
|
@ -1462,6 +1462,7 @@ export interface BrowserContextChannel extends BrowserContextEventTarget, EventT
|
|||
updateSubscription(params: BrowserContextUpdateSubscriptionParams, metadata?: CallMetadata): Promise<BrowserContextUpdateSubscriptionResult>;
|
||||
clockInstall(params: BrowserContextClockInstallParams, metadata?: CallMetadata): Promise<BrowserContextClockInstallResult>;
|
||||
clockJump(params: BrowserContextClockJumpParams, metadata?: CallMetadata): Promise<BrowserContextClockJumpResult>;
|
||||
clockNext(params?: BrowserContextClockNextParams, metadata?: CallMetadata): Promise<BrowserContextClockNextResult>;
|
||||
clockRunAll(params?: BrowserContextClockRunAllParams, metadata?: CallMetadata): Promise<BrowserContextClockRunAllResult>;
|
||||
clockRunToLast(params?: BrowserContextClockRunToLastParams, metadata?: CallMetadata): Promise<BrowserContextClockRunToLastResult>;
|
||||
clockTick(params: BrowserContextClockTickParams, metadata?: CallMetadata): Promise<BrowserContextClockTickResult>;
|
||||
|
|
@ -1777,6 +1778,11 @@ export type BrowserContextClockJumpOptions = {
|
|||
timeString?: string,
|
||||
};
|
||||
export type BrowserContextClockJumpResult = void;
|
||||
export type BrowserContextClockNextParams = {};
|
||||
export type BrowserContextClockNextOptions = {};
|
||||
export type BrowserContextClockNextResult = {
|
||||
fakeTime: number,
|
||||
};
|
||||
export type BrowserContextClockRunAllParams = {};
|
||||
export type BrowserContextClockRunAllOptions = {};
|
||||
export type BrowserContextClockRunAllResult = {
|
||||
|
|
|
|||
|
|
@ -1219,6 +1219,10 @@ BrowserContext:
|
|||
timeNumber: number?
|
||||
timeString: string?
|
||||
|
||||
clockNext:
|
||||
returns:
|
||||
fakeTime: number
|
||||
|
||||
clockRunAll:
|
||||
returns:
|
||||
fakeTime: number
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ it.describe('tick', () => {
|
|||
});
|
||||
|
||||
await page.clock.tick(0);
|
||||
expect(calls).toEqual([{ params: [] }]);
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not trigger without sufficient delay', async ({ page, calls }) => {
|
||||
|
|
@ -58,7 +58,7 @@ it.describe('tick', () => {
|
|||
setTimeout(window.stub, 100);
|
||||
});
|
||||
await page.clock.tick(100);
|
||||
expect(calls).toEqual([{ params: [] }]);
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('triggers simultaneous timers', async ({ page, calls }) => {
|
||||
|
|
@ -68,7 +68,7 @@ it.describe('tick', () => {
|
|||
setTimeout(window.stub, 100);
|
||||
});
|
||||
await page.clock.tick(100);
|
||||
expect(calls).toEqual([{ params: [] }, { params: [] }]);
|
||||
expect(calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('triggers multiple simultaneous timers', async ({ page, calls }) => {
|
||||
|
|
@ -91,7 +91,7 @@ it.describe('tick', () => {
|
|||
await page.clock.tick(50);
|
||||
expect(calls).toEqual([]);
|
||||
await page.clock.tick(100);
|
||||
expect(calls).toEqual([{ params: [] }]);
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('triggers event when some throw', async ({ page, calls }) => {
|
||||
|
|
@ -102,7 +102,7 @@ it.describe('tick', () => {
|
|||
});
|
||||
|
||||
await expect(page.clock.tick(120)).rejects.toThrow();
|
||||
expect(calls).toEqual([{ params: [] }]);
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('creates updated Date while ticking', async ({ page, calls }) => {
|
||||
|
|
@ -210,7 +210,7 @@ it.describe('jump', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.describe('runAllAsyn', () => {
|
||||
it.describe('runAll', () => {
|
||||
it('if there are no timers just return', async ({ page }) => {
|
||||
await page.clock.install();
|
||||
await page.clock.runAll();
|
||||
|
|
@ -612,3 +612,113 @@ it.describe('shouldAdvanceTime', () => {
|
|||
expect(timeDifference).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it.describe('popup', () => {
|
||||
it('should tick after popup', async ({ page }) => {
|
||||
const now = new Date('2015-09-25');
|
||||
await page.clock.install({ now });
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup'),
|
||||
page.evaluate(() => window.open('about:blank')),
|
||||
]);
|
||||
const popupTime = await popup.evaluate(() => Date.now());
|
||||
expect(popupTime).toBe(now.getTime());
|
||||
await page.clock.tick(1000);
|
||||
const popupTimeAfter = await popup.evaluate(() => Date.now());
|
||||
expect(popupTimeAfter).toBe(now.getTime() + 1000);
|
||||
});
|
||||
|
||||
it('should tick before popup', async ({ page, browserName }) => {
|
||||
it.skip(browserName === 'chromium');
|
||||
const now = new Date('2015-09-25');
|
||||
await page.clock.install({ now });
|
||||
const newNow = await page.clock.tick(1000);
|
||||
expect(newNow).toBe(now.getTime() + 1000);
|
||||
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup'),
|
||||
page.evaluate(() => window.open('about:blank')),
|
||||
]);
|
||||
const popupTime = await popup.evaluate(() => Date.now());
|
||||
expect(popupTime).toBe(now.getTime() + 1000);
|
||||
});
|
||||
});
|
||||
|
||||
it.describe('next', () => {
|
||||
it('triggers the next timer', async ({ page, calls }) => {
|
||||
await page.clock.install();
|
||||
await page.evaluate(async () => {
|
||||
setTimeout(window.stub, 100);
|
||||
});
|
||||
expect(await page.clock.next()).toBe(100);
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('does not trigger simultaneous timers', async ({ page, calls }) => {
|
||||
await page.clock.install();
|
||||
await page.evaluate(() => {
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
await page.clock.next();
|
||||
expect(calls).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('subsequent calls trigger simultaneous timers', async ({ page, calls }) => {
|
||||
await page.clock.install();
|
||||
await page.evaluate(async () => {
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 100);
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 99);
|
||||
setTimeout(() => {
|
||||
window.stub();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
await page.clock.next();
|
||||
expect(calls).toHaveLength(1);
|
||||
await page.clock.next();
|
||||
expect(calls).toHaveLength(2);
|
||||
await page.clock.next();
|
||||
expect(calls).toHaveLength(3);
|
||||
await page.clock.next();
|
||||
expect(calls).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('subsequent calls triggers simultaneous timers with zero callAt', async ({ page, calls }) => {
|
||||
await page.clock.install();
|
||||
await page.evaluate(async () => {
|
||||
window.stub(1);
|
||||
setTimeout(() => {
|
||||
setTimeout(() => window.stub(2), 0);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
await page.clock.next();
|
||||
expect(calls).toEqual([{ params: [1] }]);
|
||||
await page.clock.next();
|
||||
expect(calls).toEqual([{ params: [1] }, { params: [2] }]);
|
||||
});
|
||||
|
||||
it('throws exception thrown by timer', async ({ page, calls }) => {
|
||||
await page.clock.install();
|
||||
await page.evaluate(async () => {
|
||||
setTimeout(() => {
|
||||
throw new Error();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
await expect(page.clock.next()).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue