summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/dom/abort
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /testing/web-platform/tests/dom/abort
parentInitial commit. (diff)
downloadfirefox-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')
-rw-r--r--testing/web-platform/tests/dom/abort/AbortSignal.any.js40
-rw-r--r--testing/web-platform/tests/dom/abort/abort-signal-any.any.js4
-rw-r--r--testing/web-platform/tests/dom/abort/abort-signal-timeout.html19
-rw-r--r--testing/web-platform/tests/dom/abort/crashtests/timeout-close.html22
-rw-r--r--testing/web-platform/tests/dom/abort/event.any.js190
-rw-r--r--testing/web-platform/tests/dom/abort/reason-constructor.html12
-rw-r--r--testing/web-platform/tests/dom/abort/resources/abort-signal-any-tests.js185
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}`);
+}