Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="variant" content="?method=backspace&block=div">
<meta name="variant" content="?method=backspace&block=p">
<meta name="variant" content="?method=backspace&block=blockquote">
<meta name="variant" content="?method=forwarddelete&block=div">
<meta name="variant" content="?method=forwarddelete&block=p">
<meta name="variant" content="?method=forwarddelete&block=blockquote">
<meta name="variant" content="?method=select-boundary&block=div">
<meta name="variant" content="?method=select-boundary&block=p">
<meta name="variant" content="?method=select-boundary&block=blockquote">
<title>Tests for joining pre and other block element</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>
</head>
<body>
<div contenteditable></div>
<script>
"use strict";
const searchParams = new URLSearchParams(document.location.search);
const testingBackspace = searchParams.get("method") == "backspace";
const testingSelectBoundary = searchParams.get("method") == "select-boundary";
const commandName =
testingBackspace || testingSelectBoundary ? "delete" : "forwarddelete";
const editingHost = document.querySelector("div[contenteditable]");
const caretInLeft = (() => {
if (testingSelectBoundary) {
return "[";
}
return testingBackspace ? "" : "[]";
})();
const caretInRight = (() => {
if (testingSelectBoundary) {
return "]";
}
return testingBackspace ? "[]" : "";
})();
const tag = searchParams.get("block");
// These expectations are odd because they don't preserve white-space style
// coming from another element. However, this is traditional behavior so that
// browsers should not change the behavior.
const tests = [
{
initialHTML:
`<pre>abc${caretInLeft}</pre>` +
`<${tag}>${caretInRight}def</${tag}>`,
expectedHTML: [
"<pre>abcdef</pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre>${caretInRight}def</pre>`,
expectedHTML: [
`<${tag}>abcdef</${tag}>`,
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<span style="white-space:pre">def</span></${tag}>`,
],
},
{
initialHTML:
`<pre>abc${caretInLeft}</pre>` +
`<${tag}>${caretInRight}def<br>ghi</${tag}>`,
expectedHTML: [
`<pre>abcdef</pre>` +
`<${tag}>ghi</${tag}>`,
],
},
{
initialHTML:
`<pre>abc${caretInLeft}</pre>` +
`<${tag}>${caretInRight}def<div>ghi</div></${tag}>`,
expectedHTML: [
"<pre>abcdef</pre>" +
`<${tag}><div>ghi</div></${tag}>`,
],
skip: tag == "p",
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre>${caretInRight}def\nghi</pre>`,
expectedHTML: [
`<${tag}>abcdef</${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<span style="white-space:pre">def</span></${tag}>` +
"<pre>ghi</pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre>${caretInRight}def<br>ghi</pre>`,
expectedHTML: [
`<${tag}>abcdef</${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<span style="white-space:pre">def</span></${tag}>` +
"<pre>ghi</pre>",
],
},
{
initialHTML:
`<pre>abc${caretInLeft}</pre>` +
`<${tag}><b>${caretInRight}def</b></${tag}>`,
expectedHTML: [
"<pre>abc<b>def</b></pre>",
],
},
{
initialHTML:
`<pre>abc${caretInLeft}</pre>` +
`<${tag}><b>${caretInRight}def<br>ghi</b></${tag}>`,
expectedHTML: [
"<pre>abc<b>def</b></pre>" +
`<${tag}><b>ghi</b></${tag}>`,
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def\nghi</b></pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre><b>ghi</b></pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
"<pre><b>ghi</b></pre>",
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre><b>ghi</b></pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def<br>ghi</b></pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre><b>ghi</b></pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
"<pre><b>ghi</b></pre>",
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre><b>ghi</b></pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def</b>\nghi</pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
"<pre>ghi</pre>",
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre>ghi</pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def</b><br>ghi</pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
"<pre>ghi</pre>",
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre>ghi</pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def\n</b>ghi</pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
`<pre>ghi</pre>`,
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre>ghi</pre>",
],
},
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre><b>${caretInRight}def<br></b>ghi</pre>`,
expectedHTML: [
`<${tag}>abc<b>def</b></${tag}>` +
"<pre>ghi</pre>",
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<b style="white-space:pre">def</b></${tag}>` +
"<pre>ghi</pre>",
`<${tag}>abc<span style="white-space:pre"><b>def</b></span></${tag}>` +
"<pre>ghi</pre>",
],
},
// One linefeed at start of <pre> should be ignored.
// Note that if setupEditingHost() does not touch the text node in <pre>,
// the leading line break is ignored, but if it touches the text node,
// the value is set to as-is. Therefore, the following tests can work
// with empty caretInRight value.
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre>\ndef\nghi</pre>`,
expectedHTML: [
`<${tag}>abcdef</${tag}>` +
`<pre>ghi</pre>`,
],
expectedHTMLWithStyledPre: [
`<${tag}>abc<span style="white-space:pre">def</span></${tag}>` +
"<pre>ghi</pre>",
],
skip: caretInRight !== "",
},
// When there are two line breaks at start of <pre>, the first one should be
// ignored by the parser but the second one should make empty first line.
// Therefore, the first empty line should be removed.
{
initialHTML:
`<${tag}>abc${caretInLeft}</${tag}>` +
`<pre>\n\ndef\nghi</pre>`,
expectedHTML: [
`<${tag}>abc</${tag}>` +
"<pre>def\nghi</pre>",
],
skip: caretInRight !== "",
},
];
const utils = new EditorTestUtils(editingHost);
const betweenBlockAndPre = new RegExp(`</${tag}><pre>`);
const betweenPreAndBlock = new RegExp(`</pre><${tag}>`);
function putStyleElement() {
const styleElement = document.createElement("style");
styleElement.textContent = "pre { white-space: pre; }";
document.head.appendChild(styleElement);
}
for (const specifyPreStyle of [false, true]) {
for (const t of tests) {
if (t.skip) {
continue;
}
if (specifyPreStyle && !t.expectedHTMLWithStyledPre) {
continue;
}
promise_test(async () => {
if (specifyPreStyle) {
putStyleElement();
}
try {
utils.setupEditingHost(t.initialHTML);
await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey());
utils.normalizeStyleAttributeValues();
assert_in_array(
editingHost.innerHTML,
specifyPreStyle ? t.expectedHTMLWithStyledPre : t.expectedHTML,
`white-space should${
!specifyPreStyle ? " not" : ""
} be preserved by <span> elements`
);
} finally {
if (specifyPreStyle) {
document.querySelector("style")?.remove();
}
}
}, `${commandName} at ${t.initialHTML.replace(/\n/g, "\\n")}${
specifyPreStyle ? " (with <style>pre { white-space: pre; }</style>)" : ""
}`);
// Repeat same tests with inserting a line break between the paragraphs.
const initialHTMLWithLineBreak =
t.initialHTML
.replace(betweenBlockAndPre, `</${tag}>\n<pre>`)
.replace(betweenPreAndBlock, `</pre>\n<${tag}>`);
promise_test(async () => {
if (specifyPreStyle) {
putStyleElement();
}
try {
utils.setupEditingHost(initialHTMLWithLineBreak);
await (testingBackspace ? utils.sendBackspaceKey() : utils.sendDeleteKey());
utils.normalizeStyleAttributeValues();
assert_in_array(
editingHost.innerHTML,
specifyPreStyle ? t.expectedHTMLWithStyledPre : t.expectedHTML,
`white-space should${
!specifyPreStyle ? " not" : ""
} be preserved by <span> elements (testing with a line break between paragraphs)`
);
} finally {
if (specifyPreStyle) {
document.querySelector("style")?.remove();
}
}
}, `${commandName} at ${initialHTMLWithLineBreak.replace(/\n/g, "\\n")}${
specifyPreStyle ? " (with <style>pre { white-space: pre; }</style>)" : ""
}`);
}
}
</script>
</body>
</html>