| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <title>beforeunload return value cancelation behavior</title> |
| <link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#the-event-handler-processing-algorithm"> |
| <link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| |
| <div id="log"></div> |
| |
| <script> |
| "use strict"; |
| |
| promise_test(t => { |
| let onbeforeunloadHappened = false; |
| window.onbeforeunload = t.step_func(() => { |
| onbeforeunloadHappened = true; |
| return "cancel me"; |
| }); |
| |
| const eventWatcher = new EventWatcher(t, window, "beforeunload"); |
| const promise = eventWatcher.wait_for("beforeunload").then(e => { |
| assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); |
| assert_false(e.defaultPrevented, "The event must not have been canceled"); |
| window.onbeforeunload = null; |
| }); |
| |
| window.dispatchEvent(new CustomEvent("beforeunload")); |
| |
| return promise; |
| }, "Returning a string must not cancel the event: CustomEvent, non-cancelable"); |
| |
| promise_test(t => { |
| let onbeforeunloadHappened = false; |
| window.onbeforeunload = t.step_func(() => { |
| onbeforeunloadHappened = true; |
| return "cancel me"; |
| }); |
| |
| const eventWatcher = new EventWatcher(t, window, "beforeunload"); |
| const promise = eventWatcher.wait_for("beforeunload").then(e => { |
| assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); |
| assert_false(e.defaultPrevented, "The event must not have been canceled"); |
| window.onbeforeunload = null; |
| t.done(); |
| }); |
| |
| window.dispatchEvent(new CustomEvent("beforeunload", { cancelable: true })); |
| |
| return promise; |
| }, "Returning a string must not cancel the event: CustomEvent, cancelable"); |
| |
| promise_test(t => { |
| let onbeforeunloadHappened = false; |
| window.onbeforeunload = t.step_func(() => { |
| onbeforeunloadHappened = true; |
| return false; |
| }); |
| |
| const eventWatcher = new EventWatcher(t, window, "beforeunload"); |
| const promise = eventWatcher.wait_for("beforeunload").then(e => { |
| assert_true(onbeforeunloadHappened, "CustomEvent must be able to trigger the event handler"); |
| assert_false(e.defaultPrevented, "The event must not have been canceled"); |
| window.onbeforeunload = null; |
| t.done(); |
| }); |
| |
| window.dispatchEvent(new CustomEvent("beforeunload", { cancelable: true })); |
| |
| return promise; |
| }, "Returning false must not cancel the event, because it's coerced to the DOMString \"false\" which does not cancel " + |
| "CustomEvents: CustomEvent, cancelable"); |
| |
| // This test can be removed if we update the DOM Standard to disallow createEvent("BeforeUnloadEvent"). Browser support |
| // is inconsistent. https://github.com/whatwg/dom/issues/362 |
| promise_test(t => { |
| const eventWatcher = new EventWatcher(t, window, "click"); |
| const promise = eventWatcher.wait_for("click").then(e => { |
| assert_false(e.defaultPrevented, "The event must not have been canceled"); |
| window.onbeforeunload = null; |
| t.done(); |
| }); |
| |
| const ev = document.createEvent("BeforeUnloadEvent"); |
| ev.initEvent("click", false, true); |
| window.dispatchEvent(ev); |
| |
| return promise; |
| }, "Returning a string must not cancel the event: BeforeUnloadEvent with type \"click\", cancelable"); |
| |
| const testCases = [ |
| { |
| valueToReturn: null, |
| expectCancelation: false, |
| expectedReturnValue: "" |
| }, |
| { |
| valueToReturn: undefined, |
| expectCancelation: false, |
| expectedReturnValue: "" |
| }, |
| { |
| valueToReturn: "", |
| expectCancelation: true, |
| expectedReturnValue: "" |
| }, |
| { |
| valueToReturn: false, |
| expectCancelation: true, |
| expectedReturnValue: "false" |
| }, |
| { |
| valueToReturn: true, |
| expectCancelation: true, |
| expectedReturnValue: "true" |
| }, |
| { |
| valueToReturn: 0, |
| expectCancelation: true, |
| expectedReturnValue: "0" |
| }, |
| { |
| valueToReturn: null, |
| expectCancelation: false, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| }, |
| { |
| valueToReturn: undefined, |
| expectCancelation: false, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| }, |
| { |
| valueToReturn: "", |
| expectCancelation: true, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| }, |
| { |
| valueToReturn: false, |
| expectCancelation: true, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| }, |
| { |
| valueToReturn: true, |
| expectCancelation: true, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| }, |
| { |
| valueToReturn: 0, |
| expectCancelation: true, |
| setReturnValue: "foo", |
| expectedReturnValue: "foo" |
| } |
| ]; |
| |
| var testCaseIndex = 0; |
| function runNextTest() { |
| const testCase = testCases[testCaseIndex]; |
| |
| const labelAboutReturnValue = testCase.setReturnValue === undefined ? "" : |
| `; setting returnValue to ${testCase.setReturnValue}`; |
| |
| async_test(t => { |
| const iframe = document.createElement("iframe"); |
| iframe.onload = t.step_func(() => { |
| iframe.contentWindow.runTest(t, testCase); |
| if (++testCaseIndex < testCases.length) |
| runNextTest(); |
| }); |
| |
| iframe.src = "beforeunload-canceling-1.html"; |
| document.body.appendChild(iframe); |
| }, `Returning ${testCase.valueToReturn} with a real iframe unloading${labelAboutReturnValue}`); |
| } |
| |
| runNextTest(); |
| </script> |