Skip to content

Commit 58e55cf

Browse files
dizhang168mohamedamir
authored andcommitted
[selection api] Rewrite Selection-getComposedRanges-range-update.html
This change reformat the tentative test Selection-getComposedRanges-range-update.html to match the spec at whatwg/dom#1342: 1. If selection is across different roots, getRangeAt(0) should throw INDEX_SIZE_ERR. 2. If a live range sets its end/start to a disconnected node, the live range and the selection are both collapsed. 3. If a live range sets its end/start to cross a shadow boundary such that the range has start before end, collapse the live range, but not the composed selection range. 4. If a live range sets its end/start to cross a shadow boundary such that the range has start after end, collapse both the live range and the composed selection range. We also clean up the other range API tests: selectNode(), collapse, createRange(), addRange(). Change-Id: I03f9309be67b21a781c47d555732a3480322097b Bug: 40286116 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6383722 Reviewed-by: Dominic Farolino <[email protected]> Commit-Queue: Di Zhang <[email protected]> Cr-Commit-Position: refs/heads/main@{#1437019}
1 parent 7274558 commit 58e55cf

File tree

1 file changed

+161
-66
lines changed

1 file changed

+161
-66
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html>
33
<body>
4-
<meta name="assert" content="Selection's getComposedRanges should be updated when its associated live range changes">
4+
<meta name="assert" content="Selection's composed range should be updated when its associated legacy uncomposed range changes">
55
<link rel="help" href="https://w3c.github.io/selection-api/#dom-selection-getcomposedranges">
66
<script src="/resources/testharness.js"></script>
77
<script src="/resources/testharnessreport.js"></script>
@@ -17,6 +17,7 @@
1717
</div>
1818
</template>
1919
</div>
20+
<div id="lightEnd">End outside shadow DOM</div>
2021

2122
<script>
2223

@@ -27,48 +28,150 @@
2728
const innerRoot = innerHost.shadowRoot;
2829

