chore(clock): split wall and monotonic time (#31198)
This commit is contained in:
parent
43d6d012d4
commit
e280d0bd35
|
|
@ -44,7 +44,7 @@ enum TimerType {
|
||||||
type Timer = {
|
type Timer = {
|
||||||
type: TimerType;
|
type: TimerType;
|
||||||
func: TimerHandler;
|
func: TimerHandler;
|
||||||
args: () => any[];
|
args: any[];
|
||||||
delay: number;
|
delay: number;
|
||||||
callAt: number;
|
callAt: number;
|
||||||
createdAt: number;
|
createdAt: number;
|
||||||
|
|
@ -58,10 +58,9 @@ interface Embedder {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClockController {
|
export class ClockController {
|
||||||
readonly start: number;
|
readonly timeOrigin: number;
|
||||||
private _now: number;
|
private _now: { time: number, ticks: number, timeFrozen: boolean };
|
||||||
private _loopLimit: number;
|
private _loopLimit: number;
|
||||||
private _adjustedSystemTime = 0;
|
|
||||||
private _duringTick = false;
|
private _duringTick = false;
|
||||||
private _timers = new Map<number, Timer>();
|
private _timers = new Map<number, Timer>();
|
||||||
private _uniqueTimerId = idCounterStart;
|
private _uniqueTimerId = idCounterStart;
|
||||||
|
|
@ -70,8 +69,8 @@ export class ClockController {
|
||||||
|
|
||||||
constructor(embedder: Embedder, startDate: Date | number | undefined, loopLimit: number = 1000) {
|
constructor(embedder: Embedder, startDate: Date | number | undefined, loopLimit: number = 1000) {
|
||||||
const start = Math.floor(getEpoch(startDate));
|
const start = Math.floor(getEpoch(startDate));
|
||||||
this.start = start;
|
this.timeOrigin = start;
|
||||||
this._now = start;
|
this._now = { time: start, ticks: 0, timeFrozen: false };
|
||||||
this._embedder = embedder;
|
this._embedder = embedder;
|
||||||
this._loopLimit = loopLimit;
|
this._loopLimit = loopLimit;
|
||||||
}
|
}
|
||||||
|
|
@ -82,11 +81,22 @@ export class ClockController {
|
||||||
}
|
}
|
||||||
|
|
||||||
now(): number {
|
now(): number {
|
||||||
return this._now;
|
return this._now.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTime(now: Date | number, options: { freeze?: boolean } = {}) {
|
||||||
|
this._now.time = getEpoch(now);
|
||||||
|
this._now.timeFrozen = !!options.freeze;
|
||||||
}
|
}
|
||||||
|
|
||||||
performanceNow(): DOMHighResTimeStamp {
|
performanceNow(): DOMHighResTimeStamp {
|
||||||
return this._now - this._adjustedSystemTime - this.start;
|
return this._now.ticks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _advanceNow(toTicks: number) {
|
||||||
|
if (!this._now.timeFrozen)
|
||||||
|
this._now.time += toTicks - this._now.ticks;
|
||||||
|
this._now.ticks = toTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _doTick(msFloat: number): Promise<number> {
|
private async _doTick(msFloat: number): Promise<number> {
|
||||||
|
|
@ -94,119 +104,72 @@ export class ClockController {
|
||||||
throw new TypeError('Negative ticks are not supported');
|
throw new TypeError('Negative ticks are not supported');
|
||||||
|
|
||||||
const ms = Math.floor(msFloat);
|
const ms = Math.floor(msFloat);
|
||||||
let tickTo = this._now + ms;
|
const tickTo = this._now.ticks + ms;
|
||||||
let tickFrom = this._now;
|
let tickFrom = this._now.ticks;
|
||||||
let previous = this._now;
|
let previous = this._now.ticks;
|
||||||
let firstException: Error | undefined;
|
let firstException: Error | undefined;
|
||||||
this._duringTick = true;
|
|
||||||
|
|
||||||
// perform each timer in the requested range
|
|
||||||
let timer = this._firstTimerInRange(tickFrom, tickTo);
|
let timer = this._firstTimerInRange(tickFrom, tickTo);
|
||||||
while (timer && tickFrom <= tickTo) {
|
while (timer && tickFrom <= tickTo) {
|
||||||
tickFrom = timer.callAt;
|
tickFrom = timer.callAt;
|
||||||
this._now = timer.callAt;
|
const error = await this._callTimer(timer).catch(e => e);
|
||||||
const oldNow = this._now;
|
firstException = firstException || error;
|
||||||
try {
|
|
||||||
this._callTimer(timer);
|
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
} catch (e) {
|
|
||||||
firstException = firstException || e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compensate for any setSystemTime() call during timer callback
|
|
||||||
if (oldNow !== this._now) {
|
|
||||||
tickFrom += this._now - oldNow;
|
|
||||||
tickTo += this._now - oldNow;
|
|
||||||
previous += this._now - oldNow;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer = this._firstTimerInRange(previous, tickTo);
|
timer = this._firstTimerInRange(previous, tickTo);
|
||||||
previous = tickFrom;
|
previous = tickFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._duringTick = false;
|
this._advanceNow(tickTo);
|
||||||
this._now = tickTo;
|
|
||||||
if (firstException)
|
if (firstException)
|
||||||
throw firstException;
|
throw firstException;
|
||||||
|
|
||||||
return this._now;
|
return this._now.ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
async recordTick(tickValue: string | number) {
|
async recordTick(tickValue: string | number) {
|
||||||
const msFloat = parseTime(tickValue);
|
const msFloat = parseTime(tickValue);
|
||||||
this._now += msFloat;
|
this._advanceNow(this._now.ticks + msFloat);
|
||||||
}
|
}
|
||||||
|
|
||||||
async tick(tickValue: string | number): Promise<number> {
|
async tick(tickValue: string | number): Promise<number> {
|
||||||
return await this._doTick(parseTime(tickValue));
|
return await this._doTick(parseTime(tickValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
async next() {
|
async next(): Promise<number> {
|
||||||
const timer = this._firstTimer();
|
const timer = this._firstTimer();
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return this._now;
|
return this._now.ticks;
|
||||||
|
await this._callTimer(timer);
|
||||||
let err: Error | undefined;
|
return this._now.ticks;
|
||||||
this._duringTick = true;
|
|
||||||
this._now = timer.callAt;
|
|
||||||
try {
|
|
||||||
this._callTimer(timer);
|
|
||||||
await new Promise<void>(f => this._embedder.postTask(f));
|
|
||||||
} catch (e) {
|
|
||||||
err = e;
|
|
||||||
}
|
|
||||||
this._duringTick = false;
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
throw err;
|
|
||||||
return this._now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async runToFrame() {
|
async runToFrame(): Promise<number> {
|
||||||
return this.tick(this.getTimeToNextFrame());
|
return this.tick(this.getTimeToNextFrame());
|
||||||
}
|
}
|
||||||
|
|
||||||
async runAll() {
|
async runAll(): Promise<number> {
|
||||||
for (let i = 0; i < this._loopLimit; i++) {
|
for (let i = 0; i < this._loopLimit; i++) {
|
||||||
const numTimers = this._timers.size;
|
const numTimers = this._timers.size;
|
||||||
if (numTimers === 0)
|
if (numTimers === 0)
|
||||||
return this._now;
|
return this._now.ticks;
|
||||||
|
|
||||||
await this.next();
|
await this.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
const excessJob = this._firstTimer();
|
const excessJob = this._firstTimer();
|
||||||
if (!excessJob)
|
if (!excessJob)
|
||||||
return;
|
return this._now.ticks;
|
||||||
throw this._getInfiniteLoopError(excessJob);
|
throw this._getInfiniteLoopError(excessJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
async runToLast() {
|
async runToLast(): Promise<number> {
|
||||||
const timer = this._lastTimer();
|
const timer = this._lastTimer();
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return this._now;
|
return this._now.ticks;
|
||||||
return await this.tick(timer.callAt - this._now);
|
return await this.tick(timer.callAt - this._now.ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this._timers.clear();
|
this._timers.clear();
|
||||||
this._now = this.start;
|
this._now = { time: this.timeOrigin, ticks: 0, timeFrozen: false };
|
||||||
}
|
|
||||||
|
|
||||||
setSystemTime(systemTime: Date | number) {
|
|
||||||
// determine time difference
|
|
||||||
const newNow = getEpoch(systemTime);
|
|
||||||
const difference = newNow - this._now;
|
|
||||||
|
|
||||||
this._adjustedSystemTime = this._adjustedSystemTime + difference;
|
|
||||||
// update 'system clock'
|
|
||||||
this._now = newNow;
|
|
||||||
|
|
||||||
// update timers and intervals to keep them stable
|
|
||||||
for (const timer of this._timers.values()) {
|
|
||||||
timer.createdAt += difference;
|
|
||||||
timer.callAt += difference;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async jump(tickValue: string | number): Promise<number> {
|
async jump(tickValue: string | number): Promise<number> {
|
||||||
|
|
@ -214,13 +177,13 @@ export class ClockController {
|
||||||
const ms = Math.floor(msFloat);
|
const ms = Math.floor(msFloat);
|
||||||
|
|
||||||
for (const timer of this._timers.values()) {
|
for (const timer of this._timers.values()) {
|
||||||
if (this._now + ms > timer.callAt)
|
if (this._now.ticks + ms > timer.callAt)
|
||||||
timer.callAt = this._now + ms;
|
timer.callAt = this._now.ticks + ms;
|
||||||
}
|
}
|
||||||
return await this.tick(ms);
|
return await this.tick(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
addTimer(options: { func: TimerHandler, type: TimerType, delay?: number | string, args?: () => any[] }): number {
|
addTimer(options: { func: TimerHandler, type: TimerType, delay?: number | string, args?: any[] }): number {
|
||||||
if (options.func === undefined)
|
if (options.func === undefined)
|
||||||
throw new Error('Callback must be provided to timer calls');
|
throw new Error('Callback must be provided to timer calls');
|
||||||
|
|
||||||
|
|
@ -233,10 +196,10 @@ export class ClockController {
|
||||||
const timer: Timer = {
|
const timer: Timer = {
|
||||||
type: options.type,
|
type: options.type,
|
||||||
func: options.func,
|
func: options.func,
|
||||||
args: options.args || (() => []),
|
args: options.args || [],
|
||||||
delay,
|
delay,
|
||||||
callAt: this._now + (delay || (this._duringTick ? 1 : 0)),
|
callAt: this._now.ticks + (delay || (this._duringTick ? 1 : 0)),
|
||||||
createdAt: this._now,
|
createdAt: this._now.ticks,
|
||||||
id: this._uniqueTimerId++,
|
id: this._uniqueTimerId++,
|
||||||
error: new Error(),
|
error: new Error(),
|
||||||
};
|
};
|
||||||
|
|
@ -278,12 +241,32 @@ export class ClockController {
|
||||||
return lastTimer;
|
return lastTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _callTimer(timer: Timer) {
|
private async _callTimer(timer: Timer) {
|
||||||
|
this._advanceNow(timer.callAt);
|
||||||
|
|
||||||
if (timer.type === TimerType.Interval)
|
if (timer.type === TimerType.Interval)
|
||||||
this._timers.get(timer.id)!.callAt += timer.delay;
|
this._timers.get(timer.id)!.callAt += timer.delay;
|
||||||
else
|
else
|
||||||
this._timers.delete(timer.id);
|
this._timers.delete(timer.id);
|
||||||
callFunction(timer.func, timer.args());
|
|
||||||
|
this._duringTick = true;
|
||||||
|
try {
|
||||||
|
if (typeof timer.func !== 'function') {
|
||||||
|
(() => { eval(timer.func); })();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = timer.args;
|
||||||
|
if (timer.type === TimerType.AnimationFrame)
|
||||||
|
args = [this._now.ticks];
|
||||||
|
else if (timer.type === TimerType.IdleCallback)
|
||||||
|
args = [{ didTimeout: false, timeRemaining: () => 0 }];
|
||||||
|
|
||||||
|
timer.func.apply(null, args);
|
||||||
|
await new Promise<void>(f => this._embedder.postTask(f));
|
||||||
|
} finally {
|
||||||
|
this._duringTick = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getInfiniteLoopError(job: Timer) {
|
private _getInfiniteLoopError(job: Timer) {
|
||||||
|
|
@ -336,7 +319,7 @@ export class ClockController {
|
||||||
}
|
}
|
||||||
|
|
||||||
getTimeToNextFrame() {
|
getTimeToNextFrame() {
|
||||||
return 16 - ((this._now - this.start) % 16);
|
return 16 - this._now.ticks % 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
clearTimer(timerId: number, type: TimerType) {
|
clearTimer(timerId: number, type: TimerType) {
|
||||||
|
|
@ -375,7 +358,7 @@ export class ClockController {
|
||||||
|
|
||||||
advanceAutomatically(advanceTimeDelta: number = 20): () => void {
|
advanceAutomatically(advanceTimeDelta: number = 20): () => void {
|
||||||
return this._embedder.postTaskPeriodically(
|
return this._embedder.postTaskPeriodically(
|
||||||
() => this.tick(advanceTimeDelta!),
|
() => this._doTick(advanceTimeDelta!),
|
||||||
advanceTimeDelta,
|
advanceTimeDelta,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -556,13 +539,6 @@ function compareTimers(a: Timer, b: Timer) {
|
||||||
// As timer ids are unique, no fallback `0` is necessary
|
// As timer ids are unique, no fallback `0` is necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
function callFunction(func: TimerHandler, args: any[]) {
|
|
||||||
if (typeof func === 'function')
|
|
||||||
func.apply(null, args);
|
|
||||||
else
|
|
||||||
(() => { eval(func); })();
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxTimeout = Math.pow(2, 31) - 1; // see https://heycam.github.io/webidl/#abstract-opdef-converttoint
|
const maxTimeout = Math.pow(2, 31) - 1; // see https://heycam.github.io/webidl/#abstract-opdef-converttoint
|
||||||
const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs
|
const idCounterStart = 1e12; // arbitrarily large number to avoid collisions with native timer IDs
|
||||||
|
|
||||||
|
|
@ -605,7 +581,7 @@ function createApi(clock: ClockController, originals: ClockMethods): ClockMethod
|
||||||
return clock.addTimer({
|
return clock.addTimer({
|
||||||
type: TimerType.Timeout,
|
type: TimerType.Timeout,
|
||||||
func,
|
func,
|
||||||
args: () => args,
|
args,
|
||||||
delay
|
delay
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -618,7 +594,7 @@ function createApi(clock: ClockController, originals: ClockMethods): ClockMethod
|
||||||
return clock.addTimer({
|
return clock.addTimer({
|
||||||
type: TimerType.Interval,
|
type: TimerType.Interval,
|
||||||
func,
|
func,
|
||||||
args: () => args,
|
args,
|
||||||
delay,
|
delay,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -631,7 +607,6 @@ function createApi(clock: ClockController, originals: ClockMethods): ClockMethod
|
||||||
type: TimerType.AnimationFrame,
|
type: TimerType.AnimationFrame,
|
||||||
func: callback,
|
func: callback,
|
||||||
delay: clock.getTimeToNextFrame(),
|
delay: clock.getTimeToNextFrame(),
|
||||||
args: () => [clock.performanceNow()],
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
cancelAnimationFrame: (timerId: number): void => {
|
cancelAnimationFrame: (timerId: number): void => {
|
||||||
|
|
@ -646,7 +621,6 @@ function createApi(clock: ClockController, originals: ClockMethods): ClockMethod
|
||||||
return clock.addTimer({
|
return clock.addTimer({
|
||||||
type: TimerType.IdleCallback,
|
type: TimerType.IdleCallback,
|
||||||
func: callback,
|
func: callback,
|
||||||
args: () => [],
|
|
||||||
delay: options?.timeout ? Math.min(options?.timeout, timeToNextIdlePeriod) : timeToNextIdlePeriod,
|
delay: options?.timeout ? Math.min(options?.timeout, timeToNextIdlePeriod) : timeToNextIdlePeriod,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -670,7 +644,7 @@ function getClearHandler(type: TimerType) {
|
||||||
function fakePerformance(clock: ClockController, performance: Performance): Performance {
|
function fakePerformance(clock: ClockController, performance: Performance): Performance {
|
||||||
const result: any = {
|
const result: any = {
|
||||||
now: () => clock.performanceNow(),
|
now: () => clock.performanceNow(),
|
||||||
timeOrigin: clock.start,
|
timeOrigin: clock.timeOrigin,
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line no-proto
|
// eslint-disable-next-line no-proto
|
||||||
for (const key of Object.keys((performance as any).__proto__)) {
|
for (const key of Object.keys((performance as any).__proto__)) {
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ it.describe('setTimeout', () => {
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
clock.setTimeout(stub, 5000);
|
clock.setTimeout(stub, 5000);
|
||||||
await clock.tick(1000);
|
await clock.tick(1000);
|
||||||
clock.setSystemTime(new clock.Date().getTime() + 1000);
|
clock.setTime(new clock.Date().getTime() + 1000);
|
||||||
await clock.tick(3990);
|
await clock.tick(3990);
|
||||||
expect(stub.callCount).toBe(0);
|
expect(stub.callCount).toBe(0);
|
||||||
await clock.tick(20);
|
await clock.tick(20);
|
||||||
|
|
@ -167,7 +167,7 @@ it.describe('setTimeout', () => {
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
clock.setTimeout(stub, 5000);
|
clock.setTimeout(stub, 5000);
|
||||||
await clock.tick(1000);
|
await clock.tick(1000);
|
||||||
clock.setSystemTime(new clock.Date().getTime() - 1000);
|
clock.setTime(new clock.Date().getTime() - 1000);
|
||||||
await clock.tick(3990);
|
await clock.tick(3990);
|
||||||
expect(stub.callCount).toBe(0);
|
expect(stub.callCount).toBe(0);
|
||||||
await clock.tick(20);
|
await clock.tick(20);
|
||||||
|
|
@ -502,7 +502,7 @@ it.describe('tick', () => {
|
||||||
|
|
||||||
it('is not influenced by forward system clock changes', async ({ clock }) => {
|
it('is not influenced by forward system clock changes', async ({ clock }) => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
clock.setSystemTime(new clock.Date().getTime() + 1000);
|
clock.setTime(new clock.Date().getTime() + 1000);
|
||||||
};
|
};
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
clock.setTimeout(callback, 1000);
|
clock.setTimeout(callback, 1000);
|
||||||
|
|
@ -515,7 +515,7 @@ it.describe('tick', () => {
|
||||||
|
|
||||||
it('is not influenced by forward system clock changes 2', async ({ clock }) => {
|
it('is not influenced by forward system clock changes 2', async ({ clock }) => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
clock.setSystemTime(new clock.Date().getTime() - 1000);
|
clock.setTime(new clock.Date().getTime() - 1000);
|
||||||
};
|
};
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
clock.setTimeout(callback, 1000);
|
clock.setTimeout(callback, 1000);
|
||||||
|
|
@ -528,7 +528,7 @@ it.describe('tick', () => {
|
||||||
|
|
||||||
it('is not influenced by forward system clock changes when an error is thrown', async ({ clock }) => {
|
it('is not influenced by forward system clock changes when an error is thrown', async ({ clock }) => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
clock.setSystemTime(new clock.Date().getTime() + 1000);
|
clock.setTime(new clock.Date().getTime() + 1000);
|
||||||
throw new Error();
|
throw new Error();
|
||||||
};
|
};
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
|
|
@ -544,7 +544,7 @@ it.describe('tick', () => {
|
||||||
|
|
||||||
it('is not influenced by forward system clock changes when an error is thrown 2', async ({ clock }) => {
|
it('is not influenced by forward system clock changes when an error is thrown 2', async ({ clock }) => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
clock.setSystemTime(new clock.Date().getTime() - 1000);
|
clock.setTime(new clock.Date().getTime() - 1000);
|
||||||
throw new Error();
|
throw new Error();
|
||||||
};
|
};
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
|
|
@ -653,7 +653,7 @@ it.describe('tick', () => {
|
||||||
it('is not influenced by forward system clock changes in promises', async ({ clock }) => {
|
it('is not influenced by forward system clock changes in promises', async ({ clock }) => {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
void Promise.resolve().then(() => {
|
void Promise.resolve().then(() => {
|
||||||
clock.setSystemTime(new clock.Date().getTime() + 1000);
|
clock.setTime(new clock.Date().getTime() + 1000);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
|
|
@ -1363,7 +1363,7 @@ it.describe('setInterval', () => {
|
||||||
clock.setInterval(stub, 10);
|
clock.setInterval(stub, 10);
|
||||||
await clock.tick(11);
|
await clock.tick(11);
|
||||||
expect(stub.callCount).toBe(1);
|
expect(stub.callCount).toBe(1);
|
||||||
clock.setSystemTime(new clock.Date().getTime() + 1000);
|
clock.setTime(new clock.Date().getTime() + 1000);
|
||||||
await clock.tick(8);
|
await clock.tick(8);
|
||||||
expect(stub.callCount).toBe(1);
|
expect(stub.callCount).toBe(1);
|
||||||
await clock.tick(3);
|
await clock.tick(3);
|
||||||
|
|
@ -1374,7 +1374,7 @@ it.describe('setInterval', () => {
|
||||||
const stub = createStub();
|
const stub = createStub();
|
||||||
clock.setInterval(stub, 10);
|
clock.setInterval(stub, 10);
|
||||||
await clock.tick(5);
|
await clock.tick(5);
|
||||||
clock.setSystemTime(new clock.Date().getTime() - 1000);
|
clock.setTime(new clock.Date().getTime() - 1000);
|
||||||
await clock.tick(6);
|
await clock.tick(6);
|
||||||
expect(stub.callCount).toBe(1);
|
expect(stub.callCount).toBe(1);
|
||||||
await clock.tick(10);
|
await clock.tick(10);
|
||||||
|
|
@ -1465,7 +1465,7 @@ it.describe('date', () => {
|
||||||
|
|
||||||
it('listens to system clock changes', async ({ clock }) => {
|
it('listens to system clock changes', async ({ clock }) => {
|
||||||
const date1 = new clock.Date();
|
const date1 = new clock.Date();
|
||||||
clock.setSystemTime(date1.getTime() + 1000);
|
clock.setTime(date1.getTime() + 1000);
|
||||||
const date2 = new clock.Date();
|
const date2 = new clock.Date();
|
||||||
expect(date2.getTime() - date1.getTime()).toBe(1000);
|
expect(date2.getTime() - date1.getTime()).toBe(1000);
|
||||||
});
|
});
|
||||||
|
|
@ -2056,6 +2056,9 @@ it.describe('requestIdleCallback', () => {
|
||||||
clock.requestIdleCallback(stub);
|
clock.requestIdleCallback(stub);
|
||||||
await clock.tick(1000);
|
await clock.tick(1000);
|
||||||
expect(stub.called).toBeTruthy();
|
expect(stub.called).toBeTruthy();
|
||||||
|
const idleCallbackArg = stub.firstCall.args[0];
|
||||||
|
expect(idleCallbackArg.didTimeout).toBeFalsy();
|
||||||
|
expect(idleCallbackArg.timeRemaining()).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('runs no later than timeout option even if there are any timers', async ({ clock }) => {
|
it('runs no later than timeout option even if there are any timers', async ({ clock }) => {
|
||||||
|
|
|
||||||
|
|
@ -587,8 +587,8 @@ it.describe('popup', () => {
|
||||||
it('should tick before popup', async ({ page, browserName }) => {
|
it('should tick before popup', async ({ page, browserName }) => {
|
||||||
const now = new Date('2015-09-25');
|
const now = new Date('2015-09-25');
|
||||||
await page.clock.installFakeTimers(now);
|
await page.clock.installFakeTimers(now);
|
||||||
const newNow = await page.clock.runFor(1000);
|
const ticks = await page.clock.runFor(1000);
|
||||||
expect(newNow).toBe(now.getTime() + 1000);
|
expect(ticks).toBe(1000);
|
||||||
|
|
||||||
const [popup] = await Promise.all([
|
const [popup] = await Promise.all([
|
||||||
page.waitForEvent('popup'),
|
page.waitForEvent('popup'),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue