diff --git a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html index b89d3bb54b8ebe..6b30f2aba13909 100644 --- a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html +++ b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-nosrc.html @@ -175,4 +175,39 @@ assert_equals(history.length, startingHistoryLength + 1, "history.length increases after normal navigation from non-initial empty document"); }, "form submission"); + +// This test is very similar to the `location.href` test a few cases above, but +// the difference is that instead of navigating from: +// initial about:blank Document => HTTP => HTTP +// ... we navigate from: +// initial about:blank Document => (non-initial) about:blank Document => HTTP +// +// We do this to ensure/assert that an explicit navigation to about:blank +// *after* the iframe has finished initializing, is counted as a normal +// navigation away from the initial about:blank Document, and the "initial-ness" +// of the initial about:blank Document is not carried over to the next +// about:blank Document. +promise_test(async t => { + const startingHistoryLength = history.length; + // Create an iframe with src not set, which will stay on the initial empty + // document. + const iframe = insertIframe(t); + assert_equals(history.length, startingHistoryLength, + "Inserting iframe with no src must not change history.length"); + + // Navigate away from the initial empty document through setting location.href + // to `about:blank`. This should do a replacement TO ANOTHER about:blank + // Document, which is not the initial about:blank Document. + iframe.contentWindow.location.href = 'about:blank'; + await waitForLoad(t, iframe, 'about:blank'); + assert_equals(history.length, startingHistoryLength, + "history.length must not change after normal navigation on document loaded by iframe with no src"); + + // Navigate again using the same method, but this time it shouldn't do a + // replacement since it's no longer on the initial empty document. + iframe.contentWindow.location.href = url2; + await waitForLoad(t, iframe, url2); + assert_equals(history.length, startingHistoryLength + 1, + "history.length increases after normal navigation from non-initial empty document"); +}, "initial about:blank => non-initial about:blank (via location.href) => normal HTTP navigation"); diff --git a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html index a75257d91cf6c5..626588f335093b 100644 --- a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html +++ b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/iframe-src-aboutblank-navigate-immediately.html @@ -16,32 +16,42 @@ promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank. This would trigger a - // navigation to a non-initial about:blank document. + // Create an iframe with src set to about:blank. Per the HTML Standard, this + // stays on the "initial about:blank Document" [1], because the "process the + // iframe attributes" algorithm [2] catches the "about:blank" navigation and + // fires a special synchronous `load` event at the initial about:blank + // Document, instead of replacing it with a non-initial, second about:blank + // Document. This is documented in the note at the end of [3]. + // + // [1]: https://html.spec.whatwg.org/#is-initial-about:blank. + // [2]: https://html.spec.whatwg.org/#process-the-iframe-attributes + // [3]: https://html.spec.whatwg.org/#completely-finish-loading const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Trigger a navigation to url1 through the iframe's src attribute. - // The iframe should still be on the initial empty document, and the - // navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // the iframe's src attribute. Because we're navigating from the initial + // about:blank Document, the navigation should be a replacement. iframe.src = url1; + // Wait for the latest navigation to finish. await waitForLoad(t, iframe, url1); assert_equals(history.length, startingHistoryLength, - "history.length must not change after normal navigation on initial empty document"); -}, "Navigating to a different document with src"); + "history.length must not change after normal navigation from initial " + + "about:blank Document"); +}, "Navigating away from the initial about:blank Document to a different " + + "one, with src"); promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank but navigate away from it immediately below. const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Navigate away from the initial empty document through setting - // location.href. The iframe should still be on the initial empty document, - // and the navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // location.href. Because we're navigating from the initial about:blank + // Document, the navigation should be a replacement. iframe.contentWindow.location.href = url1; await waitForLoad(t, iframe, url1); assert_equals(history.length, startingHistoryLength, @@ -50,14 +60,13 @@ promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank but navigate away from it immediately below. const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Navigate away from the initial empty document through location.assign(). - // The iframe should still be on the initial empty document, and the - // navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // location.assign(). Because we're navigating from the initial about:blank + // Document, the navigation should be a replacement. iframe.contentWindow.location.assign(url1); await waitForLoad(t, iframe, url1); assert_equals(history.length, startingHistoryLength, @@ -66,14 +75,13 @@ promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank but navigate away from it immediately below. const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Navigate away from the initial empty document through window.open(). - // The iframe should still be on the initial empty document, and the - // navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // window.open(). Because we're navigating from the initial about:blank + // Document, the navigation should be a replacement. iframe.contentWindow.open(url1, "_self"); await waitForLoad(t, iframe, url1); assert_equals(history.length, startingHistoryLength, @@ -82,14 +90,13 @@ promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank but navigate away from it immediately below. const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Navigate away from the initial empty document through clicking an - // element. The iframe should still be on the initial empty document, and the - // navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // clicking an `` element. Because we're navigating from the initial + // about:blank Document, the navigation should be a replacement. const a = iframe.contentDocument.createElement("a"); a.href = url1; iframe.contentDocument.body.appendChild(a); @@ -101,14 +108,13 @@ promise_test(async t => { const startingHistoryLength = history.length; - // Create an iframe with src set to about:blank but navigate away from it immediately below. const iframe = insertIframeWithAboutBlankSrc(t); assert_equals(history.length, startingHistoryLength, "Inserting iframe with src='about:blank' must not change history.length"); - // Navigate away from the initial empty document through form submission. - // The iframe should still be on the initial empty document, and the - // navigation should do replacement. + // Trigger a navigation from the initial about:blank Document, to url1 through + // a form submission. Because we're navigating from the initial about:blank + // Document, the navigation should be a replacement. const form = iframe.contentDocument.createElement("form"); form.action = "/common/blank.html"; iframe.contentDocument.body.appendChild(form); diff --git a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/resources/helpers.js b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/resources/helpers.js index 8d9473a9497d74..8866f7750627db 100644 --- a/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/resources/helpers.js +++ b/html/browsers/browsing-the-web/navigating-across-documents/initial-empty-document/resources/helpers.js @@ -37,7 +37,16 @@ window.insertIframeWith204Src = (t) => { return iframe; }; -// Creates an iframe with src="about:blank" and appends it to the document. +// Creates an iframe with src="about:blank" and appends it to the document. The +// resulting document in the iframe is the initial about:blank Document [1], +// because during the "process the iframe attributes" algorithm [2], `src` +// navigations to `about:blank` are caught and result in a synchronous load +// event; not a SEPARATE navigation to a non-initial `about:blank` Document. See +// the documentation in [3] as well. +// +// [1]: https://html.spec.whatwg.org/#is-initial-about:blank +// [2]: https://html.spec.whatwg.org/#process-the-iframe-attributes +// [3]: https://html.spec.whatwg.org/#completely-finish-loading window.insertIframeWithAboutBlankSrc = (t) => { const iframe = document.createElement("iframe"); t.add_cleanup(() => iframe.remove()); @@ -47,12 +56,14 @@ window.insertIframeWithAboutBlankSrc = (t) => { }; // Creates an iframe with src="about:blank", appends it to the document, and -// waits for the non-initial about:blank document finished loading. +// waits for initial about:blank Document to finish loading. window.insertIframeWithAboutBlankSrcWaitForLoad = async (t) => { const iframe = insertIframeWithAboutBlankSrc(t); const aboutBlankLoad = new Promise(resolve => { - // In some browsers, the non-initial about:blank navigation commits + // In some browsers, when the initial about:blank Document is influenced by + // a `src=about:blank` attribute, the about:blank navigation commits // asynchronously, while in other browsers, it would commit synchronously. + // // This means we can't wait for the "load" event as it might have already // ran. Instead, just wait for 100ms before resolving, as the non-initial // about:blank navigation will most likely take less than 100 ms to commit.