2930
test(() => {
30-
// Step 1: Setting a composed live range that crosses boundaries
31+
// Setting a selction crossing to shadow tree
3132
selection.setBaseAndExtent(light.firstChild, 10, innerHost.firstChild, 5);
33+
assert_throws_dom("INDEX_SIZE_ERR", function () { selection.getRangeAt(0) });
34+
}, 'If selection crosses shadow boundaries, getRangeAt(0) should throw an IndexSizeError because the end is not in the document tree.');
35+
36+
test(() => {
37+
// Setting a selection within light tree
38+
selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
3239
const liveRange = selection.getRangeAt(0);
33-
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
40+
const newSpan = document.createElement("span");
41+
liveRange.setStart(newSpan, 0);
42+
43+
assert_true(liveRange.collapsed);
44+
assert_equals(liveRange.startContainer, newSpan);
45+
assert_equals(liveRange.startOffset, 0);
46+
47+
assert_true(selection.isCollapsed);
48+
assert_equals(selection.anchorNode, null);
49+
assert_equals(selection.anchorOffset, 0);
50+
51+
assert_throws_dom("INDEX_SIZE_ERR", function () { selection.getRangeAt(0) });
52+
assert_equals(selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] }).length, 0);
53+
54+
}, 'modify getRangeAt() range: setStart() to disconnected node will collapse and remove the live range from the selection.');
55+
56+
test(() => {
57+
// Setting a selection within light tree
58+
selection.setBaseAndExtent(light.firstChild, 10, light.firstChild, 20);
59+
const liveRange = selection.getRangeAt(0);
60+
let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
61+
62+
assert_equals(liveRange.startContainer, light.firstChild);
63+
assert_equals(liveRange.startOffset, 10);
64+
assert_equals(liveRange.endContainer, light.firstChild);
65+
assert_equals(liveRange.endOffset, 20);
66+
67+
assert_equals(selection.anchorNode, light.firstChild);
68+
assert_equals(selection.anchorOffset, 10);
69+
assert_equals(selection.focusNode, light.firstChild);
70+
assert_equals(selection.focusOffset, 20);
71+
72+
assert_equals(composedRange.startContainer, light.firstChild);
73+
assert_equals(composedRange.startOffset, 10);
74+
assert_equals(composedRange.endContainer, light.firstChild);
75+
assert_equals(composedRange.endOffset, 20);
3476

77+
liveRange.setEnd(innerHost.firstChild, 5);
78+
composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
79+
80+
assert_true(liveRange.collapsed);
3581
assert_equals(liveRange.startContainer, innerHost.firstChild);
3682
assert_equals(liveRange.startOffset, 5);
37-
assert_equals(liveRange.endContainer, innerHost.firstChild);
38-
assert_equals(liveRange.endOffset, 5);
3983

84+
assert_true(selection.isCollapsed);
4085
assert_equals(selection.anchorNode, innerHost.firstChild);
4186
assert_equals(selection.anchorOffset, 5);
42-
assert_equals(selection.focusNode, innerHost.firstChild);
43-
assert_equals(selection.focusOffset, 5);
4487

4588
assert_equals(composedRange.startContainer, light.firstChild);
4689
assert_equals(composedRange.startOffset, 10);
4790
assert_equals(composedRange.endContainer, innerHost.firstChild);
4891
assert_equals(composedRange.endOffset, 5);
92+
}, 'modify getRangeAt() range: setEnd() crosses shadow boundary into the shadow DOM and after start, which collapses live range. Composed selection range is not collapsed.');
93+
94+
test(() => {
95+
// Setting a selection within light tree
96+
selection.setBaseAndExtent(lightEnd.firstChild, 10, lightEnd.firstChild, 20);
97+
const liveRange = selection.getRangeAt(0);
98+
let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
99+
100+
assert_equals(liveRange.startContainer, lightEnd.firstChild);
101+
assert_equals(liveRange.startOffset, 10);
102+
assert_equals(liveRange.endContainer, lightEnd.firstChild);
103+
assert_equals(liveRange.endOffset, 20);
104+
105+
assert_equals(selection.anchorNode, lightEnd.firstChild);
106+
assert_equals(selection.anchorOffset, 10);
107+
assert_equals(selection.focusNode, lightEnd.firstChild);
108+
assert_equals(selection.focusOffset, 20);
49109

50-
// Step 2: Update the live range only using setEnd
51-
liveRange.setEnd(innerHost.firstChild, 6);
52-
const composedRange2 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
110+
assert_equals(composedRange.startContainer, lightEnd.firstChild);
111+
assert_equals(composedRange.startOffset, 10);
112+
assert_equals(composedRange.endContainer, lightEnd.firstChild);
113+
assert_equals(composedRange.endOffset, 20);
114+
115+
liveRange.setStart(innerHost.firstChild, 5);
116+
composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
53117

118+
assert_true(liveRange.collapsed);
54119
assert_equals(liveRange.startContainer, innerHost.firstChild);
55120
assert_equals(liveRange.startOffset, 5);
56-
assert_equals(liveRange.endContainer, innerHost.firstChild);
57-
assert_equals(liveRange.endOffset, 6);
58121

122+
assert_true(selection.isCollapsed);
123+
assert_equals(selection.anchorNode, innerHost.firstChild);
124+
assert_equals(selection.anchorOffset, 5);
125+
126+
assert_equals(composedRange.startContainer, innerHost.firstChild);
127+
assert_equals(composedRange.startOffset, 5);
128+
assert_equals(composedRange.endContainer, lightEnd.firstChild);
129+
assert_equals(composedRange.endOffset, 20);
130+
}, 'modify getRangeAt() range: setStart() crosses shadow boundary into the shadow DOM and before end, which collapses live range. Composed selection range is not collapsed.');
131+
132+
test(() => {
133+
// Setting a selection within light tree
134+
selection.setBaseAndExtent(light.firstChild, 10, light.firstChild, 20);
135+
const liveRange = selection.getRangeAt(0);
136+
let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
137+
138+
assert_equals(liveRange.startContainer, light.firstChild);
139+
assert_equals(liveRange.startOffset, 10);
140+
assert_equals(liveRange.endContainer, light.firstChild);
141+
assert_equals(liveRange.endOffset, 20);
142+
143+
assert_equals(selection.anchorNode, light.firstChild);
144+
assert_equals(selection.anchorOffset, 10);
145+
assert_equals(selection.focusNode, light.firstChild);
146+
assert_equals(selection.focusOffset, 20);
147+
148+
assert_equals(composedRange.startContainer, light.firstChild);
149+
assert_equals(composedRange.startOffset, 10);
150+
assert_equals(composedRange.endContainer, light.firstChild);
151+
assert_equals(composedRange.endOffset, 20);
152+
153+
liveRange.setStart(innerHost.firstChild, 5);
154+
composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
155+
156+
assert_true(liveRange.collapsed);
157+
assert_equals(liveRange.startContainer, innerHost.firstChild);
158+
assert_equals(liveRange.startOffset, 5);
159+
160+
assert_true(selection.isCollapsed);
59161
assert_equals(selection.anchorNode, innerHost.firstChild);
60162
assert_equals(selection.anchorOffset, 5);
61-
assert_equals(selection.focusNode, innerHost.firstChild);
62-
assert_equals(selection.focusOffset, 6);
63163

64-
assert_equals(composedRange2.startContainer, light.firstChild);
65-
assert_equals(composedRange2.startOffset, 10);
66-
assert_equals(composedRange2.endContainer, innerHost.firstChild);
67-
assert_equals(composedRange2.endOffset, 6);
164+
assert_true(composedRange.collapsed);
165+
assert_equals(composedRange.startContainer, innerHost.firstChild);
166+
assert_equals(composedRange.startOffset, 5);
167+
}, 'modify getRangeAt() range: setStart() crosses shadow boundary into the shadow DOM and after end, which collapses both live range and composed selection range.');
68168

