fix(testing): FakeTime fakes AbortSignal.timeout (#5500)

Co-authored-by: Asher Gomez <ashersaupingomez@gmail.com>
This commit is contained in:
Milly 2024-07-22 13:07:48 +09:00 committed by GitHub
parent 88019ee78d
commit 55297e90a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 76 additions and 1 deletions

View File

@ -7,4 +7,5 @@ export const _internals = {
clearTimeout, clearTimeout,
setInterval, setInterval,
clearInterval, clearInterval,
AbortSignalTimeout: AbortSignal.timeout,
}; };

View File

@ -197,12 +197,21 @@ function setTimer(
return id; return id;
} }
function fakeAbortSignalTimeout(delay: number): AbortSignal {
const aborter = new AbortController();
fakeSetTimeout(() => {
aborter.abort(new DOMException("Signal timed out.", "TimeoutError"));
}, delay);
return aborter.signal;
}
function overrideGlobals() { function overrideGlobals() {
globalThis.Date = FakeDate; globalThis.Date = FakeDate;
globalThis.setTimeout = fakeSetTimeout; globalThis.setTimeout = fakeSetTimeout;
globalThis.clearTimeout = fakeClearTimeout; globalThis.clearTimeout = fakeClearTimeout;
globalThis.setInterval = fakeSetInterval; globalThis.setInterval = fakeSetInterval;
globalThis.clearInterval = fakeClearInterval; globalThis.clearInterval = fakeClearInterval;
AbortSignal.timeout = fakeAbortSignalTimeout;
} }
function restoreGlobals() { function restoreGlobals() {
@ -211,6 +220,7 @@ function restoreGlobals() {
globalThis.clearTimeout = _internals.clearTimeout; globalThis.clearTimeout = _internals.clearTimeout;
globalThis.setInterval = _internals.setInterval; globalThis.setInterval = _internals.setInterval;
globalThis.clearInterval = _internals.clearInterval; globalThis.clearInterval = _internals.clearInterval;
AbortSignal.timeout = _internals.AbortSignalTimeout;
} }
function* timerIdGen() { function* timerIdGen() {

View File

@ -13,8 +13,9 @@ import {
import { FakeTime, TimeError } from "./time.ts"; import { FakeTime, TimeError } from "./time.ts";
import { _internals } from "./_time.ts"; import { _internals } from "./_time.ts";
import { assertSpyCall, spy, type SpyCall } from "./mock.ts"; import { assertSpyCall, spy, type SpyCall } from "./mock.ts";
import { deadline, delay } from "@std/async";
function fromNow(): () => number { function fromNow(): (..._args: unknown[]) => number {
const start: number = Date.now(); const start: number = Date.now();
return () => Date.now() - start; return () => Date.now() - start;
} }
@ -722,3 +723,66 @@ Deno.test("time.start returns the started time of the fake time", () => {
time.now = 2000; time.now = 2000;
assertEquals(time.start, 1000); assertEquals(time.start, 1000);
}); });
Deno.test("FakeTime doesn't affect AbortSignal.timeout unchanged if uninitialized", () => {
assertStrictEquals(AbortSignal.timeout, _internals.AbortSignalTimeout);
});
Deno.test("FakeTime fakes AbortSignal.timeout", () => {
{
using _time = new FakeTime(9001);
assertNotEquals(AbortSignal.timeout, _internals.AbortSignalTimeout);
}
assertStrictEquals(AbortSignal.timeout, _internals.AbortSignalTimeout);
});
Deno.test("FakeTime controls AbortSignal.timeout", () => {
using time: FakeTime = new FakeTime();
const cb = spy(fromNow());
const expected: SpyCall[] = [];
const signal = AbortSignal.timeout(1000);
signal.onabort = () => cb();
time.tick(250);
assertEquals(cb.calls, expected);
time.tick(250);
assertEquals(cb.calls, expected);
time.tick(500);
expected.push({ args: [], returned: 1000 });
assertEquals(cb.calls, expected);
time.tick(2500);
assertEquals(cb.calls, expected);
assertEquals(signal.aborted, true);
assertInstanceOf(signal.reason, DOMException);
assertEquals(signal.reason.name, "TimeoutError");
assertEquals(signal.reason.message, "Signal timed out.");
const signalA = AbortSignal.timeout(1000);
signalA.addEventListener("abort", () => cb("a"));
const signalB = AbortSignal.timeout(2000);
signalB.addEventListener("abort", () => cb("b"));
const signalC = AbortSignal.timeout(1500);
signalC.addEventListener("abort", () => cb("c"));
assertEquals(cb.calls, expected);
time.tick(2500);
expected.push({ args: ["a"], returned: 4500 });
expected.push({ args: ["c"], returned: 5000 });
expected.push({ args: ["b"], returned: 5500 });
assertEquals(cb.calls, expected);
});
// https://github.com/denoland/std/issues/5499
Deno.test("FakeTime regression test for issue #5499", async () => {
using t = new FakeTime();
const p = deadline(delay(1_000), 10);
let state: "pending" | "rejected" | "fulfilled" = "pending";
p.then(() => {
state = "fulfilled";
}).catch(() => {
state = "rejected";
});
await t.tickAsync(10);
await t.runMicrotasks();
assertEquals(state, "rejected");
});