summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/selection
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/selection')
-rw-r--r--testing/web-platform/tests/selection/crashtests/selection-modify-around-textarea.html23
-rw-r--r--testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-empty-details.html29
-rw-r--r--testing/web-platform/tests/selection/crashtests/selection-modify-line-boundary-around-shadow.html30
-rw-r--r--testing/web-platform/tests/selection/selection-range-after-editinghost-removed.html69
-rw-r--r--testing/web-platform/tests/selection/selection-range-after-textcontrol-removed.html55
-rw-r--r--testing/web-platform/tests/selection/selection-range-in-shadow-after-the-shadow-removed.tentative.html96
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>