browser_onbeforeunload_navigation.js (4630B)
1 "use strict"; 2 3 const TEST_PAGE = 4 "http://mochi.test:8888/browser/docshell/test/browser/file_bug1046022.html"; 5 const TARGETED_PAGE = 6 "data:text/html," + 7 encodeURIComponent("<body>Shouldn't be seeing this</body>"); 8 9 const { PromptTestUtils } = ChromeUtils.importESModule( 10 "resource://testing-common/PromptTestUtils.sys.mjs" 11 ); 12 13 var loadStarted = false; 14 var tabStateListener = { 15 resolveLoad: null, 16 expectLoad: null, 17 18 onStateChange(webprogress, request, flags) { 19 const WPL = Ci.nsIWebProgressListener; 20 if (flags & WPL.STATE_IS_WINDOW) { 21 if (flags & WPL.STATE_START) { 22 loadStarted = true; 23 } else if (flags & WPL.STATE_STOP) { 24 let url = request.QueryInterface(Ci.nsIChannel).URI.spec; 25 is(url, this.expectLoad, "Should only see expected document loads"); 26 if (url == this.expectLoad) { 27 this.resolveLoad(); 28 } 29 } 30 } 31 }, 32 QueryInterface: ChromeUtils.generateQI([ 33 "nsIWebProgressListener", 34 "nsISupportsWeakReference", 35 ]), 36 }; 37 38 function promiseLoaded(url, callback) { 39 if (tabStateListener.expectLoad) { 40 throw new Error("Can't wait for multiple loads at once"); 41 } 42 tabStateListener.expectLoad = url; 43 return new Promise(resolve => { 44 tabStateListener.resolveLoad = resolve; 45 if (callback) { 46 callback(); 47 } 48 }).then(() => { 49 tabStateListener.expectLoad = null; 50 tabStateListener.resolveLoad = null; 51 }); 52 } 53 54 function promiseStayOnPagePrompt(browser, acceptNavigation) { 55 return PromptTestUtils.handleNextPrompt( 56 browser, 57 { modalType: Services.prompt.MODAL_TYPE_CONTENT, promptType: "confirmEx" }, 58 { buttonNumClick: acceptNavigation ? 0 : 1 } 59 ); 60 } 61 62 add_task(async function test() { 63 await SpecialPowers.pushPrefEnv({ 64 set: [["dom.require_user_interaction_for_beforeunload", false]], 65 }); 66 67 let testTab = await BrowserTestUtils.openNewForegroundTab( 68 gBrowser, 69 TEST_PAGE, 70 false, 71 true 72 ); 73 let browser = testTab.linkedBrowser; 74 browser.addProgressListener( 75 tabStateListener, 76 Ci.nsIWebProgress.NOTIFY_STATE_WINDOW 77 ); 78 79 const NUM_TESTS = 7; 80 await SpecialPowers.spawn(browser, [NUM_TESTS], testCount => { 81 let { testFns } = this.content.wrappedJSObject; 82 Assert.equal( 83 testFns.length, 84 testCount, 85 "Should have the correct number of test functions" 86 ); 87 }); 88 89 for (let allowNavigation of [false, true]) { 90 for (let i = 0; i < NUM_TESTS; i++) { 91 info( 92 `Running test ${i} with navigation ${ 93 allowNavigation ? "allowed" : "forbidden" 94 }` 95 ); 96 97 if (allowNavigation) { 98 // If we're allowing navigations, we need to re-load the test 99 // page after each test, since the tests will each navigate away 100 // from it. 101 await promiseLoaded(TEST_PAGE, () => { 102 browser.loadURI(Services.io.newURI(TEST_PAGE), { 103 triggeringPrincipal: document.nodePrincipal, 104 }); 105 }); 106 } 107 108 let promptPromise = promiseStayOnPagePrompt(browser, allowNavigation); 109 let loadPromise; 110 if (allowNavigation) { 111 loadPromise = promiseLoaded(TARGETED_PAGE); 112 } 113 114 let winID = await SpecialPowers.spawn( 115 browser, 116 [i, TARGETED_PAGE], 117 (testIdx, url) => { 118 let { testFns } = this.content.wrappedJSObject; 119 this.content.onbeforeunload = testFns[testIdx]; 120 this.content.location = url; 121 return this.content.windowGlobalChild.innerWindowId; 122 } 123 ); 124 125 await promptPromise; 126 await loadPromise; 127 128 if (allowNavigation) { 129 await SpecialPowers.spawn( 130 browser, 131 [TARGETED_PAGE, winID], 132 (url, winID) => { 133 this.content.onbeforeunload = null; 134 Assert.equal( 135 this.content.location.href, 136 url, 137 "Page should have navigated to the correct URL" 138 ); 139 Assert.notEqual( 140 this.content.windowGlobalChild.innerWindowId, 141 winID, 142 "Page should have a new inner window" 143 ); 144 } 145 ); 146 } else { 147 await SpecialPowers.spawn(browser, [TEST_PAGE, winID], (url, winID) => { 148 this.content.onbeforeunload = null; 149 Assert.equal( 150 this.content.location.href, 151 url, 152 "Page should have the same URL" 153 ); 154 Assert.equal( 155 this.content.windowGlobalChild.innerWindowId, 156 winID, 157 "Page should have the same inner window" 158 ); 159 }); 160 } 161 } 162 } 163 164 gBrowser.removeTab(testTab); 165 });