Integrate sinon with @sinonjs/fake-timers, with fixes (#43148)

* fix(sinonjs__fake-timers): refactor as ambient module, higher arity callbacks

* feat!(sinon): sinon abstracted timers to @sinonjs/fake-timers so use that package to avoid interface discrepancies, add async variant tests, bump to 9.0

* chore(sinon): add module path map to scoped sinon dependency

* chore(sinonjs__fake-timers): revert ambient module declaration, rely on type inference in tests

* chore(sinon): rely on type inference in async clock tests
This commit is contained in:
Andrew Zammit 2020-03-31 16:14:31 -07:00 committed by GitHub
parent c26df8232d
commit be9dcd06bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 162 additions and 222 deletions

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
@ -20,4 +25,4 @@
"index.d.ts",
"mochaccino-tests.ts"
]
}
}

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
@ -20,4 +25,4 @@
"index.d.ts",
"should-sinon-tests.ts"
]
}
}

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -16,7 +16,8 @@
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"paths": {
"sinon-chai": [ "sinon-chai/v2" ]
"sinon-chai": [ "sinon-chai/v2" ],
"@sinonjs/fake-timers": [ "sinonjs__fake-timers" ]
}
},
"files": [

View File

@ -14,6 +14,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
@ -20,4 +25,4 @@
"index.d.ts",
"sinon-express-mock-tests.ts"
]
}
}

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
@ -20,4 +25,4 @@
"index.d.ts",
"sinon-mongoose-tests.ts"
]
}
}

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -13,6 +13,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -1,4 +1,4 @@
// Type definitions for Sinon 7.5
// Type definitions for Sinon 9.0
// Project: https://sinonjs.org
// Definitions by: William Sears <https://github.com/mrbigdog2u>
// Jonathan Little <https://github.com/rationull>
@ -14,6 +14,8 @@
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.8
import * as FakeTimers from '@sinonjs/fake-timers';
// sinon uses DOM dependencies which are absent in browser-less environment like node.js
// to avoid compiler errors this monkey patch is used
// see more details in https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11351
@ -725,84 +727,17 @@ declare namespace Sinon {
(obj: any): SinonMock;
}
type SinonTimerId = number | { id: number };
type SinonTimerId = FakeTimers.TimerId;
interface SinonFakeTimers {
now: number;
loopLimit: number;
setTimeout(callback: (...args: any[]) => void, timeout: number, ...args: any[]): SinonTimerId;
clearTimeout(id: SinonTimerId): void;
setInterval(callback: (...args: any[]) => void, timeout: number, ...args: any[]): SinonTimerId;
clearInterval(id: SinonTimerId): void;
setImmediate(callback: (...args: any[]) => void, ...args: any[]): SinonTimerId;
clearImmediate(id: SinonTimerId): void;
requestAnimationFrame(callback: (time: number) => void): SinonTimerId;
cancelAnimationFrame(id: SinonTimerId): void;
nextTick(callback: (...args: any[]) => void, ...args: any[]): void;
queueMicrotask(callback: () => void): void;
requestIdleCallback(func: (...args: any[]) => void, timeout?: number, ...args: any[]): SinonTimerId;
cancelIdleCallback(timerId: SinonTimerId): void;
/**
* Tick the clock ahead time milliseconds.
* Causes all timers scheduled within the affected time range to be called.
* 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.
* time may be negative, which causes the clock to change but wont fire any callbacks.
* @param ms
*/
tick(ms: number | string): number;
/**
* Advances the clock to the the moment of the first scheduled timer, firing it.
*/
next(): number;
/**
* This 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 timers they use, or the delays in those timers.
*/
runAll(): number;
runToLast(): number;
reset(): void;
runMicrotasks(): void;
runToFrame(): number;
Date(): Date;
Date(year: number): Date;
Date(year: number, month: number): Date;
Date(year: number, month: number, day: number): Date;
Date(year: number, month: number, day: number, hour: number): Date;
Date(year: number, month: number, day: number, hour: number, minute: number): Date;
Date(year: number, month: number, day: number, hour: number, minute: number, second: number): Date;
Date(year: number, month: number, day: number, hour: number, minute: number, second: number, ms: number): Date;
/**
* Restore the faked methods.
* Call in e.g. tearDown.
*/
restore(): void;
uninstall(): void;
/**
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
* without affecting timers, intervals or immediates.
* @param now The new 'now' in unix milliseconds
*/
setSystemTime(now: number): void;
/**
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
* without affecting timers, intervals or immediates.
* @param now The new 'now' as a JavaScript Date
*/
setSystemTime(date: Date): void;
countTimers(): number;
}
type SinonFakeTimers = FakeTimers.InstalledMethods &
FakeTimers.NodeClock &
FakeTimers.BrowserClock & {
/**
* Restore the faked methods.
* Call in e.g. tearDown.
*/
restore(): void;
};
interface SinonFakeTimersConfig {
now: number | Date;

View File

@ -153,11 +153,21 @@ function testClock() {
clock.cancelAnimationFrame(animTimer);
clock.nextTick(fn);
clock.tick(1);
clock.tick('00:10');
clock.tickAsync(500).then(val => val.toExponential());
clock.tickAsync('500').then(val => val.toExponential());
clock.next();
clock.nextAsync().then(val => val.toExponential());
clock.runAll();
clock.runAllAsync().then(val => val.toExponential());
clock.runToLast();
clock.runToLastAsync().then(val => val.toExponential());
clock.reset();
clock.runMicrotasks();
clock.runToFrame();

View File

@ -1,3 +1,5 @@
import * as FakeTimers from '@sinonjs/fake-timers';
// sinon uses DOM dependencies which are absent in browser-less environment like node.js
// to avoid compiler errors this monkey patch is used
// see more details in https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11351
@ -758,119 +760,17 @@ declare namespace Sinon {
(obj: any): SinonMock;
}
type SinonTimerId = number | { id: number };
type SinonTimerId = FakeTimers.TimerId;
interface SinonFakeTimers {
now: number;
loopLimit: number;
setTimeout<TArgs extends any[] = any[]>(
callback: (...args: TArgs) => void,
timeout: number,
...args: TArgs
): SinonTimerId;
clearTimeout(id: SinonTimerId): void;
setInterval<TArgs extends any[] = any[]>(
callback: (...args: TArgs) => void,
timeout: number,
...args: TArgs
): SinonTimerId;
clearInterval(id: SinonTimerId): void;
setImmediate<TArgs extends any[] = any[]>(
callback: (...args: TArgs) => void,
...args: TArgs
): SinonTimerId;
clearImmediate(id: SinonTimerId): void;
requestAnimationFrame(callback: (time: number) => void): SinonTimerId;
cancelAnimationFrame(id: SinonTimerId): void;
nextTick<TArgs extends any[] = any[]>(
callback: (...args: TArgs) => void,
...args: TArgs): void;
queueMicrotask(callback: () => void): void;
requestIdleCallback<TArgs extends any[] = any[]>(func: (...args: TArgs) => void, timeout?: number, ...args:
TArgs): SinonTimerId;
cancelIdleCallback(timerId: SinonTimerId): void;
/**
* Tick the clock ahead time milliseconds.
* Causes all timers scheduled within the affected time range to be called.
* 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.
* time may be negative, which causes the clock to change but wont fire any callbacks.
* @param ms
*/
tick(ms: number | string): number;
/**
* Advances the clock to the the moment of the first scheduled timer, firing it.
*/
next(): number;
/**
* This 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 timers they use, or the delays in those timers.
*/
runAll(): number;
runToLast(): number;
reset(): void;
runMicrotasks(): void;
runToFrame(): number;
Date(): Date;
Date(year: number): Date;
Date(year: number, month: number): Date;
Date(year: number, month: number, day: number): Date;
Date(year: number, month: number, day: number, hour: number): Date;
Date(
year: number,
month: number,
day: number,
hour: number,
minute: number
): Date;
Date(
year: number,
month: number,
day: number,
hour: number,
minute: number,
second: number
): Date;
Date(
year: number,
month: number,
day: number,
hour: number,
minute: number,
second: number,
ms: number
): Date;
/**
* Restore the faked methods.
* Call in e.g. tearDown.
*/
restore(): void;
uninstall(): void;
/**
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
* without affecting timers, intervals or immediates.
* @param now The new 'now' in unix milliseconds
*/
setSystemTime(now: number): void;
/**
* Simulate the user changing the system clock while your program is running. It changes the 'now' timestamp
* without affecting timers, intervals or immediates.
* @param now The new 'now' as a JavaScript Date
*/
setSystemTime(date: Date): void;
countTimers(): number;
}
type SinonFakeTimers = FakeTimers.InstalledMethods &
FakeTimers.NodeClock &
FakeTimers.BrowserClock & {
/**
* Restore the faked methods.
* Call in e.g. tearDown.
*/
restore(): void;
};
interface SinonFakeTimersConfig {
now: number | Date;

View File

@ -160,11 +160,21 @@ function testClock() {
clock.cancelAnimationFrame(animTimer);
clock.nextTick(fn);
clock.tick(1);
clock.tick('00:10');
clock.tickAsync(500).then(val => val.toExponential());
clock.tickAsync('500').then(val => val.toExponential());
clock.next();
clock.nextAsync().then(val => val.toExponential());
clock.runAll();
clock.runAllAsync().then(val => val.toExponential());
clock.runToLast();
clock.runToLastAsync().then(val => val.toExponential());
clock.reset();
clock.runMicrotasks();
clock.runToFrame();

View File

@ -15,6 +15,11 @@
"../../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -15,6 +15,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},

View File

@ -38,14 +38,14 @@ export interface GlobalTimers<TTimerId extends TimerId> {
* @param args Any extra arguments to pass to the callback.
* @returns Time identifier for cancellation.
*/
setTimeout: (callback: () => void, timeout: number, ...args: any[]) => TTimerId;
setTimeout: (callback: (...args: any[]) => void, timeout: number, ...args: any[]) => TTimerId;
/**
* Clears a timer, as long as it was created using setTimeout.
*
* @param id Timer ID or object.
*/
clearTimeout: (id: TimerId) => void;
clearTimeout: (id: TTimerId) => void;
/**
* Schedules a callback to be fired every time timeout milliseconds have ticked by.
@ -55,7 +55,7 @@ export interface GlobalTimers<TTimerId extends TimerId> {
* @param args Any extra arguments to pass to the callback.
* @returns Time identifier for cancellation.
*/
setInterval: (callback: () => void, timeout: number, ...args: any[]) => TTimerId;
setInterval: (callback: (...args: any[]) => void, timeout: number, ...args: any[]) => TTimerId;
/**
* Clears a timer, as long as it was created using setInterval.
@ -68,10 +68,11 @@ export interface GlobalTimers<TTimerId extends TimerId> {
* Schedules the callback to be fired once 0 milliseconds have ticked by.
*
* @param callback Callback to be fired.
* @param args Any extra arguments to pass to the callback.
* @remarks You'll still have to call clock.tick() for the callback to fire.
* @remarks If called during a tick the callback won't fire until 1 millisecond has ticked by.
*/
setImmediate: (callback: () => void) => TTimerId;
setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => TTimerId;
/**
* Clears a timer, as long as it was created using setImmediate.
@ -166,22 +167,25 @@ export interface FakeClock<TTimerId extends TimerId> extends GlobalTimers<TTimer
/**
* Advances the clock to the the moment of the first scheduled timer, firing it.
* @returns Fake milliseconds since the unix epoch.
*/
next: () => void;
next: () => number;
/**
* Advances the clock to the the moment of the first scheduled timer, firing it.
*
* Also breaks the event loop, allowing any scheduled promise callbacks to execute _before_ running the timers.
* @returns Fake milliseconds since the unix epoch.
*/
nextAsync: () => Promise<void>;
nextAsync: () => Promise<number>;
/**
* Advance the clock, firing callbacks if necessary.
*
* @param time How many ticks to advance by.
* @returns Fake milliseconds since the unix epoch.
*/
tick: (time: number | string) => void;
tick: (time: number | string) => number;
/**
* Advance the clock, firing callbacks if necessary.
@ -189,8 +193,9 @@ export interface FakeClock<TTimerId extends TimerId> extends GlobalTimers<TTimer
* Also breaks the event loop, allowing any scheduled promise callbacks to execute _before_ running the timers.
*
* @param time How many ticks to advance by.
* @returns Fake milliseconds since the unix epoch.
*/
tickAsync: (time: number | string) => Promise<void>;
tickAsync: (time: number | string) => Promise<number>;
/**
* Removes all timers and tick without firing them and restore now to its original value.
@ -201,8 +206,9 @@ export interface FakeClock<TTimerId extends TimerId> extends GlobalTimers<TTimer
* Runs all pending timers until there are none remaining.
*
* @remarks If new timers are added while it is executing they will be run as well.
* @returns Fake milliseconds since the unix epoch.
*/
runAll: () => void;
runAll: () => number;
/**
* Runs all pending timers until there are none remaining.
@ -210,27 +216,31 @@ export interface FakeClock<TTimerId extends TimerId> extends GlobalTimers<TTimer
* Also breaks the event loop, allowing any scheduled promise callbacks to execute _before_ running the timers.
*
* @remarks If new timers are added while it is executing they will be run as well.
* @returns Fake milliseconds since the unix epoch.
*/
runAllAsync: () => Promise<void>;
runAllAsync: () => Promise<number>;
/**
* Advanced the clock to the next animation frame while firing all scheduled callbacks.
* @returns Fake milliseconds since the unix epoch.
*/
runToFrame: () => void;
runToFrame: () => number;
/**
* Takes note of the last scheduled timer when it is run, and advances the clock to
* that time firing callbacks as necessary.
* @returns Fake milliseconds since the unix epoch.
*/
runToLast: () => void;
runToLast: () => number;
/**
* Takes note of the last scheduled timer when it is run, and advances the clock to
* that time firing callbacks as necessary.
*
* Also breaks the event loop, allowing any scheduled promise callbacks to execute _before_ running the timers.
* @returns Fake milliseconds since the unix epoch.
*/
runToLastAsync: () => Promise<void>;
runToLastAsync: () => Promise<number>;
/**
* Simulates a user changing the system clock.
@ -273,7 +283,7 @@ export type NodeClock = FakeClock<NodeTimer> & {
/**
* Simulates process.nextTick().
*/
nextTick: (callback: () => void) => void;
nextTick: (callback: (...args: any[]) => void, ...args: any[]) => void;
/**
* Run all pending microtasks scheduled with nextTick.
@ -353,8 +363,7 @@ export interface FakeTimerInstallOpts {
/**
* Creates a clock and installs it globally.
*
* @param now Current time for the clock, as with FakeTimers.createClock().
* @param toFake Names of methods that should be faked.
* @param [opts] Options for the fake timer.
*/
export function install(opts?: FakeTimerInstallOpts): InstalledClock;

View File

@ -1,4 +1,4 @@
import FakeTimers = require('sinonjs__fake-timers');
import * as FakeTimers from '@sinonjs/fake-timers';
const global: FakeTimers.FakeTimerWithContext = FakeTimers.withGlobal({});
const timers: FakeTimers.GlobalTimers<FakeTimers.TimerId> = FakeTimers.timers;
@ -86,17 +86,17 @@ browserClock.tick('08');
nodeClock.tick(7);
nodeClock.tick('08:03');
browserClock.tickAsync(7).then(() => {});
browserClock.tickAsync('08').then(() => {});
browserClock.tickAsync(7).then(val => val.toExponential());
browserClock.tickAsync('08').then(val => val.toExponential());
nodeClock.tickAsync(7).then(() => {});
nodeClock.tickAsync('08:03').then(() => {});
nodeClock.tickAsync(7).then(val => val.toExponential());
nodeClock.tickAsync('08:03').then(val => val.toExponential());
browserClock.next();
nodeClock.next();
browserClock.nextAsync().then(() => {});
nodeClock.nextAsync().then(() => {});
browserClock.nextAsync().then(val => val.toExponential());
nodeClock.nextAsync().then(val => val.toExponential());
browserClock.reset();
nodeClock.reset();
@ -104,8 +104,8 @@ nodeClock.reset();
browserClock.runAll();
nodeClock.runAll();
browserClock.runAllAsync().then(() => {});
nodeClock.runAllAsync().then(() => {});
browserClock.runAllAsync().then(val => val.toExponential());
nodeClock.runAllAsync().then(val => val.toExponential());
nodeClock.runMicrotasks();
@ -115,8 +115,8 @@ nodeClock.runToFrame();
browserClock.runToLast();
nodeClock.runToLast();
browserClock.runToLastAsync().then(() => {});
nodeClock.runToLastAsync().then(() => {});
browserClock.runToLastAsync().then(val => val.toExponential());
nodeClock.runToLastAsync().then(val => val.toExponential());
browserClock.setSystemTime();
browserClock.setSystemTime(7);

View File

@ -14,6 +14,11 @@
"../"
],
"types": [],
"paths": {
"@sinonjs/fake-timers": [
"sinonjs__fake-timers"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},