summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties')
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/dynamic-getter.html88
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-first-letter-marker-multicol.html18
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-tests.js401
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter.html64
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-domnoderemoved-crash.html16
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter-tests.js42
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter.html88
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/multiple-text-nodes.window.js16
-rw-r--r--testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/outertext-setter.html180
9 files changed, 913 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/dynamic-getter.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/dynamic-getter.html
new file mode 100644
index 0000000000..e34fcf5ac1
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/dynamic-getter.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<title>innerText/outerText getter test with dynamic style changes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="container"></div>
+<script>
+let container = document.querySelector('#container');
+
+function testText(html, expectedPlain, msg, mutate) {
+ test(function() {
+ container.innerHTML = html;
+
+ // Cause a flush of style and layout
+ document.body.offsetTop;
+
+ mutate();
+
+ var e = document.getElementById('target');
+ if (!e) {
+ e = container.firstChild;
+ }
+ assert_equals(e.innerText, expectedPlain, "innerText");
+ assert_equals(e.outerText, expectedPlain, "outerText");
+ container.textContext = '';
+ }, msg + ' (' + format_value(html) + ')');
+}
+
+function setStyle(id, attr, value) {
+ let el = document.getElementById(id);
+ if (el) {
+ el.style[attr] = value;
+ }
+}
+
+testText("<div id='target'><div id='child'>abc", "ABC",
+ "text-transform applied to child element", function() {
+ setStyle("child", "text-transform", "uppercase");
+ });
+testText("<div id='parent'><div id='target'>abc", "ABC",
+ "text-transform applied to parent element", function() {
+ setStyle("parent", "text-transform", "uppercase");
+ });
+
+testText("<div id='target'>abc<div id='child'>def", "abc",
+ "display: none applied to child element", function() {
+ setStyle("child", "display", "none");
+ });
+testText("<div id='parent'>invisible<div id='target'>abc", "abc",
+ "display: none applied to parent element", function() {
+ setStyle("parent", "display", "none");
+ });
+
+testText("<div id='target'>abc", "abc\ndef",
+ "insert node into sub-tree", function() {
+ let el = document.getElementById("target");
+ if (el) {
+ let c = document.createTextNode("def");
+ let d = document.createElement("div");
+ d.appendChild(c);
+ el.appendChild(d);
+ }
+ });
+
+testText("<div id='target'>abc<div id='remove'>def", "abc",
+ "remove node from sub-tree", function() {
+ let el = document.getElementById("target");
+ let victim = document.getElementById("remove");
+ if (el && victim) {
+ el.removeChild(victim);
+ }
+ });
+
+testText("<div id='target'>", "abcdef",
+ "insert whole sub-tree", function() {
+ var el = document.getElementById("target");
+ if (el) {
+ var def = document.createTextNode("def");
+ var s = document.createElement("span");
+ s.appendChild(def);
+
+ var abc = document.createTextNode("abc");
+ var d = document.createElement("div");
+ d.appendChild(abc);
+ d.appendChild(s);
+ el.appendChild(d);
+ }
+ });
+</script>
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-first-letter-marker-multicol.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-first-letter-marker-multicol.html
new file mode 100644
index 0000000000..3b579dca1c
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-first-letter-marker-multicol.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<title>Test innerText/outerText for a combination of a list item with ::first-letter in multicol</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#dom-innertext">
+<link rel="help" href="https://crbug.com/1174985">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #item { display: list-item; }
+ #item::first-letter { background: lime; }
+ .col { column-count: 1; }
+</style>
+<div id="item" class="col"><div class="col">PASS</div></div>
+<script>
+ test(() => {
+ assert_equals(item.innerText, "PASS", "innerText");
+ assert_equals(item.outerText, "PASS", "outerText");
+ }, "");
+</script>
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-tests.js b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-tests.js
new file mode 100644
index 0000000000..fd32e8d69a
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter-tests.js
@@ -0,0 +1,401 @@
+testText("<div>abc", "abc", "Simplest possible test");
+
+/**** white-space:normal ****/
+
+testText("<div> abc", "abc", "Leading whitespace removed");
+testText("<div>abc ", "abc", "Trailing whitespace removed");
+testText("<div>abc def", "abc def", "Internal whitespace compressed");
+testText("<div>abc\ndef", "abc def", "\\n converted to space");
+testText("<div>abc\rdef", "abc def", "\\r converted to space");
+testText("<div>abc\tdef", "abc def", "\\t converted to space");
+testText("<div>abc <br>def", "abc\ndef", "Trailing whitespace before hard line break removed");
+testText("<div>abc<br> def", "abc\ndef", "Leading whitespace after hard line break removed");
+
+/**** <pre> ****/
+
+testText("<pre> abc", " abc", "Leading whitespace preserved");
+testText("<pre>abc ", "abc ", "Trailing whitespace preserved");
+testText("<pre>abc def", "abc def", "Internal whitespace preserved");
+testText("<pre>abc\ndef", "abc\ndef", "\\n preserved");
+testText("<pre>abc\rdef", "abc\ndef", "\\r converted to newline");
+testText("<pre>abc\tdef", "abc\tdef", "\\t preserved");
+testText("<div><pre>abc</pre><pre>def</pre>", "abc\ndef", "Two <pre> siblings");
+
+/**** <div style="white-space:pre"> ****/
+
+testText("<div style='white-space:pre'> abc", " abc", "Leading whitespace preserved");
+testText("<div style='white-space:pre'>abc ", "abc ", "Trailing whitespace preserved");
+testText("<div style='white-space:pre'>abc def", "abc def", "Internal whitespace preserved");
+testText("<div style='white-space:pre'>abc\ndef", "abc\ndef", "\\n preserved");
+testText("<div style='white-space:pre'>abc\rdef", "abc\ndef", "\\r converted to newline");
+testText("<div style='white-space:pre'>abc\tdef", "abc\tdef", "\\t preserved");
+
+/**** <span style="white-space:pre"> ****/
+
+testText("<span style='white-space:pre'> abc", " abc", "Leading whitespace preserved");
+testText("<span style='white-space:pre'>abc ", "abc ", "Trailing whitespace preserved");
+testText("<span style='white-space:pre'>abc def", "abc def", "Internal whitespace preserved");
+testText("<span style='white-space:pre'>abc\ndef", "abc\ndef", "\\n preserved");
+testText("<span style='white-space:pre'>abc\rdef", "abc\ndef", "\\r converted to newline");
+testText("<span style='white-space:pre'>abc\tdef", "abc\tdef", "\\t preserved");
+
+/**** <div style="white-space:pre-line"> ****/
+
+testText("<div style='white-space:pre-line'> abc", "abc", "Leading whitespace removed");
+testText("<div style='white-space:pre-line'>abc ", "abc", "Trailing whitespace removed");
+testText("<div style='white-space:pre-line'>abc def", "abc def", "Internal whitespace collapsed");
+testText("<div style='white-space:pre-line'>abc\ndef", "abc\ndef", "\\n preserved");
+testText("<div style='white-space:pre-line'>abc\rdef", "abc\ndef", "\\r converted to newline");
+testText("<div style='white-space:pre-line'>abc\tdef", "abc def", "\\t converted to space");
+
+/**** Collapsing whitespace across element boundaries ****/
+
+testText("<div><span>abc </span> def", "abc def", "Whitespace collapses across element boundaries");
+testText("<div><span>abc </span><span></span> def", "abc def", "Whitespace collapses across element boundaries");
+testText("<div><span>abc </span><span style='white-space:pre'></span> def", "abc def", "Whitespace collapses across element boundaries");
+testText("<div>abc <input> def", "abc def", "Whitespace around <input> should not be collapsed");
+testText("<div>abc <span style='display:inline-block'></span> def", "abc def", "Whitespace around inline-block should not be collapsed");
+testText("<div>abc <span style='display:inline-block'> def </span> ghi", "abc def ghi", "Trailing space at end of inline-block should be collapsed");
+testText("<div><input> <div>abc</div>", "abc", "Whitespace between <input> and block should be collapsed");
+testText("<div><span style='inline-block'></span> <div>abc</div>", "abc", "Whitespace between inline-block and block should be collapsed");
+testText("<div>abc <img> def", "abc def", "Whitespace around <img> should not be collapsed");
+testText("<div>abc <img width=1 height=1> def", "abc def", "Whitespace around <img> should not be collapsed");
+testText("<div><img> abc", " abc", "Leading whitesapce should not be collapsed");
+testText("<div>abc <img>", "abc ", "Trailing whitesapce should not be collapsed");
+testText("<div>abc <b></b> def", "abc def", "Whitespace around empty span should be collapsed");
+testText("<div>abc <b><i></i></b> def", "abc def", "Whitespace around empty spans should be collapsed");
+testText("<div><canvas></canvas> abc", " abc", "<canvas> should not collapse following space");
+testText("<div>abc <img style='display:block'> def", "abc\ndef", "Replaced element <img> with display:block should be treated as block-level");
+testText("<div>abc <canvas style='display:block'></canvas> def", "abc\ndef", "Replaced element <canvas> with display:block should be treated as block-level");
+
+/**** Soft line breaks ****/
+
+testText("<div style='width:0'>abc def", "abc def", "Soft line breaks ignored");
+testText("<div style='width:0'>abc-def", "abc-def", "Soft line break at hyphen ignored");
+testText("<div style='width:0'><span>abc</span> <span>def</span>", "abc def", "Whitespace text node preserved");
+
+/**** Soft line breaks when word-break:break-word is in effect ****/
+/* (based on Testcase #2 at https://bugzilla.mozilla.org/show_bug.cgi?id=1241631) */
+
+testText("<div style='width:1px; word-break:break-word'>Hello Kitty</div>", "Hello Kitty", "Soft breaks ignored in presence of word-break:break-word");
+testText("<div style='width:1px; word-break:break-word'><x>Hello</x> <x>Kitty</x></div>", "Hello Kitty", "Element boundaries ignored for soft break handling (1)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello</x> <x> Kitty</x></div>", "Hello Kitty", "Whitespace collapses across element boundaries at soft break (1)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello</x><x> Kitty</x></div>", "Hello Kitty", "Element boundaries ignored for soft break handling (2)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x> <x>Kitty</x></div>", "Hello Kitty", "Whitespace collapses across element boundaries at soft break (2)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x><x>Kitty</x></div>", "Hello Kitty", "Element boundaries ignored for soft break handling (3)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x><x> Kitty</x></div>", "Hello Kitty", "Whitespace collapses across element boundaries at soft break (3)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x> <x> Kitty</x></div>", "Hello Kitty", "Whitespace collapses across element boundaries at soft break (4)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello</x> Kitty</div>", "Hello Kitty", "Element boundaries ignored for soft break handling (4)");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x>Kitty</div>", "Hello Kitty", "Element boundaries ignored for soft break handling (5)");
+testText("<div style='width:1px; word-break:break-word; text-transform:uppercase'>Hello Kitty</div>", "HELLO KITTY", "Soft breaks ignored, text-transform applied");
+testText("<div style='width:1px; word-break:break-word'>Hello<br> Kitty</div>", "Hello\nKitty", "<br> returned as newline, following space collapsed");
+testText("<div style='width:1px; word-break:break-word'>Hello <br>Kitty</div>", "Hello\nKitty", "<br> returned as newline, preceding space collapsed");
+testText("<div style='width:1px; word-break:break-word'><x>Hello </x> <br> <x> Kitty</x></div>", "Hello\nKitty", "<br> returned as newline, adjacent spaces collapsed across element boundaries");
+
+/**** first-line/first-letter ****/
+
+testText("<div class='first-line-uppercase' style='width:0'>abc def", "ABC def", "::first-line styles applied");
+testText("<div class='first-letter-uppercase' style='width:0'>abc def", "Abc def", "::first-letter styles applied");
+testText("<div class='first-letter-float' style='width:0'>abc def", "abc def", "::first-letter float ignored");
+
+/**** &nbsp; ****/
+
+testText("<div>&nbsp;", "\xA0", "&nbsp; preserved");
+
+/**** display:none ****/
+
+testText("<div style='display:none'>abc", "abc", "display:none container");
+testText("<div style='display:none'>abc def", "abc def", "No whitespace compression in display:none container");
+testText("<div style='display:none'> abc def ", " abc def ", "No removal of leading/trailing whitespace in display:none container");
+testText("<div>123<span style='display:none'>abc", "123", "display:none child not rendered");
+testText("<div style='display:none'><span id='target'>abc", "abc", "display:none container with non-display-none target child");
+testTextInSVG("<div id='target'>abc", "abc", "non-display-none child of svg");
+testTextInSVG("<div style='display:none' id='target'>abc", "abc", "display:none child of svg");
+testTextInSVG("<div style='display:none'><div id='target'>abc", "abc", "child of display:none child of svg");
+
+/**** display:contents ****/
+
+if (CSS.supports("display", "contents")) {
+ testText("<div style='display:contents'>abc", "abc", "display:contents container");
+ testText("<div><div style='display:contents'>abc", "abc", "display:contents container");
+ testText("<div>123<span style='display:contents'>abc", "123abc", "display:contents rendered");
+ testText("<div style='display:contents'> ", "", "display:contents not processed via textContent");
+ testText("<div><div style='display:contents'> ", "", "display:contents not processed via textContent");
+}
+
+/**** visibility:hidden ****/
+
+testText("<div style='visibility:hidden'>abc", "", "visibility:hidden container");
+testText("<div>123<span style='visibility:hidden'>abc", "123", "visibility:hidden child not rendered");
+testText("<div style='visibility:hidden'>123<span style='visibility:visible'>abc", "abc", "visibility:visible child rendered");
+
+/**** visibility:collapse ****/
+
+testText("<table><tbody style='visibility:collapse'><tr><td>abc", "", "visibility:collapse row-group");
+testText("<table><tr style='visibility:collapse'><td>abc", "", "visibility:collapse row");
+testText("<table><tr><td style='visibility:collapse'>abc", "", "visibility:collapse cell");
+testText("<table><tbody style='visibility:collapse'><tr><td style='visibility:visible'>abc", "abc",
+ "visibility:collapse row-group with visible cell");
+testText("<table><tr style='visibility:collapse'><td style='visibility:visible'>abc", "abc",
+ "visibility:collapse row with visible cell");
+testText("<div style='display:flex'><span style='visibility:collapse'>1</span><span>2</span></div>",
+ "2", "visibility:collapse honored on flex item");
+testText("<div style='display:grid'><span style='visibility:collapse'>1</span><span>2</span></div>",
+ "2", "visibility:collapse honored on grid item");
+
+/**** opacity:0 ****/
+
+testText("<div style='opacity:0'>abc", "abc", "opacity:0 container");
+testText("<div style='opacity:0'>abc def", "abc def", "Whitespace compression in opacity:0 container");
+testText("<div style='opacity:0'> abc def ", "abc def", "Remove leading/trailing whitespace in opacity:0 container");
+testText("<div>123<span style='opacity:0'>abc", "123abc", "opacity:0 child rendered");
+
+/**** generated content ****/
+
+testText("<div class='before'>", "", "Generated content not included");
+testText("<div><div class='before'>", "", "Generated content on child not included");
+
+/**** innerText on replaced elements ****/
+
+testText("<button>abc", "abc", "<button> contents preserved");
+testText("<fieldset>abc", "abc", "<fieldset> contents preserved");
+testText("<fieldset><legend>abc", "abc", "<fieldset> <legend> contents preserved");
+testText("<input type='text' value='abc'>", "", "<input> contents ignored");
+testText("<textarea>abc", "", "<textarea> contents ignored");
+testText("<iframe>abc", "", "<iframe> contents ignored");
+testText("<iframe><div id='target'>abc", "", "<iframe> contents ignored");
+testText("<iframe src='data:text/html,abc'>", "","<iframe> subdocument ignored");
+testText("<audio style='display:block'>abc", "", "<audio> contents ignored");
+testText("<audio style='display:block'><source id='target' class='poke' style='display:block'>", "abc", "<audio> contents ok for element not being rendered");
+testText("<audio style='display:block'><source id='target' class='poke' style='display:none'>", "abc", "<audio> contents ok for element not being rendered");
+testText("<video>abc", "", "<video> contents ignored");
+testText("<video style='display:block'><source id='target' class='poke' style='display:block'>", "abc", "<video> contents ok for element not being rendered");
+testText("<video style='display:block'><source id='target' class='poke' style='display:none'>", "abc", "<video> contents ok for element not being rendered");
+testText("<canvas>abc", "", "<canvas> contents ignored");
+testText("<canvas><div id='target'>abc", "abc", "<canvas><div id='target'> contents ok for element not being rendered");
+testText("<img alt='abc'>", "", "<img> alt text ignored");
+testText("<img src='about:blank' class='poke'>", "", "<img> contents ignored");
+testText("<div><svg><text>abc</text></svg></div>", "abc", "<svg> text contents preserved");
+testText("<div><svg><defs><text>abc</text></defs></svg></div>", "", "<svg><defs> text contents ignored");
+testText("<div><svg><stop>abc</stop></svg></div>", "", "<svg> non-rendered text ignored");
+testText("<svg><foreignObject><span id='target'>abc</span></foreignObject></svg>", "abc", "<foreignObject> contents preserved");
+
+/**** <select>, <optgroup> & <option> ****/
+
+testText("<select size='1'><option>abc</option><option>def", "abc\ndef", "<select size='1'> contents of options preserved");
+testText("<select size='2'><option>abc</option><option>def", "abc\ndef", "<select size='2'> contents of options preserved");
+testText("<select size='1'><option id='target'>abc</option><option>def", "abc", "<select size='1'> contents of target option preserved");
+testText("<select size='2'><option id='target'>abc</option><option>def", "abc", "<select size='2'> contents of target option preserved");
+testText("<div>a<select></select>bc", "abc", "empty <select>");
+testText("<div>a<select><optgroup></select>bc", "a\nbc", "empty <optgroup> in <select>");
+testText("<div>a<select><option></select>bc", "a\nbc", "empty <option> in <select>");
+testText("<select class='poke'></select>", "", "<select> containing text node child");
+testText("<select><optgroup class='poke-optgroup'></select>", "", "<optgroup> containing <optgroup>");
+testText("<select><optgroup><option>abc</select>", "abc", "<optgroup> containing <option>");
+testText("<select><option class='poke-div'>123</select>", "123\nabc", "<div> in <option>");
+testText("<div>a<optgroup></optgroup>bc", "a\nbc", "empty <optgroup> in <div>");
+testText("<div>a<optgroup>123</optgroup>bc", "a\nbc", "<optgroup> in <div>");
+testText("<div>a<option></option>bc", "a\nbc", "empty <option> in <div>");
+testText("<div>a<option>123</option>bc", "a\n123\nbc", "<option> in <div>");
+
+/**** innerText on replaced element children ****/
+
+testText("<div><button>abc", "abc", "<button> contents preserved");
+testText("<div><fieldset>abc", "abc", "<fieldset> contents preserved");
+testText("<div><fieldset><legend>abc", "abc", "<fieldset> <legend> contents preserved");
+testText("<div><input type='text' value='abc'>", "", "<input> contents ignored");
+testText("<div><textarea>abc", "", "<textarea> contents ignored");
+testText("<div><select size='1'><option>abc</option><option>def", "abc\ndef", "<select size='1'> contents of options preserved");
+testText("<div><select size='2'><option>abc</option><option>def", "abc\ndef", "<select size='2'> contents of options preserved");
+testText("<div><iframe>abc", "", "<iframe> contents ignored");
+testText("<div><iframe src='data:text/html,abc'>", ""," <iframe> subdocument ignored");
+testText("<div><audio>abc", "", "<audio> contents ignored");
+testText("<div><video>abc", "", "<video> contents ignored");
+testText("<div><canvas>abc", "", "<canvas> contents ignored");
+testText("<div><img alt='abc'>", "", "<img> alt text ignored");
+
+/**** Lines around blocks ****/
+
+testText("<div>123<div>abc</div>def", "123\nabc\ndef", "Newline at block boundary");
+testText("<div>123<span style='display:block'>abc</span>def", "123\nabc\ndef", "Newline at display:block boundary");
+testText("<div>abc<div></div>def", "abc\ndef", "Empty block induces single line break");
+testText("<div>abc<div></div><div></div>def", "abc\ndef", "Consecutive empty blocks ignored");
+testText("<div><p>abc", "abc", "No blank lines around <p> alone");
+testText("<div><p>abc</p> ", "abc", "No blank lines around <p> followed by only collapsible whitespace");
+testText("<div> <p>abc</p>", "abc", "No blank lines around <p> preceded by only collapsible whitespace");
+testText("<div><p>abc<p>def", "abc\n\ndef", "Blank line between consecutive <p>s");
+testText("<div><p>abc</p> <p>def", "abc\n\ndef", "Blank line between consecutive <p>s separated only by collapsible whitespace");
+testText("<div><p>abc</p><div></div><p>def", "abc\n\ndef", "Blank line between consecutive <p>s separated only by empty block");
+testText("<div><p>abc</p><div>123</div><p>def", "abc\n\n123\n\ndef", "Blank lines between <p>s separated by non-empty block");
+testText("<div>abc<div><p>123</p></div>def", "abc\n\n123\n\ndef", "Blank lines around a <p> in its own block");
+testText("<div>abc<p>def", "abc\n\ndef", "Blank line before <p>");
+testText("<div><p>abc</p>def", "abc\n\ndef", "Blank line after <p>");
+testText("<div><p>abc<p></p><p></p><p>def", "abc\n\ndef", "One blank line between <p>s, ignoring empty <p>s");
+testText("<div style='visibility:hidden'><p><span style='visibility:visible'>abc</span></p>\n<div style='visibility:visible'>def</div>",
+ "abc\ndef", "Invisible <p> doesn't induce extra line breaks");
+testText("<div>abc<div style='margin:2em'>def", "abc\ndef", "No blank lines around <div> with margin");
+testText("<div>123<span style='display:inline-block'>abc</span>def", "123abcdef", "No newlines at display:inline-block boundary");
+testText("<div>123<span style='display:inline-block'> abc </span>def", "123abcdef", "Leading/trailing space removal at display:inline-block boundary");
+testText("<div>123<p style='margin:0px'>abc</p>def", "123\n\nabc\n\ndef", "Blank lines around <p> even without margin");
+testText("<div>123<h1>abc</h1>def", "123\nabc\ndef", "No blank lines around <h1>");
+testText("<div>123<h2>abc</h2>def", "123\nabc\ndef", "No blank lines around <h2>");
+testText("<div>123<h3>abc</h3>def", "123\nabc\ndef", "No blank lines around <h3>");
+testText("<div>123<h4>abc</h4>def", "123\nabc\ndef", "No blank lines around <h4>");
+testText("<div>123<h5>abc</h5>def", "123\nabc\ndef", "No blank lines around <h5>");
+testText("<div>123<h6>abc</h6>def", "123\nabc\ndef", "No blank lines around <h6>");
+
+/**** Spans ****/
+
+testText("<div>123<span>abc</span>def", "123abcdef", "<span> boundaries are irrelevant");
+testText("<div>123 <span>abc</span> def", "123 abc def", "<span> boundaries are irrelevant");
+testText("<div style='width:0'>123 <span>abc</span> def", "123 abc def", "<span> boundaries are irrelevant");
+testText("<div>123<em>abc</em>def", "123abcdef", "<em> gets no special treatment");
+testText("<div>123<b>abc</b>def", "123abcdef", "<b> gets no special treatment");
+testText("<div>123<i>abc</i>def", "123abcdef", "<i> gets no special treatment");
+testText("<div>123<strong>abc</strong>def", "123abcdef", "<strong> gets no special treatment");
+testText("<div>123<tt>abc</tt>def", "123abcdef", "<tt> gets no special treatment");
+testText("<div>123<code>abc</code>def", "123abcdef", "<code> gets no special treatment");
+
+/**** Soft hyphen ****/
+
+testText("<div>abc&shy;def", "abc\xADdef", "soft hyphen preserved");
+testText("<div style='width:0'>abc&shy;def", "abc\xADdef", "soft hyphen preserved");
+
+/**** Tables ****/
+
+testText("<div><table style='white-space:pre'> <td>abc</td> </table>", "abc", "Ignoring non-rendered table whitespace");
+testText("<div><table><tr><td>abc<td>def</table>", "abc\tdef", "Tab-separated table cells");
+testText("<div><table><tr><td>abc<td><td>def</table>", "abc\t\tdef", "Tab-separated table cells including empty cells");
+testText("<div><table><tr><td>abc<td><td></table>", "abc\t\t", "Tab-separated table cells including trailing empty cells");
+testText("<div><table><tr><td>abc<tr><td>def</table>", "abc\ndef", "Newline-separated table rows");
+testText("<div>abc<table><td>def</table>ghi", "abc\ndef\nghi", "Newlines around table");
+testText("<div><table style='border-collapse:collapse'><tr><td>abc<td>def</table>", "abc\tdef",
+ "Tab-separated table cells in a border-collapse table");
+testText("<div><table><tfoot>x</tfoot><tbody>y</tbody></table>", "xy", "tfoot not reordered");
+testText("<table><tfoot><tr><td>footer</tfoot><thead><tr><td style='visibility:collapse'>thead</thead><tbody><tr><td>tbody</tbody></table>",
+ "footer\n\ntbody", "");
+testText("<table><tr><td id=target>abc</td><td>def</td>", "abc", "No tab on table-cell itself");
+testText("<table><tr id=target><td>abc</td><td>def</td></tr><tr id=target><td>ghi</td><td>jkl</td></tr>", "abc\tdef", "No newline on table-row itself");
+
+/**** Table captions ****/
+
+testText("<div><table><tr><td>abc<caption>def</caption></table>", "abc\ndef", "Newline between cells and caption");
+
+/**** display:table ****/
+
+testText("<div><div class='table'><span class='cell'>abc</span>\n<span class='cell'>def</span></div>",
+ "abc\tdef", "Tab-separated table cells");
+testText("<div><div class='table'><span class='row'><span class='cell'>abc</span></span>\n<span class='row'><span class='cell'>def</span></span></div>",
+ "abc\ndef", "Newline-separated table rows");
+testText("<div>abc<div class='table'><span class='cell'>def</span></div>ghi", "abc\ndef\nghi", "Newlines around table");
+
+/**** display:inline-table ****/
+
+testText("<div><div class='itable'><span class='cell'>abc</span>\n<span class='cell'>def</span></div>", "abc\tdef", "Tab-separated table cells");
+testText("<div><div class='itable'><span class='row'><span class='cell'>abc</span></span>\n<span class='row'><span class='cell'>def</span></span></div>",
+ "abc\ndef", "Newline-separated table rows");
+testText("<div>abc<div class='itable'><span class='cell'>def</span></div>ghi", "abcdefghi", "No newlines around inline-table");
+testText("<div>abc<div class='itable'><span class='row'><span class='cell'>def</span></span>\n<span class='row'><span class='cell'>123</span></span></div>ghi",
+ "abcdef\n123ghi", "Single newline in two-row inline-table");
+
+/**** display:table-row/table-cell/table-caption ****/
+testText("<div style='display:table-row'>", "", "display:table-row on the element itself");
+testText("<div style='display:table-cell'>", "", "display:table-cell on the element itself");
+testText("<div style='display:table-caption'>", "", "display:table-caption on the element itself");
+
+/**** Lists ****/
+
+testText("<div><ol><li>abc", "abc", "<ol> list items get no special treatment");
+testText("<div><ul><li>abc", "abc", "<ul> list items get no special treatment");
+
+/**** Misc elements ****/
+
+testText("<div><script style='display:block'>abc", "abc", "display:block <script> is rendered");
+testText("<div><style style='display:block'>abc", "abc", "display:block <style> is rendered");
+testText("<div><noscript style='display:block'>abc", "", "display:block <noscript> is not rendered (it's not parsed!)");
+testText("<div><template style='display:block'>abc", "",
+ "display:block <template> contents are not rendered (the contents are in a different document)");
+testText("<div>abc<br>def", "abc\ndef", "<br> induces line break");
+testText("<div>abc<br>", "abc\n", "<br> induces line break even at end of block");
+testText("<div><br class='poke'>", "\n", "<br> content ignored");
+testText("<div>abc<hr>def", "abc\ndef", "<hr> induces line break");
+testText("<div>abc<hr><hr>def", "abc\ndef", "<hr><hr> induces just one line break");
+testText("<div>abc<hr><hr><hr>def", "abc\ndef", "<hr><hr><hr> induces just one line break");
+testText("<div><hr class='poke'>", "abc", "<hr> content rendered");
+testText("<div>abc<!--comment-->def", "abcdef", "comment ignored");
+testText("<br>", "", "<br>");
+testText("<p>", "", "empty <p>");
+testText("<div>", "", "empty <div>");
+
+/**** text-transform ****/
+
+testText("<div><div style='text-transform:uppercase'>abc", "ABC", "text-transform is applied");
+testText("<div><div style='text-transform:uppercase'>Ma\xDF", "MASS", "text-transform handles es-zet");
+testText("<div><div lang='tr' style='text-transform:uppercase'>i \u0131", "\u0130 I", "text-transform handles Turkish casing");
+
+/**** block-in-inline ****/
+
+testText("<div>abc<span>123<div>456</div>789</span>def", "abc123\n456\n789def", "block-in-inline doesn't add unnecessary newlines");
+
+/**** floats ****/
+
+testText("<div>abc<div style='float:left'>123</div>def", "abc\n123\ndef", "floats induce a block boundary");
+testText("<div>abc<span style='float:left'>123</span>def", "abc\n123\ndef", "floats induce a block boundary");
+testText("<div style='float:left'>123", "123", "float on the element itself");
+
+/**** position ****/
+
+testText("<div>abc<div style='position:absolute'>123</div>def", "abc\n123\ndef", "position:absolute induces a block boundary");
+testText("<div>abc<span style='position:absolute'>123</span>def", "abc\n123\ndef", "position:absolute induces a block boundary");
+testText("<div style='position:absolute'>123", "123", "position:absolute on the element itself");
+testText("<div>abc<div style='position:relative'>123</div>def", "abc\n123\ndef", "position:relative has no effect");
+testText("<div>abc<span style='position:relative'>123</span>def", "abc123def", "position:relative has no effect");
+
+/**** text-overflow:ellipsis ****/
+
+testText("<div style='overflow:hidden'>abc", "abc", "overflow:hidden ignored");
+// XXX Chrome skips content with width:0 or height:0 and overflow:hidden;
+// should we spec that?
+testText("<div style='width:0; overflow:hidden'>abc", "abc", "overflow:hidden ignored even with zero width");
+testText("<div style='height:0; overflow:hidden'>abc", "abc", "overflow:hidden ignored even with zero height");
+testText("<div style='width:0; overflow:hidden; text-overflow:ellipsis'>abc", "abc", "text-overflow:ellipsis ignored");
+
+/**** Support on non-HTML elements ****/
+
+testText("<svg>abc", undefined, "innerText not supported on SVG elements");
+testText("<math>abc", undefined, "innerText not supported on MathML elements");
+
+/**** Ruby ****/
+
+testText("<div><ruby>abc<rt>def</rt></ruby>", "abcdef", "<rt> and no <rp>");
+testText("<div><ruby>abc<rp>(</rp><rt>def</rt><rp>)</rp></ruby>", "abcdef", "<rp>");
+testText("<div><rp>abc</rp>", "", "Lone <rp>");
+testText("<div><rp style='visibility:hidden'>abc</rp>", "", "visibility:hidden <rp>");
+testText("<div><rp style='display:block'>abc</rp>def", "abc\ndef", "display:block <rp>");
+testText("<div><rp style='display:block'> abc </rp>def", "abc\ndef", "display:block <rp> with whitespace");
+testText("<div><select class='poke-rp'></select>", "", "<rp> in a <select>");
+
+/**** Shadow DOM ****/
+
+if ("attachShadow" in document.body) {
+ testText("<div class='shadow'>", "", "Shadow DOM contents ignored");
+ testText("<div><div class='shadow'>", "", "Shadow DOM contents ignored");
+}
+
+/**** Flexbox ****/
+
+if (CSS.supports('display', 'flex')) {
+ testText("<div style='display:flex'><div style='order:1'>1</div><div>2</div></div>",
+ "1\n2", "CSS 'order' property ignored");
+ testText("<div style='display:flex'><span>1</span><span>2</span></div>",
+ "1\n2", "Flex items blockified");
+}
+
+/**** Grid ****/
+
+if (CSS.supports('display', 'grid')) {
+ testText("<div style='display:grid'><div style='order:1'>1</div><div>2</div></div>",
+ "1\n2", "CSS 'order' property ignored");
+ testText("<div style='display:grid'><span>1</span><span>2</span></div>",
+ "1\n2", "Grid items blockified");
+}
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter.html
new file mode 100644
index 0000000000..ffb3d34fe9
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/getter.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<title>innerText/outerText getter test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.before::before { content:'abc'; }
+.table { display:table; }
+.itable { display:inline-table; }
+.row { display:table-row; }
+.cell { display:table-cell; }
+.first-line-uppercase::first-line { text-transform:uppercase; }
+.first-letter-uppercase::first-letter { text-transform:uppercase; }
+.first-letter-float::first-letter { float:left; }
+</style>
+<div id="container"></div>
+<svg id="svgContainer"></svg>
+<script>
+let container = document.querySelector('#container');
+let svgContainer = document.querySelector('#svgContainer');
+function testText(html, expectedPlain, msg) {
+ textTextInContainer(container, html, expectedPlain, msg);
+}
+function testTextInSVG(html, expectedPlain, msg) {
+ textTextInContainer(svgContainer, html, expectedPlain, msg);
+}
+function textTextInContainer(cont, html, expectedPlain, msg) {
+ test(function() {
+ container.innerHTML = html;
+ if (cont != container) {
+ while (container.firstChild) {
+ cont.appendChild(container.firstChild);
+ }
+ }
+ var e = document.getElementById('target');
+ if (!e) {
+ e = cont.firstChild;
+ }
+ var pokes = document.getElementsByClassName('poke');
+ for (var i = 0; i < pokes.length; ++i) {
+ pokes[i].textContent = 'abc';
+ }
+ ['rp', 'optgroup', 'div'].forEach(function(tag) {
+ pokes = document.getElementsByClassName('poke-' + tag);
+ for (var i = 0; i < pokes.length; ++i) {
+ var el = document.createElement(tag);
+ el.textContent = "abc";
+ pokes[i].appendChild(el);
+ }
+ });
+ var shadows = document.getElementsByClassName('shadow');
+ for (var i = 0; i < shadows.length; ++i) {
+ var s = shadows[i].attachShadow({ mode: "open" });
+ s.textContent = 'abc';
+ }
+ while (e && e.nodeType != Node.ELEMENT_NODE) {
+ e = e.nextSibling;
+ }
+ assert_equals(e.innerText, expectedPlain, "innerText");
+ assert_equals(e.outerText, expectedPlain, "outerText");
+ cont.textContent = '';
+ }, msg + ' (' + format_value(html) + ')');
+}
+</script>
+<script src="getter-tests.js"></script>
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-domnoderemoved-crash.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-domnoderemoved-crash.html
new file mode 100644
index 0000000000..94043caf69
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-domnoderemoved-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1411135">
+
+<div id=parentelement><div id=childelement>hello world</div></div>
+
+<script>
+ let removed = false;
+ childelement.addEventListener('DOMNodeRemoved', () => {
+ if (!removed) {
+ removed = true;
+ childelement.remove();
+ }
+ });
+ parentelement.innerText = 'hello world';
+</script>
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter-tests.js b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter-tests.js
new file mode 100644
index 0000000000..99ae5ec185
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter-tests.js
@@ -0,0 +1,42 @@
+testText("<div>", "abc", "abc", "Simplest possible test");
+testHTML("<div>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in non-white-space:pre elements");
+testHTML("<pre>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in <pre> element");
+testHTML("<textarea>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in <textarea> element");
+testHTML("<div style='white-space:pre'>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in white-space:pre element");
+testHTML("<div>", "abc\rdef", "abc<br>def", "CRs convert to <br> in non-white-space:pre elements");
+testHTML("<pre>", "abc\rdef", "abc<br>def", "CRs convert to <br> in <pre> element");
+testHTML("<div>", "abc\r\ndef", "abc<br>def", "Newline/CR pair converts to <br> in non-white-space:pre element");
+testHTML("<div>", "abc\n\ndef", "abc<br><br>def", "Newline/newline pair converts to two <br>s in non-white-space:pre element");
+testHTML("<div>", "abc\r\rdef", "abc<br><br>def", "CR/CR pair converts to two <br>s in non-white-space:pre element");
+testHTML("<div style='white-space:pre'>", "abc\rdef", "abc<br>def", "CRs convert to <br> in white-space:pre element");
+testText("<div>", "abc<def", "abc<def", "< preserved");
+testText("<div>", "abc>def", "abc>def", "> preserved");
+testText("<div>", "abc&", "abc&", "& preserved");
+testText("<div>", "abc\"def", "abc\"def", "\" preserved");
+testText("<div>", "abc\'def", "abc\'def", "\' preserved");
+testHTML("<svg>", "abc", "", "innerText not supported on SVG elements");
+testHTML("<math>", "abc", "", "innerText not supported on MathML elements");
+testText("<div>", "abc\0def", "abc\0def", "Null characters preserved");
+testText("<div>", "abc\tdef", "abc\tdef", "Tabs preserved");
+testText("<div>", " abc", " abc", "Leading whitespace preserved");
+testText("<div>", "abc ", "abc ", "Trailing whitespace preserved");
+testText("<div>", "abc def", "abc def", "Whitespace not compressed");
+testText("<div>abc\n\n", "abc", "abc", "Existing text deleted");
+testText("<div><br>", "abc", "abc", "Existing <br> deleted");
+testHTML("<div>", "", "", "Assigning the empty string");
+testHTML("<div>", null, "", "Assigning null");
+testHTML("<div>", undefined, "undefined", "Assigning undefined");
+testHTML("<div>", "\rabc", "<br>abc", "Start with CR");
+testHTML("<div>", "\nabc", "<br>abc", "Start with LF");
+testHTML("<div>", "\r\nabc", "<br>abc", "Start with CRLF");
+testHTML("<div>", "abc\r", "abc<br>", "End with CR");
+testHTML("<div>", "abc\n", "abc<br>", "End with LF");
+testHTML("<div>", "abc\r\n", "abc<br>", "End with CRLF");
+
+// Setting innerText on these should not throw
+["area", "base", "basefont", "bgsound", "br", "col", "embed", "frame", "hr",
+"image", "img", "input", "keygen", "link", "menuitem", "meta", "param",
+"source", "track", "wbr", "colgroup", "frameset", "head", "html", "table",
+"tbody", "tfoot", "thead", "tr"].forEach(function(tag) {
+ testText(document.createElement(tag), "abc", "abc", "innerText on <" + tag + "> element");
+});
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter.html
new file mode 100644
index 0000000000..a835a164ed
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/innertext-setter.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<title>innerText setter test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="container"></div>
+<script>
+// As of March 2017, WebKit and Blink have inconsistent results depending on
+// rendered or not. setupTest() tests a rendered case, and setupTestDetached()
+// tests a not-rendered case.
+
+function setupTest(context, plain) {
+ var container = document.getElementById("container");
+ // context is either a string or an element node
+ if (typeof context === "string") {
+ container.innerHTML = context;
+ } else {
+ container.innerHTML = "";
+ container.appendChild(context);
+ }
+ var e = container.firstChild;
+ while (e && e.nodeType != Node.ELEMENT_NODE) {
+ e = e.nextSibling;
+ }
+ e.offsetWidth;
+ var oldChild = e.firstChild;
+ e.innerText = plain;
+ return [e, oldChild];
+}
+
+function setupTestDetached(context, plain) {
+ var detachedContainer = document.createElement("div");
+ // context is either a string or an element node
+ if (typeof context === "string") {
+ detachedContainer.innerHTML = context;
+ } else {
+ detachedContainer.innerHTML = "";
+ detachedContainer.appendChild(context);
+ }
+ var e = detachedContainer.firstChild;
+ while (e && e.nodeType != Node.ELEMENT_NODE) {
+ e = e.nextSibling;
+ }
+ var oldChild = e.firstChild;
+ e.innerText = plain;
+ return [e, oldChild];
+}
+
+function assertNewSingleTextNode(newChild, expectedText, oldChild) {
+ assert_not_equals(newChild, null, "Should have a child");
+ assert_equals(newChild.nodeType, Node.TEXT_NODE, "Child should be a text node");
+ assert_equals(newChild.nextSibling, null, "Should have only one child");
+ assert_equals(newChild.data, expectedText);
+ assert_not_equals(newChild, oldChild, "Child should be a *new* text node");
+}
+
+function assertNoEmptyTextChild(parent) {
+ for (var child = parent.firstChild; child; child = child.nextSibling) {
+ if (child.nodeType === Node.TEXT_NODE) {
+ assert_not_equals(child.data, "", "Should not have empty text nodes");
+ }
+ }
+}
+
+function testText(context, plain, expectedText, msg) {
+ test(function(){
+ var arr = setupTest(context, plain);
+ assertNewSingleTextNode(arr[0].firstChild, expectedText, arr[1]);
+ }, msg);
+ test(function() {
+ var arr = setupTestDetached(context, plain);
+ assertNewSingleTextNode(arr[0].firstChild, expectedText, arr[1]);
+ }, msg + ", detached");
+}
+
+function testHTML(context, plain, expectedHTML, msg) {
+ test(function(){
+ var e = setupTest(context, plain)[0];
+ assert_equals(e.innerHTML, expectedHTML);
+ assertNoEmptyTextChild(e);
+ }, msg);
+ test(function() {
+ var e = setupTestDetached(context, plain)[0];
+ assert_equals(e.innerHTML, expectedHTML);
+ assertNoEmptyTextChild(e);
+ }, msg + ", detached");
+}
+</script>
+<script src="innertext-setter-tests.js"></script>
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/multiple-text-nodes.window.js b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/multiple-text-nodes.window.js
new file mode 100644
index 0000000000..07c55e9669
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/multiple-text-nodes.window.js
@@ -0,0 +1,16 @@
+async_test(t => {
+ const div = document.body.appendChild(document.createElement("div"));
+ t.add_cleanup(() => div.remove());
+ const t1 = div.appendChild(new Text(""));
+ div.appendChild(new Text(""));
+ const t2 = div.appendChild(new Text(""));
+ const t3 = div.appendChild(new Text(""));
+ t.step_timeout(() => {
+ t1.data = "X";
+ t2.data = " ";
+ t3.data = "Y";
+ assert_equals(div.innerText, "X Y", "innerText");
+ assert_equals(div.outerText, "X Y", "outerText");
+ t.done();
+ }, 100);
+}, "Ensure multiple text nodes get rendered properly");
diff --git a/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/outertext-setter.html b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/outertext-setter.html
new file mode 100644
index 0000000000..953bedc9a8
--- /dev/null
+++ b/testing/web-platform/tests/html/dom/elements/the-innertext-and-outertext-properties/outertext-setter.html
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<title>outerText setter test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<ul>
+ <li>A <span id="testReplacePrevious">B</span></li>
+ <li><span id="testReplaceFollowing">A</span> B</li>
+ <li>A <span id="testReplaceBoth">B</span> C</li>
+ <li><span id="testRemove">Testing</span> removing node using outerText.</li>
+ <li><span id="testNewlines">Replace this child with lots of newlines</span></li>
+</ul>
+
+<div id="container"></div>
+
+<script>
+"use strict";
+
+test(() => {
+ const node = document.getElementById("testReplacePrevious");
+ const parent = node.parentNode;
+
+ node.outerText = "Replaced";
+
+ assert_equals(parent.innerHTML, "A Replaced");
+ assert_equals(parent.childNodes.length, 1, "It got merged with the previous text node");
+}, "Replacing a node and merging with the previous text node");
+
+test(() => {
+ const node = document.getElementById("testReplaceFollowing");
+ const parent = node.parentNode;
+
+ node.outerText = "Replaced";
+
+ assert_equals(parent.innerHTML, "Replaced B");
+ assert_equals(parent.childNodes.length, 1, "It got merged with the following text node");
+}, "Replacing a node and merging with the following text node");
+
+test(() => {
+ const node = document.getElementById("testReplaceBoth");
+ const parent = node.parentNode;
+
+ node.outerText = "Replaced";
+
+ assert_equals(parent.innerHTML, "A Replaced C");
+ assert_equals(parent.childNodes.length, 1, "It got merged with the previous and following text node");
+}, "Replacing a node and merging with the previous and following text node");
+
+test(t => {
+ const container = document.getElementById("container");
+ t.add_cleanup(() => { container.textContent = ""; });
+
+ container.append("A", "B", document.createElement("span"), "D", "E");
+ assert_equals(container.childNodes.length, 5, "Precondition check: five separate nodes");
+
+ const node = container.childNodes[2];
+ node.outerText = "Replaced";
+
+ assert_equals(container.innerHTML, "ABReplacedDE");
+ assert_equals(container.childNodes.length, 3, "It got merged with the previous and following text node");
+ assert_equals(container.childNodes[0].data, "A");
+ assert_equals(container.childNodes[1].data, "BReplacedD");
+ assert_equals(container.childNodes[2].data, "E");
+}, "Only merges with the previous and following text nodes, does not completely normalize");
+
+test(t => {
+ const container = document.getElementById("container");
+ t.add_cleanup(() => { container.textContent = ""; });
+
+ container.append(document.createElement("span"));
+ const node = container.childNodes[0];
+ node.outerText = "";
+
+ assert_equals(container.childNodes.length, 1, "Creates text node for the empty string");
+ assert_equals(container.childNodes[0].data, "");
+}, "Empty string");
+
+test(t => {
+ const container = document.getElementById("container");
+ t.add_cleanup(() => { container.textContent = ""; });
+
+ container.append("1", "2", document.createElement("span"), "3", "4");
+ const node = container.childNodes[2];
+ node.outerText = "";
+
+ assert_equals(container.childNodes.length, 3, "It got merged with the previous and following text node");
+ assert_equals(container.childNodes[0].data, "1");
+ assert_equals(container.childNodes[1].data, "23");
+ assert_equals(container.childNodes[2].data, "4");
+}, "Empty string with surrounding text nodes");
+
+test(t => {
+ const node = document.getElementById("testNewlines");
+ const parent = node.parentNode;
+
+ node.outerText = "\n\r\n\r";
+
+ assert_equals(parent.innerHTML, "<br><br><br>");
+ assert_equals(parent.childNodes.length, 3);
+ assert_equals(parent.childNodes[0].localName, "br", "node 1");
+ assert_equals(parent.childNodes[1].localName, "br", "node 2");
+ assert_equals(parent.childNodes[2].localName, "br", "node 3");
+}, "Setting outerText to a bunch of newlines creates a bunch of <br>s with no text nodes");
+
+test(() => {
+ const node = document.getElementById("testRemove");
+ const parent = node.parentNode;
+
+ node.outerText = "";
+
+ assert_equals(parent.innerHTML, " removing node using outerText.");
+}, "Removing a node");
+
+test(() => {
+ const node = document.createElement("span");
+
+ assert_throws_dom("NoModificationAllowedError", () => { node.outerText = ""; });
+}, "Detached node");
+
+testText("<div>", "abc", "abc", "Simplest possible test");
+testHTML("<div>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in non-white-space:pre elements");
+testHTML("<pre>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in <pre> element");
+testHTML("<textarea>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in <textarea> element");
+testHTML("<div style='white-space:pre'>", "abc\ndef", "abc<br>def", "Newlines convert to <br> in white-space:pre element");
+testHTML("<div>", "abc\rdef", "abc<br>def", "CRs convert to <br> in non-white-space:pre elements");
+testHTML("<pre>", "abc\rdef", "abc<br>def", "CRs convert to <br> in <pre> element");
+testHTML("<div>", "abc\r\ndef", "abc<br>def", "Newline/CR pair converts to <br> in non-white-space:pre element");
+testHTML("<div>", "abc\n\ndef", "abc<br><br>def", "Newline/newline pair converts to two <br>s in non-white-space:pre element");
+testHTML("<div>", "abc\r\rdef", "abc<br><br>def", "CR/CR pair converts to two <br>s in non-white-space:pre element");
+testHTML("<div style='white-space:pre'>", "abc\rdef", "abc<br>def", "CRs convert to <br> in white-space:pre element");
+testText("<div>", "abc<def", "abc<def", "< preserved");
+testText("<div>", "abc>def", "abc>def", "> preserved");
+testText("<div>", "abc&", "abc&", "& preserved");
+testText("<div>", "abc\"def", "abc\"def", "\" preserved");
+testText("<div>", "abc\'def", "abc\'def", "\' preserved");
+testHTML("<svg>", "abc", "<svg></svg>", "outerText not supported on SVG elements");
+testHTML("<math>", "abc", "<math></math>", "outerText not supported on MathML elements");
+testText("<div>", "abc\0def", "abc\0def", "Null characters preserved");
+testText("<div>", "abc\tdef", "abc\tdef", "Tabs preserved");
+testText("<div>", " abc", " abc", "Leading whitespace preserved");
+testText("<div>", "abc ", "abc ", "Trailing whitespace preserved");
+testText("<div>", "abc def", "abc def", "Whitespace not compressed");
+testText("<div>abc\n\n", "abc", "abc", "Existing text deleted");
+testText("<div><br>", "abc", "abc", "Existing <br> deleted");
+testHTML("<div>", "", "", "Assigning the empty string");
+testHTML("<div>", null, "", "Assigning null");
+testHTML("<div>", undefined, "undefined", "Assigning undefined");
+testHTML("<div>", "\rabc", "<br>abc", "Start with CR");
+testHTML("<div>", "\nabc", "<br>abc", "Start with LF");
+testHTML("<div>", "\r\nabc", "<br>abc", "Start with CRLF");
+testHTML("<div>", "abc\r", "abc<br>", "End with CR");
+testHTML("<div>", "abc\n", "abc<br>", "End with LF");
+testHTML("<div>", "abc\r\n", "abc<br>", "End with CRLF");
+
+function testText(startingHTML, outerText, expected, description) {
+ test(t => {
+ const container = document.getElementById("container");
+ t.add_cleanup(() => { container.textContent = ""; });
+
+ container.innerHTML = startingHTML;
+ const elementToReplace = container.firstElementChild;
+
+ elementToReplace.outerText = outerText;
+ assert_equals(container.textContent, expected);
+ }, description);
+}
+
+function testHTML(startingHTML, outerText, expected, description) {
+ test(t => {
+ const container = document.getElementById("container");
+ t.add_cleanup(() => { container.textContent = ""; });
+
+ container.innerHTML = startingHTML;
+ const elementToReplace = container.firstElementChild;
+
+ elementToReplace.outerText = outerText;
+ assert_equals(container.innerHTML, expected);
+ }, description);
+}
+</script>