Skip to content

Commit

Permalink
Add tests for contenteditable=false elements inside contenteditable=t…
Browse files Browse the repository at this point in the history
…rue elements and for selection in empty elements (#35862)

* Add tests for selecting and deleting cE=false elements on the boundaries of cE=true elements.
* Add tests for empty inline element.
  • Loading branch information
Comandeer authored Dec 12, 2022
1 parent 4a4653e commit 3b6b8de
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 0 deletions.
60 changes: 60 additions & 0 deletions editing/other/cefalse-boundaries-deletion.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Selecting and deleting all from the cE=true element with cE=false element at the beginning</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../include/editor-test-utils.js"></script>

<div contenteditable></div>

<script>
const utils = new EditorTestUtils( document.querySelector( 'div[contenteditable]' ) );

test( () => {
utils.setupEditingHost( `<div contenteditable="false" id="cefalse-beginning">&nbsp;</div>
<p id="paragraph-beginning">Lorem ipsum dolor sit amet.</p>` );

const cefalse = document.querySelector( '#cefalse-beginning' );
const paragraph = document.querySelector( '#paragraph-beginning' );

utils.editingHost.focus();
document.execCommand( 'selectAll' );
document.execCommand( 'delete' );

assert_false( cefalse.isConnected, 'cE=false element should be removed' );
assert_false( paragraph.isConnected, 'paragraph should be removed' );
}, 'cE=false elements can be removed from the beginning of the cE=true elements' );

test( () => {
utils.setupEditingHost( `<p id="paragraph-end">Lorem ipsum dolor sit amet.</p>
<div contenteditable="false" id="cefalse-end">&nbsp;</div>` );

const cefalse = document.querySelector( '#cefalse-end' );
const paragraph = document.querySelector( '#paragraph-end' );

utils.editingHost.focus();
document.execCommand( 'selectAll' );
document.execCommand( 'delete' );

assert_false( cefalse.isConnected, 'cE=false element should be removed' );
assert_false( paragraph.isConnected, 'paragraph should be removed' );
}, 'cE=false elements can be removed from the end of the cE=true elements' );

test( () => {
utils.setupEditingHost( `<div contenteditable="false" id="cefalse-boundaries-beginning">&nbsp;</div>
<p id="paragraph-boundaries">Lorem ipsum dolor sit amet.</p>
<div contenteditable="false" id="cefalse-boundaries-end">&nbsp;</div>` );

const cefalseBeginning = document.querySelector( '#cefalse-boundaries-beginning' );
const cefalseEnd = document.querySelector( '#cefalse-boundaries-end' );
const paragraph = document.querySelector( '#paragraph-boundaries' );

utils.editingHost.focus();
document.execCommand( 'selectAll' );
document.execCommand( 'delete' );

assert_false( cefalseBeginning.isConnected, 'cE=false element at the beginning should be removed' );
assert_false( cefalseEnd.isConnected, 'cE=false element at the end should be removed' );
assert_false( paragraph.isConnected, 'paragraph should be removed' );
}, 'cE=false elements can be removed from the boundaries of the cE=true elements' );
</script>
118 changes: 118 additions & 0 deletions editing/other/empty-elements-insertion.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Placing selection and typing inside empty elements</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="../include/editor-test-utils.js"></script>
<style>
#border {
display: inline-block;
border: 2px red solid;
}

#padding {
display: inline-block;
padding: 1em;
}

#unstyled-before::before,
#unstyled-after::after,
#unstyled-both::before,
#unstyled-both::after {
content: '';
display: inline-block;
border: 2px red solid;
}
</style>
<div contenteditable></div>

<script>
const utils = new EditorTestUtils( document.querySelector( 'div[contenteditable]' ) );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="border"></strong></p>` );

const target = document.querySelector( '#border' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the styled <strong> element' );
}, 'Insert text into the inline element styled with border' );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="padding"></strong></p>` );

const target = document.querySelector( '#padding' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the styled <strong> element' );
}, 'Insert text into the inline element styled with padding' );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="unstyled"></strong></p>` );

const target = document.querySelector( '#unstyled' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the unstyled <strong> element' );
}, 'Insert text into the unstyled inline element' );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="unstyled-before"></strong></p>` );

