-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
DOM: Added a few batch-insertion scenarios that are incompatible acro…
…ss engines (#44658) Co-authored-by: Anthony Ramine <n.oxyde@gmail.com> Co-authored-by: Anne van Kesteren <annevk@annevk.nl> Co-authored-by: Dominic Farolino <domfarolino@gmail.com>
- Loading branch information
1 parent
7a902e2
commit 870bb35
Showing
12 changed files
with
526 additions
and
0 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
...nodes/insertion-removing-steps/Node-appendChild-script-and-button-from-div.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
34 changes: 34 additions & 0 deletions
34
.../insertion-removing-steps/Node-appendChild-script-and-custom-from-fragment.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
35 changes: 35 additions & 0 deletions
35
...emoving-steps/Node-appendChild-script-and-default-style-meta-from-fragment.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
29 changes: 29 additions & 0 deletions
29
...des/insertion-removing-steps/Node-appendChild-script-and-div-from-fragment.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
89 changes: 89 additions & 0 deletions
89
dom/nodes/insertion-removing-steps/Node-appendChild-script-and-iframe.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
33 changes: 33 additions & 0 deletions
33
.../insertion-removing-steps/Node-appendChild-script-and-source-from-fragment.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
118 changes: 118 additions & 0 deletions
118
dom/nodes/insertion-removing-steps/Node-appendChild-script-and-style.tentative.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
Oops, something went wrong.