Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOM: Added a few batch-insertion scenarios that are incompatible across engines #44658

Merged
merged 31 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
dd49336
Test inserting a script and a div from a DocumentFragment
nox Feb 4, 2019
b8c4374
Test inserting a script and a custom element
nox Feb 6, 2019
05694a9
Test inserting a script and button in a form from a div
nox Feb 6, 2019
6e602f6
Test inserting three scripts where the first one modifies the third one
nox Feb 6, 2019
8a43ca1
Test inserting two text nodes from a fragment into an empty script el…
nox Feb 6, 2019
11214ff
Test inserting text and script nodes in a style element
nox Feb 7, 2019
631c9ac
Test inserting a script and a style where the script modifies the style
nox Feb 12, 2019
2ddd125
Test inserting a script and some code in an empty script
nox Feb 12, 2019
7643207
Test inserting a script and an iframe both at the same time
nox Feb 18, 2019
66357e1
Test inserting a script and a stylesheet link both at the same time
nox Feb 18, 2019
d104e23
Test inserting a script and a source in a media element
nox Feb 19, 2019
1e52f0f
Test inserting a script and a default-style meta
nox Feb 19, 2019
ae30cc5
rewrite first four files to work again
annevk Dec 9, 2019
392eed7
more
annevk Dec 13, 2019
a339b35
wip
annevk Apr 2, 2020
982a1f4
more cleanup
annevk Apr 2, 2020
55767c7
Fix a couple of tests to have more coherent results
noamr Feb 19, 2024
3ee6105
Add .tentative
noamr Feb 19, 2024
d598cb5
Change expected results to match batch insertion
noamr Feb 20, 2024
68ee4c1
Update dom/nodes/insertion-effects/Node-appendChild-script-and-button…
noamr Feb 22, 2024
b8c3dd0
Update dom/nodes/insertion-effects/Node-appendChild-script-and-styles…
noamr Feb 22, 2024
70b0596
Apply suggestions from code review
noamr Feb 23, 2024
e5eaa85
Remove redundant log divs
noamr Feb 23, 2024
7da6f2d
Apply PR fixes
noamr Feb 23, 2024
4573bb4
Some changes
domfarolino Feb 27, 2024
6bfc45b
Fix assertion
domfarolino Feb 27, 2024
5a010df
Combine tests
domfarolino Feb 27, 2024
d7174e5
Update expectations for style tests
noamr Feb 29, 2024
98aa182
Write explicit test description and combine a few more tests
domfarolino Feb 29, 2024
76b9cb2
Move to insertion-removing-steps
domfarolino Feb 29, 2024
f818763
Unnecessary src assignment
domfarolino Feb 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and button from a div</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<form id="form"></form>
<script>
let button = null;
let buttonForm = null;
test(() => {
const form = document.getElementById("form");
const script = document.createElement("script");
script.textContent = `
buttonForm = button.form;
`;
button = document.createElement("button");
const div = document.createElement("div");
div.appendChild(script);
div.appendChild(button);
assert_equals(buttonForm, null);
form.appendChild(div);
assert_equals(buttonForm, form);
}, "Script inserted before a form-associated button can observe the button's " +
"form, because by the time the script executes, the DOM insertion that " +
"associates the button with the form is already done");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and custom element from a DocumentFragment</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body>
<script>
let customConstructed = false;
let customConstructedDuringEarlierScript = false;
class CustomElement extends HTMLElement {
constructor() {
super();
customConstructed = true;
}
}
test(() => {
const script = document.createElement("script");
script.textContent = `
customElements.define("custom-element", CustomElement);
customConstructedDuringEarlierScript = customConstructed;
`;
const custom = document.createElement("custom-element");
const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(custom);
assert_false(customConstructed);
assert_false(customConstructedDuringEarlierScript);
document.head.appendChild(df);
assert_true(customConstructed);
assert_true(customConstructedDuringEarlierScript);
}, "An earlier-inserted script can upgrade a later-inserted custom element, " +
"whose upgrading is synchronously observable to the script, since DOM " +
"insertion has been completed by the time it runs");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and default-style meta from a fragment</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<link rel="alternate stylesheet" title="alternative" href="data:text/css,%23div{display:none}">
<div id="div">hello</div>
<script>
let scriptRan = false;
let computedStyleDuringInsertion = null;
test(() => {
const div = document.getElementById("div");
const meta = document.createElement("meta");
meta.httpEquiv = "default-style";
meta.content = "alternative";
const script = document.createElement("script");
script.textContent = `
computedStyleDuringInsertion = getComputedStyle(div).display;
scriptRan = true;
`;
const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(meta);
assert_equals(getComputedStyle(div).display, "block", "div has block display");
assert_false(scriptRan, "script has not run before insertion");
document.head.appendChild(df);
assert_true(scriptRan, "script has run after insertion");
assert_equals(computedStyleDuringInsertion, "none",
"display: none; style was applied during DOM insertion, before " +
"later-inserted script runs");
assert_equals(getComputedStyle(div).display, "none",
"style remains display: none; after insertion");
}, "Inserting <meta> that uses alternate stylesheets, applies the style " +
"during DOM insertion, and before script runs as a result of any atomic insertions");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and div from a DocumentFragment</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body>
<script>
let script = null;
let scriptParent = null;
let div = null;
let divParent = null;
test(() => {
script = document.createElement("script");
div = document.createElement("div");
script.textContent = `
divParent = div.parentNode;
scriptParent = script.parentNode;
`;
const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(div);
assert_equals(divParent, null);
assert_equals(scriptParent, null);
document.head.appendChild(df);
assert_equals(divParent, scriptParent);
assert_equals(divParent, document.head);
}, "Earlier-inserted scripts can observe the parentNode of later-inserted " +
"nodes, because script runs after DOM insertion completes");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and iframe</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body>
<script>

