Skip to content

Commit

Permalink
CloseWatcher: add requestClose() (#41201)
Browse files Browse the repository at this point in the history
Or rather, rename close() to requestClose(), and then add close().
Follows whatwg/html@63fb283,
per WICG/close-watcher#28.

Bug: 1171318
Change-Id: Ic1c6dff2440f38c04f7ffaaa19188403a46b9adc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4721666
Commit-Queue: Domenic Denicola <[email protected]>
Reviewed-by: Nate Chapin <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1176384}

Co-authored-by: Domenic Denicola <[email protected]>
  • Loading branch information
chromium-wpt-export-bot and domenic authored Jul 28, 2023
1 parent 8984682 commit d8c9a69
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 91 deletions.
16 changes: 8 additions & 8 deletions close-watcher/abortsignal.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@
watcher.oncancel = () => oncancel_called = true;
watcher.onclose = () => onclose_called = true;

watcher.close();
watcher.requestClose();

assert_false(oncancel_called);
assert_false(onclose_called);
}, "already-aborted AbortSignal then close() fires no events");
}, "already-aborted AbortSignal then requestClose() fires no events");

test(() => {
let controller = new AbortController();
Expand All @@ -32,11 +32,11 @@
watcher.onclose = () => onclose_called = true;

controller.abort();
watcher.close();
watcher.requestClose();

assert_false(oncancel_called);
assert_false(onclose_called);
}, "abortController.abort() then close() fires no events");
}, "abortController.abort() then requestClose() fires no events");

test(() => {
let controller = new AbortController();
Expand All @@ -46,12 +46,12 @@
watcher.oncancel = () => oncancel_call_count_++;
watcher.onclose = () => onclose_call_count_++;

watcher.close();
watcher.requestClose();
controller.abort();

assert_equals(oncancel_call_count_, 0);
assert_equals(onclose_call_count_, 1);
}, "close() then abortController.abort() fires only one close event");
}, "requestClose() then abortController.abort() fires only one close event");

promise_test(async () => {
let watcher = new CloseWatcher({ signal: AbortSignal.abort() });
Expand Down Expand Up @@ -110,14 +110,14 @@
watcher.oncancel = () => { controller.abort(); }
watcher.onclose = t.unreached_func("onclose");
await test_driver.bless("give user activation so that cancel will fire", () => {
watcher.close();
watcher.requestClose();
});
}, "abortController.abort() inside oncancel");

test(t => {
let controller = new AbortController();
let watcher = new CloseWatcher({ signal: controller.signal });
watcher.onclose = () => { controller.abort(); }
watcher.close();
watcher.requestClose();
}, "abortController.abort() inside onclose is benign");
</script>
132 changes: 65 additions & 67 deletions close-watcher/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<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>
Expand All @@ -22,133 +23,130 @@
onclose_called = true;
}

watcher.close();
watcher.requestClose();

assert_false(oncancel_called);
assert_true(onclose_called);
}, "close() with no user activation only fires close");
}, "requestClose() 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;
test(t => {
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

watcher.destroy();
watcher.requestClose();

assert_array_equals(events, []);
}, "destroy() then requestClose() fires no events");

test(t => {
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

watcher.close();
assert_array_equals(events, ["close"]);

assert_false(oncancel_called);
assert_false(onclose_called);
}, "destroy() then close() fires no events");
watcher.requestClose();
assert_array_equals(events, ["close"]);
}, "close() then requestClose() fires only one close event");

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_++;
test(t => {
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

watcher.requestClose();
assert_array_equals(events, ["close"]);

watcher.destroy();
assert_array_equals(events, ["close"]);
}, "requestClose() then destroy() fires only one close event");

test(t => {
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

watcher.close();
assert_array_equals(events, ["close"]);

watcher.destroy();
assert_equals(oncancel_call_count_, 0);
assert_equals(onclose_call_count_, 1);
assert_array_equals(events, ["close"]);
}, "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;
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

await test_driver.send_keys(document.getElementById('d'), ESC);
await sendCloseSignal();

assert_false(oncancel_called);
assert_true(onclose_called);
assert_array_equals(events, ["close"]);
}, "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;
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

watcher.destroy();
await test_driver.send_keys(document.getElementById('d'), ESC);
await sendCloseSignal();

assert_false(oncancel_called);
assert_false(onclose_called);
assert_array_equals(events, []);
}, "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_++;
let events = [];
let watcher = createRecordingCloseWatcher(t, events);

await test_driver.send_keys(document.getElementById('d'), ESC);
await sendCloseSignal();
watcher.destroy();

assert_equals(oncancel_call_count_, 0);
assert_equals(onclose_call_count_, 1);
assert_array_equals(events, ["close"]);
}, "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 events = [];
let watcher = createRecordingCloseWatcher(t, events);

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);
assert_array_equals(events, []);

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");
assert_array_equals(events, []);
}, "close via synthesized Esc 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();
watcher.requestClose();
});
}, "destroy inside oncancel");
}, "destroy() inside oncancel");

test(t => {
let watcher = new CloseWatcher();
watcher.onclose = () => { watcher.destroy(); }
watcher.close();
}, "destroy inside onclose is benign");
watcher.requestClose();
}, "destroy() inside onclose is benign");

promise_test(async t => {
let watcher = new CloseWatcher();
watcher.oncancel = () => { watcher.close(); }
watcher.oncancel = () => { watcher.requestClose(); }
await test_driver.bless("give user activation so that cancel will fire", () => {
watcher.close();
watcher.requestClose();
});
}, "close inside oncancel should not trigger an infinite loop");
}, "requestClose() 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");
watcher.onclose = () => { watcher.requestClose(); }
watcher.requestClose();
}, "requestClose() inside onclose should not trigger an infinite loop");

promise_test(async () => {
let watcher = new CloseWatcher();
Expand All @@ -158,10 +156,10 @@
watcher.addEventListener("close", () => onclose_called = true);

await test_driver.bless("give user activation so that cancel will fire", () => {
watcher.close();
watcher.requestClose();
});

assert_true(oncancel_called);
assert_true(onclose_called);
}, "close with events added via addEventListener");
}, "requestClose() with events added via addEventListener()");
</script>
14 changes: 12 additions & 2 deletions close-watcher/frame-removal.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
watcher.oncancel = () => i.remove();
watcher.onclose = () => t.unreached_func("close event must not fire");

watcher.close();
watcher.requestClose();
}, "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();
watcher.requestClose();
}, "detaching the iframe during the close event");

promise_test(async (t) => {
Expand All @@ -39,6 +39,16 @@
watcher.close();
}, "detaching the iframe then calling close()");

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.requestClose();
}, "detaching the iframe then calling requestClose()");

promise_test(async (t) => {
const i = await setupIframe();
const iCloseWatcher = i.contentWindow.CloseWatcher;
Expand Down
6 changes: 4 additions & 2 deletions close-watcher/resources/helpers.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// TODO(domenic): consider using these in all test files.

window.createRecordingCloseWatcher = (t, events, name) => {
const prefix = name === undefined ? "" : name + " ";;

const watcher = new CloseWatcher();
t.add_cleanup(() => watcher.destroy());
watcher.oncancel = () => events.push(name + " cancel");
watcher.onclose = () => events.push(name + " close");
watcher.oncancel = () => events.push(prefix + "cancel");
watcher.onclose = () => events.push(prefix + "close");

return watcher;
};
Expand Down
Loading

0 comments on commit d8c9a69

Please sign in to comment.