Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!doctype html>
<meta charset=utf-8>
<title>Test insertText when selection collapsed in void element</title>
<meta name="timeout" content="long">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<div contenteditable></div>
<script>
"use strict";
const voidElements = [
"br",
"embed",
"hr",
"img",
"input",
"wbr",
];
// This test tests whether the inserted text is inserted into, when selection
// is collapsed in the void element. The expected results are based on Blink,
// but the results of <embed> and <wbr> elements are not consistent with the
// other elements'. Therefore, Blink also does not pass some of the following
// tests.
// FYI: This cannot be tested by editing/run because there is no way to collapse
// selection into a void element with the framework.
const editor = document.querySelector("div[contenteditable]");
for (const tag of voidElements) {
test(() => {
editor.innerHTML = `<div></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "abc");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abc</div>",
"<div>abc<br></div>",
],
`The text should be inserted before the <br> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abc<${tag}></div>`,
`<div>abc<${tag}><br></div>`,
],
`The text should be inserted before the <${tag}> element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which is only child`);
test(() => {
editor.innerHTML = `<div></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
element.getBoundingClientRect();
document.execCommand("insertText", false, "abc");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abc</div>",
"<div>abc<br></div>",
],
`The text should be inserted before the <br> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abc<${tag}></div>`,
`<div>abc<${tag}><br></div>`,
],
`The text should be inserted before the <${tag}> element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which is only child (explicitly flushes maybe pending layout)`);
test(() => {
editor.innerHTML = `<div>abc</div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "def");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abcdef</div>",
"<div>abcdef<br></div>",
],
`The text should be inserted before the <br> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abcdef<${tag}></div>`,
`<div>abcdef<${tag}><br></div>`,
],
`The text should be inserted before the <${tag}> element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node`);
test(() => {
editor.innerHTML = `<div>def</div>`;
const element = document.createElement(tag);
editor.firstChild.insertBefore(element, editor.firstChild.firstChild);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "abc");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abc<br>def</div>",
"<div>abc<br>def<br></div>",
],
`The text should be inserted before the <br> element`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abc<${tag}>def</div>`,
`<div>abc<${tag}>def<br></div>`,
],
`The text should be inserted before the <${tag}> element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which is followed by a text node`);
test(() => {
editor.innerHTML = `<div><span></span></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "abc");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div><span></span>abc</div>",
"<div><span></span>abc<br></div>",
],
`The text should be inserted after the previous empty inline element of <br>`
);
} else if (tag == "input") { // visible inline?
assert_in_array(
editor.innerHTML,
[
`<div><span></span>abc<${tag}></div>`,
`<div><span></span>abc<${tag}><br></div>`,
],
`The text should be inserted after the previous empty inline element of <${tag}>`
);
} else if (tag == "hr") { // block
assert_in_array(
editor.innerHTML,
[
`<div><span></span>abc<${tag}></div>`,
`<div><span></span>abc<br><${tag}></div>`,
],
`The text should be inserted after the previous empty inline element of <${tag}>`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abc<span></span><${tag}></div>`,
`<div>abc<span></span><${tag}><br></div>`,
],
`The text should be inserted before the previous empty inline element of <${tag}>`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which follows an empty <span> element`);
test(() => {
editor.innerHTML = `<div>abc<span></span></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "def");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div>abcdef<span></span></div>",
"<div>abcdef<span></span><br></div>",
],
`The text should be inserted at end of the first text node before empty <span> and <br>`
);
} else if (tag == "hr") { // block
assert_in_array(
editor.innerHTML,
[
`<div>abc<span></span>def<${tag}></div>`,
`<div>abc<span></span>def<br><${tag}></div>`,
],
`The text should be inserted after the previous empty inline element of <${tag}> even if the empty element follows a text node`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div>abcdef<span></span><${tag}></div>`,
`<div>abcdef<span></span><${tag}><br></div>`,
],
`The text should be inserted before the previous empty inline element of <${tag}>`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node and an empty <span> element`);
test(() => {
editor.innerHTML = `<div><span>abc</span></div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "def");
if (tag == "br") {
assert_in_array(
editor.innerHTML,
[
"<div><span>abcdef</span></div>",
"<div><span>abcdef</span><br></div>",
],
`The text should be inserted at end of the text node in <span>`
);
} else if (tag == "hr") { // block
assert_in_array(
editor.innerHTML,
[
`<div><span>abc</span>def<${tag}></div>`,
`<div><span>abc</span>def<br><${tag}></div>`,
],
`The text should be inserted at after the span and before <${tag}>`
);
} else {
assert_in_array(
editor.innerHTML,
[
`<div><span>abcdef</span><${tag}></div>`,
`<div><span>abcdef</span><${tag}><br></div>`,
],
`The text should be inserted at end of the text node in <span> before <${tag}>`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which follows a non-empty <span> element`);
test(() => {
editor.innerHTML = `<div>abc<span></span>\n</div>`;
const element = document.createElement(tag);
editor.firstChild.appendChild(element);
editor.focus();
const selection = getSelection();
selection.collapse(element, 0);
document.execCommand("insertText", false, "def");
if (tag == "br") {
assert_in_array(
editor.innerHTML.replace(/\n/g, " "),
[
"<div>abcdef<span></span></div>",
"<div>abcdef<span></span><br></div>",
"<div>abcdef<span></span> </div>",
"<div>abcdef<span></span> <br></div>",
],
`The text should be inserted at end of the first text node with ignoring the empty <span> and invisible text node before <br>`
);
} else if (tag == "img" || tag == "input") { // visible inline
assert_in_array(
editor.innerHTML.replace(/\n/g, " "),
[
`<div>abc<span></span> def<${tag}></div>`,
`<div>abc<span></span> def<${tag}><br></div>`,
`<div>abc<span></span>&nbsp;def<${tag}></div>`,
`<div>abc<span></span>&nbsp;def<${tag}><br></div>`,
],
`The text should be inserted at end of the last visible text node`
);
} else if (tag == "hr") { // block
assert_in_array(
editor.innerHTML,
[
`<div>abc<span></span>def<${tag}></div>`,
`<div>abc<span></span>def<br><${tag}></div>`,
],
`The text should be inserted after the previous empty inline element`
);
} else {
assert_in_array(
editor.innerHTML.replace(/\n/g, " "),
[
`<div>abcdef<span></span> <${tag}></div>`,
`<div>abcdef<span></span> <${tag}><br></div>`,
],
`The text should be inserted before the previous empty inline element`
);
}
}, `Inserting text when selection is collapsed in <${tag}> which follows a text node, an empty <span> element and white-space only text node`);
}
</script>