browser_sessionHistory.js (9167B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 requestLongerTimeout(2); 7 8 /** 9 * Ensure that starting a load invalidates shistory. 10 */ 11 add_task(async function test_load_start() { 12 // Create a new tab. 13 let tab = BrowserTestUtils.addTab(gBrowser, "about:blank"); 14 let browser = tab.linkedBrowser; 15 await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" }); 16 17 const PAGE = "http://example.com/"; 18 19 // Load a new URI. 20 let historyReplacePromise = promiseOnHistoryReplaceEntry(browser); 21 BrowserTestUtils.startLoadingURIString(browser, PAGE); 22 23 // Remove the tab before it has finished loading. 24 await historyReplacePromise; 25 await promiseRemoveTabAndSessionState(tab); 26 27 // Undo close the tab. 28 tab = ss.undoCloseTab(window, 0); 29 browser = tab.linkedBrowser; 30 await promiseTabRestored(tab); 31 32 // Check that the correct URL was restored. 33 is(browser.currentURI.spec, PAGE, "url is correct"); 34 35 // Cleanup. 36 gBrowser.removeTab(tab); 37 }); 38 39 /** 40 * Ensure that anchor navigation invalidates shistory. 41 */ 42 add_task(async function test_hashchange() { 43 const PATH = getRootDirectory(gTestPath).replace( 44 "chrome://mochitests/content/", 45 "http://example.com/" 46 ); 47 const URL = PATH + "file_sessionHistory_hashchange.html"; 48 // Create a new tab. 49 let tab = BrowserTestUtils.addTab(gBrowser, URL); 50 let browser = tab.linkedBrowser; 51 await promiseBrowserLoaded(browser); 52 53 // Check that we start with a single shistory entry. 54 await TabStateFlusher.flush(browser); 55 let { entries } = JSON.parse(ss.getTabState(tab)); 56 is(entries.length, 1, "there is one shistory entry"); 57 58 // Click the link and wait for a hashchange event. 59 let eventPromise = BrowserTestUtils.waitForContentEvent( 60 browser, 61 "hashchange", 62 true 63 ); 64 await SpecialPowers.spawn(browser, [], async function () { 65 content.document.querySelector("#a").click(); 66 }); 67 info("About to watch for a hash change event"); 68 await eventPromise; 69 info("Got a hash change event"); 70 71 // Check that we now have two shistory entries. 72 await TabStateFlusher.flush(browser); 73 ({ entries } = JSON.parse(ss.getTabState(tab))); 74 is(entries.length, 2, "there are two shistory entries"); 75 76 // Cleanup. 77 gBrowser.removeTab(tab); 78 }); 79 80 /** 81 * Ensure that loading pages from the bfcache invalidates shistory. 82 */ 83 add_task(async function test_pageshow() { 84 const URL = "data:text/html;charset=utf-8,<h1>first</h1>"; 85 const URL2 = "data:text/html;charset=utf-8,<h1>second</h1>"; 86 87 // Create a new tab. 88 let tab = BrowserTestUtils.addTab(gBrowser, URL); 89 let browser = tab.linkedBrowser; 90 await promiseBrowserLoaded(browser); 91 92 // Create a second shistory entry. 93 BrowserTestUtils.startLoadingURIString(browser, URL2); 94 await promiseBrowserLoaded(browser); 95 96 // Wait until shistory changes. 97 let pageShowPromise = BrowserTestUtils.waitForContentEvent( 98 browser, 99 "pageshow", 100 true 101 ); 102 103 // Go back to the previous url which is loaded from the bfcache. 104 browser.goBack(); 105 await pageShowPromise; 106 is(browser.currentURI.spec, URL, "correct url after going back"); 107 108 // Check that loading from bfcache did invalidate shistory. 109 await TabStateFlusher.flush(browser); 110 let { index } = JSON.parse(ss.getTabState(tab)); 111 is(index, 1, "first history entry is selected"); 112 113 // Cleanup. 114 gBrowser.removeTab(tab); 115 }); 116 117 /** 118 * Ensure that subframe navigation invalidates shistory. 119 */ 120 add_task(async function test_subframes() { 121 const URL = 122 "data:text/html;charset=utf-8," + 123 "<iframe src=http%3A//example.com/ name=t></iframe>" + 124 "<a id=a1 href=http%3A//example.com/1 target=t>clickme</a>" + 125 "<a id=a2 href=http%3A//example.com/%23section target=t>clickme</a>"; 126 127 // Create a new tab. 128 let tab = BrowserTestUtils.addTab(gBrowser, URL); 129 let browser = tab.linkedBrowser; 130 await promiseBrowserLoaded(browser); 131 132 // Check that we have a single shistory entry. 133 await TabStateFlusher.flush(browser); 134 let { entries } = JSON.parse(ss.getTabState(tab)); 135 is(entries.length, 1, "there is one shistory entry"); 136 is(entries[0].children.length, 1, "the entry has one child"); 137 138 // Navigate the subframe. 139 await SpecialPowers.spawn(browser, [], async function () { 140 content.document.notifyUserGestureActivation(); 141 content.document.querySelector("#a1").click(); 142 }); 143 await promiseBrowserLoaded( 144 browser, 145 false /* wait for subframe load only */, 146 "http://example.com/1" 147 ); 148 149 // Check shistory. 150 await TabStateFlusher.flush(browser); 151 ({ entries } = JSON.parse(ss.getTabState(tab))); 152 is(entries.length, 2, "there now are two shistory entries"); 153 is(entries[1].children.length, 1, "the second entry has one child"); 154 155 // Go back in history. 156 let goneBack = promiseBrowserLoaded( 157 browser, 158 false /* wait for subframe load only */, 159 "http://example.com/" 160 ); 161 info("About to go back in history"); 162 browser.goBack(); 163 await goneBack; 164 165 // Navigate the subframe again. 166 let eventPromise = BrowserTestUtils.waitForContentEvent( 167 browser, 168 "hashchange", 169 true 170 ); 171 await SpecialPowers.spawn(browser, [], async function () { 172 content.document.querySelector("#a2").click(); 173 }); 174 await eventPromise; 175 176 // Check shistory. 177 await TabStateFlusher.flush(browser); 178 ({ entries } = JSON.parse(ss.getTabState(tab))); 179 is(entries.length, 2, "there now are two shistory entries"); 180 is(entries[1].children.length, 1, "the second entry has one child"); 181 182 // Cleanup. 183 gBrowser.removeTab(tab); 184 }); 185 186 /** 187 * Ensure that navigating from an about page invalidates shistory. 188 */ 189 add_task(async function test_about_page_navigate() { 190 // Create a new tab. 191 let tab = BrowserTestUtils.addTab(gBrowser, "about:blank"); 192 let browser = tab.linkedBrowser; 193 await BrowserTestUtils.browserLoaded(browser, { wantLoad: "about:blank" }); 194 195 // Check that we have a single shistory entry. 196 await TabStateFlusher.flush(browser); 197 let { entries } = JSON.parse(ss.getTabState(tab)); 198 is(entries.length, 1, "there is one shistory entry"); 199 is(entries[0].url, "about:blank", "url is correct"); 200 201 // Verify that the title is also recorded. 202 is(entries[0].title, "about:blank", "title is correct"); 203 204 BrowserTestUtils.startLoadingURIString(browser, "about:robots"); 205 await promiseBrowserLoaded(browser); 206 207 // Check that we have changed the history entry. 208 await TabStateFlusher.flush(browser); 209 ({ entries } = JSON.parse(ss.getTabState(tab))); 210 is(entries.length, 1, "there is one shistory entry"); 211 is(entries[0].url, "about:robots", "url is correct"); 212 213 // Cleanup. 214 gBrowser.removeTab(tab); 215 }); 216 217 /** 218 * Ensure that history.pushState and history.replaceState invalidate shistory. 219 */ 220 add_task(async function test_pushstate_replacestate() { 221 // Create a new tab. 222 let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com/1"); 223 let browser = tab.linkedBrowser; 224 await promiseBrowserLoaded(browser); 225 226 // Check that we have a single shistory entry. 227 await TabStateFlusher.flush(browser); 228 let { entries } = JSON.parse(ss.getTabState(tab)); 229 is(entries.length, 1, "there is one shistory entry"); 230 is(entries[0].url, "http://example.com/1", "url is correct"); 231 232 await SpecialPowers.spawn(browser, [], async function () { 233 content.window.history.pushState({}, "", "test-entry/"); 234 }); 235 236 // Check that we have added the history entry. 237 await TabStateFlusher.flush(browser); 238 ({ entries } = JSON.parse(ss.getTabState(tab))); 239 is(entries.length, 2, "there is another shistory entry"); 240 is(entries[1].url, "http://example.com/test-entry/", "url is correct"); 241 242 await SpecialPowers.spawn(browser, [], async function () { 243 content.window.history.replaceState({}, "", "test-entry2/"); 244 }); 245 246 // Check that we have modified the history entry. 247 await TabStateFlusher.flush(browser); 248 ({ entries } = JSON.parse(ss.getTabState(tab))); 249 is(entries.length, 2, "there is still two shistory entries"); 250 is( 251 entries[1].url, 252 "http://example.com/test-entry/test-entry2/", 253 "url is correct" 254 ); 255 256 // Cleanup. 257 gBrowser.removeTab(tab); 258 }); 259 260 /** 261 * Ensure that slow loading subframes will invalidate shistory. 262 */ 263 add_task(async function test_slow_subframe_load() { 264 const SLOW_URL = 265 "http://mochi.test:8888/browser/browser/components/" + 266 "sessionstore/test/browser_sessionHistory_slow.sjs"; 267 268 const URL = 269 "data:text/html;charset=utf-8," + 270 "<frameset cols=50%25,50%25>" + 271 "<frame src='" + 272 SLOW_URL + 273 "'>" + 274 "</frameset>"; 275 276 // Add a new tab with a slow loading subframe 277 let tab = BrowserTestUtils.addTab(gBrowser, URL); 278 let browser = tab.linkedBrowser; 279 await promiseBrowserLoaded(browser); 280 281 await TabStateFlusher.flush(browser); 282 let { entries } = JSON.parse(ss.getTabState(tab)); 283 284 // Check the number of children. 285 is(entries.length, 1, "there is one root entry ..."); 286 is(entries[0].children.length, 1, "... with one child entries"); 287 288 // Check URLs. 289 ok(entries[0].url.startsWith("data:text/html"), "correct root url"); 290 is(entries[0].children[0].url, SLOW_URL, "correct url for subframe"); 291 292 // Cleanup. 293 gBrowser.removeTab(tab); 294 });