browser_586068-browser_state_interrupted.js (5816B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const PREF_RESTORE_ON_DEMAND = "browser.sessionstore.restore_on_demand"; 6 7 requestLongerTimeout(2); 8 9 add_task(async function test() { 10 Services.prefs.setBoolPref(PREF_RESTORE_ON_DEMAND, false); 11 registerCleanupFunction(function () { 12 Services.prefs.clearUserPref(PREF_RESTORE_ON_DEMAND); 13 }); 14 15 // The first state will be loaded using setBrowserState, followed by the 2nd 16 // state also being loaded using setBrowserState, interrupting the first restore. 17 let state1 = { 18 windows: [ 19 { 20 tabs: [ 21 { 22 entries: [ 23 { url: "http://example.org#1", triggeringPrincipal_base64 }, 24 ], 25 extData: { uniq: r() }, 26 }, 27 { 28 entries: [ 29 { url: "http://example.org#2", triggeringPrincipal_base64 }, 30 ], 31 extData: { uniq: r() }, 32 }, 33 { 34 entries: [ 35 { url: "http://example.org#3", triggeringPrincipal_base64 }, 36 ], 37 extData: { uniq: r() }, 38 }, 39 { 40 entries: [ 41 { url: "http://example.org#4", triggeringPrincipal_base64 }, 42 ], 43 extData: { uniq: r() }, 44 }, 45 ], 46 selected: 1, 47 }, 48 { 49 tabs: [ 50 { 51 entries: [ 52 { url: "http://example.com#1", triggeringPrincipal_base64 }, 53 ], 54 extData: { uniq: r() }, 55 }, 56 { 57 entries: [ 58 { url: "http://example.com#2", triggeringPrincipal_base64 }, 59 ], 60 extData: { uniq: r() }, 61 }, 62 { 63 entries: [ 64 { url: "http://example.com#3", triggeringPrincipal_base64 }, 65 ], 66 extData: { uniq: r() }, 67 }, 68 { 69 entries: [ 70 { url: "http://example.com#4", triggeringPrincipal_base64 }, 71 ], 72 extData: { uniq: r() }, 73 }, 74 ], 75 selected: 3, 76 }, 77 ], 78 }; 79 let state2 = { 80 windows: [ 81 { 82 tabs: [ 83 { 84 entries: [ 85 { url: "http://example.org#5", triggeringPrincipal_base64 }, 86 ], 87 extData: { uniq: r() }, 88 }, 89 { 90 entries: [ 91 { url: "http://example.org#6", triggeringPrincipal_base64 }, 92 ], 93 extData: { uniq: r() }, 94 }, 95 { 96 entries: [ 97 { url: "http://example.org#7", triggeringPrincipal_base64 }, 98 ], 99 extData: { uniq: r() }, 100 }, 101 { 102 entries: [ 103 { url: "http://example.org#8", triggeringPrincipal_base64 }, 104 ], 105 extData: { uniq: r() }, 106 }, 107 ], 108 selected: 3, 109 }, 110 { 111 tabs: [ 112 { 113 entries: [ 114 { url: "http://example.com#5", triggeringPrincipal_base64 }, 115 ], 116 extData: { uniq: r() }, 117 }, 118 { 119 entries: [ 120 { url: "http://example.com#6", triggeringPrincipal_base64 }, 121 ], 122 extData: { uniq: r() }, 123 }, 124 { 125 entries: [ 126 { url: "http://example.com#7", triggeringPrincipal_base64 }, 127 ], 128 extData: { uniq: r() }, 129 }, 130 { 131 entries: [ 132 { url: "http://example.com#8", triggeringPrincipal_base64 }, 133 ], 134 extData: { uniq: r() }, 135 }, 136 ], 137 selected: 1, 138 }, 139 ], 140 }; 141 142 // interruptedAfter will be set after the selected tab from each window have loaded. 143 let interruptedAfter = 0; 144 let loadedWindow1 = false; 145 let loadedWindow2 = false; 146 let numTabs = state2.windows[0].tabs.length + state2.windows[1].tabs.length; 147 148 let loadCount = 0; 149 let promiseRestoringTabs = new Promise(resolve => { 150 gProgressListener.setCallback(function (aBrowser, aNeedRestore) { 151 loadCount++; 152 153 if ( 154 aBrowser.currentURI.spec == state1.windows[0].tabs[2].entries[0].url 155 ) { 156 loadedWindow1 = true; 157 } 158 if ( 159 aBrowser.currentURI.spec == state1.windows[1].tabs[0].entries[0].url 160 ) { 161 loadedWindow2 = true; 162 } 163 164 if (!interruptedAfter && loadedWindow1 && loadedWindow2) { 165 interruptedAfter = loadCount; 166 ss.setBrowserState(JSON.stringify(state2)); 167 return; 168 } 169 170 if (loadCount < numTabs + interruptedAfter) { 171 return; 172 } 173 174 // We don't actually care about load order in this test, just that they all 175 // do load. 176 is(loadCount, numTabs + interruptedAfter, "all tabs were restored"); 177 is(aNeedRestore, 0, "there are no tabs left needing restore"); 178 179 // Remove the progress listener. 180 gProgressListener.unsetCallback(); 181 resolve(); 182 }); 183 }); 184 185 // We also want to catch the extra windows (there should be 2), so we need to observe domwindowopened 186 Services.ww.registerNotification(function observer(aSubject, aTopic) { 187 if (aTopic == "domwindowopened") { 188 let win = aSubject; 189 win.addEventListener( 190 "load", 191 function () { 192 Services.ww.unregisterNotification(observer); 193 win.gBrowser.addTabsProgressListener(gProgressListener); 194 }, 195 { once: true } 196 ); 197 } 198 }); 199 200 let backupState = ss.getBrowserState(); 201 ss.setBrowserState(JSON.stringify(state1)); 202 await promiseRestoringTabs; 203 204 // Cleanup. 205 await promiseAllButPrimaryWindowClosed(); 206 await promiseBrowserState(backupState); 207 });