diff --git a/builtins/web/abort/abort-signal.cpp b/builtins/web/abort/abort-signal.cpp index 2bc6a3a5..aa343fd6 100644 --- a/builtins/web/abort/abort-signal.cpp +++ b/builtins/web/abort/abort-signal.cpp @@ -142,6 +142,7 @@ bool AbortSignal::throwIfAborted(JSContext *cx, unsigned argc, JS::Value *vp) { if (is_aborted(self)) { RootedValue reason(cx, JS::GetReservedSlot(self, std::to_underlying(Slots::Reason))); JS_SetPendingException(cx, reason); + return false; } return true; diff --git a/tests/integration/abort/abort.js b/tests/integration/abort/abort.js new file mode 100644 index 00000000..11bb9489 --- /dev/null +++ b/tests/integration/abort/abort.js @@ -0,0 +1,61 @@ +import { serveTest } from "../test-server.js"; +import { strictEqual, throws } from "../../assert.js"; + +export const handler = serveTest(async (t) => { + await t.test("throwIfAborted-throws-when-aborted", () => { + const controller = new AbortController(); + const reason = new Error("boom"); + controller.abort(reason); + + strictEqual(controller.signal.aborted, true, "signal should be aborted"); + + let thrown; + try { + controller.signal.throwIfAborted(); + } catch (e) { + thrown = e; + } + + strictEqual(thrown, reason, "throwIfAborted must throw the abort reason"); + }); + + await t.test("throwIfAborted-is-noop-when-not-aborted", () => { + const controller = new AbortController(); + strictEqual(controller.signal.aborted, false, "signal should not be aborted"); + // Must not throw when the signal is not aborted. + let threw = false; + try { + controller.signal.throwIfAborted(); + } catch { + threw = true; + } + strictEqual(threw, false, "throwIfAborted must not throw when not aborted"); + }); + + await t.test("throwIfAborted-throws-default-AbortError", () => { + const controller = new AbortController(); + controller.abort(); // no reason -> default AbortError DOMException + + throws(() => controller.signal.throwIfAborted()); + + let name; + try { + controller.signal.throwIfAborted(); + } catch (e) { + name = e.name; + } + strictEqual(name, "AbortError", "default abort reason is an AbortError"); + }); + + await t.test("AbortSignal.abort-throwIfAborted", () => { + const reason = new Error("static-abort"); + const signal = AbortSignal.abort(reason); + let thrown; + try { + signal.throwIfAborted(); + } catch (e) { + thrown = e; + } + strictEqual(thrown, reason, "AbortSignal.abort(reason).throwIfAborted() throws reason"); + }); +}); diff --git a/tests/integration/handlers.js b/tests/integration/handlers.js index fc07035a..ceae4da7 100644 --- a/tests/integration/handlers.js +++ b/tests/integration/handlers.js @@ -1,3 +1,4 @@ +export { handler as abort } from './abort/abort.js'; export { handler as blob } from './blob/blob.js'; export { handler as btoa } from './btoa/btoa.js'; export { handler as performance } from './performance/performance.js'; diff --git a/tests/tests.cmake b/tests/tests.cmake index 7b7840f3..7011d95c 100644 --- a/tests/tests.cmake +++ b/tests/tests.cmake @@ -62,6 +62,7 @@ test_e2e(no-init-location) test_e2e(init-location) integration_tests( + abort blob btoa crypto