browser_browsingContext-webProgress.js (7123B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 add_setup(async function () { 7 await SpecialPowers.pushPrefEnv({ 8 set: [["test.wait300msAfterTabSwitch", true]], 9 }); 10 }); 11 12 add_task(async function () { 13 const tab = await BrowserTestUtils.openNewForegroundTab( 14 gBrowser, 15 "about:blank" 16 ); 17 const browser = tab.linkedBrowser; 18 const aboutBlankBrowsingContext = browser.browsingContext; 19 const { webProgress } = aboutBlankBrowsingContext; 20 ok( 21 webProgress, 22 "Got a WebProgress interface on BrowsingContext in the parent process" 23 ); 24 is( 25 webProgress.browsingContext, 26 browser.browsingContext, 27 "WebProgress.browsingContext refers to the right BrowsingContext" 28 ); 29 30 const onLocationChanged = waitForNextLocationChange(webProgress); 31 const newLocation = "data:text/html;charset=utf-8,first-page"; 32 let loaded = BrowserTestUtils.browserLoaded(browser); 33 BrowserTestUtils.startLoadingURIString(browser, newLocation); 34 await loaded; 35 36 const firstPageBrowsingContext = browser.browsingContext; 37 const isBfcacheInParentEnabled = 38 SpecialPowers.Services.appinfo.sessionHistoryInParent && 39 SpecialPowers.Services.prefs.getBoolPref("fission.bfcacheInParent"); 40 is( 41 aboutBlankBrowsingContext, 42 firstPageBrowsingContext, 43 "The first navigation away from the initial about:blank reuses the BrowsingContext with or without bfcacheInParent" 44 ); 45 46 info("Wait for onLocationChange to be fired"); 47 { 48 const { browsingContext, location, request, flags } = 49 await onLocationChanged; 50 is( 51 browsingContext, 52 firstPageBrowsingContext, 53 "Location change fires on the new BrowsingContext" 54 ); 55 ok(location instanceof Ci.nsIURI); 56 is(location.spec, newLocation); 57 ok(request instanceof Ci.nsIChannel); 58 is(request.URI.spec, newLocation); 59 is(flags, 0); 60 } 61 62 const onIframeLocationChanged = waitForNextLocationChange(webProgress); 63 const iframeLocation = "data:text/html;charset=utf-8,iframe"; 64 const iframeBC = await SpecialPowers.spawn( 65 browser, 66 [iframeLocation], 67 async url => { 68 const iframe = content.document.createElement("iframe"); 69 await new Promise(resolve => { 70 iframe.addEventListener("load", resolve, { once: true }); 71 iframe.src = url; 72 content.document.body.appendChild(iframe); 73 }); 74 75 return iframe.browsingContext; 76 } 77 ); 78 ok( 79 iframeBC.webProgress, 80 "The iframe BrowsingContext also exposes a WebProgress" 81 ); 82 { 83 const { browsingContext, location, request, flags } = 84 await onIframeLocationChanged; 85 is( 86 browsingContext, 87 iframeBC, 88 "Iframe location change fires on the iframe BrowsingContext" 89 ); 90 ok(location instanceof Ci.nsIURI); 91 is(location.spec, iframeLocation); 92 ok(request instanceof Ci.nsIChannel); 93 is(request.URI.spec, iframeLocation); 94 is(flags, 0); 95 } 96 97 const onSecondLocationChanged = waitForNextLocationChange(webProgress); 98 const onSecondPageDocumentStart = waitForNextDocumentStart(webProgress); 99 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 100 const secondLocation = "http://example.com/document-builder.sjs?html=com"; 101 loaded = BrowserTestUtils.browserLoaded(browser); 102 BrowserTestUtils.startLoadingURIString(browser, secondLocation); 103 await loaded; 104 105 const secondPageBrowsingContext = browser.browsingContext; 106 if (isBfcacheInParentEnabled) { 107 isnot( 108 firstPageBrowsingContext, 109 secondPageBrowsingContext, 110 "With bfcache in parent, navigations spawn a new BrowsingContext" 111 ); 112 } else { 113 is( 114 firstPageBrowsingContext, 115 secondPageBrowsingContext, 116 "Without bfcache in parent, navigations reuse the same BrowsingContext" 117 ); 118 } 119 { 120 const { browsingContext, location, request, flags } = 121 await onSecondLocationChanged; 122 is( 123 browsingContext, 124 secondPageBrowsingContext, 125 "Second location change fires on the new BrowsingContext" 126 ); 127 ok(location instanceof Ci.nsIURI); 128 is(location.spec, secondLocation); 129 ok(request instanceof Ci.nsIChannel); 130 is(request.URI.spec, secondLocation); 131 is(flags, 0); 132 } 133 { 134 const { browsingContext, request } = await onSecondPageDocumentStart; 135 is( 136 browsingContext, 137 firstPageBrowsingContext, 138 "STATE_START, when navigating to another process, fires on the BrowsingContext we navigate *from*" 139 ); 140 ok(request instanceof Ci.nsIChannel); 141 is(request.URI.spec, secondLocation); 142 } 143 144 const onBackLocationChanged = waitForNextLocationChange(webProgress, true); 145 const onBackDocumentStart = waitForNextDocumentStart(webProgress); 146 browser.goBack(); 147 148 { 149 const { browsingContext, location, request, flags } = 150 await onBackLocationChanged; 151 is( 152 browsingContext, 153 firstPageBrowsingContext, 154 "location change, when navigating back, fires on the BrowsingContext we navigate *to*" 155 ); 156 ok(location instanceof Ci.nsIURI); 157 is(location.spec, newLocation); 158 ok(request instanceof Ci.nsIChannel); 159 is(request.URI.spec, newLocation); 160 is(flags, 0); 161 } 162 { 163 const { browsingContext, request } = await onBackDocumentStart; 164 is( 165 browsingContext, 166 secondPageBrowsingContext, 167 "STATE_START, when navigating back, fires on the BrowsingContext we navigate *from*" 168 ); 169 ok(request instanceof Ci.nsIChannel); 170 is(request.URI.spec, newLocation); 171 } 172 173 BrowserTestUtils.removeTab(tab); 174 }); 175 176 function waitForNextLocationChange(webProgress, onlyTopLevel = false) { 177 return new Promise(resolve => { 178 const wpl = { 179 QueryInterface: ChromeUtils.generateQI([ 180 "nsIWebProgressListener", 181 "nsISupportsWeakReference", 182 ]), 183 onLocationChange(progress, request, location, flags) { 184 if (onlyTopLevel && progress.browsingContext.parent) { 185 // Ignore non-toplevel. 186 return; 187 } 188 webProgress.removeProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL); 189 resolve({ 190 browsingContext: progress.browsingContext, 191 location, 192 request, 193 flags, 194 }); 195 }, 196 }; 197 // Add a strong reference to the progress listener. 198 resolve.wpl = wpl; 199 webProgress.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL); 200 }); 201 } 202 203 function waitForNextDocumentStart(webProgress) { 204 return new Promise(resolve => { 205 const wpl = { 206 QueryInterface: ChromeUtils.generateQI([ 207 "nsIWebProgressListener", 208 "nsISupportsWeakReference", 209 ]), 210 onStateChange(progress, request, flags) { 211 if ( 212 flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT && 213 flags & Ci.nsIWebProgressListener.STATE_START 214 ) { 215 webProgress.removeProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL); 216 resolve({ browsingContext: progress.browsingContext, request }); 217 } 218 }, 219 }; 220 // Add a strong reference to the progress listener. 221 resolve.wpl = wpl; 222 webProgress.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL); 223 }); 224 }