const target = document.querySelector( '#unstyled-before' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the <strong> element' );
}, 'Insert text into the unstyled inline element with the styled ::before pseudoelement' );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="unstyled-after"></strong></p>` );

const target = document.querySelector( '#unstyled-after' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the <strong> element' );
}, 'Insert text into the unstyled inline element with the styled ::after pseudoelement' );

promise_test( async () => {
utils.setupEditingHost( `<p><strong id="unstyled-both"></strong></p>` );

const target = document.querySelector( '#unstyled-both' );
const actions = new test_driver.Actions();
await actions
.pointerMove( 0, 0, { origin: target } )
.pointerDown( { button: actions.ButtonType.LEFT } )
.pointerUp( { button: actions.ButtonType.LEFT } )
.send();
document.execCommand( 'insertText', false, 'a' );
assert_greater_than( target.innerHTML.length, 0, 'The text should be inserted into the <strong> element' );
}, 'Insert text into the unstyled inline element with the styled ::before and ::after pseudoelements' );
</script>
44 changes: 44 additions & 0 deletions editing/other/link-boundaries-insertion.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Placing selection and typing inside empty elements</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../include/editor-test-utils.js"></script>

<div contenteditable></div>

<script>
const utils = new EditorTestUtils( document.querySelector( 'div[contenteditable]' ) );

test( () => {
utils.setupEditingHost( `<p><a href="https://example.com" id="test-end">Link</a></p>` );

const target = document.querySelector( '#test-end' );
const range = document.createRange();
const selection = getSelection();

range.selectNodeContents( target );
selection.removeAllRanges();
selection.addRange( range );
selection.collapseToEnd();

document.execCommand( 'insertText', false, 'a' );
assert_equals( target.innerHTML, 'Linka', 'The text should be inserted into the link' );
}, 'Insert text into the selection at the end of a link' );

test( () => {
utils.setupEditingHost( `<p><a href="https://example.com" id="test-beginning">Link</a></p>` );

const target = document.querySelector( '#test-beginning' );
const range = document.createRange();
const selection = getSelection();

range.selectNodeContents( target );
selection.removeAllRanges();
selection.addRange( range );
selection.collapseToStart();

document.execCommand( 'insertText', false, 'a' );
assert_equals( target.innerHTML, 'aLink', 'The text should be inserted into the link' );
}, 'Insert text into the selection at the beginning of a link' );
</script>
25 changes: 25 additions & 0 deletions selection/caret/empty-elements.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Placing selection inside empty elements</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div contenteditable id="host">
<p><strong id="strong"></strong></p>
</div>
<script>
test( () => {
const range = document.createRange();

range.setStart( strong, 0 );
range.collapse()
getSelection().removeAllRanges();
getSelection().addRange( range );

const selectedRange = getSelection().getRangeAt( 0 );

assert_equals( selectedRange.startContainer, strong );
assert_equals( selectedRange.startOffset, 0 );
assert_equals( selectedRange.endContainer, strong );
assert_equals( selectedRange.endOffset, 0 );
}, 'Selection can be placed inside the empty element' );
</script>
72 changes: 72 additions & 0 deletions selection/contenteditable/cefalse-on-boundaries.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!DOCTYPE HTML>
<meta charset=utf-8>
<title>Selection of contenteditable=false at the beginning and end of contenteditable element</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div contenteditable id="host">
<div contenteditable="false" id="beginning">&nbsp;</div>
<p id="paragraph">Lorem ipsum dolor sit amet.</p>
<div contenteditable="false" id="end">&nbsp;</div>
</div>
<script>
test( () => {
const range = document.createRange();

range.setStartBefore( beginning );
range.setEndAfter( paragraph );
getSelection().removeAllRanges();
getSelection().addRange( range );

const selectedRange = getSelection().getRangeAt( 0 );

assert_equals( selectedRange.startContainer, host );
assert_equals( selectedRange.startOffset, 1 );
assert_equals( selectedRange.endContainer, host );
assert_equals( selectedRange.endOffset, 4 );
}, 'Selection can start on cE=false element at the beginning of the cE=true element' );

test( () => {
const range = document.createRange();

range.setStartBefore( paragraph );
range.setEndAfter( end );
getSelection().removeAllRanges();
getSelection().addRange( range );

const selectedRange = getSelection().getRangeAt( 0 );

assert_equals( selectedRange.startContainer, host );
assert_equals( selectedRange.startOffset, 3 );
assert_equals( selectedRange.endContainer, host );
assert_equals( selectedRange.endOffset, 6 );
}, 'Selection can end on cE=false element at the end of the cE=true element' );

test( () => {
const range = document.createRange();

range.setStartBefore( beginning );
range.setEndAfter( end );
getSelection().removeAllRanges();
getSelection().addRange( range );

const selectedRange = getSelection().getRangeAt( 0 );

assert_equals( selectedRange.startContainer, host );
assert_equals( selectedRange.startOffset, 1 );
assert_equals( selectedRange.endContainer, host );
assert_equals( selectedRange.endOffset, 6 );
}, 'Selection can start and end on cE=false elements at the boundaries of cE=true element' );

test( () => {
const range = document.createRange();

range.selectNodeContents( host );

const selectedRange = getSelection().getRangeAt( 0 );

assert_equals( selectedRange.startContainer, host );
assert_equals( selectedRange.startOffset, 1 );
assert_equals( selectedRange.endContainer, host );
assert_equals( selectedRange.endOffset, 6 );
}, 'Range#selectNodeContents() correctly select contents of cE=true element with cE=false elements on boundaries' );
</script>

0 comments on commit 3b6b8de

Please sign in to comment.