diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/close-watcher | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
8 files changed, 644 insertions, 0 deletions
diff --git a/testing/web-platform/tests/close-watcher/META.yml b/testing/web-platform/tests/close-watcher/META.yml new file mode 100644 index 0000000000..4534ab8abe --- /dev/null +++ b/testing/web-platform/tests/close-watcher/META.yml @@ -0,0 +1,4 @@ +spec: https://wicg.github.io/close-watcher/ +suggested_reviewers: + - domenic + - natechapin diff --git a/testing/web-platform/tests/close-watcher/abortsignal.html b/testing/web-platform/tests/close-watcher/abortsignal.html new file mode 100644 index 0000000000..eb70ffed1b --- /dev/null +++ b/testing/web-platform/tests/close-watcher/abortsignal.html @@ -0,0 +1,123 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> + +<div id='d' style='height: 100px; width: 100px'></div> +<script> +// *not* \uu001B; see https://w3c.github.io/webdriver/#keyboard-actions +const ESC = '\uE00C'; + +test(() => { + let watcher = new CloseWatcher({ signal: AbortSignal.abort() }); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + watcher.close(); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "already-aborted AbortSignal then close() fires no events"); + +test(() => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + controller.abort(); + watcher.close(); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "abortController.abort() then close() fires no events"); + +test(() => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + let oncancel_call_count_ = 0; + let onclose_call_count_ = 0; + watcher.oncancel = () => oncancel_call_count_++; + watcher.onclose = () => onclose_call_count_++; + + watcher.close(); + controller.abort(); + + assert_equals(oncancel_call_count_, 0); + assert_equals(onclose_call_count_, 1); +}, "close() then abortController.abort() fires only one close event"); + +promise_test(async () => { + let watcher = new CloseWatcher({ signal: AbortSignal.abort() }); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + await test_driver.send_keys(document.getElementById('d'), ESC); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "already-aborted AbortSignal then Esc key fires no events"); + +promise_test(async t => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + controller.abort(); + await test_driver.send_keys(document.getElementById('d'), ESC); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "abortController.abort() then close via Esc key fires no events"); + +promise_test(async t => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + let oncancel_call_count_ = 0; + let onclose_call_count_ = 0; + watcher.oncancel = () => oncancel_call_count_++; + watcher.onclose = () => onclose_call_count_++; + + await test_driver.send_keys(document.getElementById('d'), ESC); + controller.abort(); + + assert_equals(oncancel_call_count_, 0); + assert_equals(onclose_call_count_, 1); +}, "Esc key then abortController.abort() fires only one close event"); + +test(t => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + controller.abort(); + let watcher2 = new CloseWatcher(); + t.add_cleanup(() => watcher2.destroy()); +}, "abortController.abort()ing a free CloseWatcher allows a new one to be created without a user activation"); + +promise_test(async t => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + watcher.oncancel = () => { controller.abort(); } + watcher.onclose = t.unreached_func("onclose"); + await test_driver.bless("give user activation so that cancel will fire", () => { + watcher.close(); + }); +}, "abortController.abort() inside oncancel"); + +test(t => { + let controller = new AbortController(); + let watcher = new CloseWatcher({ signal: controller.signal }); + watcher.onclose = () => { controller.abort(); } + watcher.close(); +}, "abortController.abort() inside onclose is benign"); +</script> diff --git a/testing/web-platform/tests/close-watcher/after-other-listeners.html b/testing/web-platform/tests/close-watcher/after-other-listeners.html new file mode 100644 index 0000000000..7dfe398012 --- /dev/null +++ b/testing/web-platform/tests/close-watcher/after-other-listeners.html @@ -0,0 +1,26 @@ +<!doctype html> +<link rel=author href="mailto:jarhar@chromium.org"> +<link rel=author href="mailto:japhet@chromium.org"> +<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1312594"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> + +<div id='d' style='height: 100px; width: 100px'></div> +<script> +// *not* \uu001B; see https://w3c.github.io/webdriver/#keyboard-actions +const ESC = '\uE00C'; + +promise_test(async t => { + let watcher = new CloseWatcher(); + let onclose_called = false; + watcher.onclose = () => onclose_called = true; + + window.onkeydown = e => e.preventDefault(); + + await test_driver.send_keys(document.getElementById('d'), ESC); + assert_false(onclose_called); +}, "normal event listeners come before CloseWatcher"); +</script> diff --git a/testing/web-platform/tests/close-watcher/basic.html b/testing/web-platform/tests/close-watcher/basic.html new file mode 100644 index 0000000000..1c26c0ce15 --- /dev/null +++ b/testing/web-platform/tests/close-watcher/basic.html @@ -0,0 +1,167 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> + +<div id='d' style='height: 100px; width: 100px'></div> +<script> +// *not* \uu001B; see https://w3c.github.io/webdriver/#keyboard-actions +const ESC = '\uE00C'; + +test(() => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = e => { + assert_equals(e.constructor, Event); + assert_false(e.cancelable); + assert_false(e.bubbles); + onclose_called = true; + } + + watcher.close(); + + assert_false(oncancel_called); + assert_true(onclose_called); +}, "close() with no user activation only fires close"); + +test(() => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + watcher.destroy(); + watcher.close(); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "destroy() then close() fires no events"); + +test(() => { + let watcher = new CloseWatcher(); + let oncancel_call_count_ = 0; + let onclose_call_count_ = 0; + watcher.oncancel = () => oncancel_call_count_++; + watcher.onclose = () => onclose_call_count_++; + + watcher.close(); + watcher.destroy(); + assert_equals(oncancel_call_count_, 0); + assert_equals(onclose_call_count_, 1); +}, "close() then destroy() fires only one close event"); + +promise_test(async t => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + await test_driver.send_keys(document.getElementById('d'), ESC); + + assert_false(oncancel_called); + assert_true(onclose_called); +}, "Esc key does not count as user activation, so it fires close but not cancel"); + +promise_test(async t => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + watcher.destroy(); + await test_driver.send_keys(document.getElementById('d'), ESC); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "destroy() then close via Esc key fires no events"); + +promise_test(async t => { + let watcher = new CloseWatcher(); + let oncancel_call_count_ = 0; + let onclose_call_count_ = 0; + watcher.oncancel = () => oncancel_call_count_++; + watcher.onclose = () => onclose_call_count_++; + + await test_driver.send_keys(document.getElementById('d'), ESC); + watcher.destroy(); + + assert_equals(oncancel_call_count_, 0); + assert_equals(onclose_call_count_, 1); +}, "Esc key then destroy() fires only one close event"); + +test(t => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.oncancel = () => oncancel_called = true; + watcher.onclose = () => onclose_called = true; + + t.add_cleanup(() => watcher.destroy()); + + let keydown = new KeyboardEvent('keydown', {'key': 'Escape', 'keyCode': 27}); + window.dispatchEvent(keydown); + let keyup = new KeyboardEvent('keyup', {'key': 'Escape', 'keyCode': 27}); + window.dispatchEvent(keyup); + + assert_false(oncancel_called); + assert_false(onclose_called); + + let keyup2 = document.createEvent("Event"); + keyup2.initEvent("keyup", true); + window.dispatchEvent(keyup2); + + assert_false(oncancel_called); + assert_false(onclose_called); +}, "close via synthesized escape key should not work"); + +promise_test(async t => { + let watcher = new CloseWatcher(); + watcher.oncancel = () => { watcher.destroy(); } + watcher.onclose = t.unreached_func("onclose"); + await test_driver.bless("give user activation so that cancel will fire", () => { + watcher.close(); + }); +}, "destroy inside oncancel"); + +test(t => { + let watcher = new CloseWatcher(); + watcher.onclose = () => { watcher.destroy(); } + watcher.close(); +}, "destroy inside onclose is benign"); + +promise_test(async t => { + let watcher = new CloseWatcher(); + watcher.oncancel = () => { watcher.close(); } + await test_driver.bless("give user activation so that cancel will fire", () => { + watcher.close(); + }); +}, "close inside oncancel should not trigger an infinite loop"); + +test(t => { + let watcher = new CloseWatcher(); + watcher.onclose = () => { watcher.close(); } + watcher.close(); +}, "close inside onclose should not trigger an infinite loop"); + +promise_test(async () => { + let watcher = new CloseWatcher(); + let oncancel_called = false; + let onclose_called = false; + watcher.addEventListener("cancel", () => oncancel_called = true); + watcher.addEventListener("close", () => onclose_called = true); + + await test_driver.bless("give user activation so that cancel will fire", () => { + watcher.close(); + }); + + assert_true(oncancel_called); + assert_true(onclose_called); +}, "close with events added via addEventListener"); +</script> diff --git a/testing/web-platform/tests/close-watcher/frame-removal.html b/testing/web-platform/tests/close-watcher/frame-removal.html new file mode 100644 index 0000000000..b8bbac04f9 --- /dev/null +++ b/testing/web-platform/tests/close-watcher/frame-removal.html @@ -0,0 +1,59 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +promise_test(async (t) => { + const i = await setupIframe(); + const watcher = new i.contentWindow.CloseWatcher(); + watcher.oncancel = () => i.remove(); + watcher.onclose = () => t.unreached_func("close event must not fire"); + + watcher.close(); +}, "detaching the iframe during the cancel event"); + +promise_test(async (t) => { + const i = await setupIframe(); + const watcher = new i.contentWindow.CloseWatcher(); + watcher.onclose = () => i.remove(); + + watcher.close(); +}, "detaching the iframe during the close event"); + +promise_test(async (t) => { + const i = await setupIframe(); + const watcher = new i.contentWindow.CloseWatcher(); + i.remove(); + + watcher.destroy(); +}, "detaching the iframe then calling destroy()"); + +promise_test(async (t) => { + const i = await setupIframe(); + const watcher = new i.contentWindow.CloseWatcher(); + watcher.oncancel = () => t.unreached_func("cancel event must not fire"); + watcher.onclose = () => t.unreached_func("close event must not fire"); + i.remove(); + + watcher.close(); +}, "detaching the iframe then calling close()"); + +promise_test(async (t) => { + const i = await setupIframe(); + const iCloseWatcher = i.contentWindow.CloseWatcher; + const iDOMException = i.contentWindow.DOMException; + i.remove(); + + assert_throws_dom("InvalidStateError", iDOMException, () => new iCloseWatcher()); +}, "detaching the iframe then constructing a CloseWatcher"); + +function setupIframe() { + return new Promise(resolve => { + const i = document.createElement("iframe"); + i.onload = () => resolve(i); + i.src = "/common/blank.html"; + document.body.append(i); + }); +} +</script> diff --git a/testing/web-platform/tests/close-watcher/resources/helpers.js b/testing/web-platform/tests/close-watcher/resources/helpers.js new file mode 100644 index 0000000000..4e024a1908 --- /dev/null +++ b/testing/web-platform/tests/close-watcher/resources/helpers.js @@ -0,0 +1,21 @@ +// TODO(domenic): consider using these in all test files. + +window.createRecordingCloseWatcher = (t, events, name) => { + const watcher = new CloseWatcher(); + t.add_cleanup(() => watcher.destroy()); + watcher.oncancel = () => events.push(name + " cancel"); + watcher.onclose = () => events.push(name + " close"); + + return watcher; +}; + +window.createBlessedRecordingCloseWatcher = (t, events, name) => { + return test_driver.bless("create " + name, () => createRecordingCloseWatcher(t, events, name)); +}; + +window.sendCloseSignal = () => { + // *not* \uu001B; see https://w3c.github.io/webdriver/#keyboard-actions + const ESC = '\uE00C'; + + return test_driver.send_keys(document.getElementById("d"), ESC); +}; diff --git a/testing/web-platform/tests/close-watcher/user-activation-multiple-plus-free.html b/testing/web-platform/tests/close-watcher/user-activation-multiple-plus-free.html new file mode 100644 index 0000000000..8a86624913 --- /dev/null +++ b/testing/web-platform/tests/close-watcher/user-activation-multiple-plus-free.html @@ -0,0 +1,32 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="resources/helpers.js"></script> + +<div id="d" style="height: 100px; width: 100px;"></div> +<script> + +// This test needs to be separate from user-activation.html since, unlike those, +// it relies on there not being any lingering user activation from previous +// tests hanging around. That is, we need to be sure freeWatcher is created with +// no user activation, to ensure that activationWatcher1 and activationWatcher2 +// get grouped as expected. +promise_test(async t => { + const events = []; + createRecordingCloseWatcher(t, events, "freeWatcher"); + + await test_driver.bless("create two more CloseWatchers", () => { + createRecordingCloseWatcher(t, events, "activationWatcher1"); + createRecordingCloseWatcher(t, events, "activationWatcher2"); + }); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher2 close", "activationWatcher1 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher2 close", "activationWatcher1 close", "freeWatcher close"]); +}, "Multiple CloseWatchers created from a single user activation close together, but original free CloseWatcher closes separately"); +</script> diff --git a/testing/web-platform/tests/close-watcher/user-activation.html b/testing/web-platform/tests/close-watcher/user-activation.html new file mode 100644 index 0000000000..64f217533d --- /dev/null +++ b/testing/web-platform/tests/close-watcher/user-activation.html @@ -0,0 +1,212 @@ +<!doctype html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-vendor.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="resources/helpers.js"></script> + +<div id="d" style="height: 100px; width: 100px;"></div> +<script> +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + + await test_driver.bless("call close()", () => freeWatcher.close()); + + assert_array_equals(events, ["freeWatcher cancel", "freeWatcher close"]); +}, "CloseWatchers created without user activation, but close()d via user activation, fires cancel"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + freeWatcher.addEventListener("cancel", e => e.preventDefault()); + + await test_driver.bless("call close()", () => freeWatcher.close()); + + assert_array_equals(events, ["freeWatcher cancel"]); +}, "CloseWatchers created without user activation, but close()d via user activation, fires cancel, which can be preventDefault()ed"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + + await test_driver.bless("grant user activation", () => sendCloseSignal()); + + assert_array_equals(events, ["freeWatcher cancel", "freeWatcher close"]); +}, "CloseWatchers created without user activation, but closed via a close signal after user activation, fires cancel"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + freeWatcher.addEventListener("cancel", e => e.preventDefault()); + + await test_driver.bless("grant user activation", () => sendCloseSignal()); + + assert_array_equals(events, ["freeWatcher cancel"]); +}, "CloseWatchers created without user activation, but closed via a close signal after user activation, fires cancel, which can be preventDefault()ed"); + +promise_test(async t => { + const events = []; + createRecordingCloseWatcher(t, events, "freeWatcher"); + createRecordingCloseWatcher(t, events, "watcher1"); + createRecordingCloseWatcher(t, events, "watcher2"); + + await sendCloseSignal(); + assert_array_equals(events, ["watcher2 close", "watcher1 close", "freeWatcher close"]); +}, "Multiple CloseWatchers created without user activation close together (with no cancel)"); + +promise_test(async t => { + const events = []; + createRecordingCloseWatcher(t, events, "freeWatcher"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher"); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher close", "freeWatcher close"]); +}, "Creating a CloseWatcher from user activation keeps it separate from the free CloseWatcher, but they don't fire cancel"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher"); + + await test_driver.bless("call activationWatcher.close()", () => activationWatcher.close()); + assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close"]); + + await test_driver.bless("call freeWatcher.close()", () => freeWatcher.close()); + assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close", "freeWatcher cancel", "freeWatcher close"]); +}, "Creating a CloseWatcher from user activation, and close()ing CloseWatchers with user activation, fires cancel"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher"); + + await test_driver.bless("grant user activation", () => sendCloseSignal()); + assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close"]); + + await test_driver.bless("grant user activation", () => sendCloseSignal()); + assert_array_equals(events, ["activationWatcher cancel", "activationWatcher close", "freeWatcher cancel", "freeWatcher close"]); +}, "Creating a CloseWatcher from user activation, and closing CloseWatchers with a close signal after user activation, fires cancel"); + +promise_test(async t => { + const events = []; + createRecordingCloseWatcher(t, events, "freeWatcher"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2"); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher2 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["activationWatcher2 close", "activationWatcher1 close"]); +}, "Multiple CloseWatchers created with user activation close in reverse order"); + +promise_test(async t => { + const events = []; + createRecordingCloseWatcher(t, events, "freeWatcher"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2"); + await createBlessedRecordingCloseWatcher(t, events, "activationWatcher3"); + createRecordingCloseWatcher(t, events, "watcher4"); + + await sendCloseSignal(); + assert_array_equals(events, ["watcher4 close", "activationWatcher3 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close", "activationWatcher1 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["watcher4 close", "activationWatcher3 close", "activationWatcher2 close", "activationWatcher1 close", "freeWatcher close"]); +}, "3 user activations let you have 3 + 1 = 4 ungrouped close watchers/0 cancel events"); + +promise_test(async t => { + const events = []; + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + const activationWatcher1 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1"); + activationWatcher1.addEventListener("cancel", e => e.preventDefault()); + + await test_driver.bless("call activationWatcher1.close()", () => activationWatcher1.close()); + assert_array_equals(events, ["activationWatcher1 cancel"]); + + // This time we go straight to close, without a second cancel. + activationWatcher1.close(); + assert_array_equals(events, ["activationWatcher1 cancel", "activationWatcher1 close"]); + + freeWatcher.close(); + assert_array_equals(events, ["activationWatcher1 cancel", "activationWatcher1 close", "freeWatcher close"]); +}, "3 user activations let you have 2 close watchers with 1 cancel event, even if the first cancel event is prevented"); + +promise_test(async t => { + const events = []; + const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1"); + + freeWatcher1.destroy(); + assert_array_equals(events, []); + + const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher2 close"]); +}, "destroy()ing the free CloseWatcher allows a new free one to be created without user activation, and it receives the close signal"); + +promise_test(async t => { + const events = []; + const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1"); + + freeWatcher1.close(); + assert_array_equals(events, ["freeWatcher1 close"]); + + const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher1 close", "freeWatcher2 close"]); +}, "close()ing the free CloseWatcher allows a new free one to be created without user activation, and it receives the close signal"); + +promise_test(async t => { + const events = []; + const freeWatcher1 = createRecordingCloseWatcher(t, events, "freeWatcher1"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher1 close"]); + + const freeWatcher2 = createRecordingCloseWatcher(t, events, "freeWatcher2"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher1 close", "freeWatcher2 close"]); +}, "closing the free CloseWatcher via a close signal allows a new free one to be created without user activation, and it receives a second close signal"); + +promise_test(async t => { + const events = []; + const activationWatcher = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher"); + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher close", "activationWatcher close"]); +}, "The second watcher can be the free watcher, if the first is created with user activation"); + +promise_test(async t => { + const events = []; + const activationWatcher1 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher1"); + const activationWatcher2 = await createBlessedRecordingCloseWatcher(t, events, "activationWatcher2"); + const freeWatcher = createRecordingCloseWatcher(t, events, "freeWatcher"); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher close", "activationWatcher2 close"]); + + await sendCloseSignal(); + assert_array_equals(events, ["freeWatcher close", "activationWatcher2 close", "activationWatcher1 close"]); +}, "The third watcher can be the free watcher, if the first two are created with user activation"); +</script> |