const kScriptContent = `
state = iframe.contentWindow ? "iframe with content window" : "contentWindow is null";
`;

// This test ensures that a later-inserted script can observe an
// earlier-inserted iframe's contentWindow.
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());

const script = document.createElement("script");
script.textContent = kScriptContent;

const div = document.createElement("div");
div.appendChild(iframe);
div.appendChild(script);

assert_equals(state, "script not run yet");
document.body.appendChild(div);
assert_equals(state, "iframe with content window");
}, "Script inserted after an iframe in the same appendChild() call can " +
"observe the iframe's non-null contentWindow");

// The below tests assert that an earlier-inserted script does not observe a
// later-inserted iframe's contentWindow.
test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());

const script = document.createElement("script");
script.textContent = kScriptContent;

const div = document.createElement("div");
div.appendChild(script);
div.appendChild(iframe);

assert_equals(state, "script not run yet");
document.body.appendChild(div);
assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a div) does not " +
"observe the iframe's contentWindow, since the 'script running' and " +
"'iframe setup' both happen in order, after DOM insertion completes");

test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());

const script = document.createElement("script");
script.textContent = kScriptContent;

const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(iframe);

assert_equals(state, "script not run yet");
document.body.appendChild(df);
assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a DocumentFragment) " +
"does not observe the iframe's contentWindow, since the 'script running' " +
"and 'iframe setup' both happen in order, after DOM insertion completes");

