Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 0d33897

Browse files
committed
Implement AbortSignal.timeout
1 parent d5fb9e6 commit 0d33897

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

packages/core/src/plugins/core.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
import { File, FormData, Headers } from "undici";
3737
import { MiniflareCoreError } from "../error";
3838
import {
39+
AbortSignal,
3940
DOMException,
4041
FetchEvent,
4142
Request,
@@ -366,11 +367,7 @@ export class CorePlugin extends Plugin<CoreOptions> implements CoreOptions {
366367
Event,
367368
EventTarget,
368369
AbortController,
369-
// Fix for Jest :(, jest-environment-node doesn't include AbortSignal in
370-
// the global scope, but does include AbortController
371-
AbortSignal:
372-
globalThis.AbortSignal ??
373-
Object.getPrototypeOf(new AbortController().signal).constructor,
370+
AbortSignal,
374371

375372
FetchEvent,
376373
ScheduledEvent,

packages/core/src/standards/timers.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,23 @@ export function inputGatedSetInterval<Args extends any[]>(
2929
...args
3030
);
3131
}
32+
33+
// Fix for Jest :(, jest-environment-node doesn't include AbortSignal in
34+
// the global scope, but does include AbortController
35+
export const AbortSignal =
36+
globalThis.AbortSignal ??
37+
Object.getPrototypeOf(new AbortController().signal).constructor;
38+
39+
// Polyfill `AbortSignal.timeout` as described here:
40+
// https://community.cloudflare.com/t/2021-12-10-workers-runtime-release-notes/334982
41+
// @ts-expect-error `timeout` isn't included in Node.js yet
42+
AbortSignal.timeout ??= (ms?: number) => {
43+
if (typeof ms !== "number") {
44+
throw new TypeError(
45+
"Failed to execute 'timeout' on 'AbortSignal': parameter 1 is not of type 'integer'."
46+
);
47+
}
48+
const controller = new AbortController();
49+
setTimeout(() => controller.abort(), ms);
50+
return controller.signal;
51+
};

packages/core/test/standards/timers.spec.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
triggerPromise,
66
waitsForInputGate,
77
} from "@miniflare/shared-test";
8-
import test from "ava";
8+
import test, { ThrowsExpectation } from "ava";
99

1010
test("inputGatedSetTimeout: calls callback with no input gate in context", async (t) => {
1111
const [trigger, promise] = triggerPromise<[number, string]>();
@@ -92,3 +92,31 @@ test("inputGatedSetInterval: waits for input gate to open before calling callbac
9292

9393
clearInterval(handle);
9494
});
95+
96+
test("AbortSignal.timeout: triggers signal after timeout", async (t) => {
97+
// @ts-expect-error `timeout` isn't included in Node.js yet
98+
const signal = AbortSignal.timeout(50);
99+
let aborted;
100+
signal.addEventListener("abort", () => (aborted = true));
101+
t.false(signal.aborted);
102+
await setTimeout(100);
103+
t.true(signal.aborted);
104+
t.true(aborted);
105+
});
106+
test("AbortSignal.timeout: requires numeric timeout", (t) => {
107+
const expectations: ThrowsExpectation = {
108+
instanceOf: TypeError,
109+
message:
110+
"Failed to execute 'timeout' on 'AbortSignal': parameter 1 is not of type 'integer'.",
111+
};
112+
// @ts-expect-error `timeout` isn't included in Node.js yet
113+
t.throws(() => AbortSignal.timeout(), expectations);
114+
// @ts-expect-error `timeout` isn't included in Node.js yet
115+
t.throws(() => AbortSignal.timeout("42"), expectations);
116+
});
117+
test("AbortSignal.timeout: included on constructor obtained via AbortController#signal prototype", (t) => {
118+
const controller = new AbortController();
119+
const constructor = Object.getPrototypeOf(controller.signal).constructor;
120+
// @ts-expect-error `timeout` isn't included in Node.js yet
121+
t.is(constructor.timeout, AbortSignal.timeout);
122+
});

0 commit comments

Comments
 (0)