diff options
Diffstat (limited to 'testing/web-platform/tests/selection')
6 files changed, 302 insertions, 0 deletions
diff --git a/testing/web-platform/tests/selection/crashtests/selection-modify-around-textarea.html b/testing/web-platform/tests/selection/crashtests/selection-modify-around-textarea.html new file mode 100644 index 0000000000..113dea5ffa --- /dev/null +++ b/testing/web-platform/tests/selection/crashtests/selection-modify-around-textarea.html @@ -0,0 +1,23 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script> +"use strict"; +document.addEventListener("DOMContentLoaded", () => { + const time = document.querySelector("time"); + getSelection().setBaseAndExtent(time, 2, time, 3); + getSelection().modify("move", "left", "line"); + getSelection().collapseToStart(); +}); +</script> +</head> +<body><time style="user-select:none"> +<h5> +<pre contenteditable></pre> +<textarea></textarea> +</h5> +<h6></h6> +<textarea></textarea> +</body> +</html> diff --git a/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-empty-details.html b/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-empty-details.html new file mode 100644 index 0000000000..815a819c33 --- /dev/null +++ b/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-empty-details.html @@ -0,0 +1,29 @@ +<!doctype html> +<html class="test-wait"> +<head> +<meta charset="utf-8"> +<script> +"use strict"; + +addEventListener("load", () => { + let i = 0; + const details = document.querySelector("details"); + const id = setInterval(() => { + getSelection().modify("move", "forward", "lineboundary"); + if (details.isConnected) { + details.outerHTML = undefined; + } + if (++i == 5) { + document.documentElement.removeAttribute("class"); + clearInterval(id); + } + }, 0); + document.execCommand("selectAll"); +}, {once: true}); +</script> +</head> +<body> +<details>a</details> +<span contenteditable></span> +</body> +</html> diff --git a/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-shadow.html b/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-shadow.html new file mode 100644 index 0000000000..bfca0402a7 --- /dev/null +++ b/testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-shadow.html @@ -0,0 +1,30 @@ +<!doctype html> +<html class="reftest-wait"> +<head> +<meta charset="utf-8"> +<script> +document.addEventListener("DOMContentLoaded", () => { + const shadowRoot = b.attachShadow({mode: "closed"}); + shadowRoot.textContent = "A"; + getSelection().collapse(shadowRoot.firstChild, 1); + + function moveCaretAndReplaceBodyWithAddress() { + getSelection().modify("move", "forward", "lineboundary"); + document.documentElement.replaceChild(a, document.body); + } + + requestAnimationFrame(() => { + requestAnimationFrame(moveCaretAndReplaceBodyWithAddress); + requestAnimationFrame(moveCaretAndReplaceBodyWithAddress); + requestAnimationFrame( + () => document.documentElement.removeAttribute("class") + ); + }); +}, {once: true}); +</script> +</head> +<body> +<address id="a"></address> +<div id="b"></div> +</body> +</html> diff --git a/testing/web-platform/tests/selection/selection-range-after-editinghost-removed.html b/testing/web-platform/tests/selection/selection-range-after-editinghost-removed.html new file mode 100644 index 0000000000..921903062a --- /dev/null +++ b/testing/web-platform/tests/selection/selection-range-after-editinghost-removed.html @@ -0,0 +1,69 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<title>Selection range in an editing host after the host is removed</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; + +addEventListener("load", () => { + const container = document.querySelector("div"); + test(() => { + const editingHost = document.createElement("div"); + editingHost.contentEditable = true; + editingHost.innerHTML = "ABC<br>"; + container.appendChild(editingHost); + editingHost.focus(); + getSelection().collapse(editingHost, 0); + editingHost.remove(); + assert_equals(getSelection().focusNode, container, "focusNode should be the container"); + assert_equals(getSelection().focusOffset, 0, "focusOffset should be 0"); + }, "Selection range in an editing host should be collapsed where the host was after it's removed"); + + test(() => { + const wrapper = document.createElement("div"); + wrapper.id = "wrapper"; + const editingHost = document.createElement("div"); + editingHost.contentEditable = true; + editingHost.innerHTML = "ABC<br>"; + wrapper.appendChild(editingHost); + container.appendChild(wrapper); + editingHost.focus(); + getSelection().collapse(editingHost, 0); + wrapper.remove(); + assert_equals(getSelection().focusNode, container, "focusNode should be the container"); + assert_equals(getSelection().focusOffset, 0, "focusOffset should be 0"); + }, "Selection range in an editing host should be collapsed where the host was after its parent is removed"); + + test(() => { + const editingHost = document.createElement("div"); + editingHost.contentEditable = true; + editingHost.innerHTML = "ABC<br>"; + container.appendChild(editingHost); + editingHost.focus(); + getSelection().collapse(editingHost, 0); + editingHost.replaceWith(editingHost); + assert_equals(getSelection().focusNode, container, "focusNode should be the container"); + assert_equals(getSelection().focusOffset, 0, "focusOffset should be 0"); + editingHost.remove(); + }, "Selection range in an editing host should be collapsed where the host was after it's replaced with itself (.replaceWith)"); + + test(() => { + const editingHost = document.createElement("div"); + editingHost.contentEditable = true; + editingHost.innerHTML = "ABC<br>"; + container.appendChild(editingHost); + editingHost.focus(); + getSelection().collapse(editingHost, 0); + container.replaceChild(editingHost, editingHost); + assert_equals(getSelection().focusNode, container, "focusNode should be the container"); + assert_equals(getSelection().focusOffset, 0, "focusOffset should be 0"); + editingHost.remove(); + }, "Selection range in an editing host should be collapsed where the host was after it's replaced with itself (.replaceChild)"); +}, {once: true}); +</script> +</head> +<body><div id="container"></div></body> +</html> diff --git a/testing/web-platform/tests/selection/selection-range-after-textcontrol-removed.html b/testing/web-platform/tests/selection/selection-range-after-textcontrol-removed.html new file mode 100644 index 0000000000..e618f10f1d --- /dev/null +++ b/testing/web-platform/tests/selection/selection-range-after-textcontrol-removed.html @@ -0,0 +1,55 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<meta name="variant" content="?textControl=text"> +<meta name="variant" content="?textControl=password"> +<meta name="variant" content="?textControl=number"> +<meta name="variant" content="?textControl=textarea"> +<title>Selection range after text control is removed</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; + +/** + * Browsers may use internal Selection and/or Range to implement the selection + * in text controls. They should not be appear outside the host text control + * after the host is removed. + */ +addEventListener("load", () => { + const textControlType = (new URLSearchParams(document.location.search)).get("mode"); + function createTextControlElement() { + const textControl = + document.createElement(textControlType == "textarea" ? "textarea" : "input"); + if (textControlType != "textarea") { + textControl.type = textControlType; + } + return textControl; + } + + test(() => { + const textControl = createTextControlElement(); + document.body.appendChild(textControl); + textControl.select(); + getSelection().removeAllRanges(); + textControl.remove(); + assert_equals(getSelection().rangeCount, 0); + }, "Removing the text control should not add selection range"); + + test(() => { + const wrapper = document.createElement("div"); + wrapper.id = "wrapper"; + const textControl = createTextControlElement(); + wrapper.appendChild(textControl); + document.body.appendChild(wrapper); + textControl.select(); + getSelection().removeAllRanges(); + wrapper.remove(); + assert_equals(getSelection().rangeCount, 0); + }, "Removing the text control parent should not add selection range"); +}, {once: true}); +</script> +</head> +<body></body> +</html> diff --git a/testing/web-platform/tests/selection/selection-range-in-shadow-after-the-shadow-removed.tentative.html b/testing/web-platform/tests/selection/selection-range-in-shadow-after-the-shadow-removed.tentative.html new file mode 100644 index 0000000000..e9f63715a2 --- /dev/null +++ b/testing/web-platform/tests/selection/selection-range-in-shadow-after-the-shadow-removed.tentative.html @@ -0,0 +1,96 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<meta name="variant" content="?mode=closed"> +<meta name="variant" content="?mode=open"> +<title>Selection range in shadow after removing the shadow</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<script> +"use strict"; + +addEventListener("load", () => { + const mode = (new URLSearchParams(document.location.search)).get("mode"); + const container = document.querySelector("div"); + test(() => { + const host = document.createElement("div"); + host.id = "host"; + const root = host.attachShadow({mode}); + root.innerHTML = '<div id="in-shadow">ABC</div>'; + container.appendChild(host); + getSelection().collapse(root.firstChild.firstChild, 2); + const range = getSelection().getRangeAt(0); + host.remove(); + // The range should be kept in the shadow because it's referred by JS as + // a range. + assert_equals(range.startContainer, root.firstChild.firstChild, "startContainer should not be changed"); + assert_equals(range.startOffset, 2, "startOffset should not be changed"); + // It may be reasonable to just remove the range in removed shadow. + // This matches with move-selection-range-into-different-root.tentative.html + assert_equals(getSelection().rangeCount, 0, "Selection should not have the range in removed shadow"); + }, "Selection range in shadow should not be as a selection range after the host is removed"); + + test(() => { + const wrapper = document.createElement("div"); + wrapper.id = "wrapper"; + const host = document.createElement("div"); + host.id = "host"; + const root = host.attachShadow({mode}); + root.innerHTML = '<div id="in-shadow">ABC</div>'; + wrapper.appendChild(host); + container.appendChild(wrapper); + getSelection().collapse(root.firstChild.firstChild, 2); + const range = getSelection().getRangeAt(0); + wrapper.remove(); + // The range should be kept in the shadow because it's referred by JS as + // a range. + assert_equals(range.startContainer, root.firstChild.firstChild, "startContainer should not be changed"); + assert_equals(range.startOffset, 2, "startOffset should not be changed"); + // It may be reasonable to just remove the range in removed shadow. + // This matches with move-selection-range-into-different-root.tentative.html + assert_equals(getSelection().rangeCount, 0, "Selection should not have the range in removed shadow"); + }, "Selection range in shadow should not be as a selection range after the host parent is removed"); + + test(() => { + const host = document.createElement("div"); + host.id = "host"; + const root = host.attachShadow({mode}); + root.innerHTML = '<div id="in-shadow">ABC</div>'; + container.appendChild(host); + getSelection().collapse(root.firstChild.firstChild, 2); + const range = getSelection().getRangeAt(0); + host.replaceWith(host); + // The range should be kept in the shadow because it's referred by JS as + // a range. + assert_equals(range.startContainer, root.firstChild.firstChild, "startContainer should not be changed"); + assert_equals(range.startOffset, 2, "startOffset should not be changed"); + // It may be reasonable to just remove the range in removed shadow. + // This matches with move-selection-range-into-different-root.tentative.html + assert_equals(getSelection().rangeCount, 0, "Selection should not have the range in removed shadow"); + host.remove(); + }, "Selection range in shadow should not be as a selection range after the host is replaced with itself (.replaceWith)"); + + test(() => { + const host = document.createElement("div"); + host.id = "host"; + const root = host.attachShadow({mode}); + root.innerHTML = '<div id="in-shadow">ABC</div>'; + container.appendChild(host); + getSelection().collapse(root.firstChild.firstChild, 2); + const range = getSelection().getRangeAt(0); + container.replaceChild(host, host); + // The range should be kept in the shadow because it's referred by JS as + // a range. + assert_equals(range.startContainer, root.firstChild.firstChild, "startContainer should not be changed"); + assert_equals(range.startOffset, 2, "startOffset should not be changed"); + // It may be reasonable to just remove the range in removed shadow. + // This matches with move-selection-range-into-different-root.tentative.html + assert_equals(getSelection().rangeCount, 0, "Selection should not have the range in removed shadow"); + host.remove(); + }, "Selection range in shadow should not be as a selection range after the host is replaced with itself (.replaceChild"); +}, {once: true}); +</script> +</head> +<body><div id="container"></div></body> +</html> |