From 09427933ac4883cb6cbe756eaa9c980eb8b76b1d Mon Sep 17 00:00:00 2001 From: Domenic Denicola Date: Wed, 12 Oct 2022 20:11:46 +0900 Subject: [PATCH] Test that History is associated with Document, not Window This is done by expanding the object-association.js helper and using it. We can also remove an outdated workaround in that file for extra load events, since no modern browsers suffer from that. See https://github.com/whatwg/html/issues/2566. --- common/object-association.js | 68 ++++++++++--------- ...history-associated-with-document.window.js | 6 ++ 2 files changed, 43 insertions(+), 31 deletions(-) create mode 100644 html/browsers/history/the-history-interface/history-associated-with-document.window.js diff --git a/common/object-association.js b/common/object-association.js index 458aae67db0cef..669c17c07b1ae5 100644 --- a/common/object-association.js +++ b/common/object-association.js @@ -1,58 +1,64 @@ "use strict"; -// For now this only has per-Window tests, but we could expand it to also test per-Document +// This is for testing whether an object (e.g., a global property) is associated with Window, or +// with Document. Recall that Window and Document are 1:1 except when doing a same-origin navigation +// away from the initial about:blank. In that case the Window object gets reused for the new +// Document. +// +// So: +// - If something is per-Window, then it should maintain its identity across an about:blank +// navigation. +// - If something is per-Document, then it should be recreated across an about:blank navigation. -/** - * Run tests for window[propertyName] after discarding the browsing context, navigating, etc. - * @param {string} propertyName - */ window.testIsPerWindow = propertyName => { - test(t => { + runTests(propertyName, assert_equals, "must not"); +}; + +window.testIsPerDocument = propertyName => { + runTests(propertyName, assert_not_equals, "must"); +}; + +function runTests(propertyName, equalityOrInequalityAsserter, mustOrMustNotReplace) { + async_test(t => { const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + assert_implements(before, `window.${propertyName} must be implemented`); - iframe.remove(); + iframe.onload = t.step_func_done(() => { + const after = frame[propertyName]; + equalityOrInequalityAsserter(after, before); + }); - const after = frame[propertyName]; - assert_equals(after, before, `window.${propertyName} should not change after iframe.remove()`); - }, `Discarding the browsing context must not change window.${propertyName}`); + iframe.src = "/common/blank.html"; + }, `Navigating from the initial about:blank ${mustOrMustNotReplace} replace window.${propertyName}`); - async_test(t => { + // Per spec, discarding a browsing context should not change any of the global objects. + test(() => { const iframe = document.createElement("iframe"); document.body.appendChild(iframe); const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); - - // Note: cannot use step_func_done for this because it might be called twice, per the below comment. - iframe.onload = t.step_func(() => { - if (frame.location.href === "about:blank") { - // Browsers are not reliable on whether about:blank fires the load event; see - // https://github.com/whatwg/html/issues/490 - return; - } + assert_implements(before, `window.${propertyName} must be implemented`); - const after = frame[propertyName]; - assert_equals(after, before); - t.done(); - }); + iframe.remove(); - iframe.src = "/common/blank.html"; - }, `Navigating from the initial about:blank must not replace window.${propertyName}`); + const after = frame[propertyName]; + assert_equals(after, before, `window.${propertyName} should not change after iframe.remove()`); + }, `Discarding the browsing context must not change window.${propertyName}`); - // Per spec, document.open() should not change any of the Window state. + // Per spec, document.open() should not change any of the global objects. In historical versions + // of the spec, it did, so we test here. async_test(t => { const iframe = document.createElement("iframe"); iframe.onload = t.step_func_done(() => { const frame = iframe.contentWindow; const before = frame[propertyName]; - assert_true(before !== undefined && before !== null, `window.${propertyName} must be implemented`); + assert_implements(before, `window.${propertyName} must be implemented`); frame.document.open(); @@ -64,5 +70,5 @@ window.testIsPerWindow = propertyName => { iframe.src = "/common/blank.html"; document.body.appendChild(iframe); - }, `document.open() must replace window.${propertyName}`); -}; + }, `document.open() must not replace window.${propertyName}`); +} diff --git a/html/browsers/history/the-history-interface/history-associated-with-document.window.js b/html/browsers/history/the-history-interface/history-associated-with-document.window.js new file mode 100644 index 00000000000000..94c1b2cf6b0a4b --- /dev/null +++ b/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");