test_bug500328.html (25599B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=500328 5 --> 6 <head> 7 <title>Test for Bug 500328</title> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 <script src="/tests/SimpleTest/EventUtils.js"></script> 10 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 11 </head> 12 <body> 13 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500328">Mozilla Bug 500328</a> 14 <p id="display"></p> 15 <div id="status"></div> 16 <div id="content"> 17 <iframe id="iframe"></iframe> 18 <iframe id="iframe2"></iframe> 19 <a id="link">link</a> 20 </div> 21 <pre id="test"> 22 <script type="application/javascript"> 23 24 /** Test for Bug 500328 */ 25 26 SimpleTest.waitForExplicitFinish(); 27 28 var iframe = document.getElementById("iframe"); 29 var iframeCw = iframe.contentWindow; 30 31 var iframe2 = document.getElementById("iframe2"); 32 var iframe2Cw = iframe2.contentWindow; 33 34 const unvisitedColor = "rgb(0, 0, 238)"; 35 const visitedColor = "rgb(85, 26, 139)"; 36 37 var gCallbackOnIframeLoad = false; 38 var gCallbackOnIframePageShow = false; 39 var gCallbackOnPopState = false; 40 var gNumPopStates = 0; 41 var gLastPopStateEvent; 42 var gLastScriptHistoryState; 43 44 var gGen; 45 46 function statusMsg(msg) { 47 var msgElem = document.createElement("p"); 48 msgElem.appendChild(document.createTextNode(msg)); 49 50 document.getElementById("status").appendChild(msgElem); 51 } 52 53 function longWait() { 54 function hitEventLoop(times, func) { 55 if (times > 0) { 56 setTimeout(hitEventLoop, 0, times - 1, func); 57 } else { 58 setTimeout(func, 0); 59 } 60 } 61 hitEventLoop(100, function() { gGen.next(); }); 62 } 63 64 function shortWait() { 65 setTimeout(function() { gGen.next(); }, 0); 66 } 67 68 function onChildPopState(e) { 69 gNumPopStates++; 70 gLastPopStateEvent = e; 71 if (gCallbackOnPopState) { 72 statusMsg("Popstate(" + JSON.stringify(e.state) + "). Calling gGen.next()."); 73 gCallbackOnPopState = false; 74 gGen.next(); 75 } 76 else { 77 statusMsg("Popstate(" + JSON.stringify(e.state) + "). NOT calling gGen.next()."); 78 } 79 } 80 81 function onChildScript(state) { 82 gLastScriptHistoryState = state; 83 } 84 85 function getURLFromEvent(e) { 86 try { 87 var target = e.target; 88 if ("contentWindow" in target) { 89 return target.contentWindow.location.toString(); 90 } 91 if ("ownerDocument" in target && target.ownerDocument) { 92 return target.ownerDocument.location.toString(); 93 } 94 if ("location" in target) { 95 return target.location.toString(); 96 } 97 return target.toString(); 98 } 99 catch(ex) { 100 return "<cross-site object>"; 101 } 102 } 103 104 function onChildLoad(e) { 105 if(gCallbackOnIframeLoad) { 106 statusMsg("Got load for " + getURLFromEvent(e) + ". About to call gGen.next()."); 107 gCallbackOnIframeLoad = false; 108 gGen.next(); 109 } 110 else { 111 statusMsg("Got load for " + getURLFromEvent(e) + ", but not calling gGen.next() because gCallbackOnIframeLoad was false."); 112 } 113 } 114 115 function onChildPageShow(e) { 116 if(gCallbackOnIframePageShow) { 117 statusMsg("Got pageshow for " + getURLFromEvent(e) + ". About to call gGen.next()."); 118 gCallbackOnIframePageShow = false; 119 SimpleTest.executeSoon(function() { gGen.next(); }); 120 } 121 else { 122 statusMsg("Got pageshow for " + getURLFromEvent(e) + ", but not calling gGen.next() because gCallbackOnIframePageShow was false."); 123 } 124 } 125 126 function enableChildLoadCallback() { 127 gCallbackOnIframeLoad = true; 128 } 129 130 function enableChildPageShowCallback() { 131 gCallbackOnIframePageShow = true; 132 } 133 134 function enableChildPopStateCallback() { 135 gCallbackOnPopState = true; 136 } 137 138 function clearPopStateCounter() { 139 gNumPopStates = 0; 140 } 141 142 function noPopStateExpected(msg) { 143 is(gNumPopStates, 0, msg); 144 145 // Even if there's an error, set gNumPopStates to 0 so other tests don't 146 // fail. 147 gNumPopStates = 0; 148 } 149 150 function popstateExpected(msg) { 151 is(gNumPopStates, 1, msg); 152 gNumPopStates = 0; 153 } 154 155 function getColor(elem) { 156 var utils = SpecialPowers.getDOMWindowUtils(document.defaultView); 157 return utils.getVisitedDependentComputedStyle(elem, "", "color"); 158 } 159 160 function getSHistory(theWindow) 161 { 162 const Ci = SpecialPowers.Ci; 163 var sh = SpecialPowers.wrap(theWindow).docShell 164 .QueryInterface(Ci.nsIWebNavigation) 165 .sessionHistory; 166 if (!sh || sh == null) 167 throw("Couldn't get shistory for window!"); 168 169 return sh; 170 } 171 172 function getSHTitle(sh, offset) 173 { 174 if (!offset) 175 offset = 0; 176 177 // False instructs the SHistory not to modify its current index. 178 return sh.legacySHistory.getEntryAtIndex(sh.index + offset).title; 179 } 180 181 // Tests that win's location ends with str 182 function locationEndsWith(win, str) { 183 var exp = new RegExp(str + "$"); 184 ok(win.location.toString().match(exp), 185 "Wrong window location. Expected it to end with " + 186 str + ", but actuall was " + win.location); 187 } 188 189 function expectException(func, msg) { 190 var failed = false; 191 try { 192 func(); 193 } catch(ex) { 194 failed = true; 195 } 196 197 ok(failed, msg + " succeeded, but should have failed."); 198 } 199 200 function* runTest() { 201 // We can't enable universal XPConnect privleges in this function, because 202 // test 5 needs to be running at normal privleges in order to test the 203 // same-origin policy. 204 205 /** 206 * PRELIMINARY: 207 * 1. Clear the popstate counter 208 */ 209 210 clearPopStateCounter(); 211 212 // The URL of file_bug500328_1.html on http://localhost:8888 213 var innerLoc; 214 215 // Now we can start the tests 216 217 /** 218 * TEST 1 tests basic pushState functionality 219 */ 220 enableChildLoadCallback(); 221 iframeCw.location = "file_bug500328_1.html"; 222 yield undefined; 223 innerLoc = iframeCw.location.toString(); 224 // No popstate during initial load. 225 shortWait(); 226 yield undefined; 227 noPopStateExpected("No initial popstate."); 228 is(JSON.stringify(gLastScriptHistoryState), "null", "null initial state."); 229 statusMsg("Awake after first load."); 230 231 // Make sure that the pushstate below doesn't trigger a hashchange. 232 iframeCw.onhashchange = function() { 233 ok(false, "Pushstate shouldn't trigger a hashchange."); 234 }; 235 236 var testObj1 = 42; 237 var testObj2 = { x: 4.2 }; 238 iframeCw.history.pushState(testObj1, "test 1"); 239 is(JSON.stringify(iframeCw.history.state), JSON.stringify(testObj1), 240 "correct state after pushState"); 241 is(iframeCw.location.search, "", 242 "First pushstate should leave us where we were."); 243 244 iframeCw.history.pushState(testObj2, "test 1#foo", "?test1#foo"); 245 is(JSON.stringify(iframeCw.history.state), JSON.stringify(testObj2), 246 "correct state after pushState"); 247 isnot(iframeCw.history.state, testObj2, 248 "correct state object identity after pushState"); 249 is(iframeCw.location.search, "?test1", 250 "Second pushstate should push us to '?test1'."); 251 is(iframeCw.location.hash, "#foo", 252 "Second pushstate should push us to '#foo'"); 253 shortWait(); 254 yield undefined; 255 256 // Let the hashchange event fire, if it's going to. 257 longWait(); 258 yield undefined; 259 iframeCw.onhashchange = null; 260 261 statusMsg("About to go back to page 1."); 262 // We don't have to yield here because this back() and the resulting popstate 263 // are completely synchronous. In fact, if we did yield, JS would throw an 264 // error because we'd be calling gGen.next from within gGen.next. 265 iframeCw.history.back(); 266 267 statusMsg("Awake after going back to page 1."); 268 popstateExpected("Going back to page 1 should trigger a popstate."); 269 is(gLastPopStateEvent.isTrusted, true, 'Popstate event should be trusted.'); 270 is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1), 271 "Wrong state object popped after going back to page 1."); 272 ok(gLastPopStateEvent.state === iframeCw.history.state, 273 "Wrong state object in document after going back to page 1."); 274 ok(iframeCw.location.toString().match(/file_bug500328_1.html$/), 275 "Going back to page 1 hould take us to original page."); 276 277 iframeCw.history.back(); 278 popstateExpected("Going back to page 0 should trigger a popstate."); 279 is(gLastPopStateEvent.state, null, 280 "Going back to page 0 should pop a null state."); 281 is(iframeCw.history.state, null, 282 "Going back to page 0 should pop a null state."); 283 is(iframeCw.location.search, "", 284 "Going back to page 0 should clear the querystring."); 285 286 iframeCw.history.forward(); 287 popstateExpected("Going forward to page 1 should trigger a popstate."); 288 is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj1), 289 "Wrong state object popped after going forward to page 1."); 290 is(gLastPopStateEvent.state, iframeCw.history.state, 291 "Wrong state object in document after going forward to page 1."); 292 ok(iframeCw.location.toString().match(/file_bug500328_1.html$/), 293 "Going forward to page 1 should leave us at original page."); 294 295 statusMsg("About to go forward to page 2."); 296 iframeCw.history.forward(); 297 statusMsg("Awake after going forward to page 2."); 298 popstateExpected("Going forward to page 2 should trigger a popstate."); 299 is(JSON.stringify(gLastPopStateEvent.state), JSON.stringify(testObj2), 300 "Wrong state object popped after going forward to page 2."); 301 is(iframeCw.history.state, gLastPopStateEvent.state, 302 "Wrong state object in document after going forward to page 2."); 303 ok(iframeCw.location.toString().match(/file_bug500328_1.html\?test1#foo$/), 304 "Going forward to page 2 took us to " + iframeCw.location.toString()); 305 306 statusMsg("About to reload page 2."); 307 iframeCw.location.reload(); 308 enableChildLoadCallback(); 309 yield undefined; 310 statusMsg("Awake after reloading page 2."); 311 noPopStateExpected("Reloading page 2 should not trigger popstate."); 312 is(JSON.stringify(iframeCw.history.state), JSON.stringify(testObj2), 313 "Wrong state object after reloading page 2."); 314 is(JSON.stringify(gLastScriptHistoryState), JSON.stringify(testObj2), 315 "Wrong state object while reloading page 2."); 316 ok(iframeCw.location.toString().match(/file_bug500328_1.html\?test1#foo$/), 317 "Reloading page 2 took us to " + iframeCw.location.toString()); 318 319 // The iframe's current location is file_bug500328_1.html?test1#foo. 320 // Clicking link1 should take us to file_bug500328_1.html?test1#1. 321 322 enableChildPopStateCallback(); 323 sendMouseEvent({type:'click'}, 'link-anchor1', iframeCw); 324 yield undefined; 325 popstateExpected("Clicking on link-anchor1 should trigger a popstate."); 326 is(iframeCw.location.search, "?test1", 327 "search should be ?test1 after clicking link."); 328 is(iframeCw.location.hash, "#1", 329 "hash should be #1 after clicking link."); 330 is(iframeCw.history.state, null, 331 "Wrong state object in document after clicking link to hash '#1'."); 332 333 /* 334 * Reload file_bug500328_1.html; we're now going to test that link hrefs 335 * and colors are updated correctly on push/popstates. 336 */ 337 338 iframe.onload = onChildLoad; 339 enableChildLoadCallback(); 340 iframeCw.location = "about:blank"; 341 yield undefined; 342 enableChildLoadCallback(); 343 iframeCw.location = "file_bug500328_1.html"; 344 yield undefined; 345 noPopStateExpected("No popstate after re-loading file_bug500328_1.html"); 346 statusMsg("Done loading file_bug500328_1.html for the second time."); 347 348 var ifLink = iframeCw.document.getElementById("link-anchor1"); 349 var rand = Date.now() + "-" + Math.random(); 350 ifLink.href = rand; 351 352 // Poll the document until the link has the correct color, or this test times 353 // out. Unfortunately I can't come up with a more elegant way to do this. 354 // We could listen to MozAfterPaint, but that doesn't guarantee that we'll 355 // observe the new color. 356 while (getColor(ifLink) != unvisitedColor) { 357 // Dump so something shows up in the mochitest logs if we spin here. 358 dump("ifLink has wrong initial color. Spinning...\n"); 359 setTimeout(function() { gGen.next(); }, 0); 360 yield undefined; 361 } 362 363 // Navigate iframe2 to dir/${rand} 364 iframe2.onload = onChildLoad; 365 enableChildLoadCallback(); 366 iframe2Cw.location = "mytestdir/" + rand; 367 yield undefined; 368 369 // PushState the iframe into the mytestdir directory. This should cause 370 // ifLink to turn purple, since we just visited mytestdir/${rand} in iframe2. 371 iframeCw.history.pushState(null, "foo", "mytestdir/foo"); 372 373 // Check that the link's color is now visitedColor 374 while (getColor(ifLink) != visitedColor) { 375 dump("ifLink has wrong color after pushstate. Spinning...\n"); 376 setTimeout(function() { gGen.next(); }, 0); 377 yield undefined; 378 } 379 380 ok(ifLink.href.match("mytestdir\\/" + rand + "$"), 381 "inner frame's link should end with 'mytestdir/${rand}'"); 382 383 // Navigate out of the mytestdir directory. This should cause ifLink to turn 384 // blue again. 385 iframeCw.history.pushState(null, "bar", "../file_bug500328_1.html"); 386 387 // Check that the link's color is back to the unvisited color. 388 while (getColor(ifLink) != unvisitedColor) { 389 dump("ifLink has wrong color after pushstating out of dir. Spinning...\n"); 390 setTimeout(function() { gGen.next(); }, 0); 391 yield undefined; 392 } 393 394 ok(!ifLink.href.match("mytestdir"), 395 "inner frame's link shouldn't contain 'mytestdir'."); 396 397 /* 398 * TEST 2 tests that pushstate's same-origin checks are correct. 399 */ 400 var filename = 'file_bug500328_2.html'; 401 var dirname = document.location.pathname.replace(/[^\/]*$/, ''); 402 statusMsg("Dirname is: " + dirname); 403 iframeCw.location = filename; 404 iframe.onload = onChildLoad; 405 enableChildLoadCallback(); 406 yield undefined; 407 408 // This function tries to pushstate and replacestate to the given URL and 409 // fails the test if the calls succeed. 410 var tryBadPushAndReplaceState = function(url) { 411 // XXX ex should be a SECURITY_ERR, not a plain Error. 412 413 var hist = iframeCw.history; 414 var url2 = url + dirname + filename; 415 416 expectException(function() { hist.pushState({}, "foo", url); }, 417 'pushState to ' + url); 418 419 expectException(function() { hist.pushState({}, "foo", url2); }, 420 'pushState to ' + url2); 421 422 expectException(function() { hist.replaceState({}, "foo", url); }, 423 'replaceState to ' + url); 424 425 expectException(function() { hist.replaceState({}, "foo", url2); }, 426 'replaceState to ' + url2); 427 } 428 429 // We're currently at http://example.com/[dirname]/[filename] 430 tryBadPushAndReplaceState("https://mochi.test:8888"); 431 tryBadPushAndReplaceState("http://foo.mochitest:8888"); 432 tryBadPushAndReplaceState("http://mochi.test:1234"); 433 tryBadPushAndReplaceState("http://mochi.test.a:8888"); 434 tryBadPushAndReplaceState("http://mochi.tes:8888"); 435 tryBadPushAndReplaceState("http://mmochi.test:8888"); 436 tryBadPushAndReplaceState("http://me@mochi.test:8888"); 437 438 /** 439 * TEST 3 tests that the session history entries' titles are properly sync'ed 440 * after push/pop states. 441 * 442 * We have to run this test in a popup rather than an iframe because only the 443 * root docshell has a session history object. 444 */ 445 statusMsg("About to open popup."); 446 var popup = window.open("file_bug500328_1.html", "popup0", 447 "height=200,width=200,location=yes," + 448 "menubar=yes,status=yes,toolbar=yes,dependent=yes"); 449 450 enableChildLoadCallback(); 451 var shistory = getSHistory(popup); 452 yield undefined; 453 shortWait(); 454 yield undefined; 455 noPopStateExpected("Shouldn't get popstate after opening window."); 456 457 popup.history.pushState(null, "title 0"); 458 ok(SpecialPowers.isBackButtonEnabled(popup), 459 "Back button was not enabled after initial pushstate."); 460 461 popup.document.title = "title 1"; 462 463 // Yield to the event loop so listeners will be notified of the title change 464 // and so that the hash change we trigger below generates a new session 465 // history entry. 466 shortWait(); 467 yield undefined; 468 469 // Check that the current session history entry's title has been updated to 470 // reflect the new document title. 471 is(getSHTitle(shistory), "title 1", "SHEntry title test 1"); 472 473 // Change the page's hash to #1, which will trigger a popstate event. 474 // We don't have to wait, because this happens synchronously. 475 popup.location.hash = "#1"; 476 popstateExpected("Didn't get popstate after changing hash."); 477 478 popup.document.title = "title 2"; 479 480 // Yield so listeners will be notified of the title change we just performed. 481 shortWait(); 482 yield undefined; 483 484 is(getSHTitle(shistory), "title 2", "SHEntry title test 2"); 485 486 // Go back. Happens synchronously. We should get a popstate. 487 statusMsg("About to go back."); 488 popup.history.go(-1); 489 popstateExpected("Didn't get a popstate after going back."); 490 491 // Even though we went back, we expect the SHEntry title to remain the same 492 // because the document didn't change. 493 is(getSHTitle(shistory), "title 2", "SHEntry title test 3"); 494 495 popup.document.title = "Changed 1"; 496 shortWait(); 497 yield undefined; 498 499 // This check is really a test of bug 509055. 500 is(getSHTitle(shistory), "Changed 1", "SHEntry title test 4"); 501 502 popup.close(); 503 504 /** 505 * TEST 4 tests replaceState and that we don't get double popstates on 506 * window.open. It also stress-tests the system and its interaction with 507 * bfcache by making many push/replace state calls. 508 */ 509 popup = window.open("file_bug500328_1.html", "popup1", 510 "height=200,width=200,location=yes," + 511 "menubar=yes,status=yes,toolbar=yes,dependent=yes"); 512 513 // The initial about:blank load into the new window shouldn't result in us 514 // seeing a popstate. Once file_bug500328_1.html is loaded, it'll overwrite 515 // popup.onpopstate, and this assertion won't fire for that popstate and 516 // others after. 517 // 518 // If we fired the popstate event asynchronously, we'd expect this assert to 519 // fire. 520 popup.onpopstate = function() { 521 ok(false, "Initial load of popup shouldn't give us a popstate."); 522 }; 523 524 shistory = getSHistory(popup); 525 526 enableChildLoadCallback(); 527 yield undefined; 528 statusMsg("Awake after loading content into popup."); 529 530 popup.history.replaceState({n:1, ok:true}, "state 1", "good1.html"); 531 locationEndsWith(popup, "good1.html"); 532 533 // Even though we replaceState with title "state 1", the title should remain 534 // "test 1" because we ignore the title argument in push/replaceState. 535 // See bug 544535. 536 is(getSHTitle(shistory), "test 1", "SHEntry title 'state 1'"); 537 538 // Flush the event loop so our next load creates a new session history entry. 539 shortWait(); 540 yield undefined; 541 542 enableChildLoadCallback(); 543 popup.location = "file_bug500328_1.html"; 544 yield undefined; 545 546 // Flush the event loop so nsDocShell::OnNewURI runs and our load is recorded 547 // properly. 548 shortWait(); 549 yield undefined; 550 551 // Now go back and make sure everything is as it should be. 552 enableChildPageShowCallback(); 553 popup.history.back(); 554 yield undefined; 555 // Flush the event loop so the document's location is updated and any 556 // popstates fire. 557 shortWait(); 558 yield undefined; 559 noPopStateExpected("no popstate during initial load"); 560 561 locationEndsWith(popup, "good1.html"); 562 is(JSON.stringify(popup.history.state), '{"n":1,"ok":true}', 563 "Wrong state popped after going back to initial state."); 564 565 // We're back at state 0, which was replaceState-ed to state1.html. Let's do 566 // some push/pop/replaces to make sure everything works OK when we involve 567 // large numbers of SHEntries. 568 for(var i = 2; i <= 30; i++) { 569 if (i % 3 == 0) { 570 popup.history.pushState({n:i, ok:true}, "state " + i, "good" + i + ".html"); 571 } 572 else { 573 popup.history.pushState({n:i}, "state " + i, "state" + i + ".html"); 574 for(var j = 0; j < i % 4; j++) { 575 popup.history.replaceState({n:i, nn:j}, "state " + i + ", " + j); 576 } 577 popup.history.replaceState({n:i, ok:true}, "state " + i, "good" + i + ".html"); 578 } 579 } 580 581 for(var i = 29; i >= 1; i--) { 582 popup.history.back(); 583 popstateExpected("Didn't get a popstate on iteration " + i); 584 locationEndsWith(popup, "good" + i + ".html"); 585 is(gLastPopStateEvent.state.n, i, "Bad counter on last popstate event."); 586 ok(gLastPopStateEvent.state.ok, 587 "Last popstate event should have 'ok' set to true."); 588 } 589 590 popup.close(); 591 592 /** 593 * TEST 5 tests misc security features and implementation details of 594 * Push/ReplaceState 595 */ 596 597 /* 598 * Test that we can't push/replace an object with a large (over 640k 599 * characters) JSON representation. 600 */ 601 602 // (In case you're curious, this loop generates an object which serializes to 603 // 694581 characters.) 604 var bigObject = new Object(); 605 for(var i = 0; i < 51200; i++) { 606 bigObject[i] = i; 607 } 608 // statusMsg("Big object has size " + JSON.stringify(bigObject).length); 609 610 // We shouldn't be able to pushstate this large object, due to space 611 // constraints. 612 expectException( 613 function() { iframeCw.history.pushState(bigObject, "foo"); }, 614 "pushState-ing large object"); 615 616 expectException( 617 function() { iframeCw.history.replaceState(bigObject, "foo"); }, 618 "replaceState-ing large object"); 619 620 /* 621 * Make sure we can't push/replace state on an iframe of a different origin. 622 * This will work if this function has requested Universal XPConnect 623 * privileges, so any code which needs those privileges can't be in this 624 * function. 625 */ 626 enableChildLoadCallback(); 627 iframeCw.location = "http://example.com"; 628 iframe.onload = onChildLoad; 629 yield undefined; 630 iframe.onload = null; 631 632 expectException( 633 function() { iframeCw.history.pushState({}, "foo"); }, 634 "pushState-ing in a different origin"); 635 636 expectException( 637 function() { iframeCw.history.replaceState({}, "foo"); }, 638 "replaceState-ing in a different origin"); 639 640 /* 641 * If we do the following: 642 * * Start at page A. 643 * * PushState to page B. 644 * * Refresh. The server responds with a 404 645 * * Go back. 646 * Then at the end, page A should be displayed, not the 404 page. 647 */ 648 enableChildLoadCallback(); 649 iframe.onload = onChildLoad; 650 iframeCw.location = "about:blank"; 651 yield undefined; 652 iframe.onload = null; 653 654 enableChildLoadCallback(); 655 // navigate to http://mochi.test:8888/[...]/file_bug500328_1.html 656 iframeCw.location = innerLoc; 657 yield undefined; 658 659 // PushState to a URL which doesn't exist 660 iframeCw.history.pushState({}, "", rand); 661 662 // Refresh. We'll end up a 404 page. 663 iframe.onload = onChildLoad; 664 enableChildLoadCallback(); 665 iframeCw.location.reload(true); 666 yield undefined; 667 iframe.onload = null; 668 669 // Since the last page was a 404, going back should actually show the 670 // contents of the old page, instead of persisting the contents of the 404 671 // page. 672 enableChildPageShowCallback(); 673 iframeCw.history.back(); 674 yield undefined; 675 676 // Make sure that we're actually showing the contents of 677 // file_bug500328_1.html, as opposed to the 404 page. 678 var identifierElem = iframeCw.document.getElementById("link-anchor1"); 679 ok(identifierElem != undefined && identifierElem != null, 680 "iframe didn't contain file_bug500328_1.html's contents."); 681 682 /** 683 * TEST 6 tests that the referrer is set properly after push/replace states. 684 */ 685 686 /* 687 * First, a simple test: 688 * * Load file_bug500328_1.html into iframe 689 * * PushState to newpage1.html#foo 690 * * Instruct the iframe to load file_bug500328_1.html into itself. 691 * The referer should be newpage1.html, without the hash. 692 * 693 * This also tests that we can call pushState from within the onload handler. 694 */ 695 enableChildLoadCallback(); 696 iframeCw.location = "file_bug500328_1.html"; 697 yield undefined; 698 699 // Run within the onload handler. This should work without issue. 700 iframeCw.history.pushState(null, "", "newpage1.html"); 701 702 // iframeCw.navigateTo() causes the iframe to set its location on our 703 // behalf. We can't just set its location ourselves, because then *we* 704 // become the referrer. 705 enableChildLoadCallback(); 706 iframeCw.navigateTo("file_bug500328_1.html"); 707 yield undefined; 708 709 ok(iframeCw.document.referrer.toString().match(/newpage1.html$/), 710 "Wrong referrer after pushState. Expected newpage1.html, but was " + 711 iframeCw.document.referrer); 712 713 /* 714 * We're back at file_bug500328_1.html. Now do the following: 715 * * replaceState to newpage2.html#foo 716 * * Click a link back to file_bug500328_1.html 717 * The referrer should be newpage2.html, without the hash. 718 */ 719 iframeCw.history.replaceState(null, null, "newpage2.html#foo"); 720 enableChildLoadCallback(); 721 sendMouseEvent({type:'click'}, 'link-self', iframeCw); 722 yield undefined; 723 724 ok(iframeCw.document.referrer.toString().match(/newpage2.html$/), 725 "Wrong referrer after replaceState. Expected newpage2.html, but was " + 726 iframeCw.document.referrer); 727 728 /* 729 * Set up a cycle with the popstate event to make sure it's properly 730 * collected. 731 */ 732 var evt = document.createEvent("popstateevent"); 733 evt.initEvent("foo", false, false, evt); 734 735 /* */ 736 SimpleTest.finish(); 737 statusMsg("********** Finished tests ***********"); 738 while(true) 739 { 740 yield undefined; 741 742 // I don't think this will actually make the mochitest fail, but there's 743 // not much we can do about this. Realistically, though, regressions are 744 // not likely to fire extra events -- this trap is here mostly to catch 745 // errors made while wriring tests. 746 ok(false, "Got extra event!"); 747 } 748 749 /* 750 statusMsg("XXXXXXXXXXXXXX"); 751 while(true) { 752 yield undefined; 753 statusMsg("Woken up."); 754 } 755 */ 756 } 757 758 // Important: Wait to start the tests until the page has loaded. Otherwise, 759 // the test will occasionally fail when it begins running before the iframes 760 // have finished their initial load of about:blank. 761 window.addEventListener('load', function() { 762 gGen = runTest(); 763 gGen.next(); 764 }); 765 766 </script> 767 </pre> 768 </body> 769 </html>