69-
// Step 3: selectNode() calls both setStart/setEnd
169+
test(() => {
170+
// Setting a selection within light tree
171+
selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
172+
const liveRange = selection.getRangeAt(0);
70173
liveRange.selectNode(innerHost);
71-
const composedRange3 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
174+
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
72175

73176
assert_equals(liveRange.startContainer, outerRoot);
74177
assert_equals(liveRange.startOffset, 3);
@@ -80,30 +183,31 @@
80183
assert_equals(selection.focusNode, outerRoot);
81184
assert_equals(selection.focusOffset, 4);
82185

83-
assert_equals(composedRange3.startContainer, outerRoot);
84-
assert_equals(composedRange3.startOffset, 3);
85-
assert_equals(composedRange3.endContainer, outerRoot);
86-
assert_equals(composedRange3.endOffset, 4);
186+
assert_equals(composedRange.startContainer, outerRoot);
187+
assert_equals(composedRange.startOffset, 3);
188+
assert_equals(composedRange.endContainer, outerRoot);
189+
assert_equals(composedRange.endOffset, 4);
190+
}, 'modify getRangeAt() range: selectNode() innerHost for all ranges.');
87191

88-
// Step 4: collapse(false) calls setEnd only
192+
test(() => {
193+
// Setting a selection within light tree
194+
selection.setBaseAndExtent(light.firstChild, 10, lightEnd.firstChild, 20);
195+
const liveRange = selection.getRangeAt(0);
89196
liveRange.collapse();
90-
const composedRange4 = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
197+
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
91198

92-
assert_equals(liveRange.startContainer, outerRoot);
93-
assert_equals(liveRange.startOffset, 4);
94-
assert_equals(liveRange.endContainer, outerRoot);
95-
assert_equals(liveRange.endOffset, 4);
199+
assert_true(liveRange.collapsed);
200+
assert_equals(liveRange.startContainer, lightEnd.firstChild);
201+
assert_equals(liveRange.startOffset, 20);
96202

97-
assert_equals(selection.anchorNode, outerRoot);
98-
assert_equals(selection.anchorOffset, 4);
99-
assert_equals(selection.focusNode, outerRoot);
100-
assert_equals(selection.focusOffset, 4);
203+
assert_true(selection.isCollapsed);
204+
assert_equals(selection.anchorNode, lightEnd.firstChild);
205+
assert_equals(selection.anchorOffset, 20);
101206

102-
assert_equals(composedRange4.startContainer, outerRoot);
103-
assert_equals(composedRange4.startOffset, 4);
104-
assert_equals(composedRange4.endContainer, outerRoot);
105-
assert_equals(composedRange4.endOffset, 4);
106-
}, 'modify getRangeAt() range.');
207+
assert_true(composedRange.collapsed);
208+
assert_equals(composedRange.startContainer, lightEnd.firstChild);
209+
assert_equals(composedRange.startOffset, 20);
210+
}, 'modify getRangeAt() range: collapse() collapses all ranges.');
107211

108212
test(() => {
109213
// Step 1: Creating a live range and only setting its end/anchor
@@ -112,37 +216,32 @@
112216
liveRange.setEnd(innerHost.firstChild, 5);
113217
const composedRanges = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] });
114218

219+
assert_true(liveRange.collapsed);
115220
assert_equals(liveRange.startContainer, innerHost.firstChild);
116221
assert_equals(liveRange.startOffset, 5);
117-
assert_equals(liveRange.endContainer, innerHost.firstChild);
118-
assert_equals(liveRange.endOffset, 5);
119222

