mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
LibWeb: Implement HTMLElement.innerText closer to spec
And here's the wild part: instead of cloning WPT tests, import the relevant WPT tests that this fixes into our own test suite. This works by adding a small Ladybird-specific callback in resources/testharnessreport.js (which is what that file is meant for!) Note that these run as text tests, and so they must signal the runner when they are done. Tests using the "usual" WPT harness should just work, but tests that do something more freestyle will need manual signaling if they are to be imported. I've also increased the test timeout here from 30 to 60 seconds, to accommodate the larger WPT-style tests.
This commit is contained in:
parent
afe74afa9e
commit
ec0838b84e
Notes:
github-actions[bot]
2024-10-27 11:11:23 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/ec0838b84eb Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1944
25 changed files with 6638 additions and 21 deletions
|
@ -7,3 +7,5 @@ Userland/Libraries/LibJS/Tests/builtins/DisposableStack/DisposableStack.prototyp
|
||||||
Userland/Libraries/LibJS/Tests/modules/top-level-dispose.mjs
|
Userland/Libraries/LibJS/Tests/modules/top-level-dispose.mjs
|
||||||
Userland/Libraries/LibJS/Tests/using-declaration.js
|
Userland/Libraries/LibJS/Tests/using-declaration.js
|
||||||
Userland/Libraries/LibJS/Tests/using-for-loops.js
|
Userland/Libraries/LibJS/Tests/using-for-loops.js
|
||||||
|
|
||||||
|
Tests/LibWeb/Text/input/wpt-import
|
||||||
|
|
|
@ -75,7 +75,7 @@ struct TestCompletion {
|
||||||
|
|
||||||
using TestPromise = Core::Promise<TestCompletion>;
|
using TestPromise = Core::Promise<TestCompletion>;
|
||||||
|
|
||||||
constexpr inline int DEFAULT_TIMEOUT_MS = 30000; // 30sec
|
constexpr inline int DEFAULT_TIMEOUT_MS = 60'000;
|
||||||
|
|
||||||
ErrorOr<void> run_tests(Core::AnonymousBuffer const& theme, Gfx::IntSize window_size);
|
ErrorOr<void> run_tests(Core::AnonymousBuffer const& theme, Gfx::IntSize window_size);
|
||||||
void run_dump_test(HeadlessWebView&, Test&, URL::URL const&, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS);
|
void run_dump_test(HeadlessWebView&, Test&, URL::URL const&, int timeout_in_milliseconds = DEFAULT_TIMEOUT_MS);
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
before after
|
before
|
||||||
|
after
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
hello
|
hello
|
||||||
|
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
Fallback
|
|
||||||
|
Fallback
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 7 tests
|
||||||
|
|
||||||
|
7 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass text-transform applied to child element ("<div id='target'><div id='child'>abc")
|
||||||
|
Pass text-transform applied to parent element ("<div id='parent'><div id='target'>abc")
|
||||||
|
Pass display: none applied to child element ("<div id='target'>abc<div id='child'>def")
|
||||||
|
Pass display: none applied to parent element ("<div id='parent'>invisible<div id='target'>abc")
|
||||||
|
Pass insert node into sub-tree ("<div id='target'>abc")
|
||||||
|
Pass remove node from sub-tree ("<div id='target'>abc<div id='remove'>def")
|
||||||
|
Pass insert whole sub-tree ("<div id='target'>")
|
|
@ -0,0 +1,11 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 1 tests
|
||||||
|
|
||||||
|
1 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass Test innerText/outerText for a combination of a list item with ::first-letter in multicol
|
|
@ -0,0 +1,282 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 271 tests
|
||||||
|
|
||||||
|
209 Pass
|
||||||
|
62 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass Simplest possible test ("<div>abc")
|
||||||
|
Fail Leading whitespace removed ("<div> abc") assert_equals: innerText expected "abc" but got " abc"
|
||||||
|
Fail Trailing whitespace removed ("<div>abc ") assert_equals: innerText expected "abc" but got "abc "
|
||||||
|
Pass Internal whitespace compressed ("<div>abc def")
|
||||||
|
Pass \n converted to space ("<div>abc\ndef")
|
||||||
|
Pass \r converted to space ("<div>abc\rdef")
|
||||||
|
Pass \t converted to space ("<div>abc\tdef")
|
||||||
|
Fail Trailing whitespace before hard line break removed ("<div>abc <br>def") assert_equals: innerText expected "abc\ndef" but got "abc \ndef"
|
||||||
|
Fail Leading whitespace after hard line break removed ("<div>abc<br> def") assert_equals: innerText expected "abc\ndef" but got "abc\n def"
|
||||||
|
Pass Leading whitespace preserved ("<pre> abc")
|
||||||
|
Pass Trailing whitespace preserved ("<pre>abc ")
|
||||||
|
Pass Internal whitespace preserved ("<pre>abc def")
|
||||||
|
Pass \n preserved ("<pre>abc\ndef")
|
||||||
|
Pass \r converted to newline ("<pre>abc\rdef")
|
||||||
|
Pass \t preserved ("<pre>abc\tdef")
|
||||||
|
Pass Two <pre> siblings ("<div><pre>abc</pre><pre>def</pre>")
|
||||||
|
Pass Leading whitespace preserved ("<div style='white-space:pre'> abc")
|
||||||
|
Pass Trailing whitespace preserved ("<div style='white-space:pre'>abc ")
|
||||||
|
Pass Internal whitespace preserved ("<div style='white-space:pre'>abc def")
|
||||||
|
Pass \n preserved ("<div style='white-space:pre'>abc\ndef")
|
||||||
|
Pass \r converted to newline ("<div style='white-space:pre'>abc\rdef")
|
||||||
|
Pass \t preserved ("<div style='white-space:pre'>abc\tdef")
|
||||||
|
Pass Leading whitespace preserved ("<span style='white-space:pre'> abc")
|
||||||
|
Pass Trailing whitespace preserved ("<span style='white-space:pre'>abc ")
|
||||||
|
Pass Internal whitespace preserved ("<span style='white-space:pre'>abc def")
|
||||||
|
Pass \n preserved ("<span style='white-space:pre'>abc\ndef")
|
||||||
|
Pass \r converted to newline ("<span style='white-space:pre'>abc\rdef")
|
||||||
|
Pass \t preserved ("<span style='white-space:pre'>abc\tdef")
|
||||||
|
Fail Leading whitespace removed ("<div style='white-space:pre-line'> abc") assert_equals: innerText expected "abc" but got " abc"
|
||||||
|
Fail Trailing whitespace removed ("<div style='white-space:pre-line'>abc ") assert_equals: innerText expected "abc" but got "abc "
|
||||||
|
Pass Internal whitespace collapsed ("<div style='white-space:pre-line'>abc def")
|
||||||
|
Fail \n preserved ("<div style='white-space:pre-line'>abc\ndef") assert_equals: innerText expected "abc\ndef" but got "abc def"
|
||||||
|
Fail \r converted to newline ("<div style='white-space:pre-line'>abc\rdef") assert_equals: innerText expected "abc\ndef" but got "abc def"
|
||||||
|
Pass \t converted to space ("<div style='white-space:pre-line'>abc\tdef")
|
||||||
|
Fail Whitespace collapses across element boundaries ("<div><span>abc </span> def") assert_equals: innerText expected "abc def" but got "abc def"
|
||||||
|
Fail Whitespace collapses across element boundaries ("<div><span>abc </span><span></span> def") assert_equals: innerText expected "abc def" but got "abc def"
|
||||||
|
Fail Whitespace collapses across element boundaries ("<div><span>abc </span><span style='white-space:pre'></span> def") assert_equals: innerText expected "abc def" but got "abc def"
|
||||||
|
Pass Whitespace around <input> should not be collapsed ("<div>abc <input> def")
|
||||||
|
Pass Whitespace around inline-block should not be collapsed ("<div>abc <span style='display:inline-block'></span> def")
|
||||||
|
Fail Trailing space at end of inline-block should be collapsed ("<div>abc <span style='display:inline-block'> def </span> ghi") assert_equals: innerText expected "abc def ghi" but got "abc def ghi"
|
||||||
|
Pass Whitespace around inline-flex should not be collapsed ("<div>abc <span style='display:inline-flex'></span> def")
|
||||||
|
Fail Trailing space at end of inline-flex should be collapsed ("<div>abc <span style='display:inline-flex'> def </span> ghi") assert_equals: innerText expected "abc def ghi" but got "abc def ghi"
|
||||||
|
Pass Whitespace around inline-grid should not be collapsed ("<div>abc <span style='display:inline-grid'></span> def")
|
||||||
|
Fail Trailing space at end of grid-flex should be collapsed ("<div>abc <span style='display:inline-grid'> def </span> ghi") assert_equals: innerText expected "abc def ghi" but got "abc def ghi"
|
||||||
|
Fail Whitespace between <input> and block should be collapsed ("<div><input> <div>abc</div>") assert_equals: innerText expected "abc" but got " \nabc"
|
||||||
|
Fail Whitespace between inline-block and block should be collapsed ("<div><span style='inline-block'></span> <div>abc</div>") assert_equals: innerText expected "abc" but got " \nabc"
|
||||||
|
Fail Whitespace between inline-flex and block should be collapsed ("<div><span style='inline-flex'></span> <div>abc</div>") assert_equals: innerText expected "abc" but got " \nabc"
|
||||||
|
Fail Whitespace between inline-grid and block should be collapsed ("<div><span style='inline-grid'></span> <div>abc</div>") assert_equals: innerText expected "abc" but got " \nabc"
|
||||||
|
Pass Whitespace around <img> should not be collapsed ("<div>abc <img> def")
|
||||||
|
Pass Whitespace around <img> should not be collapsed ("<div>abc <img width=1 height=1> def")
|
||||||
|
Pass Leading whitesapce should not be collapsed ("<div><img> abc")
|
||||||
|
Pass Trailing whitesapce should not be collapsed ("<div>abc <img>")
|
||||||
|
Fail Whitespace around empty span should be collapsed ("<div>abc <b></b> def") assert_equals: innerText expected "abc def" but got "abc def"
|
||||||
|
Fail Whitespace around empty spans should be collapsed ("<div>abc <b><i></i></b> def") assert_equals: innerText expected "abc def" but got "abc def"
|
||||||
|
Pass <canvas> should not collapse following space ("<div><canvas></canvas> abc")
|
||||||
|
Fail Replaced element <img> with display:block should be treated as block-level ("<div>abc <img style='display:block'> def") assert_equals: innerText expected "abc\ndef" but got "abc \n def"
|
||||||
|
Fail Replaced element <canvas> with display:block should be treated as block-level ("<div>abc <canvas style='display:block'></canvas> def") assert_equals: innerText expected "abc\ndef" but got "abc \n def"
|
||||||
|
Pass Soft line breaks ignored ("<div style='width:0'>abc def")
|
||||||
|
Pass Soft line break at hyphen ignored ("<div style='width:0'>abc-def")
|
||||||
|
Pass Whitespace text node preserved ("<div style='width:0'><span>abc</span> <span>def</span>")
|
||||||
|
Pass Soft breaks ignored in presence of word-break:break-word ("<div style='width:1px; word-break:break-word'>Hello Kitty</div>")
|
||||||
|
Pass Element boundaries ignored for soft break handling (1) ("<div style='width:1px; word-break:break-word'><x>Hello</x> <x>Kitty</x></div>")
|
||||||
|
Fail Whitespace collapses across element boundaries at soft break (1) ("<div style='width:1px; word-break:break-word'><x>Hello</x> <x> Kitty</x></div>") assert_equals: innerText expected "Hello Kitty" but got "Hello Kitty"
|
||||||
|
Pass Element boundaries ignored for soft break handling (2) ("<div style='width:1px; word-break:break-word'><x>Hello</x><x> Kitty</x></div>")
|
||||||
|
Fail Whitespace collapses across element boundaries at soft break (2) ("<div style='width:1px; word-break:break-word'><x>Hello </x> <x>Kitty</x></div>") assert_equals: innerText expected "Hello Kitty" but got "Hello Kitty"
|
||||||
|
Pass Element boundaries ignored for soft break handling (3) ("<div style='width:1px; word-break:break-word'><x>Hello </x><x>Kitty</x></div>")
|
||||||
|
Fail Whitespace collapses across element boundaries at soft break (3) ("<div style='width:1px; word-break:break-word'><x>Hello </x><x> Kitty</x></div>") assert_equals: innerText expected "Hello Kitty" but got "Hello Kitty"
|
||||||
|
Fail Whitespace collapses across element boundaries at soft break (4) ("<div style='width:1px; word-break:break-word'><x>Hello </x> <x> Kitty</x></div>") assert_equals: innerText expected "Hello Kitty" but got "Hello Kitty"
|
||||||
|
Pass Element boundaries ignored for soft break handling (4) ("<div style='width:1px; word-break:break-word'><x>Hello</x> Kitty</div>")
|
||||||
|
Pass Element boundaries ignored for soft break handling (5) ("<div style='width:1px; word-break:break-word'><x>Hello </x>Kitty</div>")
|
||||||
|
Pass Soft breaks ignored, text-transform applied ("<div style='width:1px; word-break:break-word; text-transform:uppercase'>Hello Kitty</div>")
|
||||||
|
Fail <br> returned as newline, following space collapsed ("<div style='width:1px; word-break:break-word'>Hello<br> Kitty</div>") assert_equals: innerText expected "Hello\nKitty" but got "Hello\n Kitty"
|
||||||
|
Fail <br> returned as newline, preceding space collapsed ("<div style='width:1px; word-break:break-word'>Hello <br>Kitty</div>") assert_equals: innerText expected "Hello\nKitty" but got "Hello \nKitty"
|
||||||
|
Fail <br> returned as newline, adjacent spaces collapsed across element boundaries ("<div style='width:1px; word-break:break-word'><x>Hello </x> <br> <x> Kitty</x></div>") assert_equals: innerText expected "Hello\nKitty" but got "Hello \n Kitty"
|
||||||
|
Fail ::first-line styles applied ("<div class='first-line-uppercase' style='width:0'>abc def") assert_equals: innerText expected "ABC def" but got "abc def"
|
||||||
|
Fail ::first-letter styles applied ("<div class='first-letter-uppercase' style='width:0'>abc def") assert_equals: innerText expected "Abc def" but got "abc def"
|
||||||
|
Pass ::first-letter float ignored ("<div class='first-letter-float' style='width:0'>abc def")
|
||||||
|
Pass preserved ("<div> ")
|
||||||
|
Pass display:none container ("<div style='display:none'>abc")
|
||||||
|
Pass No whitespace compression in display:none container ("<div style='display:none'>abc def")
|
||||||
|
Pass No removal of leading/trailing whitespace in display:none container ("<div style='display:none'> abc def ")
|
||||||
|
Pass display:none child not rendered ("<div>123<span style='display:none'>abc")
|
||||||
|
Pass display:none container with non-display-none target child ("<div style='display:none'><span id='target'>abc")
|
||||||
|
Pass non-display-none child of svg ("<div id='target'>abc")
|
||||||
|
Pass display:none child of svg ("<div style='display:none' id='target'>abc")
|
||||||
|
Pass child of display:none child of svg ("<div style='display:none'><div id='target'>abc")
|
||||||
|
Pass display:contents container ("<div style='display:contents'>abc")
|
||||||
|
Pass display:contents container ("<div><div style='display:contents'>abc")
|
||||||
|
Pass display:contents rendered ("<div>123<span style='display:contents'>abc")
|
||||||
|
Fail display:contents not processed via textContent ("<div style='display:contents'> ") assert_equals: innerText expected "" but got " "
|
||||||
|
Fail display:contents not processed via textContent ("<div><div style='display:contents'> ") assert_equals: innerText expected "" but got " "
|
||||||
|
Pass visibility:hidden container ("<div style='visibility:hidden'>abc")
|
||||||
|
Pass visibility:hidden child not rendered ("<div>123<span style='visibility:hidden'>abc")
|
||||||
|
Pass visibility:visible child rendered ("<div style='visibility:hidden'>123<span style='visibility:visible'>abc")
|
||||||
|
Pass visibility:collapse row-group ("<table><tbody style='visibility:collapse'><tr><td>abc")
|
||||||
|
Pass visibility:collapse row ("<table><tr style='visibility:collapse'><td>abc")
|
||||||
|
Pass visibility:collapse cell ("<table><tr><td style='visibility:collapse'>abc")
|
||||||
|
Pass visibility:collapse row-group with visible cell ("<table><tbody style='visibility:collapse'><tr><td style='visibility:visible'>abc")
|
||||||
|
Pass visibility:collapse row with visible cell ("<table><tr style='visibility:collapse'><td style='visibility:visible'>abc")
|
||||||
|
Pass visibility:collapse honored on flex item ("<div style='display:flex'><span style='visibility:collapse'>1</span><span>2</span></div>")
|
||||||
|
Pass visibility:collapse honored on grid item ("<div style='display:grid'><span style='visibility:collapse'>1</span><span>2</span></div>")
|
||||||
|
Pass opacity:0 container ("<div style='opacity:0'>abc")
|
||||||
|
Pass Whitespace compression in opacity:0 container ("<div style='opacity:0'>abc def")
|
||||||
|
Fail Remove leading/trailing whitespace in opacity:0 container ("<div style='opacity:0'> abc def ") assert_equals: innerText expected "abc def" but got " abc def "
|
||||||
|
Pass opacity:0 child rendered ("<div>123<span style='opacity:0'>abc")
|
||||||
|
Pass Generated content not included ("<div class='before'>")
|
||||||
|
Pass Generated content on child not included ("<div><div class='before'>")
|
||||||
|
Pass <button> contents preserved ("<button>abc")
|
||||||
|
Pass <fieldset> contents preserved ("<fieldset>abc")
|
||||||
|
Pass <fieldset> <legend> contents preserved ("<fieldset><legend>abc")
|
||||||
|
Pass <input> contents ignored ("<input type='text' value='abc'>")
|
||||||
|
Pass <textarea> contents ignored ("<textarea>abc")
|
||||||
|
Pass <iframe> contents ignored ("<iframe>abc")
|
||||||
|
Pass <iframe> contents ignored ("<iframe><div id='target'>abc")
|
||||||
|
Pass <iframe> subdocument ignored ("<iframe src='data:text/html,abc'>")
|
||||||
|
Pass <audio> contents ignored ("<audio style='display:block'>abc")
|
||||||
|
Pass <audio> contents ok for element not being rendered ("<audio style='display:block'><source id='target' class='poke' style='display:block'>")
|
||||||
|
Pass <audio> contents ok for element not being rendered ("<audio style='display:block'><source id='target' class='poke' style='display:none'>")
|
||||||
|
Pass <video> contents ignored ("<video>abc")
|
||||||
|
Pass <video> contents ok for element not being rendered ("<video style='display:block'><source id='target' class='poke' style='display:block'>")
|
||||||
|
Pass <video> contents ok for element not being rendered ("<video style='display:block'><source id='target' class='poke' style='display:none'>")
|
||||||
|
Pass <canvas> contents ignored ("<canvas>abc")
|
||||||
|
Pass <canvas><div id='target'> contents ok for element not being rendered ("<canvas><div id='target'>abc")
|
||||||
|
Pass <img> alt text ignored ("<img alt='abc'>")
|
||||||
|
Pass <img> contents ignored ("<img src='about:blank' class='poke'>")
|
||||||
|
Pass <svg> text contents preserved ("<div><svg><text>abc</text></svg></div>")
|
||||||
|
Pass <svg><defs> text contents ignored ("<div><svg><defs><text>abc</text></defs></svg></div>")
|
||||||
|
Fail <svg> non-rendered text ignored ("<div><svg><stop>abc</stop></svg></div>") assert_equals: innerText expected "" but got "abc"
|
||||||
|
Pass <foreignObject> contents preserved ("<svg><foreignObject><span id='target'>abc</span></foreignObject></svg>")
|
||||||
|
Fail <select size='1'> contents of options preserved ("<select size='1'><option>abc</option><option>def") assert_equals: innerText expected "abc\ndef" but got ""
|
||||||
|
Fail <select size='2'> contents of options preserved ("<select size='2'><option>abc</option><option>def") assert_equals: innerText expected "abc\ndef" but got ""
|
||||||
|
Pass <select size='1'> contents of target option preserved ("<select size='1'><option id='target'>abc</option><option>def")
|
||||||
|
Pass <select size='2'> contents of target option preserved ("<select size='2'><option id='target'>abc</option><option>def")
|
||||||
|
Pass empty <select> ("<div>a<select></select>bc")
|
||||||
|
Fail empty <optgroup> in <select> ("<div>a<select><optgroup></select>bc") assert_equals: innerText expected "a\nbc" but got "abc"
|
||||||
|
Fail empty <option> in <select> ("<div>a<select><option></select>bc") assert_equals: innerText expected "a\nbc" but got "abc"
|
||||||
|
Pass <select> containing text node child ("<select class='poke'></select>")
|
||||||
|
Pass <optgroup> containing <optgroup> ("<select><optgroup class='poke-optgroup'></select>")
|
||||||
|
Fail <optgroup> containing <option> ("<select><optgroup><option>abc</select>") assert_equals: innerText expected "abc" but got ""
|
||||||
|
Fail <div> in <option> ("<select><option class='poke-div'>123</select>") assert_equals: innerText expected "123\nabc" but got ""
|
||||||
|
Fail empty <optgroup> in <div> ("<div>a<optgroup></optgroup>bc") assert_equals: innerText expected "a\nbc" but got "abc"
|
||||||
|
Fail <optgroup> in <div> ("<div>a<optgroup>123</optgroup>bc") assert_equals: innerText expected "a\nbc" but got "a123bc"
|
||||||
|
Fail empty <option> in <div> ("<div>a<option></option>bc") assert_equals: innerText expected "a\nbc" but got "abc"
|
||||||
|
Fail <option> in <div> ("<div>a<option>123</option>bc") assert_equals: innerText expected "a\n123\nbc" but got "abc"
|
||||||
|
Pass <button> contents preserved ("<div><button>abc")
|
||||||
|
Pass <fieldset> contents preserved ("<div><fieldset>abc")
|
||||||
|
Pass <fieldset> <legend> contents preserved ("<div><fieldset><legend>abc")
|
||||||
|
Pass <input> contents ignored ("<div><input type='text' value='abc'>")
|
||||||
|
Pass <textarea> contents ignored ("<div><textarea>abc")
|
||||||
|
Fail <select size='1'> contents of options preserved ("<div><select size='1'><option>abc</option><option>def") assert_equals: innerText expected "abc\ndef" but got ""
|
||||||
|
Fail <select size='2'> contents of options preserved ("<div><select size='2'><option>abc</option><option>def") assert_equals: innerText expected "abc\ndef" but got ""
|
||||||
|
Pass <iframe> contents ignored ("<div><iframe>abc")
|
||||||
|
Pass <iframe> subdocument ignored ("<div><iframe src='data:text/html,abc'>")
|
||||||
|
Pass <audio> contents ignored ("<div><audio>abc")
|
||||||
|
Pass <video> contents ignored ("<div><video>abc")
|
||||||
|
Pass <canvas> contents ignored ("<div><canvas>abc")
|
||||||
|
Pass <object> contents ignored ("<div><object>abc")
|
||||||
|
Pass <img> alt text ignored ("<div><img alt='abc'>")
|
||||||
|
Pass Newline at block boundary ("<div>123<div>abc</div>def")
|
||||||
|
Pass Newline at display:block boundary ("<div>123<span style='display:block'>abc</span>def")
|
||||||
|
Pass Empty block induces single line break ("<div>abc<div></div>def")
|
||||||
|
Pass Consecutive empty blocks ignored ("<div>abc<div></div><div></div>def")
|
||||||
|
Pass No blank lines around <p> alone ("<div><p>abc")
|
||||||
|
Fail No blank lines around <p> followed by only collapsible whitespace ("<div><p>abc</p> ") assert_equals: innerText expected "abc" but got "abc\n\n "
|
||||||
|
Fail No blank lines around <p> preceded by only collapsible whitespace ("<div> <p>abc</p>") assert_equals: innerText expected "abc" but got " \n\nabc"
|
||||||
|
Pass Blank line between consecutive <p>s ("<div><p>abc<p>def")
|
||||||
|
Fail Blank line between consecutive <p>s separated only by collapsible whitespace ("<div><p>abc</p> <p>def") assert_equals: innerText expected "abc\n\ndef" but got "abc\n\n \n\ndef"
|
||||||
|
Pass Blank line between consecutive <p>s separated only by empty block ("<div><p>abc</p><div></div><p>def")
|
||||||
|
Pass Blank lines between <p>s separated by non-empty block ("<div><p>abc</p><div>123</div><p>def")
|
||||||
|
Pass Blank lines around a <p> in its own block ("<div>abc<div><p>123</p></div>def")
|
||||||
|
Pass Blank line before <p> ("<div>abc<p>def")
|
||||||
|
Pass Blank line after <p> ("<div><p>abc</p>def")
|
||||||
|
Pass One blank line between <p>s, ignoring empty <p>s ("<div><p>abc<p></p><p></p><p>def")
|
||||||
|
Pass Invisible <p> doesn't induce extra line breaks ("<div style='visibility:hidden'><p><span style='visibility:visible'>abc</span></p>\n<div style='visibility:visible'>def</div>")
|
||||||
|
Pass No blank lines around <div> with margin ("<div>abc<div style='margin:2em'>def")
|
||||||
|
Pass No newlines at display:inline-block boundary ("<div>123<span style='display:inline-block'>abc</span>def")
|
||||||
|
Fail Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: innerText expected "123abcdef" but got "123 abc def"
|
||||||
|
Fail Leading/trailing space removal at display:inline-flex boundary ("<div>123<span style='display:inline-flex'> abc </span>def") assert_equals: innerText expected "123abcdef" but got "123 abc def"
|
||||||
|
Fail Leading/trailing space removal at display:inline-grid boundary ("<div>123<span style='display:inline-grid'> abc </span>def") assert_equals: innerText expected "123abcdef" but got "123 abc def"
|
||||||
|
Pass Blank lines around <p> even without margin ("<div>123<p style='margin:0px'>abc</p>def")
|
||||||
|
Pass No blank lines around <h1> ("<div>123<h1>abc</h1>def")
|
||||||
|
Pass No blank lines around <h2> ("<div>123<h2>abc</h2>def")
|
||||||
|
Pass No blank lines around <h3> ("<div>123<h3>abc</h3>def")
|
||||||
|
Pass No blank lines around <h4> ("<div>123<h4>abc</h4>def")
|
||||||
|
Pass No blank lines around <h5> ("<div>123<h5>abc</h5>def")
|
||||||
|
Pass No blank lines around <h6> ("<div>123<h6>abc</h6>def")
|
||||||
|
Pass 2 blank lines around <p> even when display:block ("<div>123<p style='display:block'>abc")
|
||||||
|
Pass 2 blank lines around <p> even when display:inline-block ("<div>123<p style='display:inline-block'>abc")
|
||||||
|
Pass <span> boundaries are irrelevant ("<div>123<span>abc</span>def")
|
||||||
|
Pass <span> boundaries are irrelevant ("<div>123 <span>abc</span> def")
|
||||||
|
Pass <span> boundaries are irrelevant ("<div style='width:0'>123 <span>abc</span> def")
|
||||||
|
Pass <em> gets no special treatment ("<div>123<em>abc</em>def")
|
||||||
|
Pass <b> gets no special treatment ("<div>123<b>abc</b>def")
|
||||||
|
Pass <i> gets no special treatment ("<div>123<i>abc</i>def")
|
||||||
|
Pass <strong> gets no special treatment ("<div>123<strong>abc</strong>def")
|
||||||
|
Pass <tt> gets no special treatment ("<div>123<tt>abc</tt>def")
|
||||||
|
Pass <code> gets no special treatment ("<div>123<code>abc</code>def")
|
||||||
|
Pass soft hyphen preserved ("<div>abc­def")
|
||||||
|
Pass soft hyphen preserved ("<div style='width:0'>abc­def")
|
||||||
|
Fail Ignoring non-rendered table whitespace ("<div><table style='white-space:pre'> <td>abc</td> </table>") assert_equals: innerText expected "abc" but got " abc\t "
|
||||||
|
Pass Tab-separated table cells ("<div><table><tr><td>abc<td>def</table>")
|
||||||
|
Pass Tab-separated table cells including empty cells ("<div><table><tr><td>abc<td><td>def</table>")
|
||||||
|
Pass Tab-separated table cells including trailing empty cells ("<div><table><tr><td>abc<td><td></table>")
|
||||||
|
Pass Newline-separated table rows ("<div><table><tr><td>abc<tr><td>def</table>")
|
||||||
|
Pass Newlines around table ("<div>abc<table><td>def</table>ghi")
|
||||||
|
Pass Tab-separated table cells in a border-collapse table ("<div><table style='border-collapse:collapse'><tr><td>abc<td>def</table>")
|
||||||
|
Pass tfoot not reordered ("<div><table><tfoot>x</tfoot><tbody>y</tbody></table>")
|
||||||
|
Fail ("<table><tfoot><tr><td>footer</tfoot><thead><tr><td style='visibility:collapse'>thead</thead><tbody><tr><td>tbody</tbody></table>") assert_equals: innerText expected "footer\n\ntbody" but got "footertbody"
|
||||||
|
Pass No tab on table-cell itself ("<table><tr><td id=target>abc</td><td>def</td>")
|
||||||
|
Pass No newline on table-row itself ("<table><tr id=target><td>abc</td><td>def</td></tr><tr id=target><td>ghi</td><td>jkl</td></tr>")
|
||||||
|
Pass Newline between cells and caption ("<div><table><tr><td>abc<caption>def</caption></table>")
|
||||||
|
Fail Tab-separated table cells ("<div><div class='table'><span class='cell'>abc</span>\n<span class='cell'>def</span></div>") assert_equals: innerText expected "abc\tdef" but got "abc\t def"
|
||||||
|
Fail Newline-separated table rows ("<div><div class='table'><span class='row'><span class='cell'>abc</span></span>\n<span class='row'><span class='cell'>def</span></span></div>") assert_equals: innerText expected "abc\ndef" but got "abc\n def"
|
||||||
|
Pass Newlines around table ("<div>abc<div class='table'><span class='cell'>def</span></div>ghi")
|
||||||
|
Fail Tab-separated table cells ("<div><div class='itable'><span class='cell'>abc</span>\n<span class='cell'>def</span></div>") assert_equals: innerText expected "abc\tdef" but got "abc\t def"
|
||||||
|
Fail Newline-separated table rows ("<div><div class='itable'><span class='row'><span class='cell'>abc</span></span>\n<span class='row'><span class='cell'>def</span></span></div>") assert_equals: innerText expected "abc\ndef" but got "abc\n def"
|
||||||
|
Pass No newlines around inline-table ("<div>abc<div class='itable'><span class='cell'>def</span></div>ghi")
|
||||||
|
Fail Single newline in two-row inline-table ("<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") assert_equals: innerText expected "abcdef\n123ghi" but got "abcdef\n 123ghi"
|
||||||
|
Pass display:table-row on the element itself ("<div style='display:table-row'>")
|
||||||
|
Pass display:table-cell on the element itself ("<div style='display:table-cell'>")
|
||||||
|
Pass display:table-caption on the element itself ("<div style='display:table-caption'>")
|
||||||
|
Pass <ol> list items get no special treatment ("<div><ol><li>abc")
|
||||||
|
Pass <ul> list items get no special treatment ("<div><ul><li>abc")
|
||||||
|
Pass display:block <script> is rendered ("<div><script style='display:block'>abc")
|
||||||
|
Pass display:block <style> is rendered ("<div><style style='display:block'>abc")
|
||||||
|
Pass display:block <noscript> is not rendered (it's not parsed!) ("<div><noscript style='display:block'>abc")
|
||||||
|
Pass display:block <template> contents are not rendered (the contents are in a different document) ("<div><template style='display:block'>abc")
|
||||||
|
Pass <br> induces line break ("<div>abc<br>def")
|
||||||
|
Pass <br> induces line break even at end of block ("<div>abc<br>")
|
||||||
|
Pass <br> content ignored ("<div><br class='poke'>")
|
||||||
|
Pass <hr> induces line break ("<div>abc<hr>def")
|
||||||
|
Pass <hr><hr> induces just one line break ("<div>abc<hr><hr>def")
|
||||||
|
Pass <hr><hr><hr> induces just one line break ("<div>abc<hr><hr><hr>def")
|
||||||
|
Pass <hr> content rendered ("<div><hr class='poke'>")
|
||||||
|
Pass comment ignored ("<div>abc<!--comment-->def")
|
||||||
|
Pass <br> ("<br>")
|
||||||
|
Pass empty <p> ("<p>")
|
||||||
|
Pass empty <div> ("<div>")
|
||||||
|
Pass unopened <details> ignored ("<div><details><summary>abc</summary>123")
|
||||||
|
Pass opened <details> content shown ("<div><details open><summary>abc</summary>123")
|
||||||
|
Pass text-transform is applied ("<div><div style='text-transform:uppercase'>abc")
|
||||||
|
Pass text-transform handles es-zet ("<div><div style='text-transform:uppercase'>Maß")
|
||||||
|
Fail text-transform handles Turkish casing ("<div><div lang='tr' style='text-transform:uppercase'>i ı") assert_equals: innerText expected "İ I" but got "I I"
|
||||||
|
Pass block-in-inline doesn't add unnecessary newlines ("<div>abc<span>123<div>456</div>789</span>def")
|
||||||
|
Pass floats induce a block boundary ("<div>abc<div style='float:left'>123</div>def")
|
||||||
|
Pass floats induce a block boundary ("<div>abc<span style='float:left'>123</span>def")
|
||||||
|
Pass float on the element itself ("<div style='float:left'>123")
|
||||||
|
Pass position:absolute induces a block boundary ("<div>abc<div style='position:absolute'>123</div>def")
|
||||||
|
Pass position:absolute induces a block boundary ("<div>abc<span style='position:absolute'>123</span>def")
|
||||||
|
Pass position:absolute on the element itself ("<div style='position:absolute'>123")
|
||||||
|
Pass position:relative has no effect ("<div>abc<div style='position:relative'>123</div>def")
|
||||||
|
Pass position:relative has no effect ("<div>abc<span style='position:relative'>123</span>def")
|
||||||
|
Pass overflow:hidden ignored ("<div style='overflow:hidden'>abc")
|
||||||
|
Pass overflow:hidden ignored even with zero width ("<div style='width:0; overflow:hidden'>abc")
|
||||||
|
Pass overflow:hidden ignored even with zero height ("<div style='height:0; overflow:hidden'>abc")
|
||||||
|
Pass text-overflow:ellipsis ignored ("<div style='width:0; overflow:hidden; text-overflow:ellipsis'>abc")
|
||||||
|
Pass innerText not supported on SVG elements ("<svg>abc")
|
||||||
|
Pass innerText not supported on MathML elements ("<math>abc")
|
||||||
|
Pass <rt> and no <rp> ("<div><ruby>abc<rt>def</rt></ruby>")
|
||||||
|
Pass <rp> ("<div><ruby>abc<rp>(</rp><rt>def</rt><rp>)</rp></ruby>")
|
||||||
|
Pass Lone <rp> ("<div><rp>abc</rp>")
|
||||||
|
Pass visibility:hidden <rp> ("<div><rp style='visibility:hidden'>abc</rp>")
|
||||||
|
Pass display:block <rp> ("<div><rp style='display:block'>abc</rp>def")
|
||||||
|
Fail display:block <rp> with whitespace ("<div><rp style='display:block'> abc </rp>def") assert_equals: innerText expected "abc\ndef" but got " abc \ndef"
|
||||||
|
Pass <rp> in a <select> ("<div><select class='poke-rp'></select>")
|
||||||
|
Pass Shadow DOM contents ignored ("<div class='shadow'>")
|
||||||
|
Pass Shadow DOM contents ignored ("<div><div class='shadow'>")
|
||||||
|
Pass CSS 'order' property ignored ("<div style='display:flex'><div style='order:1'>1</div><div>2</div></div>")
|
||||||
|
Pass Flex items blockified ("<div style='display:flex'><span>1</span><span>2</span></div>")
|
||||||
|
Pass CSS 'order' property ignored ("<div style='display:grid'><div style='order:1'>1</div><div>2</div></div>")
|
||||||
|
Pass Grid items blockified ("<div style='display:grid'><span>1</span><span>2</span></div>")
|
|
@ -0,0 +1 @@
|
||||||
|
PASS
|
|
@ -0,0 +1,136 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 126 tests
|
||||||
|
|
||||||
|
126 Pass
|
||||||
|
Details
|
||||||
|
Result Test Name MessagePass Simplest possible test
|
||||||
|
Pass Simplest possible test, detached
|
||||||
|
Pass Newlines convert to <br> in non-white-space:pre elements
|
||||||
|
Pass Newlines convert to <br> in non-white-space:pre elements, detached
|
||||||
|
Pass Newlines convert to <br> in <pre> element
|
||||||
|
Pass Newlines convert to <br> in <pre> element, detached
|
||||||
|
Pass Newlines convert to <br> in <textarea> element
|
||||||
|
Pass Newlines convert to <br> in <textarea> element, detached
|
||||||
|
Pass Newlines convert to <br> in white-space:pre element
|
||||||
|
Pass Newlines convert to <br> in white-space:pre element, detached
|
||||||
|
Pass CRs convert to <br> in non-white-space:pre elements
|
||||||
|
Pass CRs convert to <br> in non-white-space:pre elements, detached
|
||||||
|
Pass CRs convert to <br> in <pre> element
|
||||||
|
Pass CRs convert to <br> in <pre> element, detached
|
||||||
|
Pass Newline/CR pair converts to <br> in non-white-space:pre element
|
||||||
|
Pass Newline/CR pair converts to <br> in non-white-space:pre element, detached
|
||||||
|
Pass Newline/newline pair converts to two <br>s in non-white-space:pre element
|
||||||
|
Pass Newline/newline pair converts to two <br>s in non-white-space:pre element, detached
|
||||||
|
Pass CR/CR pair converts to two <br>s in non-white-space:pre element
|
||||||
|
Pass CR/CR pair converts to two <br>s in non-white-space:pre element, detached
|
||||||
|
Pass CRs convert to <br> in white-space:pre element
|
||||||
|
Pass CRs convert to <br> in white-space:pre element, detached
|
||||||
|
Pass < preserved
|
||||||
|
Pass < preserved, detached
|
||||||
|
Pass > preserved
|
||||||
|
Pass > preserved, detached
|
||||||
|
Pass & preserved
|
||||||
|
Pass & preserved, detached
|
||||||
|
Pass " preserved
|
||||||
|
Pass " preserved, detached
|
||||||
|
Pass ' preserved
|
||||||
|
Pass ' preserved, detached
|
||||||
|
Pass innerText not supported on SVG elements
|
||||||
|
Pass innerText not supported on SVG elements, detached
|
||||||
|
Pass innerText not supported on MathML elements
|
||||||
|
Pass innerText not supported on MathML elements, detached
|
||||||
|
Pass Null characters preserved
|
||||||
|
Pass Null characters preserved, detached
|
||||||
|
Pass Tabs preserved
|
||||||
|
Pass Tabs preserved, detached
|
||||||
|
Pass Leading whitespace preserved
|
||||||
|
Pass Leading whitespace preserved, detached
|
||||||
|
Pass Trailing whitespace preserved
|
||||||
|
Pass Trailing whitespace preserved, detached
|
||||||
|
Pass Whitespace not compressed
|
||||||
|
Pass Whitespace not compressed, detached
|
||||||
|
Pass Existing text deleted
|
||||||
|
Pass Existing text deleted, detached
|
||||||
|
Pass Existing <br> deleted
|
||||||
|
Pass Existing <br> deleted, detached
|
||||||
|
Pass Assigning the empty string
|
||||||
|
Pass Assigning the empty string, detached
|
||||||
|
Pass Assigning null
|
||||||
|
Pass Assigning null, detached
|
||||||
|
Pass Assigning undefined
|
||||||
|
Pass Assigning undefined, detached
|
||||||
|
Pass Start with CR
|
||||||
|
Pass Start with CR, detached
|
||||||
|
Pass Start with LF
|
||||||
|
Pass Start with LF, detached
|
||||||
|
Pass Start with CRLF
|
||||||
|
Pass Start with CRLF, detached
|
||||||
|
Pass End with CR
|
||||||
|
Pass End with CR, detached
|
||||||
|
Pass End with LF
|
||||||
|
Pass End with LF, detached
|
||||||
|
Pass End with CRLF
|
||||||
|
Pass End with CRLF, detached
|
||||||
|
Pass innerText on <area> element
|
||||||
|
Pass innerText on <area> element, detached
|
||||||
|
Pass innerText on <base> element
|
||||||
|
Pass innerText on <base> element, detached
|
||||||
|
Pass innerText on <basefont> element
|
||||||
|
Pass innerText on <basefont> element, detached
|
||||||
|
Pass innerText on <bgsound> element
|
||||||
|
Pass innerText on <bgsound> element, detached
|
||||||
|
Pass innerText on <br> element
|
||||||
|
Pass innerText on <br> element, detached
|
||||||
|
Pass innerText on <col> element
|
||||||
|
Pass innerText on <col> element, detached
|
||||||
|
Pass innerText on <embed> element
|
||||||
|
Pass innerText on <embed> element, detached
|
||||||
|
Pass innerText on <frame> element
|
||||||
|
Pass innerText on <frame> element, detached
|
||||||
|
Pass innerText on <hr> element
|
||||||
|
Pass innerText on <hr> element, detached
|
||||||
|
Pass innerText on <image> element
|
||||||
|
Pass innerText on <image> element, detached
|
||||||
|
Pass innerText on <img> element
|
||||||
|
Pass innerText on <img> element, detached
|
||||||
|
Pass innerText on <input> element
|
||||||
|
Pass innerText on <input> element, detached
|
||||||
|
Pass innerText on <keygen> element
|
||||||
|
Pass innerText on <keygen> element, detached
|
||||||
|
Pass innerText on <link> element
|
||||||
|
Pass innerText on <link> element, detached
|
||||||
|
Pass innerText on <menuitem> element
|
||||||
|
Pass innerText on <menuitem> element, detached
|
||||||
|
Pass innerText on <meta> element
|
||||||
|
Pass innerText on <meta> element, detached
|
||||||
|
Pass innerText on <param> element
|
||||||
|
Pass innerText on <param> element, detached
|
||||||
|
Pass innerText on <source> element
|
||||||
|
Pass innerText on <source> element, detached
|
||||||
|
Pass innerText on <track> element
|
||||||
|
Pass innerText on <track> element, detached
|
||||||
|
Pass innerText on <wbr> element
|
||||||
|
Pass innerText on <wbr> element, detached
|
||||||
|
Pass innerText on <colgroup> element
|
||||||
|
Pass innerText on <colgroup> element, detached
|
||||||
|
Pass innerText on <frameset> element
|
||||||
|
Pass innerText on <frameset> element, detached
|
||||||
|
Pass innerText on <head> element
|
||||||
|
Pass innerText on <head> element, detached
|
||||||
|
Pass innerText on <html> element
|
||||||
|
Pass innerText on <html> element, detached
|
||||||
|
Pass innerText on <table> element
|
||||||
|
Pass innerText on <table> element, detached
|
||||||
|
Pass innerText on <tbody> element
|
||||||
|
Pass innerText on <tbody> element, detached
|
||||||
|
Pass innerText on <tfoot> element
|
||||||
|
Pass innerText on <tfoot> element, detached
|
||||||
|
Pass innerText on <thead> element
|
||||||
|
Pass innerText on <thead> element, detached
|
||||||
|
Pass innerText on <tr> element
|
||||||
|
Pass innerText on <tr> element, detached
|
|
@ -0,0 +1,12 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 2 tests
|
||||||
|
|
||||||
|
2 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail innerText should be the same for the pre-line and pre examples assert_equals: expected "one\ntwo\nthree\nfour" but got "one two three four"
|
||||||
|
Fail innerText has collapsed whitespace but preserved newlines with pre-line assert_equals: expected "one\ntwo\nthree\nfour\n" but got " one two three four "
|
|
@ -0,0 +1,54 @@
|
||||||
|
Summary
|
||||||
|
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Rerun
|
||||||
|
|
||||||
|
Found 43 tests
|
||||||
|
|
||||||
|
2 Pass
|
||||||
|
41 Fail
|
||||||
|
Details
|
||||||
|
Result Test Name MessageFail Replacing a node and merging with the previous text node assert_equals: expected "A Replaced" but got "A <span id=\"testReplacePrevious\">B</span>"
|
||||||
|
Fail Replacing a node and merging with the following text node assert_equals: expected "Replaced B" but got "<span id=\"testReplaceFollowing\">A</span> B"
|
||||||
|
Fail Replacing a node and merging with the previous and following text node assert_equals: expected "A Replaced C" but got "A <span id=\"testReplaceBoth\">B</span> C"
|
||||||
|
Fail Only merges with the previous and following text nodes, does not completely normalize assert_equals: expected "ABReplacedDE" but got "AB<span></span>DE"
|
||||||
|
Fail Empty string assert_equals: expected (string) "" but got (undefined) undefined
|
||||||
|
Fail Empty string with surrounding text nodes assert_equals: It got merged with the previous and following text node expected 3 but got 5
|
||||||
|
Fail Setting outerText to a bunch of newlines creates a bunch of <br>s with no text nodes assert_equals: expected "<br><br><br>" but got "<span id=\"testNewlines\">Replace this child with lots of newlines</span>"
|
||||||
|
Fail Removing a node assert_equals: expected " removing node using outerText." but got "<span id=\"testRemove\">Testing</span> removing node using outerText."
|
||||||
|
Fail Detached node assert_throws_dom: function "() => { node.outerText = ""; }" did not throw
|
||||||
|
Fail Simplest possible test assert_equals: expected "abc" but got ""
|
||||||
|
Fail Newlines convert to <br> in non-white-space:pre elements assert_equals: expected "abc<br>def" but got "<div></div>"
|
||||||
|
Fail Newlines convert to <br> in <pre> element assert_equals: expected "abc<br>def" but got "<pre></pre>"
|
||||||
|
Fail Newlines convert to <br> in <textarea> element assert_equals: expected "abc<br>def" but got "<textarea></textarea>"
|
||||||
|
Fail Newlines convert to <br> in white-space:pre element assert_equals: expected "abc<br>def" but got "<div style=\"white-space:pre\"></div>"
|
||||||
|
Fail CRs convert to <br> in non-white-space:pre elements assert_equals: expected "abc<br>def" but got "<div></div>"
|
||||||
|
Fail CRs convert to <br> in <pre> element assert_equals: expected "abc<br>def" but got "<pre></pre>"
|
||||||
|
Fail Newline/CR pair converts to <br> in non-white-space:pre element assert_equals: expected "abc<br>def" but got "<div></div>"
|
||||||
|
Fail Newline/newline pair converts to two <br>s in non-white-space:pre element assert_equals: expected "abc<br><br>def" but got "<div></div>"
|
||||||
|
Fail CR/CR pair converts to two <br>s in non-white-space:pre element assert_equals: expected "abc<br><br>def" but got "<div></div>"
|
||||||
|
Fail CRs convert to <br> in white-space:pre element assert_equals: expected "abc<br>def" but got "<div style=\"white-space:pre\"></div>"
|
||||||
|
Fail < preserved assert_equals: expected "abc<def" but got ""
|
||||||
|
Fail > preserved assert_equals: expected "abc>def" but got ""
|
||||||
|
Fail & preserved assert_equals: expected "abc&" but got ""
|
||||||
|
Fail " preserved assert_equals: expected "abc\"def" but got ""
|
||||||
|
Fail ' preserved assert_equals: expected "abc'def" but got ""
|
||||||
|
Pass outerText not supported on SVG elements
|
||||||
|
Pass outerText not supported on MathML elements
|
||||||
|
Fail Null characters preserved assert_equals: expected "abc\0def" but got ""
|
||||||
|
Fail Tabs preserved assert_equals: expected "abc\tdef" but got ""
|
||||||
|
Fail Leading whitespace preserved assert_equals: expected " abc" but got ""
|
||||||
|
Fail Trailing whitespace preserved assert_equals: expected "abc " but got ""
|
||||||
|
Fail Whitespace not compressed assert_equals: expected "abc def" but got ""
|
||||||
|
Fail Existing text deleted assert_equals: expected "abc" but got "abc\n\n"
|
||||||
|
Fail Existing <br> deleted assert_equals: expected "abc" but got ""
|
||||||
|
Fail Assigning the empty string assert_equals: expected "" but got "<div></div>"
|
||||||
|
Fail Assigning null assert_equals: expected "" but got "<div></div>"
|
||||||
|
Fail Assigning undefined assert_equals: expected "undefined" but got "<div></div>"
|
||||||
|
Fail Start with CR assert_equals: expected "<br>abc" but got "<div></div>"
|
||||||
|
Fail Start with LF assert_equals: expected "<br>abc" but got "<div></div>"
|
||||||
|
Fail Start with CRLF assert_equals: expected "<br>abc" but got "<div></div>"
|
||||||
|
Fail End with CR assert_equals: expected "abc<br>" but got "<div></div>"
|
||||||
|
Fail End with LF assert_equals: expected "abc<br>" but got "<div></div>"
|
||||||
|
Fail End with CRLF assert_equals: expected "abc<br>" but got "<div></div>"
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,414 @@
|
||||||
|
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>abc <span style='display:inline-flex'></span> def", "abc def", "Whitespace around inline-flex should not be collapsed");
|
||||||
|
testText("<div>abc <span style='display:inline-flex'> def </span> ghi", "abc def ghi", "Trailing space at end of inline-flex should be collapsed");
|
||||||
|
testText("<div>abc <span style='display:inline-grid'></span> def", "abc def", "Whitespace around inline-grid should not be collapsed");
|
||||||
|
testText("<div>abc <span style='display:inline-grid'> def </span> ghi", "abc def ghi", "Trailing space at end of grid-flex 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><span style='inline-flex'></span> <div>abc</div>", "abc", "Whitespace between inline-flex and block should be collapsed");
|
||||||
|
testText("<div><span style='inline-grid'></span> <div>abc</div>", "abc", "Whitespace between inline-grid 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");
|
||||||
|
|
||||||
|
/**** ****/
|
||||||
|
|
||||||
|
testText("<div> ", "\xA0", " 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><object>abc", "", "<object> 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<span style='display:inline-flex'> abc </span>def", "123abcdef", "Leading/trailing space removal at display:inline-flex boundary");
|
||||||
|
testText("<div>123<span style='display:inline-grid'> abc </span>def", "123abcdef", "Leading/trailing space removal at display:inline-grid 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>");
|
||||||
|
testText("<div>123<p style='display:block'>abc", "123\n\nabc", "2 blank lines around <p> even when display:block");
|
||||||
|
testText("<div>123<p style='display:inline-block'>abc", "123\n\nabc", "2 blank lines around <p> even when display:inline-block");
|
||||||
|
|
||||||
|
/**** 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­def", "abc\xADdef", "soft hyphen preserved");
|
||||||
|
testText("<div style='width:0'>abc­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>");
|
||||||
|
testText("<div><details><summary>abc</summary>123", "abc", "unopened <details> ignored");
|
||||||
|
testText("<div><details open><summary>abc</summary>123", "abc\n123", "opened <details> content shown");
|
||||||
|
|
||||||
|
/**** 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");
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!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';
|
||||||
|
|
||||||
|
if (window.internals)
|
||||||
|
internals.signalTextTestIsDone("PASS");
|
||||||
|
</script>
|
|
@ -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");
|
||||||
|
});
|
|
@ -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>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<title>innerText with white-space:pre-line</title>
|
||||||
|
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1923829">
|
||||||
|
<script src="../../../../resources/testharness.js"></script>
|
||||||
|
<script src="../../../../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<div id="a" style="white-space: pre-line">one two three four</div>
|
||||||
|
|
||||||
|
<div id="b" style="white-space: pre">one two three four</div>
|
||||||
|
|
||||||
|
<div id="c" style="white-space: pre-line">
|
||||||
|
one
|
||||||
|
two
|
||||||
|
<!-- comment -->
|
||||||
|
three
|
||||||
|
four
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="d" style="white-space: pre">
|
||||||
|
one
|
||||||
|
two
|
||||||
|
<!-- comment -->
|
||||||
|
three
|
||||||
|
four
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
assert_equals(a.innerText, b.innerText);
|
||||||
|
}, "innerText should be the same for the pre-line and pre examples");
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
function collapseWhitespace(s) {
|
||||||
|
return s.replace(/ +/g, ' ') // collapse runs of spaces
|
||||||
|
.replace(/ $/mg, '') // strip trailing spaces
|
||||||
|
.replace(/^ /mg, '') // strip leading spaces
|
||||||
|
.replace(/\n\n+/g, '\n') // collapse runs of newlines
|
||||||
|
.replace(/^\n/, ''); // remove any initial newline
|
||||||
|
}
|
||||||
|
assert_equals(c.innerText, collapseWhitespace(d.innerText));
|
||||||
|
}, "innerText has collapsed whitespace but preserved newlines with pre-line");
|
||||||
|
</script>
|
|
@ -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");
|
|
@ -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>
|
4959
Tests/LibWeb/Text/input/wpt-import/resources/testharness.js
Normal file
4959
Tests/LibWeb/Text/input/wpt-import/resources/testharness.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,45 @@
|
||||||
|
/* global add_completion_callback */
|
||||||
|
/* global setup */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is intended for vendors to implement code needed to integrate
|
||||||
|
* testharness.js tests with their own test systems.
|
||||||
|
*
|
||||||
|
* Typically test system integration will attach callbacks when each test has
|
||||||
|
* run, using add_result_callback(callback(test)), or when the whole test file
|
||||||
|
* has completed, using
|
||||||
|
* add_completion_callback(callback(tests, harness_status)).
|
||||||
|
*
|
||||||
|
* For more documentation about the callback functions and the
|
||||||
|
* parameters they are called with see testharness.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If the parent window has a testharness_properties object,
|
||||||
|
* we use this to provide the test settings. This is used by the
|
||||||
|
* default in-browser runner to configure the timeout and the
|
||||||
|
* rendering of results
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
if (window.opener && "testharness_properties" in window.opener) {
|
||||||
|
/* If we pass the testharness_properties object as-is here without
|
||||||
|
* JSON stringifying and reparsing it, IE fails & emits the message
|
||||||
|
* "Could not complete the operation due to error 80700019".
|
||||||
|
*/
|
||||||
|
setup(JSON.parse(JSON.stringify(window.opener.testharness_properties)));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
add_completion_callback(function(tests, harness_status) {
|
||||||
|
if (window.internals) {
|
||||||
|
// NOTE: If we're running inside the test harness,
|
||||||
|
// filter out stuff we don't want to see, like local filesystem paths.
|
||||||
|
for (const details of document.querySelectorAll("pre, details")) {
|
||||||
|
details.style.display = 'none';
|
||||||
|
}
|
||||||
|
window.internals.signalTextTestIsDone(document.getElementById("log").innerText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// vim: set expandtab shiftwidth=4 tabstop=4:
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -21,10 +21,12 @@
|
||||||
#include <LibWeb/HTML/Focus.h>
|
#include <LibWeb/HTML/Focus.h>
|
||||||
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
#include <LibWeb/HTML/HTMLAnchorElement.h>
|
||||||
#include <LibWeb/HTML/HTMLAreaElement.h>
|
#include <LibWeb/HTML/HTMLAreaElement.h>
|
||||||
|
#include <LibWeb/HTML/HTMLBRElement.h>
|
||||||
#include <LibWeb/HTML/HTMLBaseElement.h>
|
#include <LibWeb/HTML/HTMLBaseElement.h>
|
||||||
#include <LibWeb/HTML/HTMLBodyElement.h>
|
#include <LibWeb/HTML/HTMLBodyElement.h>
|
||||||
#include <LibWeb/HTML/HTMLElement.h>
|
#include <LibWeb/HTML/HTMLElement.h>
|
||||||
#include <LibWeb/HTML/HTMLLabelElement.h>
|
#include <LibWeb/HTML/HTMLLabelElement.h>
|
||||||
|
#include <LibWeb/HTML/HTMLParagraphElement.h>
|
||||||
#include <LibWeb/HTML/NavigableContainer.h>
|
#include <LibWeb/HTML/NavigableContainer.h>
|
||||||
#include <LibWeb/HTML/VisibilityState.h>
|
#include <LibWeb/HTML/VisibilityState.h>
|
||||||
#include <LibWeb/HTML/Window.h>
|
#include <LibWeb/HTML/Window.h>
|
||||||
|
@ -209,30 +211,151 @@ void HTMLElement::append_rendered_text_fragment(StringView input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RequiredLineBreakCount {
|
||||||
|
int count { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/dom.html#rendered-text-collection-steps
|
||||||
|
static Vector<Variant<String, RequiredLineBreakCount>> rendered_text_collection_steps(DOM::Node const& node)
|
||||||
|
{
|
||||||
|
// 1. Let items be the result of running the rendered text collection steps with each child node of node in tree order, and then concatenating the results to a single list.
|
||||||
|
Vector<Variant<String, RequiredLineBreakCount>> items;
|
||||||
|
node.for_each_child([&](auto const& child) {
|
||||||
|
auto child_items = rendered_text_collection_steps(child);
|
||||||
|
items.extend(move(child_items));
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
|
||||||
|
// NOTE: Steps are re-ordered here a bit.
|
||||||
|
|
||||||
|
// 3. If node is not being rendered, then return items.
|
||||||
|
// For the purpose of this step, the following elements must act as described
|
||||||
|
// if the computed value of the 'display' property is not 'none':
|
||||||
|
// FIXME: - select elements have an associated non-replaced inline CSS box whose child boxes include only those of optgroup and option element child nodes;
|
||||||
|
// FIXME: - optgroup elements have an associated non-replaced block-level CSS box whose child boxes include only those of option element child nodes; and
|
||||||
|
// FIXME: - option element have an associated non-replaced block-level CSS box whose child boxes are as normal for non-replaced block-level CSS boxes.
|
||||||
|
auto* layout_node = node.layout_node();
|
||||||
|
if (!layout_node)
|
||||||
|
return items;
|
||||||
|
|
||||||
|
auto const& computed_values = layout_node->computed_values();
|
||||||
|
|
||||||
|
// 2. If node's computed value of 'visibility' is not 'visible', then return items.
|
||||||
|
if (computed_values.visibility() != CSS::Visibility::Visible)
|
||||||
|
return items;
|
||||||
|
|
||||||
|
// AD-HOC: If node's computed value of 'content-visibility' is 'hidden', then return items.
|
||||||
|
if (computed_values.content_visibility() == CSS::ContentVisibility::Hidden)
|
||||||
|
return items;
|
||||||
|
|
||||||
|
// 4. If node is a Text node, then for each CSS text box produced by node, in content order,
|
||||||
|
// compute the text of the box after application of the CSS 'white-space' processing rules
|
||||||
|
// and 'text-transform' rules, set items to the list of the resulting strings, and return items.
|
||||||
|
|
||||||
|
// FIXME: The CSS 'white-space' processing rules are slightly modified:
|
||||||
|
// collapsible spaces at the end of lines are always collapsed,
|
||||||
|
// but they are only removed if the line is the last line of the block,
|
||||||
|
// or it ends with a br element. Soft hyphens should be preserved. [CSSTEXT]
|
||||||
|
|
||||||
|
if (is<DOM::Text>(node)) {
|
||||||
|
auto const* layout_text_node = verify_cast<Layout::TextNode>(layout_node);
|
||||||
|
items.append(layout_text_node->text_for_rendering());
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. If node is a br element, then append a string containing a single U+000A LF code point to items.
|
||||||
|
if (is<HTML::HTMLBRElement>(node)) {
|
||||||
|
items.append("\n"_string);
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto display = computed_values.display();
|
||||||
|
|
||||||
|
// 6. If node's computed value of 'display' is 'table-cell', and node's CSS box is not the last 'table-cell' box of its enclosing 'table-row' box, then append a string containing a single U+0009 TAB code point to items.
|
||||||
|
if (display.is_table_cell() && node.next_sibling())
|
||||||
|
items.append("\t"_string);
|
||||||
|
|
||||||
|
// 7. If node's computed value of 'display' is 'table-row', and node's CSS box is not the last 'table-row' box of the nearest ancestor 'table' box, then append a string containing a single U+000A LF code point to items.
|
||||||
|
if (display.is_table_row() && node.next_sibling())
|
||||||
|
items.append("\n"_string);
|
||||||
|
|
||||||
|
// 8. If node is a p element, then append 2 (a required line break count) at the beginning and end of items.
|
||||||
|
if (is<HTML::HTMLParagraphElement>(node)) {
|
||||||
|
items.prepend(RequiredLineBreakCount { 2 });
|
||||||
|
items.append(RequiredLineBreakCount { 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. If node's used value of 'display' is block-level or 'table-caption', then append 1 (a required line break count) at the beginning and end of items. [CSSDISPLAY]
|
||||||
|
if (display.is_block_outside() || display.is_table_caption()) {
|
||||||
|
items.prepend(RequiredLineBreakCount { 1 });
|
||||||
|
items.append(RequiredLineBreakCount { 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10. Return items.
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#get-the-text-steps
|
// https://html.spec.whatwg.org/multipage/dom.html#get-the-text-steps
|
||||||
String HTMLElement::get_the_text_steps()
|
String HTMLElement::get_the_text_steps()
|
||||||
{
|
{
|
||||||
// FIXME: Implement this according to spec.
|
// 1. If element is not being rendered or if the user agent is a non-CSS user agent, then return element's descendant text content.
|
||||||
|
|
||||||
StringBuilder builder;
|
|
||||||
|
|
||||||
// innerText for element being rendered takes visibility into account, so force a layout and then walk the layout tree.
|
|
||||||
document().update_layout();
|
document().update_layout();
|
||||||
if (!layout_node())
|
if (!layout_node())
|
||||||
return text_content().value_or(String {});
|
return descendant_text_content();
|
||||||
|
|
||||||
Function<void(Layout::Node const&)> recurse = [&](auto& node) {
|
// 2. Let results be a new empty list.
|
||||||
for (auto* child = node.first_child(); child; child = child->next_sibling()) {
|
Vector<Variant<String, RequiredLineBreakCount>> results;
|
||||||
if (is<Layout::TextNode>(child))
|
|
||||||
builder.append(verify_cast<Layout::TextNode>(*child).text_for_rendering());
|
// 3. For each child node node of element:
|
||||||
if (is<Layout::BreakNode>(child))
|
for_each_child([&](Node const& node) {
|
||||||
builder.append('\n');
|
// 1. Let current be the list resulting in running the rendered text collection steps with node.
|
||||||
recurse(*child);
|
// Each item in results will either be a string or a positive integer (a required line break count).
|
||||||
|
auto current = rendered_text_collection_steps(node);
|
||||||
|
|
||||||
|
// 2. For each item item in current, append item to results.
|
||||||
|
results.extend(move(current));
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. Remove any items from results that are the empty string.
|
||||||
|
results.remove_all_matching([](auto& item) {
|
||||||
|
return item.visit(
|
||||||
|
[](String const& string) { return string.is_empty(); },
|
||||||
|
[](RequiredLineBreakCount const&) { return false; });
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5. Remove any runs of consecutive required line break count items at the start or end of results.
|
||||||
|
while (!results.is_empty() && results.first().has<RequiredLineBreakCount>())
|
||||||
|
results.take_first();
|
||||||
|
while (!results.is_empty() && results.last().has<RequiredLineBreakCount>())
|
||||||
|
results.take_last();
|
||||||
|
|
||||||
|
// 6. Replace each remaining run of consecutive required line break count items
|
||||||
|
// with a string consisting of as many U+000A LF code points as the maximum of the values
|
||||||
|
// in the required line break count items.
|
||||||
|
for (size_t i = 0; i < results.size(); ++i) {
|
||||||
|
if (!results[i].has<RequiredLineBreakCount>())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int max_line_breaks = results[i].get<RequiredLineBreakCount>().count;
|
||||||
|
size_t j = i + 1;
|
||||||
|
while (j < results.size() && results[j].has<RequiredLineBreakCount>()) {
|
||||||
|
max_line_breaks = max(max_line_breaks, results[j].get<RequiredLineBreakCount>().count);
|
||||||
|
++j;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
recurse(*layout_node());
|
|
||||||
|
|
||||||
return MUST(builder.to_string());
|
results.remove(i, j - i);
|
||||||
|
results.insert(i, MUST(String::repeated('\n', max_line_breaks)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7. Return the concatenation of the string items in results.
|
||||||
|
StringBuilder builder;
|
||||||
|
for (auto& item : results) {
|
||||||
|
item.visit(
|
||||||
|
[&](String const& string) { builder.append(string); },
|
||||||
|
[&](RequiredLineBreakCount const&) {});
|
||||||
|
}
|
||||||
|
return builder.to_string_without_validation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#dom-innertext
|
// https://html.spec.whatwg.org/multipage/dom.html#dom-innertext
|
||||||
|
|
Loading…
Reference in a new issue