diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /testing/web-platform/tests/dom/abort | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/dom/abort')
7 files changed, 472 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/abort/AbortSignal.any.js b/testing/web-platform/tests/dom/abort/AbortSignal.any.js new file mode 100644 index 0000000000..3bbdc11a92 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/AbortSignal.any.js @@ -0,0 +1,40 @@ +test(t => { + const signal = AbortSignal.abort(); + assert_true(signal instanceof AbortSignal, "returned object is an AbortSignal"); + assert_true(signal.aborted, "returned signal is already aborted"); +}, "the AbortSignal.abort() static returns an already aborted signal"); + +async_test(t => { + const s = AbortSignal.abort(); + s.addEventListener("abort", t.unreached_func("abort event listener called")); + s.onabort = t.unreached_func("abort event handler called"); + t.step_timeout(() => { t.done(); }, 2000); +}, "signal returned by AbortSignal.abort() should not fire abort event"); + +test(t => { + const signal = AbortSignal.timeout(0); + assert_true(signal instanceof AbortSignal, "returned object is an AbortSignal"); + assert_false(signal.aborted, "returned signal is not already aborted"); +}, "AbortSignal.timeout() returns a non-aborted signal"); + +async_test(t => { + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func_done(() => { + assert_true(signal.aborted, "signal is aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is a DOMException"); + assert_equals(signal.reason.name, "TimeoutError", "signal.reason is a TimeoutError"); + }); +}, "Signal returned by AbortSignal.timeout() times out"); + +async_test(t => { + let result = ""; + for (const value of ["1", "2", "3"]) { + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func(() => { result += value; }); + } + + const signal = AbortSignal.timeout(5); + signal.onabort = t.step_func_done(() => { + assert_equals(result, "123", "Timeout order should be 123"); + }); +}, "AbortSignal timeouts fire in order"); diff --git a/testing/web-platform/tests/dom/abort/abort-signal-any.any.js b/testing/web-platform/tests/dom/abort/abort-signal-any.any.js new file mode 100644 index 0000000000..b4abb14c1a --- /dev/null +++ b/testing/web-platform/tests/dom/abort/abort-signal-any.any.js @@ -0,0 +1,4 @@ +// META: script=./resources/abort-signal-any-tests.js + +abortSignalAnySignalOnlyTests(AbortSignal); +abortSignalAnyTests(AbortSignal, AbortController); diff --git a/testing/web-platform/tests/dom/abort/abort-signal-timeout.html b/testing/web-platform/tests/dom/abort/abort-signal-timeout.html new file mode 100644 index 0000000000..2a9c13d614 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/abort-signal-timeout.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>AbortSignal.timeout frame detach</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="iframe"></iframe> +<script> + async_test(t => { + const signal = iframe.contentWindow.AbortSignal.timeout(5); + signal.onabort = t.unreached_func("abort must not fire"); + + iframe.remove(); + + t.step_timeout(() => { + assert_false(signal.aborted); + t.done(); + }, 10); + }, "Signal returned by AbortSignal.timeout() is not aborted after frame detach"); +</script> diff --git a/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html b/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html new file mode 100644 index 0000000000..ee8544a7f5 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/crashtests/timeout-close.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html class="test-wait"> +<meta charset="utf-8"> +<iframe id="iframe"></iframe> +<script> + const srcdoc = ` + <!DOCTYPE html> + <meta charset="utf-8"> + <script> + const xhr = new XMLHttpRequest() + setTimeout(() => { + xhr.open('GET', '/', false) + xhr.send() + AbortSignal.timeout(41.62684667994843) + }, 1) + setTimeout(() => { + location.href = "about:blank" + parent.document.documentElement.classList.remove("test-wait") + }, 0) + </` + "script>"; + iframe.srcdoc = srcdoc; +</script> diff --git a/testing/web-platform/tests/dom/abort/event.any.js b/testing/web-platform/tests/dom/abort/event.any.js new file mode 100644 index 0000000000..bbbe28b233 --- /dev/null +++ b/testing/web-platform/tests/dom/abort/event.any.js @@ -0,0 +1,190 @@ +test(t => { + const c = new AbortController(), + s = c.signal; + let state = "begin"; + + assert_false(s.aborted); + assert_true("reason" in s, "signal has reason property"); + assert_equals(s.reason, undefined, "signal.reason is initially undefined"); + + s.addEventListener("abort", + t.step_func(e => { + assert_equals(state, "begin"); + state = "aborted"; + }) + ); + c.abort(); + + assert_equals(state, "aborted"); + assert_true(s.aborted); + assert_true(s.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(s.reason.name, "AbortError", "signal.reason is AbortError"); + + c.abort(); +}, "AbortController abort() should fire event synchronously"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + assert_equals(controller.signal, signal, + "value of controller.signal should not have changed"); + controller.abort(); + assert_equals(controller.signal, signal, + "value of controller.signal should still not have changed"); +}, "controller.signal should always return the same object"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + let eventCount = 0; + signal.onabort = () => { + ++eventCount; + }; + controller.abort(); + assert_true(signal.aborted); + assert_equals(eventCount, 1, "event handler should have been called once"); + controller.abort(); + assert_true(signal.aborted); + assert_equals(eventCount, 1, + "event handler should not have been called again"); +}, "controller.abort() should do nothing the second time it is called"); + +test(t => { + const controller = new AbortController(); + controller.abort(); + controller.signal.onabort = + t.unreached_func("event handler should not be called"); +}, "event handler should not be called if added after controller.abort()"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + signal.onabort = t.step_func(e => { + assert_equals(e.type, "abort", "event type should be abort"); + assert_equals(e.target, signal, "event target should be signal"); + assert_false(e.bubbles, "event should not bubble"); + assert_true(e.isTrusted, "event should be trusted"); + }); + controller.abort(); +}, "the abort event should have the right properties"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + const reason = Error("hello"); + controller.abort(reason); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, reason, "signal.reason"); +}, "AbortController abort(reason) should set signal.reason"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "aborting AbortController without reason creates an \"AbortError\" DOMException"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(undefined); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "AbortController abort(undefined) creates an \"AbortError\" DOMException"); + +test(t => { + const controller = new AbortController(); + const signal = controller.signal; + + assert_true("reason" in signal, "signal has reason property"); + assert_equals(signal.reason, undefined, "signal.reason is initially undefined"); + + controller.abort(null); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, null, "signal.reason"); +}, "AbortController abort(null) should set signal.reason"); + +test(t => { + const signal = AbortSignal.abort(); + + assert_true(signal.aborted, "signal.aborted"); + assert_true(signal.reason instanceof DOMException, "signal.reason is DOMException"); + assert_equals(signal.reason.name, "AbortError", "signal.reason is AbortError"); +}, "static aborting signal should have right properties"); + +test(t => { + const reason = Error("hello"); + const signal = AbortSignal.abort(reason); + + assert_true(signal.aborted, "signal.aborted"); + assert_equals(signal.reason, reason, "signal.reason"); +}, "static aborting signal with reason should set signal.reason"); + +test(t => { + const signal = AbortSignal.abort(); + + assert_true( + signal.reason instanceof DOMException, + "signal.reason is a DOMException" + ); + assert_equals( + signal.reason, + signal.reason, + "signal.reason returns the same DOMException" + ); +}, "AbortSignal.reason returns the same DOMException"); + +test(t => { + const controller = new AbortController(); + controller.abort(); + + assert_true( + controller.signal.reason instanceof DOMException, + "signal.reason is a DOMException" + ); + assert_equals( + controller.signal.reason, + controller.signal.reason, + "signal.reason returns the same DOMException" + ); +}, "AbortController.signal.reason returns the same DOMException"); + +test(t => { + const reason = new Error('boom'); + const signal = AbortSignal.abort(reason); + assert_true(signal.aborted); + assert_throws_exactly(reason, () => signal.throwIfAborted()); +}, "throwIfAborted() should throw abort.reason if signal aborted"); + +test(t => { + const signal = AbortSignal.abort('hello'); + assert_true(signal.aborted); + assert_throws_exactly('hello', () => signal.throwIfAborted()); +}, "throwIfAborted() should throw primitive abort.reason if signal aborted"); + +test(t => { + const controller = new AbortController(); + assert_false(controller.signal.aborted); + controller.signal.throwIfAborted(); +}, "throwIfAborted() should not throw if signal not aborted"); + +done(); diff --git a/testing/web-platform/tests/dom/abort/reason-constructor.html b/testing/web-platform/tests/dom/abort/reason-constructor.html new file mode 100644 index 0000000000..0515165a0f --- /dev/null +++ b/testing/web-platform/tests/dom/abort/reason-constructor.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<meta charset=utf-8> +<title>AbortSignal.reason constructor</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<iframe id="iframe"></iframe> +<script> + test(() => { + const aborted = iframe.contentWindow.AbortSignal.abort(); + assert_equals(aborted.reason.constructor, iframe.contentWindow.DOMException, "DOMException is using the correct global"); + }, "AbortSignal.reason.constructor should be from iframe"); +</script> diff --git a/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js b/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js new file mode 100644 index 0000000000..66e4141eac --- /dev/null +++ b/testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js @@ -0,0 +1,185 @@ +// Tests for AbortSignal.any() and subclasses that don't use a controller. +function abortSignalAnySignalOnlyTests(signalInterface) { + const desc = `${signalInterface.name}.any()` + + test(t => { + const signal = signalInterface.any([]); + assert_false(signal.aborted); + }, `${desc} works with an empty array of signals`); +} + +// Tests for AbortSignal.any() and subclasses that use a controller. +function abortSignalAnyTests(signalInterface, controllerInterface) { + const suffix = `(using ${controllerInterface.name})`; + const desc = `${signalInterface.name}.any()`; + + test(t => { + const controller = new controllerInterface(); + const signal = controller.signal; + const cloneSignal = signalInterface.any([signal]); + assert_false(cloneSignal.aborted); + assert_true("reason" in cloneSignal, "cloneSignal has reason property"); + assert_equals(cloneSignal.reason, undefined, + "cloneSignal.reason is initially undefined"); + assert_not_equals(signal, cloneSignal, + `${desc} returns a new signal.`); + + let eventFired = false; + cloneSignal.onabort = t.step_func((e) => { + assert_equals(e.target, cloneSignal, + `The event target is the signal returned by ${desc}`); + eventFired = true; + }); + + controller.abort("reason string"); + assert_true(signal.aborted); + assert_true(cloneSignal.aborted); + assert_true(eventFired); + assert_equals(cloneSignal.reason, "reason string", + `${desc} propagates the abort reason`); + }, `${desc} follows a single signal ${suffix}`); + + test(t => { + for (let i = 0; i < 3; ++i) { + const controllers = []; + for (let j = 0; j < 3; ++j) { + controllers.push(new controllerInterface()); + } + const combinedSignal = signalInterface.any(controllers.map(c => c.signal)); + + let eventFired = false; + combinedSignal.onabort = t.step_func((e) => { + assert_equals(e.target, combinedSignal, + `The event target is the signal returned by ${desc}`); + eventFired = true; + }); + + controllers[i].abort(); + assert_true(eventFired); + assert_true(combinedSignal.aborted); + assert_true(combinedSignal.reason instanceof DOMException, + "signal.reason is a DOMException"); + assert_equals(combinedSignal.reason.name, "AbortError", + "signal.reason is a AbortError"); + } + }, `${desc} follows multiple signals ${suffix}`); + + test(t => { + const controllers = []; + for (let i = 0; i < 3; ++i) { + controllers.push(new controllerInterface()); + } + controllers[1].abort("reason 1"); + controllers[2].abort("reason 2"); + + const signal = signalInterface.any(controllers.map(c => c.signal)); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason 1", + "The signal should be aborted with the first reason"); + }, `${desc} returns an aborted signal if passed an aborted signal ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + const signal = signalInterface.any([controller.signal, controller.signal]); + assert_false(signal.aborted); + controller.abort("reason"); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason"); + }, `${desc} can be passed the same signal more than once ${suffix}`); + + test(t => { + const controller1 = new controllerInterface(); + controller1.abort("reason 1"); + const controller2 = new controllerInterface(); + controller2.abort("reason 2"); + + const signal = signalInterface.any([controller1.signal, controller2.signal, controller1.signal]); + assert_true(signal.aborted); + assert_equals(signal.reason, "reason 1"); + }, `${desc} uses the first instance of a duplicate signal ${suffix}`); + + test(t => { + for (let i = 0; i < 3; ++i) { + const controllers = []; + for (let j = 0; j < 3; ++j) { + controllers.push(new controllerInterface()); + } + const combinedSignal1 = + signalInterface.any([controllers[0].signal, controllers[1].signal]); + const combinedSignal2 = + signalInterface.any([combinedSignal1, controllers[2].signal]); + + let eventFired = false; + combinedSignal2.onabort = t.step_func((e) => { + eventFired = true; + }); + + controllers[i].abort(); + assert_true(eventFired); + assert_true(combinedSignal2.aborted); + assert_true(combinedSignal2.reason instanceof DOMException, + "signal.reason is a DOMException"); + assert_equals(combinedSignal2.reason.name, "AbortError", + "signal.reason is a AbortError"); + } + }, `${desc} signals are composable ${suffix}`); + + async_test(t => { + const controller = new controllerInterface(); + const timeoutSignal = AbortSignal.timeout(5); + + const combinedSignal = signalInterface.any([controller.signal, timeoutSignal]); + + combinedSignal.onabort = t.step_func_done(() => { + assert_true(combinedSignal.aborted); + assert_true(combinedSignal.reason instanceof DOMException, + "combinedSignal.reason is a DOMException"); + assert_equals(combinedSignal.reason.name, "TimeoutError", + "combinedSignal.reason is a TimeoutError"); + }); + }, `${desc} works with signals returned by AbortSignal.timeout() ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + let combined = signalInterface.any([controller.signal]); + combined = signalInterface.any([combined]); + combined = signalInterface.any([combined]); + combined = signalInterface.any([combined]); + + let eventFired = false; + combined.onabort = () => { + eventFired = true; + } + + assert_false(eventFired); + assert_false(combined.aborted); + + controller.abort("the reason"); + + assert_true(eventFired); + assert_true(combined.aborted); + assert_equals(combined.reason, "the reason"); + }, `${desc} works with intermediate signals ${suffix}`); + + test(t => { + const controller = new controllerInterface(); + const signals = []; + // The first event should be dispatched on the originating signal. + signals.push(controller.signal); + // All dependents are linked to `controller.signal` (never to another + // composite signal), so this is the order events should fire. + signals.push(signalInterface.any([controller.signal])); + signals.push(signalInterface.any([controller.signal])); + signals.push(signalInterface.any([signals[0]])); + signals.push(signalInterface.any([signals[1]])); + + let result = ""; + for (let i = 0; i < signals.length; i++) { + signals[i].addEventListener('abort', () => { + result += i; + }); + } + controller.abort(); + assert_equals(result, "01234"); + }, `Abort events for ${desc} signals fire in the right order ${suffix}`); +} |