Skip to content

Commit

Permalink
feat(fake timer): add useFakeTimer function and implement fake time…
Browse files Browse the repository at this point in the history
…r object
  • Loading branch information
TomokiMiyauci committed Dec 14, 2021
1 parent f26a4b0 commit 173b5f3
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 0 deletions.
22 changes: 22 additions & 0 deletions _e2e/fake_timer_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
import { expect, fn, test, useFakeTimer } from "../mod.ts";
test("should hijack default globalThis timer functions", () => {
expect(globalThis["setTimeout"]).toEqual(globalThis["setTimeout"]);

const setTimeout = globalThis["setTimeout"];
const fakeTimer = useFakeTimer();

expect(globalThis["setTimeout"]).not.toEqual(setTimeout);

fakeTimer.useRealTimer();
});

test("should run all queued schedules", () => {
const fakeTimer = useFakeTimer();
const mockObject = fn();
setTimeout(mockObject, 1000);

expect(mockObject).not.toHaveBeenCalled();
fakeTimer.runAllTimers().useRealTimer();
expect(mockObject).toHaveBeenCalled();
});
56 changes: 56 additions & 0 deletions fake_timer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# fake timer

Replaces the native timer function with a function that allows you to control
the passage of time.

## useFakeTimer

Use fake versions of the standard timer functions. The `fakeTimer` object is the
return value. Contains a side effect of hijacking the globalThis timer.

```ts
import {
expect,
test,
useFakeTimer,
} from "https://deno.land/x/unitest@$VERSION/mod.ts";

test("should hijack default globalThis timer functions", () => {
expect(globalThis["setTimeout"]).toEqual(globalThis["setTimeout"]);

const setTimeout = globalThis["setTimeout"];
const fakeTimer = useFakeTimer();

expect(globalThis["setTimeout"]).not.toEqual(setTimeout);

fakeTimer.useRealTimer();
});
```

### fakeTimer#useRealTimer

Replaces the standard timer function. It must be called in any test using
`useFakeTimer`.

## fakeTimer#runAllTimers

Exhausts both the macro-task queue and the micro-task queue.

```ts
import {
expect,
fn,
test,
useFakeTimer,
} from "https://deno.land/x/unitest@$VERSION/mod.ts";

test("should run all queued schedules", () => {
const fakeTimer = useFakeTimer();
const mockObject = fn();
setTimeout(mockObject, 1000);

expect(mockObject).not.toHaveBeenCalled();
fakeTimer.runAllTimers().useRealTimer();
expect(mockObject).toHaveBeenCalled();
});
```
86 changes: 86 additions & 0 deletions fake_timer/fake_timer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
// This module is browser compatible.

import { withGlobal } from "http://esm.sh/@sinonjs/fake-timers";
import type { InstalledClock } from "http://esm.sh/@sinonjs/fake-timers";

/** Spec for fake timer object */
interface FakeTimerSpec {
/** Replaces the standard timer function. It must be called in any test using
* `useFakeTimer`
*/
useRealTimer(): void;

/** Exhausts both the macro-task queue and the micro-task queue.
* ```ts
* import {
* expect,
* fn,
* test,
* useFakeTimer,
* } from "https://deno.land/x/unitest@$VERSION/mod.ts";
*
* test("should run all queued schedules", () => {
* const fakeTimer = useFakeTimer();
* const mockObject = fn();
* setTimeout(mockObject, 1000);
*
* expect(mockObject).not.toHaveBeenCalled();
* fakeTimer.runAllTimers().useRealTimer();
* expect(mockObject).toHaveBeenCalled();
* });
* ```
*/
runAllTimers(): FakeTimerSpec;
}

class FakeTimer implements FakeTimerSpec {
private clock: InstalledClock;
constructor(clock: InstalledClock) {
this.clock = clock;
}

/** Exhausts both the macro-task queue and the micro-task queue. */
runAllTimers(): this {
this.clock.runAll();

return this;
}

/** Replaces the standard timer function. It must be called in any test using
* `useFakeTimer`.
*/
useRealTimer(): void {
this.clock.uninstall();
}
}

/** Use fake versions of the standard timer functions. The `fakeTimer` object is the
* return value. Contains a side effect of hijacking the globalThis timer.
* ```ts
* import {
* expect,
* test,
* useFakeTimer,
* } from "https://deno.land/x/unitest@$VERSION/mod.ts";
*
* test("should hijack default globalThis timer functions", () => {
* expect(globalThis["setTimeout"]).toEqual(globalThis["setTimeout"]);
*
* const setTimeout = globalThis["setTimeout"];
* const fakeTimer = useFakeTimer();
*
* expect(globalThis["setTimeout"]).not.toEqual(setTimeout);
*
* fakeTimer.useRealTimer();
* });
* ```
*/
function useFakeTimer(): FakeTimer {
const fakeTimer = withGlobal(globalThis);
const clock = fakeTimer.install();

return new FakeTimer(clock);
}

export { FakeTimer, useFakeTimer };
28 changes: 28 additions & 0 deletions fake_timer/fake_timer_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
import { FakeTimer, useFakeTimer } from "./fake_timer.ts";
import { withGlobal } from "http://esm.sh/@sinonjs/fake-timers";
import { fn } from "../mock/fn.ts";

import { assertEquals, assertExists } from "../dev_deps.ts";

Deno.test("useFakeTimer", () => {
const fakeTimer = useFakeTimer();

assertExists(fakeTimer);

fakeTimer.useRealTimer();
});

Deno.test("runAllTimer", () => {
const mockObject = fn();
const clock = withGlobal(globalThis).install();
const fakeTimer = new FakeTimer(clock);
setTimeout(mockObject, 1000);

assertEquals(mockObject.mock.calls.length, 0);

fakeTimer.runAllTimers();
assertEquals(mockObject.mock.calls.length, 1);

fakeTimer.useRealTimer();
});
2 changes: 2 additions & 0 deletions fake_timer/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Copyright 2021-Present the Unitest authors. All rights reserved. MIT license.
export * from "./fake_timer.ts";
11 changes: 11 additions & 0 deletions helper/equal_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,17 @@ Deno.test("equal", () => {
new WeakMap(),
false,
],
[
new WeakMap(),
[],
false,
],
[
[],
new WeakMap(),
false,
],

[
new WeakSet(),
new WeakSet(),
Expand Down
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,4 @@ export { defineTest, test } from "./test/test.ts";
export type { SetupReturn, Test } from "./test/test.ts";

export { equal, equality } from "./helper/equal.ts";
export * from "./fake_timer/fake_timer.ts";

0 comments on commit 173b5f3

Please sign in to comment.