mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com> Co-authored-by: 190n <190n@users.noreply.github.com> Co-authored-by: 190n <7763597+190n@users.noreply.github.com>
84 lines
2.8 KiB
TypeScript
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();
|
|
}
|
|
});
|