blob: 1209b7536d43743d96669edd42bfd10d5eacd578 [file] [log] [blame]
<!DOCTYPE html>
<script src='../resources/testharness.js'></script>
<script src='../resources/testharnessreport.js'></script>
<script src='resources/shadow-dom.js'></script>
<template id='ShadowTemplate'>
<ul>
<li tabindex='0' id='one'>One</li>
<li tabindex='0' id='two'>Two</li>
<li id='three'>Three</li>
</ul>
</template>
<template id='NoFocusableShadowTemplate'>
<ul>
<li id='one'>One</li>
<li id='two'>Two</li>
<li id='three'>Three</li>
</ul>
</template>
<body>
<input id='input0'>
<x-shadow id='xshadow0'></x-shadow>
<x-shadow id='xshadow1' tabindex='0'></x-shadow>
<x-shadow id='xshadow2' tabindex='0' delegatesFocus></x-shadow>
<x-shadow-nofocus id='xshadow3'></x-shadow-nofocus>
<x-shadow-nofocus id='xshadow4' tabindex='0'></x-shadow-nofocus>
<x-shadow-nofocus id='xshadow5' tabindex='0' delegatesFocus></x-shadow-nofocus>
</body>
<script>
'use strict';
function registerShadow(templateId, tagName) {
const template = document.getElementById(templateId);
customElements.define(tagName, class extends HTMLElement {
connectedCallback() {
const delegatesFocus = this.hasAttribute('delegatesFocus');
this.attachShadow({mode: 'open', delegatesFocus: delegatesFocus})
.appendChild(document.importNode(template.content, true));
}
});
}
registerShadow('ShadowTemplate', 'x-shadow');
registerShadow('NoFocusableShadowTemplate', 'x-shadow-nofocus');
test(() => {
xshadow0.focus();
assert_equals(document.activeElement.tagName, 'BODY');
assert_equals(xshadow0.shadowRoot.activeElement, null);
}, 'xshadow0 is not focusable without tabindex.');
test(() => {
xshadow1.focus();
assert_equals(document.activeElement.id, 'xshadow1');
assert_equals(xshadow1.shadowRoot.activeElement, null);
}, 'xshadow1 becomes focusable with tabindex.');
test(() => {
xshadow2.focus();
assert_equals(document.activeElement.id, 'xshadow2');
assert_equals(xshadow2.shadowRoot.activeElement.id, 'one');
}, 'on focus(), focusable xshadow2 with delegatesFocus=true delegates focus into its inner element.');
test(() => {
xshadow2.shadowRoot.querySelector('#two').focus();
assert_equals(document.activeElement.id, 'xshadow2');
assert_equals(xshadow2.shadowRoot.activeElement.id, 'two');
}, 'if an element within shadow is focused, focusing on shadow host should not slide focus to its inner element.');
test(() => {
xshadow2.focus();
assert_equals(document.activeElement.id, 'xshadow2');
assert_equals(xshadow2.shadowRoot.activeElement.id, 'two');
}, 'xshadow2.focus() shouldn\'t move focus to #one when its inner element is already focused.');
test(() => {
// Focus outside shadow DOMs.
input0.focus();
// within shadow root. This is different from mouse click behavior.
xshadow1.shadowRoot.querySelector('#three').focus();
assert_equals(document.activeElement.id, 'input0');
xshadow2.shadowRoot.querySelector('#three').focus();
assert_equals(document.activeElement.id, 'input0');
}, 'focus() inside shadow DOM should not focus its shadow host, nor focusable siblings.');
test(() => {
xshadow3.focus();
assert_equals(document.activeElement.id, 'input0');
}, 'If any element including shadow host is not focusable, focus doesn\'t change.');
test(() => {
xshadow4.focus();
assert_equals(document.activeElement.id, 'xshadow4');
xshadow5.focus();
assert_equals(document.activeElement.id, 'xshadow5');
}, 'If no element is focusable within shadow root, but the shadow host is focusable, then the host gets focus regardless of delegatesFocus.');
</script>