Files
bun.sh/test/js/node/util/test-aborted.test.ts
2025-01-28 17:47:53 -08:00

84 lines
2.8 KiB
TypeScript

// Most of this test was copied from
// https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/test/parallel/test-aborted-util.js#L1-L60
// and then translated to bun:test using Claude.
import { expect, test } from "bun:test";
import { getEventListeners } from "events";
import { aborted } from "util";
test("aborted works when provided a resource that was already aborted", () => {
const ac = new AbortController();
const abortedPromise = aborted(ac.signal, {});
ac.abort();
expect(ac.signal.aborted).toBe(true);
expect(getEventListeners(ac.signal, "abort").length).toBe(0);
return expect(abortedPromise).resolves.toBeUndefined();
});
test("aborted works when provided a resource that was not already aborted", async () => {
const ac = new AbortController();
var strong = {};
globalThis.strong = strong;
const abortedPromise = aborted(ac.signal, strong);
expect(getEventListeners(ac.signal, "abort").length).toBe(1);
const sleepy = Bun.sleep(10).then(() => {
ac.abort();
});
await 42;
expect(ac.signal.aborted).toBe(false);
expect(Bun.peek.status(abortedPromise)).toBe("pending");
await sleepy;
await abortedPromise;
expect(ac.signal.aborted).toBe(true);
expect(getEventListeners(ac.signal, "abort").length).toBe(0);
delete globalThis.strong;
return expect(abortedPromise).resolves.toBeUndefined();
});
test("aborted with gc cleanup", async () => {
const ac = new AbortController();
let finalized = false;
// make a FinalizationRegistry to tell us when the second argument to aborted()
// has been garbage collected
const registry = new FinalizationRegistry(() => {
finalized = true;
});
const abortedPromise = (() => {
const gcMe = {};
registry.register(gcMe, undefined);
const abortedPromise = aborted(ac.signal, gcMe);
return abortedPromise;
// gcMe is now out of scope and eligible to be collected
})();
abortedPromise.then(() => {
throw new Error("this promise should never resolve");
});
// wait for the object to be GC'd by ticking the event loop and forcing garbage collection
while (!finalized) {
await new Promise(resolve => setImmediate(resolve));
Bun.gc(true);
}
ac.abort();
expect(ac.signal.aborted).toBe(true);
expect(getEventListeners(ac.signal, "abort").length).toBe(0);
});
test("fails with error if not provided abort signal", async () => {
const invalidSignals = [{}, null, undefined, Symbol(), [], 1, 0, 1n, true, false, "a", () => {}];
for (const sig of invalidSignals) {
await expect(() => aborted(sig, {})).toThrow();
}
});
test("fails if not provided a resource", async () => {
const ac = new AbortController();
const invalidResources = [null, undefined, 0, 1, 0n, 1n, Symbol(), "", "a"];
for (const resource of invalidResources) {
await expect(() => aborted(ac.signal, resource)).toThrow();
}
});