test(t => {
window.state = "script not run yet";
window.iframe = document.createElement("iframe");
t.add_cleanup(() => window.iframe.remove());

const script = document.createElement("script");
script.textContent = kScriptContent;

assert_equals(state, "script not run yet");
document.body.append(script, iframe);

assert_equals(state, "contentWindow is null");
}, "A script inserted atomically before an iframe (using a append() with " +
"multiple arguments) does not observe the iframe's contentWindow, since " +
"the 'script running' and 'iframe setup' both happen in order, after DOM " +
"insertion completes");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting script and source from a fragment</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<video id="media"></video>
<script>
const happened = [];
const media = document.getElementById("media");
test(() => {
const source = document.createElement("source");
const script = document.createElement("script");
script.textContent = `
happened.push(media.networkState);
`;

const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(source);

assert_array_equals(happened, []);
media.appendChild(df);
// This is because immediately during DOM insertion, before the
// post-insertion steps invoke script, `<source>` insertion invokes the
// resource selection algorithm [1] which does this assignment. This
// assignment takes place before earlier-inserted script elements run
// post-insertion.
//
// [1]: https://html.spec.whatwg.org/#concept-media-load-algorithm
assert_array_equals(happened, [HTMLMediaElement.NETWORK_NO_SOURCE]);
}, "Empty <source> immediately sets media.networkState during DOM insertion, " +
"so that an earlier-running script can observe networkState");
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<!doctype html>
<meta charset=utf-8>
<title>Node.appendChild: inserting a script and a style where the script modifies the style</title>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<body>
<script>
// <script> & <style> element tests.
test(() => {
window.happened = [];
window.style = document.createElement("style");
let styleSheet = null;

style.appendChild(new Text("body {}"));
const script = document.createElement("script");
script.textContent = `
styleSheet = style.sheet;
happened.push(style.sheet ? "sheet" : null);
style.appendChild(new Text("body {}"));
happened.push(style.sheet?.cssRules.length);
`;

const div = document.createElement("div");
div.appendChild(script);
div.appendChild(style);

assert_array_equals(happened, []);
document.body.appendChild(div);
assert_array_equals(happened, ["sheet", 2]);
assert_not_equals(style.sheet, styleSheet, "style sheet was created only once");
}, "An earlier-inserted <script> synchronously observes a later-inserted " +
"<style> (via a div) being applied");

test(() => {
window.happened = [];
window.style = document.createElement("style");
let styleSheet = null;

style.appendChild(new Text("body {}"));
const script = document.createElement("script");
script.textContent = `
styleSheet = style.sheet;
happened.push(style.sheet ? "sheet" : null);
style.appendChild(new Text("body {}"));
happened.push(style.sheet?.cssRules.length);
`;

const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(style);

assert_array_equals(happened, []);
document.body.appendChild(df);
assert_array_equals(happened, ["sheet", 2]);
assert_not_equals(style.sheet, styleSheet, "style sheet was created only once");
}, "An earlier-inserted <script> synchronously observes a later-inserted " +
"<style> (via a DocumentFragment) being applied");

// <script> & <link rel=stylesheet> element tests.
test(() => {
window.happened = [];
window.link = document.createElement("link");
link.rel = "stylesheet";
link.href = "data:text/css,";

const script = document.createElement("script");
script.textContent = `
happened.push(link.sheet ? "sheet" : null);
`;

const df = document.createDocumentFragment();
df.appendChild(script);
df.appendChild(link);

assert_array_equals(happened, []);
document.body.appendChild(df);
assert_array_equals(happened, ["sheet"]);
}, "Earlier-inserted <script> (via a DocumentFragment) synchronously " +
"observes a later-inserted <link rel=stylesheet>'s CSSStyleSheet creation");

test(() => {
window.happened = [];
window.link = document.createElement("link");
link.rel = "stylesheet";
link.href = "data:text/css,";

const script = document.createElement("script");
script.textContent = `
happened.push(link.sheet ? "sheet" : null);
`;

const div = document.createElement("div");
div.appendChild(script);
div.appendChild(link);

assert_array_equals(happened, []);
document.body.appendChild(div);
assert_array_equals(happened, ["sheet"]);
}, "Earlier-inserted <script> (via a div) synchronously observes a " +
"later-inserted <link rel=stylesheet>'s CSSStyleSheet creation");

test(() => {
window.happened = [];
window.link = document.createElement("link");
link.rel = "stylesheet";
link.href = "data:text/css,";

const script = document.createElement("script");
script.textContent = `
happened.push(link.sheet ? "sheet" : null);
`;

assert_array_equals(happened, []);
document.body.append(script, link);
assert_array_equals(happened, ["sheet"]);
}, "Earlier-inserted <script> (via a append()) synchronously observes a " +
"later-inserted <link rel=stylesheet>'s CSSStyleSheet creation");
</script>
Loading