Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test has a WPT meta file that expects 3 subtest issues.
- This WPT test may be referenced by the following Test IDs:
- /selection/shadow-dom/tentative/Selection-getComposedRanges-slot.html - WPT Dashboard Interop Dashboard
<!DOCTYPE html>
<html>
<body>
<meta name="author" href="mailto:dizhangg@chromium.org">
<meta name="assert" content="Selection's getComposedRanges should return a sequence of static ranges, selecting from slotted content">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="container"></div>
<script>
test(() => {
container.innerHTML = '<div id=host>Second</div>';
const shadowRoot = host.attachShadow({ mode:"open" });
shadowRoot.innerHTML = 'First <slot></slot> Third';
const second = host.firstChild;
const third = shadowRoot.querySelector('slot').nextSibling;
const sel = getSelection();
// Select from slotted second to shadowed third.
sel.setBaseAndExtent(second, 3, third, 4);
assert_equals(sel.getRangeAt(0).startContainer, second);
assert_equals(sel.getRangeAt(0).startOffset, 3);
assert_equals(sel.getRangeAt(0).endContainer, second, 'Collapsed because crossing shadow tree is not supported for getRangeAt.');
assert_equals(sel.getRangeAt(0).endOffset, 3);
assert_equals(sel.getComposedRanges()[0].startContainer, container);
assert_equals(sel.getComposedRanges()[0].startOffset, 0, 'Rescoped because no shadow roots were provided');
assert_equals(sel.getComposedRanges()[0].endContainer, second);
assert_equals(sel.getComposedRanges()[0].endOffset, 3);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
// Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
sel.setBaseAndExtent(third, 4, second, 3);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
}, 'Setting the range to start on slotted content and end in shadow tree, should follow DOM tree order.');
test(() => {
container.innerHTML = [
'<div id=host>',
'<div id=div1 slot=slot2>slotted content 1</div>',
'<div id=div2 slot=slot1>slotted content 2</div>',
'</div>'
].join('');
const shadowRoot = host.attachShadow({mode: 'open'});
shadowRoot.innerHTML = [
'<span>before</span>',
'<slot name=slot1></slot>',
'<span>between</span>',
'<slot name=slot2></slot>',
'<span>after</span>',
].join('');
const sel = getSelection();
// Select from slotted div1 to slotted div2.
sel.setBaseAndExtent(div1.firstChild, 2, div2.firstChild, 2);
assert_equals(sel.getRangeAt(0).startContainer, div1.firstChild);
assert_equals(sel.getRangeAt(0).startOffset, 2);
assert_equals(sel.getRangeAt(0).endContainer, div2.firstChild, 'Not collapsed because we are not crossing shadow trees.');
assert_equals(sel.getRangeAt(0).endOffset, 2);
assert_equals(sel.getComposedRanges()[0].startContainer, div1.firstChild);
assert_equals(sel.getComposedRanges()[0].startOffset, 2);
assert_equals(sel.getComposedRanges()[0].endContainer, div2.firstChild, 'Not rescoped because we are not crossing shadow trees.');
assert_equals(sel.getComposedRanges()[0].endOffset, 2);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, div1.firstChild);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 2);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, div2.firstChild);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 2);
// Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
sel.setBaseAndExtent(div2.firstChild, 2, div1.firstChild, 2);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, div1.firstChild);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 2);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, div2.firstChild);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 2);
}, 'Setting the range to start and end on slotted content, should follow DOM tree order.');
test(() => {
container.innerHTML = '<div id=host>Second</div>';
const shadowRoot = host.attachShadow({ mode:"open" });
shadowRoot.innerHTML = '<span id="first">First</span><span id=third>Third</span>';
const second = host.firstChild;
const third = shadowRoot.getElementById('third').firstChild;
const sel = getSelection();
// Select from unslotted second to shadowed third.
sel.setBaseAndExtent(second, 3, third, 4);
assert_equals(sel.getRangeAt(0).startContainer, second);
assert_equals(sel.getRangeAt(0).startOffset, 3);
assert_equals(sel.getRangeAt(0).endContainer, second, 'Collapsed because crossing shadow tree is not supported for getRangeAt.');
assert_equals(sel.getRangeAt(0).endOffset, 3);
assert_equals(sel.getComposedRanges()[0].startContainer, container);
assert_equals(sel.getComposedRanges()[0].startOffset, 0, 'Rescoped because no shadow roots were provided');
assert_equals(sel.getComposedRanges()[0].endContainer, second);
assert_equals(sel.getComposedRanges()[0].endOffset, 3);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
// Repeat the test, but reversing base and extent. This should not affect the range's start and end positions.
sel.setBaseAndExtent(third, 4, second, 3);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startContainer, third);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].startOffset, 4);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endContainer, second);
assert_equals(sel.getComposedRanges({ shadowRoots: [shadowRoot] })[0].endOffset, 3);
}, 'Setting the range to start on unslotted content and end in shadow tree, should follow DOM tree order.');
</script>