diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/html/browsers/history/the-history-interface | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/browsers/history/the-history-interface')
111 files changed, 3349 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/001.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/001.html new file mode 100644 index 0000000000..16cb834c78 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/001.html @@ -0,0 +1,339 @@ +<!doctype html> +<html> + <head> + <title>history.pushState tests</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> +//does not test for firing of popstate onload, because this was dropped from the specification on 25 March 2011 +//covers history.state after load, in accordance with the specification draft from 25 March 2011 +//history.state before load is tested in 006 and 007 +//does not test for structured cloning of FileList, File or Blob interfaces, as these require manual file selection + +//**This test assumes that assignments to location.hash will be synchronous - this is how all browsers implement it. +//The spec (as of 25 March 2011) disagrees.**// + +var histlength, atstep = 0, lasttimer; +setup({explicit_done:true}); //tests should take under 6 seconds + execution time + +window.onload = function () { + if( location.protocol == 'file:' ) { + document.getElementsByTagName('p')[0].innerHTML = 'ERROR: This test cannot be run from file: (URL resolving will not work). It must be loaded over HTTP.'; + return; + } else if( location.protocol == 'https:' ) { + document.getElementsByTagName('p')[0].innerHTML += '<br>WARNING: Browsers may intentionally fail to update history.length when pages are loaded over HTTPS, as a privacy restriction. If possible, load this page over HTTP.'; + } + //use a timeout, because some browsers intentionally do not add history entries for URL changes in the onload thread + setTimeout(testinit,100); +}; +function testinit() { + atstep = 1; + histlength = history.length; + iframe = document.getElementsByTagName('iframe')[0].src = 'blank2.html'; + //reportload will now be called by the onload handler for the iframe +} +function reportload() { + var iframe = document.getElementsByTagName('iframe')[0], hashchng = false; + var canvassup = false, cloneobj; + + function tests1() { + //Firefox may fail when reloading, because it recovers iframe state, and therefore does not see the need to alter history length + test(function () { assert_equals( history.length, histlength + 1, 'make sure that you loaded the test in a new tab/window' ); }, 'history.length should update when loading pages in an iframe'); + histlength = history.length; + iframe.contentWindow.location.hash = 'test'; //should be synchronous **SEE COMMENT AT TOP OF FILE + test(function () { + assert_equals( history.length, histlength + 1, 'make sure that you loaded the test in a new tab/window' ); + }, 'history.length should update when setting location.hash'); + test(function () { assert_true( !!history.pushState, 'critical test; ignore any failures after this' ); }, 'history.pushState must exist'); //assert_own_property does not allow prototype inheritance + test(function () { assert_true( !!iframe.contentWindow.history.pushState, 'critical test; ignore any failures after this' ); }, 'history.pushState must exist within iframes'); + test(function () { + assert_equals( iframe.contentWindow.history.state, null ); + }, 'initial history.state should be null'); + test(function () { + histlength = history.length; + iframe.contentWindow.history.pushState('',''); + assert_equals( history.length, histlength + 1 ); + }, 'history.length should update when pushing a state'); + test(function () { + assert_equals( iframe.contentWindow.history.state, '' ); + }, 'history.state should update after a state is pushed'); + histlength = history.length; + iframe.contentWindow.addEventListener("popstate", tests2, {once: true}); + history.back(); + } + function tests2() { + test(function () { + assert_equals( history.length, histlength ); + }, 'history.length should not decrease after going back'); + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test' ); + }, 'traversing history must traverse pushed states'); + iframe.contentWindow.addEventListener("hashchange", tests3, {once: true}); + history.go(-1); + } + function tests3() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), '', '(this could cause other failures later on)' ); + }, 'traversing history must also traverse hash changes'); + + iframe.contentWindow.addEventListener("hashchange", tests4, {once: true}); + //Safari 5.0.3 fails here - it navigates *this* document to the *iframe's* location, instead of just navigating the iframe + history.go(2); + } + async function tests4() { + test(function () { + //Firefox 4 beta 11 has a messed up error object, which does not have the right error type or .SECURITY_ERR property + assert_throws_dom('SECURITY_ERR',function () { history.pushState('','','//exa mple'); }); + }, 'pushState must not be allowed to create invalid URLs'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.pushState('','','http://www.example.com/'); }); + }, 'pushState must not be allowed to create cross-origin URLs'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.pushState('','','about:blank'); }); + }, 'pushState must not be allowed to create cross-origin URLs (about:blank)'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.pushState('','','data:text/html,'); }); + }, 'pushState must not be allowed to create cross-origin URLs (data:URI)'); + test(function () { + assert_throws_dom('SECURITY_ERR', iframe.contentWindow.DOMException, function () { iframe.contentWindow.history.pushState('','','http://www.example.com/'); }); + }, 'security errors are expected to be thrown in the context of the document that owns the history object'); + let hashchange = + new Promise(function (resolve) { + iframe.contentWindow.addEventListener("hashchange", resolve, {once: true}); + }); + + test(function () { + iframe.contentWindow.location.hash = 'test2'; + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test2', 'location.hash did not change when told to' ); + }, 'location.hash must be allowed to change (part 1)'); + await hashchange; + history.go(-1); + iframe.contentWindow.addEventListener("hashchange", tests5, {once: true}); + } + function tests5() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test', 'location.hash did not change when going back' ); + }, 'location.hash must be allowed to change (part 2)'); + test(function () { + iframe.contentWindow.history.pushState('',''); + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test', 'location.hash changed when an unrelated state was pushed' ); + }, 'pushState must not alter location.hash when no URL is provided'); + history.go(1); //should do nothing, since the pushState should have removed the forward history + setTimeout(tests6,50); //.go is queued to end of thread + } + function tests6() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test' ); + }, 'pushState must remove all history after the current state'); + test(function () { + iframe.contentWindow.history.pushState('','','#test3'); + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test3' ); + }, 'pushState must be able to set location.hash'); + //begin setup for "remove any tasks queued by the history traversal task source" + iframe.contentWindow.location.hash = '#test4'; + iframe.contentWindow.history.go(-1); //must be queued + try { + //must remove the queued navigation in the same browsing context + iframe.contentWindow.history.pushState('',''); + } catch(unsuperr) {} + //allow the browser to mistakenly run the .go if it is going to + //do not put two .go commands in the same thread, in case the browser mistakenly calculates the history position when + //calling .go instead of when executing the traversal task - that could give a false PASS in the next test otherwise + setTimeout(tests7,50); + } + function tests7() { + iframe.contentWindow.history.go(-1); //must be queued, but should not be removed this time + iframe.contentWindow.addEventListener("popstate", tests8, {once: true}); + } + function tests8() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test4' ); + }, 'pushState must remove any tasks queued by the history traversal task source'); + //end "remove any tasks queued by the history traversal task source" + window.addEventListener('hashchange',function () { hashchng = true; },false); + try { + //push a state that changes the hash + iframe.contentWindow.history.pushState('','',iframe.contentWindow.location.pathname+'#test5'); + } catch(unsuperr) {} + setTimeout(tests9,50); //allow the hashchange event to process, if the browser has mistakenly fired it + } + function tests9() { + test(function () { + assert_false( hashchng ); + }, 'pushState must not fire hashchange events'); + test(function () { + iframe.contentWindow.history.pushState('','','/testing_ignore_me_404'); + assert_equals( iframe.contentWindow.location.pathname, '/testing_ignore_me_404' ); + }, 'pushState must be able to set location.pathname'); + test(function () { + var newURL = location.href.replace(/\/[^\/]*$/)+'/testing_ignore_me_404/'; + iframe.contentWindow.history.pushState('','',newURL); + assert_equals( iframe.contentWindow.location.href, newURL ); + }, 'pushState must be able to set absolute URLs to the same host'); + test(function () { + assert_throws_dom( 'DATA_CLONE_ERR', function () { + history.pushState({dummy:function () {}},''); + } ); + }, 'pushState must not be able to use a function as data'); + test(function () { + assert_throws_dom( 'DATA_CLONE_ERR', function () { + history.pushState({dummy:window},''); + } ); + }, 'pushState must not be able to use a DOM node as data'); + test(function () { + try { a.b = c; } catch(errdata) { + history.pushState({dummy:errdata},''); + assert_equals(ReferenceError.prototype, Object.getPrototypeOf(history.state.dummy)); + } + }, 'pushState must be able to use an error object as data'); + test(function () { + assert_throws_dom('DATA_CLONE_ERR', iframe.contentWindow.DOMException, function () { + iframe.contentWindow.history.pushState(document,''); + }); + }, 'security errors are expected to be thrown in the context of the document that owns the history object (2)'); + cloneobj = { + nulldata: null, + udefdata: window.undefined, + booldata: true, + numdata: 1, + strdata: 'string data', + boolobj: new Boolean(true), + numobj: new Number(1), + strobj: new String('string data'), + datedata: new Date(), + regdata: /a/g, + arrdata: [1] + }; + cloneobj.regdata.lastIndex = 1; + cloneobj.looped = cloneobj; + //test the ImageData type, if the browser supports it + var canvas = document.createElement('canvas'); + if( canvas.getContext && ( canvas = canvas.getContext('2d') ) && canvas.createImageData ) { + canvassup = true; + cloneobj.imgdata = canvas.createImageData(1,1); + } + test(function () { + try { + iframe.contentWindow.history.pushState(cloneobj,'new title'); + } catch(e) { + cloneobj.looped = null; + //try again because this object is needed for future tests + iframe.contentWindow.history.pushState(cloneobj,'new title'); + //rethrow so the browser gets a FAIL for not coping with the circular reference; "internal structured cloning algorithm" step 1 + throw(e); + } + }, 'pushState must be able to make structured clones of complex objects'); + test(function () { + assert_equals( iframe.contentWindow.history.state && iframe.contentWindow.history.state.strdata, 'string data' ); + }, 'history.state should also reference a clone of the original object'); + test(function () { + assert_not_equals( cloneobj, iframe.contentWindow.history.state ); + }, 'history.state should be a clone of the original object, not a reference to it'); + /* + behaviour is not defined per spec, and no known implementations do this + test(function () { + assert_equals( iframe.contentDocument.title, 'new title', 'not required for specification conformance' ); + }, 'pushState MIGHT set the document title'); + */ + history.go(-1); + iframe.contentWindow.addEventListener("popstate", tests10, {once: true}); + } + function tests10() { + var eventtime = setTimeout(function () { tests11(false); },500); //should be cleared by the event handler long before it has a chance to fire + iframe.contentWindow.addEventListener('popstate',function (e) { clearTimeout(eventtime); tests11(true,e); },false); + history.forward(); + } + function tests11(hasFired,ev) { + test(function () { + assert_true( hasFired ); + }, 'popstate event should fire when navigation occurs'); + test(function () { + assert_true( !!ev && typeof(ev.state) != 'undefined', 'state information was not passed' ); + assert_true( !!ev.state, 'state information does not contain the expected value - browser is probably stuck in the wrong history position' ); + assert_equals( ev.state.nulldata, null, 'state null data was not correct' ); + assert_equals( ev.state.udefdata, window.undefined, 'state undefined data was not correct' ); + assert_true( ev.state.booldata, 'state boolean data was not correct' ); + assert_equals( ev.state.numdata, 1, 'state numeric data was not correct' ); + assert_equals( ev.state.strdata, 'string data', 'state string data was not correct' ); + assert_true( !!ev.state.datedata.getTime, 'state date data was not correct' ); + assert_own_property( ev.state, 'regdata', 'state regex data was not correct' ); + assert_equals( ev.state.regdata.source, 'a', 'state regex pattern data was not correct' ); + assert_true( ev.state.regdata.global, 'state regex flag data was not correct' ); + assert_equals( ev.state.regdata.lastIndex, 0, 'state regex lastIndex data was not correct' ); + assert_equals( ev.state.arrdata.length, 1, 'state array data was not correct' ); + assert_true( ev.state.boolobj.valueOf(), 'state boolean data was not correct' ); + assert_equals( ev.state.numobj.valueOf(), 1, 'state numeric data was not correct' ); + assert_equals( ev.state.strobj.valueOf(), 'string data', 'state string data was not correct' ); + if( canvassup ) { + assert_equals( ev.state.imgdata.width, 1, 'state ImageData was not correct' ); + } + }, 'popstate event should pass the state data'); + test(function () { + assert_equals( ev.state.looped, ev.state ); + }, 'state data should cope with circular object references'); + test(function () { + assert_not_equals( cloneobj, ev.state ); + }, 'state data should be a clone of the original object, not a reference to it'); + test(function () { + assert_equals( iframe.contentWindow.history.state && iframe.contentWindow.history.state.strdata, 'string data' ); + }, 'history.state should also reference a clone of the original object (2)'); + test(function () { + assert_not_equals( cloneobj, iframe.contentWindow.history.state ); + }, 'history.state should be a clone of the original object, not a reference to it (2)'); + test(function () { + assert_equals( iframe.contentWindow.history.state, ev.state ); + }, 'history.state should be identical to the object passed to the event handler unless history.state is updated'); + try { + iframe.contentWindow.persistval = true; + iframe.contentWindow.history.pushState('','', location.href.replace(/\/[^\/]*$/,'/blank3.html') ); + } catch(unsuperr) {} + //it's already cached, so this should be very fast if the browser mistakenly loads it + //it should not need to load at all, since it's just a pushed state + setTimeout(tests12,1000); + } + function tests12() { + test(function () { + assert_true( iframe.contentWindow.persistval && !iframe.contentWindow.forreal ); + }, 'pushState should not actually load the new URL'); + atstep = 3; + iframe.contentWindow.location.reload(); //load the real URL + lasttimer = setTimeout(function () { tests13(false); },3000); //should be cleared by the onload handler long before it has a chance to fire + } + function tests13(passed) { + test(function () { + assert_true( passed, 'expected a load event to fire when reloading the URL from cache, gave up waiting after 3 seconds' ); + }, 'reloading a pushed state should actually load the new URL'); + //try to make browsers behave when reloading so that the correct URL is recovered - does not always work + iframe.contentWindow.location.href = location.href.replace(/\/[^\/]*$/,'/blank.html'); + done(); + } + + if( atstep == 1 ) { + //blank2 has loaded + atstep = 2; + //use a timeout, because some browsers intentionally do not add history entries for URL changes in an onload thread + setTimeout(tests1,100); + } else if( atstep == 3 ) { + //blank3 should now have loaded after the .reload() command + atstep = 4; + clearTimeout(lasttimer); + tests13(true); + } +} + + + + </script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <p>WARNING: This test should always be loaded in a new tab/window, to avoid browsers attempting to recover the state of frames, and history length. Do not reload the test.</p> + <div id="log">Running test...</div> + <p><iframe onload="reportload();" src="blank.html"></iframe></p> + <p><iframe src="blank.html"></iframe></p> + <p><iframe src="blank2.html"></iframe></p> + <p><iframe src="blank3.html"></iframe></p> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/002.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/002.html new file mode 100644 index 0000000000..8bce7e72ff --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/002.html @@ -0,0 +1,318 @@ +<!doctype html> +<html> + <head> + <title>history.replaceState tests</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> +//does not test for firing of popstate onload, because this was dropped from the specification on 25 March 2011 +//covers history.state after load, in accordance with the specification draft from 25 March 2011 +//history.state before load is tested in 006 and 007 +//does not test for structured cloning of FileList, File or Blob interfaces, as these require manual file selection + +//**This test assumes that assignments to location.hash will be synchronous - this is how all browsers implement it. +//The spec (as of 25 March 2011) disagrees. + +var histlength, atstep = 0, lasttimer; +setup({explicit_done:true}); //tests should take under 6 seconds + execution time + +window.onload = function () { + if( location.protocol == 'file:' ) { + document.getElementsByTagName('p')[0].innerHTML = 'ERROR: This test cannot be run from file: (URL resolving will not work). It must be loaded over HTTP.'; + return; + } else if( location.protocol == 'https:' ) { + document.getElementsByTagName('p')[0].innerHTML += '<br>WARNING: Browsers may intentionally fail to update history.length when pages are loaded over HTTPS, as a privacy restriction. If possible, load this page over HTTP.'; + } + //use a timeout, because some browsers intentionally do not add history entries for URL changes in the onload thread + setTimeout(testinit,100); +}; +function testinit() { + atstep = 1; + histlength = history.length; + iframe = document.getElementsByTagName('iframe')[0].src = 'blank2.html'; + //reportload will now be called by the onload handler for the iframe +} +function reportload() { + var iframe = document.getElementsByTagName('iframe')[0], hashchng = false; + var canvassup = false, cloneobj; + + async function tests1() { + test(function () { assert_equals( history.length, histlength + 1, 'make sure that you loaded the test in a new tab/window' ); }, 'history.length should update when loading pages in an iframe'); + histlength = history.length; + let hashchange = new Promise(function(resolve) { + iframe.contentWindow.addEventListener("hashchange", resolve, {once: true}); + }); + iframe.contentWindow.location.hash = 'test'; //should be synchronous **SEE COMMENT AT TOP OF FILE + test(function () { + assert_equals( history.length, histlength + 1, 'make sure that you loaded the test in a new tab/window' ); + }, 'history.length should update when setting location.hash'); + test(function () { assert_true( !!history.replaceState, 'critical test; ignore any failures after this' ); }, 'history.replaceState must exist'); //assert_own_property does not allow prototype inheritance + test(function () { assert_true( !!iframe.contentWindow.history.replaceState, 'critical test; ignore any failures after this' ); }, 'history.replaceState must exist within iframes'); + test(function () { + assert_equals( iframe.contentWindow.history.state, null ); + }, 'initial history.state should be null'); + + await hashchange; + hashchange = new Promise(function(resolve) { + iframe.contentWindow.addEventListener("hashchange", resolve, {once: true}); + }); + iframe.contentWindow.location.hash = 'test2'; + await hashchange; + + iframe.contentWindow.addEventListener("hashchange", tests2, {once: true}); + history.back(); + } + function tests2() { + test(function () { + histlength = history.length; + iframe.contentWindow.history.replaceState('',''); + assert_equals( history.length, histlength ); + }, 'history.length should not update when replacing a state with no URL'); + test(function () { + assert_equals( iframe.contentWindow.history.state, '' ); + }, 'history.state should update after a state is pushed'); + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test' ); + }, 'hash should not change when replaceState is called without a URL'); + test(function () { + histlength = history.length; + iframe.contentWindow.history.replaceState('','','#test3'); + assert_equals( history.length, histlength ); + }, 'history.length should not update when replacing a state with a URL'); + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test3' ); + }, 'hash should change when replaceState is called with a URL'); + iframe.contentWindow.addEventListener("hashchange", tests3, {once: true}); + history.go(-1); + } + function tests3() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), '' ); + }, 'replaceState must replace the existing state and not add an extra one'); + iframe.contentWindow.addEventListener("hashchange", tests4, {once: true}); + history.go(2); + } + function tests4() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test2' ); + }, 'replaceState must replace the existing state without altering the forward history'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.replaceState('','','//exa mple'); }); + }, 'replaceState must not be allowed to create invalid URLs'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.replaceState('','','http://www.example.com/'); }); + }, 'replaceState must not be allowed to create cross-origin URLs'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.replaceState('','','about:blank'); }); + }, 'replaceState must not be allowed to create cross-origin URLs (about:blank)'); + test(function () { + assert_throws_dom('SECURITY_ERR',function () { history.replaceState('','','data:text/html,'); }); + }, 'replaceState must not be allowed to create cross-origin URLs (data:URI)'); + test(function () { + assert_throws_dom('SECURITY_ERR',iframe.contentWindow.DOMException,function () { iframe.contentWindow.history.replaceState('','','http://www.example.com/'); }); + }, 'security errors are expected to be thrown in the context of the document that owns the history object'); + test(function () { + //avoids browsers running .go synchronously when only a hash change is involved + iframe.contentWindow.history.replaceState('','','/testing_ignore_me_404#test4'); + assert_equals( iframe.contentWindow.location.pathname, '/testing_ignore_me_404' ); + }, 'replaceState must be able to set location.pathname'); + test(function () { + var newURL = location.href.replace(/\/[^\/]*$/)+'/testing_ignore_me_404/'; + iframe.contentWindow.history.replaceState('','',newURL); + assert_equals( iframe.contentWindow.location.href, newURL ); + }, 'replaceState must be able to set absolute URLs to the same host'); + + //allow the browser to run the .go + iframe.contentWindow.addEventListener("popstate", tests5, {once: true}); + //begin setup for "[must not] remove any tasks queued by the history traversal task source" + iframe.contentWindow.history.go(-1); //must be queued so the next command takes place *beforehand* + try { + //must not remove the queued navigation in the same browsing context + iframe.contentWindow.history.replaceState('','',iframe.contentWindow.location.pathname+'#test5'); + } catch(unsuperr2) {} + } + function tests5() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test3' ); + }, 'replaceState must not remove any tasks queued by the history traversal task source'); + iframe.contentWindow.addEventListener("popstate", tests6, {once: true}); + //Safari 5.0.3 fails here - it navigates *this* document to the *iframe's* location, instead of just navigating the iframe + history.go(1); + } + function tests6() { + test(function () { + assert_equals( iframe.contentWindow.location.hash.replace(/^#/,''), 'test5' ); + }, '.go must queue a task with the history traversal task source (run asynchronously)'); + //end "[must not] remove any tasks queued by the history traversal task source" + window.addEventListener('hashchange',function () { hashchng = true; },false); + try { + //push a state that changes the hash + iframe.contentWindow.history.replaceState('','',iframe.contentWindow.location.pathname+'#test6'); + } catch(unsuperr) {} + setTimeout(tests7,50); //allow the hashchange event to process, if the browser has mistakenly fired it + } + function tests7() { + test(function () { + assert_false( hashchng ); + }, 'replaceState must not fire hashchange events'); + test(function () { + assert_throws_dom( 'DATA_CLONE_ERR', function () { + history.replaceState({dummy:function () {}},''); + } ); + }, 'replaceState must not be able to use a function as data'); + test(function () { + assert_throws_dom( 'DATA_CLONE_ERR', function () { + history.replaceState({dummy:window},''); + } ); + }, 'replaceState must not be able to use a DOM node as data'); + test(function () { + try { a.b = c; } catch(errdata) { + history.replaceState({dummy:errdata},''); + assert_equals(ReferenceError.prototype, Object.getPrototypeOf(history.state.dummy)); + } + }, 'replaceState must be able to use an error object as data'); + test(function () { + assert_throws_dom('DATA_CLONE_ERR', iframe.contentWindow.DOMException, function () { + iframe.contentWindow.history.replaceState(document,''); + }); + }, 'security errors are expected to be thrown in the context of the document that owns the history object (2)'); + cloneobj = { + nulldata: null, + udefdata: window.undefined, + booldata: true, + numdata: 1, + strdata: 'string data', + boolobj: new Boolean(true), + numobj: new Number(1), + strobj: new String('string data'), + datedata: new Date(), + regdata: /a/g, + arrdata: [1] + }; + cloneobj.regdata.lastIndex = 1; + cloneobj.looped = cloneobj; + //test the ImageData type, if the browser supports it + var canvas = document.createElement('canvas'); + if( canvas.getContext && ( canvas = canvas.getContext('2d') ) && canvas.createImageData ) { + canvassup = true; + cloneobj.imgdata = canvas.createImageData(1,1); + } + test(function () { + try { + iframe.contentWindow.history.replaceState(cloneobj,'new title'); + } catch(e) { + cloneobj.looped = null; + //try again because this object is needed for future tests + iframe.contentWindow.history.replaceState(cloneobj,'new title'); + //rethrow so the browser gets a FAIL for not coping with the circular reference; "internal structured cloning algorithm" step 1 + throw(e); + } + }, 'replaceState must be able to make structured clones of complex objects'); + test(function () { + assert_equals( iframe.contentWindow.history.state && iframe.contentWindow.history.state.strdata, 'string data' ); + }, 'history.state should also reference a clone of the original object'); + test(function () { + assert_not_equals( cloneobj, iframe.contentWindow.history.state ); + }, 'history.state should be a clone of the original object, not a reference to it'); + iframe.contentWindow.addEventListener("popstate", tests8, {once: true}); + history.go(-1); + } + function tests8() { + var eventtime = setTimeout(function () { tests9(false); },500); //should be cleared by the event handler long before it has a chance to fire + iframe.contentWindow.addEventListener('popstate',function (e) { clearTimeout(eventtime); tests9(true,e); },false); + history.forward(); + } + function tests9(hasFired,ev) { + test(function () { + assert_true( hasFired ); + }, 'popstate event should fire when navigation occurs'); + test(function () { + assert_true( !!ev && typeof(ev.state) != 'undefined', 'state information was not passed' ); + assert_true( !!ev.state, 'state information does not contain the expected value - browser is probably stuck in the wrong history position' ); + assert_equals( ev.state.nulldata, null, 'state null data was not correct' ); + assert_equals( ev.state.udefdata, window.undefined, 'state undefined data was not correct' ); + assert_true( ev.state.booldata, 'state boolean data was not correct' ); + assert_equals( ev.state.numdata, 1, 'state numeric data was not correct' ); + assert_equals( ev.state.strdata, 'string data', 'state string data was not correct' ); + assert_true( !!ev.state.datedata.getTime, 'state date data was not correct' ); + assert_own_property( ev.state, 'regdata', 'state regex data was not correct' ); + assert_equals( ev.state.regdata.source, 'a', 'state regex pattern data was not correct' ); + assert_true( ev.state.regdata.global, 'state regex flag data was not correct' ); + assert_equals( ev.state.regdata.lastIndex, 0, 'state regex lastIndex data was not correct' ); + assert_equals( ev.state.arrdata.length, 1, 'state array data was not correct' ); + assert_true( ev.state.boolobj.valueOf(), 'state boolean data was not correct' ); + assert_equals( ev.state.numobj.valueOf(), 1, 'state numeric data was not correct' ); + assert_equals( ev.state.strobj.valueOf(), 'string data', 'state string data was not correct' ); + if( canvassup ) { + assert_equals( ev.state.imgdata.width, 1, 'state ImageData was not correct' ); + } + }, 'popstate event should pass the state data'); + test(function () { + assert_equals( ev.state.looped, ev.state ); + }, 'state data should cope with circular object references'); + test(function () { + assert_not_equals( cloneobj, ev.state ); + }, 'state data should be a clone of the original object, not a reference to it'); + test(function () { + assert_equals( iframe.contentWindow.history.state && iframe.contentWindow.history.state.strdata, 'string data' ); + }, 'history.state should also reference a clone of the original object (2)'); + test(function () { + assert_not_equals( cloneobj, iframe.contentWindow.history.state ); + }, 'history.state should be a clone of the original object, not a reference to it (2)'); + test(function () { + assert_equals( iframe.contentWindow.history.state, ev.state ); + }, 'history.state should be identical to the object passed to the event handler unless history.state is updated'); + try { + iframe.contentWindow.persistval = true; + iframe.contentWindow.history.replaceState('','', location.href.replace(/\/[^\/]*$/,'/blank3.html') ); + } catch(unsuperr) {} + //it's already cached, so this should be very fast if the browser mistakenly loads it + //it should not need to load at all, since it's just a pushed state + setTimeout(tests10,1000); + } + function tests10() { + test(function () { + assert_true( iframe.contentWindow.persistval && !iframe.contentWindow.forreal ); + }, 'replaceState should not actually load the new URL'); + atstep = 3; + iframe.contentWindow.location.reload(); //load the real URL + lasttimer = setTimeout(function () { tests11(false); },3000); //should be cleared by the onload handler long before it has a chance to fire + } + function tests11(passed) { + test(function () { + assert_true( passed, 'expected a load event to fire when reloading the URL from cache, gave up waiting after 3 seconds' ); + }, 'reloading a replaced state should actually load the new URL'); + //try to make browsers behave when reloading so that the correct URL is recovered - does not always work + iframe.contentWindow.location.href = location.href.replace(/\/[^\/]*$/,'/blank.html'); + done(); + } + + if( atstep == 1 ) { + //blank2 has loaded + atstep = 2; + //use a timeout, because some browsers intentionally do not add history entries for URL changes in an onload thread + setTimeout(tests1,100); + } else if( atstep == 3 ) { + //blank3 should now have loaded after the .reload() command + atstep = 4; + clearTimeout(lasttimer); + tests11(true); + } +} + + + + </script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <p>WARNING: This test should always be loaded in a new tab/window, to avoid browsers attempting to recover the state of frames, and history length. Do not reload the test.</p> + <div id="log">Running test...</div> + <p><iframe onload="reportload();" src="blank.html"></iframe></p> + <p><iframe src="blank.html"></iframe></p> + <p><iframe src="blank2.html"></iframe></p> + <p><iframe src="blank3.html"></iframe></p> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/004.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/004.html new file mode 100644 index 0000000000..e69889724f --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/004.html @@ -0,0 +1,62 @@ +<!doctype html> +<html> + <head> + <title>Final history position for history.go should be calculated when executing the task</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> +setup({explicit_done:true}); +window.onload = function () { + var hashcount = 0; + if( location.hash && location.hash != '#' ) { + location.href = location.href.replace(/#.*$/,''); + return; + } + setTimeout(add1,100); + function add1() { + location.hash = '#foo'; + setTimeout(add2,100); + } + function add2() { + location.hash = '#bar'; + setTimeout(add3,100); + } + function add3() { + location.hash = '#baz'; + setTimeout(dojumps,100); + } + function dojumps() { + window.onhashchange = function () { + hashcount++; + }; + history.go(-2); + test(function () { + //many browsers special-case jumps that only imply hash changes and will do them synchronously - the spec does allow this + assert_equals( hashcount, 0, 'hashchange fired even though the location should not have changed' ); + assert_equals( location.hash.replace(/^#/,''), 'baz', 'the browser navigated synchronously' ); + }, '.go commands should be queued until the thread has ended'); + history.go(-1); + setTimeout(checkjumps,100); + } + function checkjumps() { + test(function () { + assert_true( !!hashcount, 'this testcase requires haschange support; the test cannot be used in this browser' ); + }, 'browser needs to support hashchange events for this testcase'); + test(function () { + assert_equals( hashcount, 2, 'the wrong number of queued commands were executed' ); + }, 'queued .go commands should all be executed when the queue is processed'); + test(function () { + assert_equals( location.hash.replace(/^#/,''), '' ); + }, 'history position should be calculated when executing, not when calling the .go command'); + done(); + } +}; + </script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/005.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/005.html new file mode 100644 index 0000000000..2152e85a3e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/005.html @@ -0,0 +1,47 @@ +<!doctype html> +<html> + <head> + <title>Popstate event listener registration</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> + +//this test checks that onpopstate works on the body element + +var readyForPop = false, bodypop = false, inlinepop = false; +setup({explicit_done:true}); + +//use a timeout to avoid "popstate fires onload" from setting the variables too early +setTimeout(step1,1000); +function step1() { + readyForPop = true; + test(function () { + history.pushState('',''); + history.pushState('',''); + }, 'history.pushState support is needed for this testcase'); + history.go(-1); + setTimeout(step2,50); //.go is queued to end of thread +} +function step2() { + test(function () { + assert_true( bodypop ); + }, '<body onpopstate="..."> should register a listener for the popstate event'); + window.onpopstate = function () { inlinepop = true; }; + history.go(-1); + setTimeout(step3,50); //.go is queued to end of thread +} +function step3() { + test(function () { + assert_true( inlinepop ); + }, 'window.onpopstate should register a listener for the popstate event'); + done(); +} + </script> + </head> + <body onpopstate="if( readyForPop ) { bodypop = true; }"> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/006.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/006.html new file mode 100644 index 0000000000..442b6f8f1e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/006.html @@ -0,0 +1,53 @@ +<!doctype html> +<html> + <head> + <title>Firing popstate after onload, even if there is no pushed/replaced state</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + <script type="text/javascript"> + +//spec (25 March 2011 draft) states that popstate must not fire after onload unless there is a pushed/replaced state that is navigated +var popfired = false; +setup({explicit_done:true}); +window.addEventListener('popstate',function (e) { popfired = true; },false); +test(function () { + assert_equals( history.state, null ); +}, 'history.state should initially be null'); +window.onload = function () { + test(function () { + assert_false( popfired ); + }, 'popstate event should not fire before onload fires'); + test(function () { + assert_equals( history.state, null ); + }, 'history.state should still be null onload'); + popfired = false; + setTimeout(function () { + test(function () { + assert_false( popfired ); + }, 'popstate event should not fire after onload fires'); + test(function () { + assert_equals( history.state, null ); + }, 'history.state should still be null after onload'); + test(function () { + var failed = false, realstate = history.state; + try { + history.state = ''; + } catch(e) { + failed = e; + } + assert_equals(history.state,realstate,'property was read/write'); + assert_false(failed); + }, 'writing to history.state should be silently ignored and not throw an error'); + done(); + },100); +}; + + </script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/007.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/007.html new file mode 100644 index 0000000000..decb197624 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/007.html @@ -0,0 +1,66 @@ +<!doctype html> +<html> + <head> + <title>Firing popstate after onload with pushed state</title> + <meta name=timeout content=long> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log">It looks like the browser stopped loading the page when encountering a .go(-1) command pointing to a pushed state. This will break the tests.</div> + <script type="text/javascript"> + +//spec (25 March 2011 draft) states that popstate must fire before onload if there is a pushed/replaced state that is navigated +var popfired = false; +setup({explicit_done:true}); +test(function () { + assert_equals( history.state, null ); +}, 'history.state should initially be null'); +window.addEventListener('popstate',function (e) { popfired = e.state; },false); +test(function () { + history.pushState('state1',''); + history.pushState('state2',''); +}, 'history.pushState support is needed for this testcase'); +test(function () { + assert_equals( history.state, 'state2' ); +}, 'history.state should reflect pushed state'); +if( history.pushState ) { history.go(-1); } +window.onload = function () { + test(function () { + assert_true( !!popfired ); + }, 'popstate event should fire before onload fires'); + test(function () { + assert_equals( popfired, 'state1' ); + }, 'the correct state should be restored when navigating during initial load'); + test(function () { + assert_equals( history.state, 'state1' ); + }, 'history.state should reflect the navigated state onload'); + popfired = false; + setTimeout(function () { + test(function () { + assert_false( !!popfired ); + }, 'popstate event should not fire after onload fires'); + test(function () { + assert_equals( history.state, 'state1' ); + }, 'history.state should reflect the navigated state after onload'); + done(); + if( history.pushState ) { history.go(-1); } //go back to the start to avoid state recovery when reloading + },100); +}; + + </script> + + <!-- + Reuse an existing server side script to slow down page load so that + history.go(-1); above gets run before load event fires. + --> + <script> + // define TEST_DELAY so that executing delay.py doesn't warn about use + // of undefined variable. + var TEST_DELAY; + </script> + <script src="/xhr/resources/delay.py?ms=2500"></script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/008.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/008.html new file mode 100644 index 0000000000..c8071e3156 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/008.html @@ -0,0 +1,40 @@ +<!doctype html> +<html> + +<!-- configure this test below to point to the script --> + + <head> + <title>history.pushState/replaceState resolving</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <p></p> + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> + +/* +Location of the script (which must be hosted on a separate domain from this test) containing the test code: +var beforehref = location.href; +test(function () { + history.pushState('','','/testing_ignore_me_404'); + assert_equals(location.href,beforehref.replace(/^(\w*:\/\/[^\/]*\/)[\w\W]*$/,'$1testing_ignore_me_404')); +}, 'history.pushState URL resolving should be done relative to the document, not the script'); +test(function () { + history.replaceState('','','/testing_ignore_me_404_2'); + assert_equals(location.href,beforehref.replace(/^(\w*:\/\/[^\/]*\/)[\w\W]*$/,'$1testing_ignore_me_404_2')); +}, 'history.replaceState URL resolving should be done relative to the document, not the script'); +*/ +var scriptlocation = 'http://www.' + location.host + location.pathname.split("/").slice(0,-1).join("/") + "/008.js"; + +if( location.protocol == 'file:' ) { + document.getElementsByTagName('p')[0].innerHTML = 'ERROR: This test cannot be run from file: (URL resolving will not work). It must be loaded over HTTP.'; +} else { + document.write('<script type="text\/javascript" src="'+scriptlocation+'"><\/script>'); +} + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/008.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/008.js new file mode 100644 index 0000000000..96a1fe5d4a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/008.js @@ -0,0 +1,11 @@ +var beforehref = location.href; + +test(function () { + history.pushState('','','/testing_ignore_me_404'); + assert_equals(location.href,beforehref.replace(/^(\w*:\/\/[^\/]*\/)[\w\W]*$/,'$1testing_ignore_me_404')); +}, 'history.pushState URL resolving should be done relative to the document, not the script'); + +test(function () { + history.replaceState('','','/testing_ignore_me_404_2'); + assert_equals(location.href,beforehref.replace(/^(\w*:\/\/[^\/]*\/)[\w\W]*$/,'$1testing_ignore_me_404_2')); +}, 'history.replaceState URL resolving should be done relative to the document, not the script'); diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/009-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-1.html new file mode 100644 index 0000000000..00b72e8ec6 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-1.html @@ -0,0 +1,20 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +window.onload = function () { + setTimeout(function () { + try { history.pushState('','','009-2.html?1234'); } catch(e) {} + location.href = '009-3.html?pipe=sub'; + },10); +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/009-3.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-3.html new file mode 100644 index 0000000000..e58b8fa5e7 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-3.html @@ -0,0 +1,28 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +var httpReferer = "{{headers[referer]}}"; +var lastUrl = location.href.replace(/\/[^\/]*$/,'\/009-2.html?1234'); +parent.test(function () { + parent.assert_equals( httpReferer, lastUrl ); +}, 'HTTP Referer should use the pushed state'); +parent.test(function () { + parent.assert_equals( document.referrer, lastUrl ); +}, 'document.referrer should use the pushed state'); +window.onload = function () { + setTimeout(function () { + try { history.pushState('','','009-4.html?2345'); } catch(e) {} + location.href = '009-5.html?pipe=sub'; + },10); +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/009-5.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-5.html new file mode 100644 index 0000000000..068a089af4 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/009-5.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +var httpReferer = unescape("{{headers[referer]}}"); +var lastUrl = location.href.replace(/\/[^\/]*$/,'\/009-4.html?2345'); +parent.test(function () { + parent.assert_equals( httpReferer, lastUrl ); +}, 'HTTP Referer should use the replaced state'); +parent.test(function () { + parent.assert_equals( document.referrer, lastUrl ); +}, 'document.referrer should use the replaced state'); +parent.done(); + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/009.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/009.html new file mode 100644 index 0000000000..c1ae0bbe03 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/009.html @@ -0,0 +1,22 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +setup({explicit_done:true}); +var iframe = document.createElement('iframe'); +window.onload = function () { + iframe.setAttribute('src','009-1.html'); + document.body.appendChild(iframe) +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/010-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-1.html new file mode 100644 index 0000000000..683397745c --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-1.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers (before onload)</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +try { history.pushState('','','010-2.html?1234'); } catch(e) {} +location.href = '010-3.html?pipe=sub'; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/010-3.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-3.html new file mode 100644 index 0000000000..b80f56c3dd --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-3.html @@ -0,0 +1,24 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers (before onload)</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> + var httpReferer = "{{headers[referer]}}"; +var lastUrl = location.href.replace(/\/[^\/]*$/,'\/010-2.html?1234'); +parent.test(function () { + parent.assert_equals( httpReferer, lastUrl ); +}, 'HTTP Referer should use the pushed state (before onload)'); +parent.test(function () { + parent.assert_equals( document.referrer, lastUrl ); +}, 'document.referrer should use the pushed state (before onload)'); +try { history.pushState('','','010-4.html?2345'); } catch(e) {} +location.href = '010-5.html?pipe=sub'; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/010-5.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-5.html new file mode 100644 index 0000000000..d150449eb2 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/010-5.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers (before onload)</title> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +var httpReferer = "{{headers[referer]}}"; +var lastUrl = location.href.replace(/\/[^\/]*$/,'\/010-4.html?2345'); +parent.test(function () { + parent.assert_equals( httpReferer, lastUrl ); +}, 'HTTP Referer should use the replaced state (before onload)'); +parent.test(function () { + parent.assert_equals( document.referrer, lastUrl ); +}, 'document.referrer should use the replaced state (before onload)'); +parent.done(); + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/010.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/010.html new file mode 100644 index 0000000000..ca109a744b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/010.html @@ -0,0 +1,22 @@ +<!doctype html> +<html> + <head> + <title>history.pushState/replaceState and referer headers (before onload)</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +setup({explicit_done:true}); +var iframe = document.createElement('iframe'); +window.onload = function () { + iframe.setAttribute('src','010-1.html'); + document.body.appendChild(iframe) +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/011.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/011.html new file mode 100644 index 0000000000..4043aff7fd --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/011.html @@ -0,0 +1,32 @@ +<!doctype html> +<html> + <head> + <title>history.pushState before onload</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +var newUrl = location.href.replace(/\/[^\/]*$/,'\/011-1.html'); +setup({explicit_done:true}); +test(function () { + history.pushState('','','011-1.html'); +}, 'pushState should be able to set the location state'); +test(function () { + assert_equals( location.href, newUrl ); +}, 'pushed location should be reflected immediately'); +window.onload = function () { + setTimeout(function () { + test(function () { + assert_equals( location.href, newUrl ); + }, 'pushed location should be retained after the page has loaded'); + done(); + },10); +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/012.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/012.html new file mode 100644 index 0000000000..f5e6251671 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/012.html @@ -0,0 +1,32 @@ +<!doctype html> +<html> + <head> + <title>history.replaceState before onload</title> + <script type="text/javascript" src="/resources/testharness.js"></script> + <script type="text/javascript" src="/resources/testharnessreport.js"></script> + </head> + <body> + + <noscript><p>Enable JavaScript and reload</p></noscript> + <div id="log"></div> + <script type="text/javascript"> +var newUrl = location.href.replace(/\/[^\/]*$/,'\/011-1.html'); +setup({explicit_done:true}); +test(function () { + history.replaceState('','','011-1.html'); +}, 'replaceState should be able to set the location state'); +test(function () { + assert_equals( location.href, newUrl ); +}, 'replaced location should be reflected immediately'); +window.onload = function () { + setTimeout(function () { + test(function () { + assert_equals( location.href, newUrl ); + }, 'replaced location should be retained after the page has loaded'); + done(); + },10); +}; + </script> + + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-new.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-new.html new file mode 100644 index 0000000000..2a545af0ed --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-new.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<head> + <title>New page</title> +</head> +<body>This is a new page.</body> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-old.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-old.html new file mode 100644 index 0000000000..a77c00fcc6 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank-old.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<head> + <title>Old page</title> +</head> +<body>This is an old page.</body> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/blank.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank.html new file mode 100644 index 0000000000..89c8724c09 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank.html @@ -0,0 +1,8 @@ +<!doctype html> +<html> + <head> + <title>Dummy page 1</title> + </head> + <body> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/blank2.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank2.html new file mode 100644 index 0000000000..f79982e328 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank2.html @@ -0,0 +1,13 @@ +<!doctype html> +<html> + <head> + <title>Dummy page 2</title> + </head> + <body> + <script type="text/javascript"> +if( self == top || !parent.reportload ) { + document.write("<p>FAIL. Browser got confused when navigating forwards, and navigated the whole window to the iframe's location, instead of just navigating the iframe. It is not possible to run the testsuite.<\/p>"); +} + </script> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/blank3.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank3.html new file mode 100644 index 0000000000..2a8989f272 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/blank3.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <title>Dummy page 3</title> + <script type="text/javascript"> +var forreal = true; + </script> + </head> + <body> + </body> +</html>
\ No newline at end of file diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_001.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_001.html new file mode 100644 index 0000000000..21ba22f6fe --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_001.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_001(Combine pushState and replaceSate methods.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + window.history.pushState(1, document.title, '?x=1'); + assert_equals(history.state, 1, "first"); + + window.history.replaceState(2, document.title, '?x=1'); + assert_equals(history.state, 2, "second") + }, "Combine pushState and replaceSate methods"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_002.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_002.html new file mode 100644 index 0000000000..29e82f51be --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_002.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_002(After calling of pushState method, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + var first; + var second; + first = window.history.length; + window.history.pushState(1, document.title, '?x=1'); + second = window.history.length; + + assert_equals(second - first, 1, "second - first"); + }, "After calling of pushState method, check length"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_003.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_003.html new file mode 100644 index 0000000000..7467d9b294 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_003.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_003(After calling of pushState and replaceState methods, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + var first; + var second; + var third; + first = window.history.length; + window.history.pushState(1, document.title, '?x=1'); + second = window.history.length; + window.history.replaceState(2, document.title, '?x=2'); + third = window.history.length; + + assert_equals(second - first, 1, "second - first"); + assert_equals(third, second, "third"); + }, "After calling of pushState and replaceState methods, check length"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_004.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_004.html new file mode 100644 index 0000000000..4e38b56205 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_004.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_004(After calling of back method, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("After calling of back method, check length"); + + var last; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + last = window.history.length; + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + assert_equals(e.state, 1, "state"); + assert_equals(window.history.length, last, "last"); + t.done(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_005.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_005.html new file mode 100644 index 0000000000..4487678015 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_005.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_005(After calling of forward method, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("After calling of forward method, check length"); + + var last; + var fired = false; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + last = window.history.length; + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + if(fired) { + assert_equals(e.state, 2, "state"); + assert_equals(window.history.length, last, "last"); + t.done(); + } + fired = true; + window.history.forward(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_006.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_006.html new file mode 100644 index 0000000000..305f593c09 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_006.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_006(After calling of go method, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("After calling of go method, check length"); + + var last; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + last = window.history.length; + + window.history.go(-1); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + assert_equals(e.state, 1, "state"); + assert_equals(window.history.length, last, "last"); + t.done(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_007.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_007.html new file mode 100644 index 0000000000..cec9ea0981 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/combination_history_007.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>combination_history_007(After calling of back and pushState method, check length.)</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("After calling of back and pushState method, check length"); + + var last; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + last = window.history.length; + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + assert_equals(e.state, 1, "state"); + assert_equals(window.history.length, last, "last"); + window.history.pushState(3, document.title, '?x=3'); + assert_equals(window.history.length, last, "last"); + t.done(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history-associated-with-document.window.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/history-associated-with-document.window.js new file mode 100644 index 0000000000..94c1b2cf6b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history-associated-with-document.window.js @@ -0,0 +1,6 @@ +// META: title=the History object must be associated with the Document object, not the Window object +// META: script=/common/object-association.js + +// See https://github.com/whatwg/html/issues/2566. + +testIsPerDocument("history"); diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history-state-after-bfcache.window.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/history-state-after-bfcache.window.js new file mode 100644 index 0000000000..5f04890a72 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history-state-after-bfcache.window.js @@ -0,0 +1,43 @@ +// META: title=Navigating back to a bfcached page does not reset history.state +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js + +// See https://github.com/whatwg/html/issues/6652. + +'use strict'; + +promise_test(async t => { + const rcHelper = new RemoteContextHelper(); + + // Open a window with noopener so that BFCache will work. + const rc = await rcHelper.addWindow(null, { features: "noopener" }); + + // Add a pageshow listener to stash the event, and set history.state using replaceState(). + await rc.executeScript(() => { + window.addEventListener('pageshow', (event) => { + window.pageshowEvent = event; + }); + + history.replaceState({ foo: 'bar' }, '', ''); + window.stashedHistoryState = history.state; + }); + + const rc2 = await rc.navigateToNew(); + await rc2.historyBack(); + + assert_implements_optional( + await rc.executeScript(() => window.pageshowEvent.persisted), + 'precondition: document was bfcached' + ); + + assert_equals( + await rc.executeScript(() => history.state.foo), + 'bar', + 'history.state was restored correctly' + ); + + assert_true( + await rc.executeScript(() => window.stashedHistoryState === history.state), + 'history.state did not get serialized and deserialized'); +}); diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/history.js new file mode 100644 index 0000000000..bb5ee6dde0 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history.js @@ -0,0 +1,35 @@ +function parse_query() { + var query = location.search.slice(1); + var vars = query.split("&"); + var fields = {}; + vars.forEach( + function (x) { + var split = x.split("="); + return fields[split[0]] = split.slice(1).join("="); + }); + return fields; +} + +var query_parts = parse_query(); +var id = "id" in query_parts ? parseInt(query_parts.id) : 1; +var urls_to_load = query_parts.urls.split(","); + +document.write(id); + +onunload = function() {}; + +function queue_next() { + t = opener.t; + setTimeout(t.step_func( + function() { +// opener.assert_equals(history.length, id); + if (urls_to_load[0]) { + var next_page = urls_to_load[0]; + (next_page.indexOf("?") > -1) ? (next_page += "&") : (next_page += "?"); + next_page += "urls=" + urls_to_load.slice(1).join(","); + next_page += "&id=" + ++id; + location = next_page; + } + } + ), 100); +} diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back-1.html new file mode 100644 index 0000000000..5487786fc0 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.back(); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back.html new file mode 100644 index 0000000000..042da4e61b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_back</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("history back"); + + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + assert_equals(e.state, 1, "history state"); + + t.done(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_1.html new file mode 100644 index 0000000000..0af3206643 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_1.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>history.back() with session history</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 2) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [2, 1], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_back-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_cross_realm_method.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_cross_realm_method.html new file mode 100644 index 0000000000..47937ef583 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_back_cross_realm_method.html @@ -0,0 +1,22 @@ +<!doctype html> +<meta charset="utf-8"> +<title>history.back() uses this's associated document's browsing context to determine if navigation is allowed</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/history.html#dom-history-back"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe id="sandboxedIframe" srcdoc="hello" sandbox="allow-scripts allow-same-origin"></iframe> +<script> +const t = async_test(); + +t.step(() => { + history.pushState({}, null, "?prev"); + history.pushState({}, null, "?current"); + + sandboxedIframe.contentWindow.history.back.call(history); +}); + +window.onpopstate = t.step_func_done(() => { + assert_equals(location.search, "?prev"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_entry.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_entry.html new file mode 100644 index 0000000000..308371c57d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_entry.html @@ -0,0 +1,11 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + } +}; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-1.html new file mode 100644 index 0000000000..1bf7d6ee3b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-1.html @@ -0,0 +1,14 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + history.forward(); + } + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-2.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-2.html new file mode 100644 index 0000000000..cf8a8d20cd --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward-2.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(-1); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward.html new file mode 100644 index 0000000000..6c37f25215 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_forward</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("history forward"); + + var fired = false; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + if(fired) { + assert_equals(e.state, 2, "history state"); + + t.done(); + } + fired = true; + window.history.forward(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_1.html new file mode 100644 index 0000000000..7817649f3a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_1.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>history.forward() with session history</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [3, 2, 3], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_forward-1.html,history_forward-2.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_cross_realm_method.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_cross_realm_method.html new file mode 100644 index 0000000000..7456099b8f --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_forward_cross_realm_method.html @@ -0,0 +1,28 @@ +<!doctype html> +<meta charset="utf-8"> +<title>history.forward() uses this's associated document's browsing context to determine if navigation is allowed</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/history.html#dom-history-forward"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe id="sandboxedIframe" srcdoc="hello" sandbox="allow-scripts allow-same-origin"></iframe> +<script> +const t = async_test(); + +t.step(() => { + history.pushState({}, null, "?prev"); + history.pushState({}, null, "?current"); + history.back(); +}); + +let isCrossRealmForward = false; +window.onpopstate = t.step_func(() => { + if (isCrossRealmForward) { + assert_equals(location.search, "?current"); + t.done(); + } else { + sandboxedIframe.contentWindow.history.forward.call(history); + isCrossRealmForward = true; + } +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_cross_realm_method.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_cross_realm_method.html new file mode 100644 index 0000000000..d8852b9f6f --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_cross_realm_method.html @@ -0,0 +1,23 @@ +<!doctype html> +<meta charset="utf-8"> +<title>history.go() uses this's associated document's browsing context to determine if navigation is allowed</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/history.html#dom-history-go"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<iframe id="sandboxedIframe" srcdoc="hello" sandbox="allow-scripts allow-same-origin"></iframe> +<script> +const t = async_test(); + +t.step(() => { + history.pushState({}, null, "?prev=2"); + history.pushState({}, null, "?prev=1"); + history.pushState({}, null, "?current"); + + sandboxedIframe.contentWindow.history.go.call(history, -2); +}); + +window.onpopstate = t.step_func_done(() => { + assert_equals(location.search, "?prev=2"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_minus.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_minus.html new file mode 100644 index 0000000000..b8fe75573d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_minus.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_go_minus</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("history go minus"); + + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + window.history.go(-1); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + assert_equals(e.state, 1, "history state"); + + t.done(); + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument-1.html new file mode 100644 index 0000000000..6a2212f34b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument-1.html @@ -0,0 +1,17 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + if (!opener.gone) { + history.go(); + opener.gone = true; + } + } + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument.html new file mode 100644 index 0000000000..11f41614bd --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_no_argument.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>history.go()</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + gone = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [3, 2, 2], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_go_no_argument-1.html,history_forward-2.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_plus.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_plus.html new file mode 100644 index 0000000000..74d4c588ca --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_plus.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_go_plus</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + var t = async_test("history go plus"); + + var fired = false; + t.step(function () { + window.history.pushState(1, document.title, '?x=1'); + window.history.pushState(2, document.title, '?x=2'); + + window.history.back(); + }); + + window.addEventListener('popstate', t.step_func(function(e) { + if(fired) { + assert_equals(e.state, 2, "history state"); + + t.done(); + } + fired = true; + window.history.go(1); + + }), false); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri-1.html new file mode 100644 index 0000000000..49249ff000 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri-1.html @@ -0,0 +1,22 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + if (!opener.gone) { + // This is meant to test that passing a string is not supported. + // According to the spec, the value passed to 'go' must be an int. + // Internet Explorer supports passing a string and will navigate + // to that Url. This test will protect against regressing in + // this area and reverting back to IE's incorrect behavior. + history.go("history_entry.html"); + opener.gone = true; + } + } + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri.html new file mode 100644 index 0000000000..e0a891a5a2 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_to_uri.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>history.go() negative tests</title> +<link rel="author" title="John Jansen" href="mailto:johnjan@microsoft.com"> +<link rel="help" href="https://html.spec.whatwg.org/multipage/browsers.html#dom-history-go"> +<meta charset="utf-8"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + gone = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [3, 2, 2], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_go_to_uri-1.html,history_forward-2.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined-1.html new file mode 100644 index 0000000000..1bf7d6ee3b --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined-1.html @@ -0,0 +1,14 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + history.forward(); + } + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined.html new file mode 100644 index 0000000000..ddc0f588b5 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_undefined.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>history.forward() with session history</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [3, 2, 2], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_go_undefined-1.html,history_forward-2.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero-1.html new file mode 100644 index 0000000000..17e520a810 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero-1.html @@ -0,0 +1,17 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {} + + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + if (!opener.gone) { + history.go(0); + opener.gone = true; + } + } + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero.html new file mode 100644 index 0000000000..b071b580c3 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>history.go(0)</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + gone = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [3, 2, 2], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_go_zero-1.html,history_forward-2.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero_which_document.window.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero_which_document.window.js new file mode 100644 index 0000000000..f697783f3e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_go_zero_which_document.window.js @@ -0,0 +1,27 @@ +// META: title=history.go(0) on an iframe must reload the iframe's document, not the parent document +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js + +promise_test(async () => { + const rcHelper = new RemoteContextHelper(); + const main = await rcHelper.addWindow(); + await main.addIframe(); + + await main.executeScript(() => { + window.didNotGetReloaded = true; + + const iframe = document.querySelector("iframe"); + + // This goes beyond the original test case in https://github.com/whatwg/html/issues/2436, and + // tests where current realm != relevant realm. The spec says to use relevant realm so the + // result is still, iframe must reload, not parent. + History.prototype.go.call(iframe.contentWindow.history, 0); + + return new Promise(resolve => { + iframe.addEventListener("load", resolve); + }); + }); + + assert_true(await main.executeScript(() => window.didNotGetReloaded)); +}); diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_properties_only_fully_active.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_properties_only_fully_active.html new file mode 100644 index 0000000000..2b2c308526 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_properties_only_fully_active.html @@ -0,0 +1,23 @@ +<!doctype html> +<title>history properties should throw SecurityError when not in a fully active Document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<body> + <iframe id="child"></iframe> +</body> +<script> + test(function(t) { + var ifr = document.getElementById("child"); + var cached_history = ifr.contentWindow.history; + var cached_DOMException = ifr.contentWindow.DOMException; + ifr.remove(); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.length; }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.scrollRestoration; }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.state; }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.go(0); }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.back(); }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.forward(); }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.pushState(1, document.title, "?x=1"); }); + assert_throws_dom("SecurityError", cached_DOMException, function() { cached_history.replaceState(2, document.title, "?x=2"); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate.html new file mode 100644 index 0000000000..5180a3f6e5 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_pushState</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + window.history.pushState(1, document.title, '?x=1'); + var state; + state = window.history.state; + assert_equals(state, 1, "history state"); + }, "history pushState"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_err.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_err.html new file mode 100644 index 0000000000..6fa0a8589d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_err.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_pushState SECURITY_ERR</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + assert_throws_dom("SecurityError", function () { + window.history.pushState(1, document.title, 'http://www.microsoft.com/test.html'); + }); + }, "history pushState SECURITY_ERR"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_nooptionalparam.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_nooptionalparam.html new file mode 100644 index 0000000000..8e4b049a19 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_nooptionalparam.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_pushState_NoOptionalParam</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + window.history.pushState(1, document.title); + + var state; + state = window.history.state; + assert_equals(state, 1, "history state"); + }, "history pushState NoOptionalParam"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url.html new file mode 100644 index 0000000000..cfbca35bfd --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url.html @@ -0,0 +1,24 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<title>History pushState sets the url</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +</head> +<body> +<div id="log"></div> +<script> +async_test(function(t) { + var oldLocation = window.location.toString(); + window.history.pushState(null, "", "#hash"); + assert_equals(oldLocation + "#hash", window.location.toString(), "pushState updates url"); + history.back(); + window.onhashchange = () => { + assert_equals(oldLocation, window.location.toString(), 'history traversal restores old url'); + t.done(); + }; +}, "history pushState sets url"); +</script> +</body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html new file mode 100644 index 0000000000..03c2afe8ea --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_pushstate_url_rewriting.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>URL rewriting allowed/disallowed for history.pushState()</title> +<link rel="help" href="https://github.com/whatwg/html/issues/6836"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; +setup({ explicit_done: true }); + +const baseWithUsernamePassword = new URL(location.href); +baseWithUsernamePassword.username = "username"; +baseWithUsernamePassword.password = "password"; + +const blobURL = URL.createObjectURL(new Blob(["foo"], { type: "text/html" })); +const blobURL2 = URL.createObjectURL(new Blob(["bar"], { type: "text/html" })); + +const basicCases = [ + [new URL("/common/blank.html", location.href), new URL("/common/blank.html#newhash", location.href), true], + [new URL("/common/blank.html", location.href), new URL("/common/blank.html?newsearch", location.href), true], + [new URL("/common/blank.html", location.href), new URL("/newpath", location.href), true], + [new URL("/common/blank.html", location.href), new URL("/common/blank.html", baseWithUsernamePassword), false], + [new URL("/common/blank.html", location.href), blobURL, false], + [new URL("/common/blank.html", location.href), "about:blank", false], + [new URL("/common/blank.html", location.href), "about:srcdoc", false], + [blobURL, blobURL, true], + [blobURL, blobURL + "#newhash", true], + [blobURL, blobURL + "?newsearch", false], + [blobURL, "blob:newpath", false], + [blobURL, "blob:" + self.origin + "/syntheticblob", false], + [blobURL, blobURL2, false], + + // Note: these are cases where we create the iframe pointing at the initial URL, + // so its origin will actually be self.origin. + ["about:blank", "about:blank", true], + ["about:blank", "about:srcdoc", false], + ["about:blank", "about:blank?newsearch", false], + ["about:blank", "about:blank#newhash", true], + ["about:blank", self.origin + "/blank", false], + + // javascript: URL navigation changes the URL to the creator document's URL, so these should all + // not work because you can't rewrite a HTTP(S) URL to a javascript: URL. + [new URL("/common/blank.html", location.href), "javascript:'foo'", false], + ["javascript:'foo'", "javascript:'foo'", false], + ["javascript:'foo'", "javascript:'foo'?newsearch", false], + ["javascript:'foo'", "javascript:'foo'#newhash", false], +].map(([from, to, expectedToWork]) => [from.toString(), to.toString(), expectedToWork]); + +for (const [from, to, expectedToWork] of basicCases) { + // Otherwise the messages are not consistent between runs which breaks some systems. + const fromForTitle = from.replaceAll(blobURL, "blob:(a blob URL for this origin)") + .replaceAll(blobURL2, "blob:(another blob URL for this origin)"); + const toForTitle = to.replaceAll(blobURL, "blob:(a blob URL for this origin)") + .replaceAll(blobURL2, "blob:(another blob URL for this origin)"); + + promise_test(async () => { + const iframe = document.createElement("iframe"); + iframe.src = from; + const loadPromise = new Promise(r => iframe.onload = r); + + document.body.append(iframe); + await loadPromise; + + if (expectedToWork) { + iframe.contentWindow.history.pushState(null, "", to); + assert_equals(iframe.contentWindow.location.href, to); + } else { + assert_throws_dom("SecurityError", iframe.contentWindow.DOMException, () => { + iframe.contentWindow.history.pushState(null, "", to); + }); + } + }, `${fromForTitle} to ${toForTitle} should ${expectedToWork ? "" : "not"} work`); +} + +const srcdocCases = [ + ["about:srcdoc", true], + ["about:srcdoc?newsearch", false], + ["about:srcdoc#newhash", true], + [self.origin + "/srcdoc", false] +]; + +for (const [to, expectedToWork] of srcdocCases) { + promise_test(async () => { + const iframe = document.createElement("iframe"); + iframe.srcdoc = "foo"; + const loadPromise = new Promise(r => iframe.onload = r); + + document.body.append(iframe); + await loadPromise; + + if (expectedToWork) { + iframe.contentWindow.history.pushState(null, "", to); + assert_equals(iframe.contentWindow.location.href, to); + } else { + assert_throws_dom("SecurityError", iframe.contentWindow.DOMException, () => { + iframe.contentWindow.history.pushState(null, "", to); + }); + } + }, `about:srcdoc to ${to} should ${expectedToWork ? "" : "not"} work`); +} + +// We need to test these separately since they're cross-origin. + +const sandboxedCases = [ + [new URL("resources/url-rewriting-helper.html", location.href), new URL("resources/url-rewriting-helper.html", location.href), true], + [new URL("resources/url-rewriting-helper.html", location.href), new URL("resources/url-rewriting-helper.html#newhash", location.href), true], + [new URL("resources/url-rewriting-helper.html", location.href), new URL("resources/url-rewriting-helper.html?newsearch", location.href), true], + [new URL("resources/url-rewriting-helper.html", location.href), new URL("/newpath", location.href), true], + [new URL("resources/url-rewriting-helper.html", location.href), new URL("resources/url-rewriting-helper.html", baseWithUsernamePassword), false], +].map(([from, to, expectedToWork]) => [from.toString(), to.toString(), expectedToWork]); + +for (const [from, to, expectedToWork] of sandboxedCases) { + promise_test(async () => { + const iframe = document.createElement("iframe"); + iframe.src = from; + iframe.sandbox = "allow-scripts"; + const loadPromise = new Promise(r => iframe.onload = r); + + document.body.append(iframe); + await loadPromise; + + const messagePromise = new Promise(r => window.addEventListener("message", r, { once: true })); + iframe.contentWindow.postMessage(to, "*"); + const { data } = await messagePromise; + + if (expectedToWork) { + assert_equals(data.result, "no exception"); + assert_equals(data.locationHref, to); + } else { + assert_equals(data.result, "exception"); + assert_equals(data.exceptionName, "SecurityError"); + } + }, `sandboxed ${from} to ${to} should ${expectedToWork ? "" : "not"} work`); +} + +fetch("resources/url-rewriting-helper.html").then(r => r.text()).then(htmlInside => { + const dataURLStart = "data:text/html;base64," + btoa(htmlInside); + + const dataURLCases = [ + [dataURLStart, dataURLStart, true], + [dataURLStart, dataURLStart + "#newhash", true], + [dataURLStart, dataURLStart + "?newsearch", false], + [dataURLStart, "data:newpath", false] + ]; + + for (const [from, to, expectedToWork] of dataURLCases) { + // Otherwise the messages are unreadably long. + const fromForTitle = from.replaceAll(dataURLStart, "data:(script to run this test)"); + const toForTitle = to.replaceAll(dataURLStart, "data:(script to run this test)"); + + promise_test(async () => { + const iframe = document.createElement("iframe"); + iframe.src = from; + const loadPromise = new Promise(r => iframe.onload = r); + + document.body.append(iframe); + await loadPromise; + + const messagePromise = new Promise(r => window.addEventListener("message", r, { once: true })); + iframe.contentWindow.postMessage(to, "*"); + const { data } = await messagePromise; + if (expectedToWork) { + assert_equals(data.result, "no exception"); + assert_equals(data.locationHref, to); + } else { + assert_equals(data.result, "exception"); + assert_equals(data.exceptionName, "SecurityError"); + } + }, `${fromForTitle} to ${toForTitle} should ${expectedToWork ? "" : "not"} work`); + } + + done(); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate.html new file mode 100644 index 0000000000..794c2f3713 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_replaceState</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + window.history.replaceState(1, document.title, '?x=1'); + + var second; + second = window.history.state; + assert_equals(second, 1, "history state"); + }, "history replaceState"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_err.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_err.html new file mode 100644 index 0000000000..15d2181820 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_err.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_replaceState SECURITY_ERR</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + assert_throws_dom("SecurityError", function () { + window.history.replaceState(1, document.title, 'http://www.microsoft.com/test.html'); + }); + }, "history replaceState SECURITY_ERR"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_nooptionalparam.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_nooptionalparam.html new file mode 100644 index 0000000000..838467d782 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_replacestate_nooptionalparam.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_replaceStateNoOptionalParam</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + window.history.replaceState(1, document.title); + + var second; + second = window.history.state; + assert_equals(second, 1, "history state"); + }, "history replaceStateNoOptionalParam"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/history_state.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_state.html new file mode 100644 index 0000000000..2ee2356b1a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/history_state.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>history_state</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + </head> + <body> + <div id="log"></div> + <script> + test(function () { + var first; + var second; + + first = window.history.state; + window.history.pushState(1, document.title, '?x=1'); + + second = window.history.state; + assert_equals(first, null, "first"); + assert_equals(second, 1, "second"); + }, "history state"); + </script> + </body> +</html> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/iframe_history_go_0.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/iframe_history_go_0.html new file mode 100644 index 0000000000..f93f4c864e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/iframe_history_go_0.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<head> + <title>iframe_history_go_0</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> +<iframe></iframe> +<script> +promise_test(async (t) => { + let iframe = null; + const OLD_URL = 'blank-old.html'; + const NEW_URL = 'blank-new.html'; + + await new Promise(resolve => { + iframe = document.createElement('iframe'); + iframe.onload = () => resolve(); + iframe.src = OLD_URL; + document.body.appendChild(iframe); + t.add_cleanup(() => iframe.remove()); + }); + + assert_equals(iframe.contentDocument.body.textContent, 'This is an old page.\n'); + + await new Promise(resolve => { + iframe.onload = () => resolve(); + iframe.src = NEW_URL; + }); + + assert_equals(iframe.contentDocument.body.textContent, 'This is a new page.\n'); + + await new Promise(resolve => { + iframe.onload = () => resolve(); + iframe.contentWindow.history.go(0); + }); + + assert_equals(iframe.contentDocument.body.textContent, 'This is a new page.\n'); +}, 'iframe\'s history.go(0) performs a location.reload()'); +</script> +</body> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001-1.html new file mode 100644 index 0000000000..9aa5d30d16 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001-1.html @@ -0,0 +1,72 @@ +<!doctype html> +<script> +var o = opener; + +var frameloaded = null; + +o.t.step(function() {o.assert_equals(history.length, 1)}); + +onload = function () { + o.t.step(function() { + o.assert_equals(history.length, 1); + o.t.done(); + }); + + o.t1.step(function() { + var iframe = document.createElement("iframe"); + iframe.src = "filler.html?id=2"; + document.body.appendChild(iframe); + frameloaded = o.t1.step_func(function () { + o.assert_equals(history.length, 1); + setTimeout(o.t1.step_func(function () { + o.assert_equals(history.length, 1); + iframe.src = "filler.html?id=3"; + frameloaded = o.t2.step_func(function() { + o.assert_equals(history.length, 2); + history.go(-1); + frameloaded = o.t3.step_func(function() { + o.assert_equals(history.length, 2); + var parts = iframe.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=2"); + o.t3.done(); + o.t4.step(function() { + var iframe0 = document.getElementsByTagName("iframe")[0]; + iframe0.src = "filler.html?id=4" + frameloaded = o.t4.step_func(function() { + o.assert_equals(history.length, 2); + var parts = iframe0.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=4"); + //This is the point at which gecko and webkit stop running tests + history.go(-1); + frameloaded = o.t5.step_func(function() { + o.assert_equals(history.length, 2); + var parts = iframe0.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=1"); + var parts = iframe.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=2"); + history.go(1); + frameloaded = o.t6.step_func(function() { + o.assert_equals(history.length, 2); + var parts = iframe0.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=4"); + var parts = iframe.contentWindow.location.href.split("/") + o.assert_equals(parts[parts.length - 1], "filler.html?id=2"); + o.t6.done(); + }); + o.t5.done(); + }); + o.t4.done(); + }); + }); + }); + o.t2.done(); + }); + o.t1.done(); + }, 500)) + }); + }); + +} +</script> + +<iframe src="filler.html?id=1"></iframe> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001.html new file mode 100644 index 0000000000..c9d1c6416d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/001.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>Joint session history with single iframe</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +setup({timeout:10000}); +var t = async_test("Session history length on initial load"); +var t1 = async_test("Session history length on adding new iframe"); +var t2 = async_test("Navigating second iframe"); +var t3 = async_test("Traversing history back (1)"); +var t4 = async_test("Navigating first iframe"); +var t5 = async_test("Traversing history back (2)"); +var t6 = async_test("Traversing history forward"); +var w = window.open("001-1.html"); +//add_completion_callback(function() {w.close()}); +</script> + diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002-1.html new file mode 100644 index 0000000000..ed69d679da --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002-1.html @@ -0,0 +1,35 @@ +<!doctype html> +<script> +var o = opener; + +var frameloaded = null; + +o.t.step(function() {o.assert_equals(history.length, 1)}); + +onload = function () { + o.t.step(function() { + o.assert_equals(history.length, 1); + o.t.done(); + }); + + o.t1.step(function() { + var iframe = document.createElement("iframe"); + iframe.src = "filler.html?id=2"; + document.body.appendChild(iframe); + o.assert_equals(history.length, 1); + frameloaded = o.t2.step_func(function() { + iframe.contentDocument.open(); + iframe.contentDocument.write("3<script>onpageshow = function() {alert('pageshow'); parent.frameloaded()}<\/script>"); + iframe.contentDocument.close(); + frameloaded = o.t2.step_func(function () { + o.assert_equals(history.length, 2); + o.t2.done(); + }); + }); + o.t1.done(); + }); + +} +</script> + +<iframe src="filler.html?id=1"></iframe> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002.html new file mode 100644 index 0000000000..b08c19e52d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/002.html @@ -0,0 +1,18 @@ +<!doctype html> +<title>Joint session history with single iframe</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +setup({timeout:10000}); +var t = async_test("Session history length on initial load"); +var t1 = async_test("Session history length on adding new iframe"); +var t2 = async_test("Navigating second iframe"); +<!-- var t3 = async_test("Traversing history back (1)"); --> +<!-- var t4 = async_test("Navigating first iframe"); --> +<!-- var t5 = async_test("Traversing history back (2)"); --> +<!-- var t6 = async_test("Traversing history forward"); --> +var w = window.open("002-1.html"); +//add_completion_callback(function() {w.close()}); +</script> + diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/filler.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/filler.html new file mode 100644 index 0000000000..93e3c7ccfc --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/joint_session_history/filler.html @@ -0,0 +1,5 @@ +<!doctype html> +<script> +document.write(location.search) +onpageshow = function() {if (parent.frameloaded) {parent.frameloaded()}} +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history.js b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history.js new file mode 100644 index 0000000000..bb5ee6dde0 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history.js @@ -0,0 +1,35 @@ +function parse_query() { + var query = location.search.slice(1); + var vars = query.split("&"); + var fields = {}; + vars.forEach( + function (x) { + var split = x.split("="); + return fields[split[0]] = split.slice(1).join("="); + }); + return fields; +} + +var query_parts = parse_query(); +var id = "id" in query_parts ? parseInt(query_parts.id) : 1; +var urls_to_load = query_parts.urls.split(","); + +document.write(id); + +onunload = function() {}; + +function queue_next() { + t = opener.t; + setTimeout(t.step_func( + function() { +// opener.assert_equals(history.length, id); + if (urls_to_load[0]) { + var next_page = urls_to_load[0]; + (next_page.indexOf("?") > -1) ? (next_page += "&") : (next_page += "?"); + next_page += "urls=" + urls_to_load.slice(1).join(","); + next_page += "&id=" + ++id; + location = next_page; + } + } + ), 100); +} diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history_entry.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history_entry.html new file mode 100644 index 0000000000..e5929ddbe8 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/history_entry.html @@ -0,0 +1,12 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onload = function() { + if (!opener.started) { + queue_next(); + } else { + opener.pages.push(id); + opener.start_test_wait(); + } +}; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-1.html new file mode 100644 index 0000000000..8c4401836a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-1.html @@ -0,0 +1,18 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onbeforeunload = function() {opener.beforeunload_ran = true; return "Opt to stay on the page"}; + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.back(); + }, 100); + } + } +</script> +<p>You should see/have seen a prompt asking if you want to leave the page.</p> +<p>Opt to stay on the page</p> +<button onclick="onbeforeunload = null; opener.start_test_wait(); document.getElementsByTagName('button')[0].disabled = true;">Click here</button> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual.html new file mode 100644 index 0000000000..587cdfb124 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_1-manual.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>Traversing the history, prompt in before unload, navigation denied</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + setup({timeout:3600000}); + var t = async_test(); + started = false; + pages = [] + timer = null; + beforeunload_ran = false; + start_test_wait = t.step_func( + function() { + clearTimeout(timer); + timer = setTimeout(t.step_func( + function() { + try { + assert_true(beforeunload_ran, "beforeunload event handler ran"); + assert_array_equals(pages, [2], "Pages opened during history navigation"); + t.done(); + } finally { + win.close(); + } + } + ), 500); + } + ); + t.step(function() {win = window.open("history_entry.html?urls=traverse_the_history_unload_prompt_1-1.html"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-1.html new file mode 100644 index 0000000000..608a579e69 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-1.html @@ -0,0 +1,18 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onbeforeunload = function() {opener.beforeunload_ran = true; return "Opt to leave the page"}; + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.back(); + }, 100); + } + } +</script> +<p>You should see/have seen a prompt asking if you want to leave the page.</p> +<p>Opt to leave the page</p> +<p>If you weren't navigated away after opting to leave the page, that's a FAIL</p> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-manual.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-manual.html new file mode 100644 index 0000000000..94b66f8b55 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_history_unload_prompt_2-manual.html @@ -0,0 +1,31 @@ +<!doctype html> +<title>Traversing the history, prompt in before unload, navigation allowed</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + setup({timeout:3600000}); + var t = async_test(); + started = false; + pages = [] + timer = null; + beforeunload_ran = false; + start_test_wait = t.step_func( + function() { + clearTimeout(timer); + timer = setTimeout(t.step_func( + function() { + try { + assert_true(beforeunload_ran, "beforeunload event handler ran"); + assert_array_equals(pages, [2,1], "Pages opened during history navigation"); + t.done(); + } finally { + win.close(); + } + } + ), 500); + } + ); + t.step(function() {win = window.open("history_entry.html?urls=traverse_the_history_unload_prompt_2-1.html"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-1.html new file mode 100644 index 0000000000..c0079b6bec --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-1.html @@ -0,0 +1,17 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function(e) {opener.unload_ran = true; return "Now refuse to leave the current page"} + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.back(); + }, 100); + } + } else { + opener.start_test_wait(); + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual.html new file mode 100644 index 0000000000..7f96a39240 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/non-automated/traverse_the_session_history_unload_prompt_1-manual.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>Traversing the history, unload event is fired on doucment</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = null; + unload_ran = false; + start_test_wait = t.step_func( + function() { + clearTimeout(timer); + timer = setTimeout(t.step_func( + function() { + try { + assert_array_equals(pages, [2], "Pages opened during history navigation"); + assert_true(unload_ran, "Unload event handler ran"); + t.done(); + } finally { + // win.close(); + } + } + ), 500); + } + ); + t.step(function() {win = window.open("history_entry.html?urls=traverse_the_history_unload_prompt_1-1.html"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-base.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-base.html new file mode 100644 index 0000000000..ea95d812d7 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-base.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.pushState() with an empty string URL and base URL different from document's URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<base href="/the-base"> + +<script> +"use strict"; + +test(() => { + const before = location.pathname; + + history.pushState(null, null, ""); + assert_equals(location.pathname, before); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-whitespace.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-whitespace.html new file mode 100644 index 0000000000..72d9be6a9c --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate-whitespace.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.pushState() with a whitespace URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + location.hash = "test"; + + const before = location.pathname; + + history.pushState(null, null, " "); + assert_equals(location.pathname, before, "pathname"); + assert_equals(location.hash, "", "hash"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate.html new file mode 100644 index 0000000000..1953709269 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/pushstate.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.pushState() with an empty string URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + location.hash = "test"; + + history.pushState(null, null, ""); + assert_equals(location.hash, "#test"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-base.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-base.html new file mode 100644 index 0000000000..224e928de6 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-base.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.replaceState() with an empty string URL and base URL different from document's URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<base href="/the-base"> + +<script> +"use strict"; + +test(() => { + const before = location.pathname; + + history.replaceState(null, null, ""); + assert_equals(location.pathname, before); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-whitespace.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-whitespace.html new file mode 100644 index 0000000000..7261cdf3fa --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate-whitespace.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.replaceState() with a whitespace URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + location.hash = "test"; + + const before = location.pathname; + + history.replaceState(null, null, " "); + assert_equals(location.pathname, before, "pathname"); + assert_equals(location.hash, "", "hash"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate.html new file mode 100644 index 0000000000..66b4cc6f82 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/pushstate-replacestate-empty-string/replacestate.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>history.replaceState() with an empty string URL</title> +<link rel="help" href="https://github.com/whatwg/html/issues/9343"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + location.hash = "test"; + + history.replaceState(null, null, ""); + assert_equals(location.hash, "#test"); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/message-opener.sub.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/message-opener.sub.html new file mode 100644 index 0000000000..441c08c0ea --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/message-opener.sub.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<script> +"use strict"; + +opener.postMessage("{{GET[id]}}", "*"); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-beforeunload.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-beforeunload.html new file mode 100644 index 0000000000..53a4a1886e --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-beforeunload.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<script> +"use strict"; + +window.addEventListener("beforeunload", () => { + history.back(); +}); + +location.href = "message-opener.sub.html?id=destination"; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-unload.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-unload.html new file mode 100644 index 0000000000..d5ffb7abae --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/traverse-during-unload.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> + +<script> +"use strict"; + +window.addEventListener("unload", () => { + history.back(); +}); + +location.href = "message-opener.sub.html?id=destination"; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/url-rewriting-helper.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/url-rewriting-helper.html new file mode 100644 index 0000000000..847d16cd1a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/resources/url-rewriting-helper.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<script> + window.onmessage = ({ data }) => { + try { + history.pushState(null, "", data); + } catch (e) { + parent.postMessage({ result: "exception", exceptionName: e.name }, "*"); + return; + } + parent.postMessage({ result: "no exception", locationHref: location.href }, "*"); + }; +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-beforeunload.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-beforeunload.html new file mode 100644 index 0000000000..cb8cdca7ff --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-beforeunload.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Traversing the history during beforeunload</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +async_test(t => { + const w = window.open("resources/message-opener.sub.html?id=start"); + t.add_cleanup(() => w.close()); + + const messages = []; + window.addEventListener("message", t.step_func(({ data }) => { + messages.push(data); + + if (messages.length === 1) { + assert_array_equals(messages, ["start"]); + w.location.href = "resources/traverse-during-beforeunload.html"; + } else if (messages.length === 2) { + assert_array_equals(messages, ["start", "destination"]); + t.done(); + } + })); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-unload.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-unload.html new file mode 100644 index 0000000000..6f6e984402 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse-during-unload.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Traversing the history during unload</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +async_test(t => { + const w = window.open("resources/message-opener.sub.html?id=start"); + t.add_cleanup(() => w.close()); + + const messages = []; + window.addEventListener("message", t.step_func(({ data }) => { + messages.push(data); + + if (messages.length === 1) { + assert_array_equals(messages, ["start"]); + w.location.href = "resources/traverse-during-unload.html"; + } else if (messages.length === 2) { + assert_array_equals(messages, ["start", "destination"]); + t.done(); + } + })); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1-1.html new file mode 100644 index 0000000000..13e89e7bc0 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1-1.html @@ -0,0 +1,16 @@ +<!doctype html> +4 +<script> + onunload = function() {} + + opener.pages.push(4); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(-2); + history.go(-1); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1.html new file mode 100644 index 0000000000..9b59bb0587 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_1.html @@ -0,0 +1,25 @@ +<!doctype html> +<title>Multiple history traversals from the same task</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = null; + start_test_wait = t.step_func( + function() { + clearTimeout(timer); + timer = setTimeout(t.step_func( + function() { + assert_array_equals(pages, [4, 2], "Pages opened during history navigation"); + t.done(); + } + ), 500); + } + ); + t.step(function() {win = window.open("history_entry.html?urls=history_entry.html,history_entry.html,traverse_the_history_1-1.html"); + t.add_cleanup(() => { win.close() }); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2-1.html new file mode 100644 index 0000000000..fecf060eb7 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(-3); + history.go(-2); + history.go(1); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2.html new file mode 100644 index 0000000000..429a97d835 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_2.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>Multiple history traversals, last would be aborted</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 2) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [6, 3], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_entry.html,history_entry.html,history_entry.html,history_entry.html,traverse_the_history_2-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3-1.html new file mode 100644 index 0000000000..e7836fedbe --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(-2); + history.go(-1); + history.go(3); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3.html new file mode 100644 index 0000000000..429a97d835 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_3.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>Multiple history traversals, last would be aborted</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 2) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [6, 3], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_entry.html,history_entry.html,history_entry.html,history_entry.html,traverse_the_history_2-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4-1.html new file mode 100644 index 0000000000..9211da1172 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(-10); //Outside the range + history.go(-1); + history.go(-2); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4.html new file mode 100644 index 0000000000..136093a2c1 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_4.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>Multiple history traversals, last would be aborted</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 2) + return; + clearTimeout(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [6, 5], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_entry.html,history_entry.html,history_entry.html,history_entry.html,traverse_the_history_4-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5-1.html new file mode 100644 index 0000000000..6a28a85683 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.go(10); //Outside the range + history.go(-1); + history.go(-2); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5.html new file mode 100644 index 0000000000..4d3d643425 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_5.html @@ -0,0 +1,26 @@ +<!doctype html> +<title>Multiple history traversals, last would be aborted</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 2) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [6, 5], "Pages opened during history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_entry.html,history_entry.html,history_entry.html,history_entry.html,traverse_the_history_5-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1-1.html new file mode 100644 index 0000000000..b9d8a0c694 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1-1.html @@ -0,0 +1,15 @@ +<!doctype html> +<script src="history.js"></script> +<script> + onunload = function() {opener.unload_ran = true;} + + opener.pages.push(id); + if (!opener.started) { + onload = function() { + setTimeout(function() { + opener.started = true; + history.back(); + }, 100); + } + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html new file mode 100644 index 0000000000..4ef0ea583d --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_unload_1.html @@ -0,0 +1,28 @@ +<!doctype html> +<title>Traversing the history, unload event is fired on doucment</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + unload_ran = false; + timer = setInterval( + function() { + if (pages.length < 2 || !unload_ran) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + assert_array_equals(pages, [2, 1], "Pages opened during history navigation"); + assert_true(unload_ran, "Unload event handler ran"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=traverse_the_history_unload_1-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1-1.html new file mode 100644 index 0000000000..945c8d81f8 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1-1.html @@ -0,0 +1,12 @@ +<!doctype html> +2 +<script> + onunload = function() {} + opener.pages.push(2); + onload = function() { + setTimeout(function() { + document.write("<!doctype html>3<script>opener.pages.push(3); if(!opener.started) {opener.started = true; history.go(-1);}<\/script>"); + document.close(); + }, 100); + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1.html new file mode 100644 index 0000000000..404d61d0cf --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_1.html @@ -0,0 +1,29 @@ +<!doctype html> +<title>Traverse the history after document.write after the load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + start_test_wait = t.step_func( + function() { + check_result = t.step_func( + function() { + if (pages.length < 3) { + setTimeout(check_result, 500); + return + } + assert_array_equals(pages, [2, 3, 1], "Pages opened during history navigation"); + t.done(); + } + ) + setTimeout(check_result, 500); + } + ); + t.step(function() { + win = window.open("history_entry.html?urls=traverse_the_history_write_after_load_1-1.html"); + t.add_cleanup(function() {win.close()}); +}); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2-1.html new file mode 100644 index 0000000000..922e1832a6 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2-1.html @@ -0,0 +1,9 @@ +<!doctype html> +3 +<script> + onunload = function() {} + opener.pages.push(3); + onload = function() { + document.write("<!doctype html>4<script>opener.pages.push(4); if(!opener.started) {opener.started = true; history.go(-2);}<\/script>"); + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2.html new file mode 100644 index 0000000000..7372e9f4ae --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_after_load_2.html @@ -0,0 +1,24 @@ +<!doctype html> +<title>Traverse the history back and forward when a history entry is written after the load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 5) + return; + setTimeout(t.step_func(function() { + //The pass condition here is based on the idea that the spec is wrong and browsers are right + assert_array_equals(pages, [3, 4, 2, 3, 4], "Pages opened during history navigation"); + t.done(); + }), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_forward-1.html,traverse_the_history_write_onload_2-1.html"); + t.add_cleanup(function() {win.close()}); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1-1.html new file mode 100644 index 0000000000..70d946c818 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1-1.html @@ -0,0 +1,9 @@ +<!doctype html> +2 +<script> + onunload = function() {} + opener.pages.push(2); + onload = function() { + document.write("<!doctype html>3<script>opener.pages.push(3); if(!opener.started) {opener.started = true; history.go(-1);}<\/script>"); + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1.html new file mode 100644 index 0000000000..febb4334da --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_1.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>Traverse the history when a history entry is written in the load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 3) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + //The pass condition here is based on the idea that the spec is wrong and browsers are right + assert_array_equals(pages, [2, 3, 1], "Pages opened durning history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=traverse_the_history_write_onload_1-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2-1.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2-1.html new file mode 100644 index 0000000000..2716514109 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2-1.html @@ -0,0 +1,9 @@ +<!doctype html> +3 +<script> + onunload = function() {} + opener.pages.push(3); + onload = function() { + document.write("<!doctype html>4<script>opener.pages.push(4); if(!opener.started) {opener.started = true; history.go(-1);}<\/script>"); + } +</script> diff --git a/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2.html b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2.html new file mode 100644 index 0000000000..aa97d22c02 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-history-interface/traverse_the_history_write_onload_2.html @@ -0,0 +1,27 @@ +<!doctype html> +<title>Traverse the history back and forward when a history entry is written in the load event</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> + var t = async_test(); + started = false; + pages = [] + timer = setInterval( + function() { + if (pages.length < 5) + return; + clearInterval(timer); + setTimeout(t.step_func( + function() { + //The pass condition here is based on the idea that the spec is wrong and browsers are right + assert_array_equals(pages, [3, 4, 2, 3, 4], "Pages opened durning history navigation"); + t.done(); + } + ), 500); + }, 50); + t.step(function() { + win = window.open("history_entry.html?urls=history_forward-1.html,traverse_the_history_write_onload_2-1.html"); + t.add_cleanup(function() { win.close(); }); + }); +</script> |