223+
assert_true(selection.isCollapsed);
120224
assert_equals(selection.anchorNode, null);
121225
assert_equals(selection.anchorOffset, 0);
122-
assert_equals(selection.focusNode, null);
123-
assert_equals(selection.focusOffset, 0);
124226

125-
assert_equals(composedRanges.length, 0);
227+
assert_equals(composedRanges.length, 0, 'range is not added to selection yet.');
126228

127229
// Step 2: Add range to selection so range API updates will change selection
128230
selection.addRange(liveRange);
129231
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
130232

131-
assert_equals(liveRange.startContainer, innerHost.firstChild);
132-
assert_equals(liveRange.startOffset, 5);
233+
assert_true(liveRange.collapsed);
133234
assert_equals(liveRange.endContainer, innerHost.firstChild);
134235
assert_equals(liveRange.endOffset, 5);
135236

237+
assert_true(selection.isCollapsed);
136238
assert_equals(selection.anchorNode, innerHost.firstChild);
137239
assert_equals(selection.anchorOffset, 5);
138-
assert_equals(selection.focusNode, innerHost.firstChild);
139-
assert_equals(selection.focusOffset, 5);
140240

241+
assert_true(composedRange.collapsed);
141242
assert_equals(composedRange.startContainer, innerHost.firstChild);
142243
assert_equals(composedRange.startOffset, 5);
143-
assert_equals(composedRange.endContainer, innerHost.firstChild);
144-
assert_equals(composedRange.endOffset, 5);
145-
}, 'modify createRange() range added to selection after setEnd call.');
244+
}, 'modify createRange() range: adding to selection sets the selection');
146245

147246
test(() => {
148247
// Step 1: Creating a live range and only setting its end/anchor
@@ -151,17 +250,15 @@
151250
// Add range to selection so range API updates will change selection
152251
selection.addRange(liveRange);
153252
liveRange.setEnd(innerHost.firstChild, 5);
154-
const composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
253+
let composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
155254

255+
assert_true(liveRange.collapsed);
156256
assert_equals(liveRange.startContainer, innerHost.firstChild);
157257
assert_equals(liveRange.startOffset, 5);
158-
assert_equals(liveRange.endContainer, innerHost.firstChild);
159-
assert_equals(liveRange.endOffset, 5);
160258

259+
assert_true(selection.isCollapsed);
161260
assert_equals(selection.anchorNode, innerHost.firstChild);
162261
assert_equals(selection.anchorOffset, 5);
163-
assert_equals(selection.focusNode, innerHost.firstChild);
164-
assert_equals(selection.focusOffset, 5);
165262

166263
assert_equals(composedRange.startContainer, document);
167264
assert_equals(composedRange.startOffset, 0);
@@ -170,21 +267,19 @@
170267

171268
// Step 2: Update the live range by setting its start/focus
172269
liveRange.setStart(light.firstChild, 10);
173-
const composedRangeAfter = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
270+
composedRange = selection.getComposedRanges({ shadowRoots: [outerRoot, innerRoot] })[0];
174271

272+
assert_true(liveRange.collapsed);
175273
assert_equals(liveRange.startContainer, light.firstChild);
176274
assert_equals(liveRange.startOffset, 10);
177-
assert_equals(liveRange.endContainer, light.firstChild);
178-
assert_equals(liveRange.endOffset, 10);
179275

276+
assert_true(selection.isCollapsed);
180277
assert_equals(selection.anchorNode, light.firstChild);
181278
assert_equals(selection.anchorOffset, 10);
182-
assert_equals(selection.focusNode, light.firstChild);
183-
assert_equals(selection.focusOffset, 10);
184279

185-
assert_equals(composedRangeAfter.startContainer, light.firstChild);
186-
assert_equals(composedRangeAfter.startOffset, 10);
187-
assert_equals(composedRangeAfter.endContainer, innerHost.firstChild);
188-
assert_equals(composedRangeAfter.endOffset, 5);
189-
}, 'modify createRange() range added to selection before setStart/setEnd calls.');
280+
assert_equals(composedRange.startContainer, light.firstChild);
281+
assert_equals(composedRange.startOffset, 10);
282+
assert_equals(composedRange.endContainer, innerHost.firstChild);
283+
assert_equals(composedRange.endOffset, 5);
284+
}, 'modify createRange() range: added to selection before setStart/setEnd calls.');
190285
</script>

0 commit comments

Comments
 (0)