chromium/third_party/blink/web_tests/shadow-dom/focus-slide-on-shadow-host.html

<!DOCTYPE html>
<script src='../resources/testharness.js'></script>
<script src='../resources/testharnessreport.js'></script>
<script src='resources/shadow-dom.js'></script>
<script src='resources/focus-utils.js'></script>
<input id='defaultFocus'>
<div id='sandbox'></div>
<script>
'use strict';

function prepareDOMTree(parent, delegatesFocus) {
    parent.innerHTML = '';
    let host = document.createElement('div');
    host.id = 'shadowHost';
    host.setAttribute('tabindex', '0');
    var root = host.attachShadow({mode: 'open', delegatesFocus: delegatesFocus});
    root.innerHTML = '<div id="innerDiv">Blink</div><input id="inputA"><input id="inputB">';
    parent.appendChild(host);
}

var host;
var innerDiv;
var inputA;
var inputB;

// TODO(https://crbug.com/1350218): Replace this with test_diver.click() and
// move test to WPT
function clickOn(el) {
    eventSender.mouseMoveTo(el.offsetLeft + 8, el.offsetTop + 8);
    eventSender.mouseDown();
    eventSender.mouseUp();
}

function resetFocus() {
    document.querySelector('#defaultFocus').focus();
}

function assert_innermost_active_element(path) {
    assert_true(isInnermostActiveElement(path), 'innermost active element should be ' + path);
}

test(() => {
    prepareDOMTree(sandbox, false);
    resetFocus();

    let host = getNodeInComposedTree('shadowHost');
    let innerDiv = getNodeInComposedTree('shadowHost/innerDiv');
    let inputA = getNodeInComposedTree('shadowHost/inputA');
    let inputB = getNodeInComposedTree('shadowHost/inputB');

    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost');

    inputA.focus();
    assert_innermost_active_element('shadowHost/inputA');
    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost');

    inputB.focus();
    assert_innermost_active_element('shadowHost/inputB');
    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost');
}, 'click on inner div should focus shadow host (with delegatesFocus = false).');

test(() => {
    prepareDOMTree(sandbox, true);
    resetFocus();

    let host = getNodeInComposedTree('shadowHost');
    let innerDiv = getNodeInComposedTree('shadowHost/innerDiv');
    let inputA = getNodeInComposedTree('shadowHost/inputA');
    let inputB = getNodeInComposedTree('shadowHost/inputB');

    inputA.value = 'wonderful';  // len = 9
    inputB.value = 'beautiful';

    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost/inputA');

    // If focus slides from shadow host, all the content will be selected.
    assert_equals(inputA.selectionStart, 0);
    assert_equals(inputA.selectionEnd, 9);

    // Clicking on non-focusable area inside shadow should not change the focus state.
    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost/inputA');
    assert_equals(inputA.selectionStart, 0);
    assert_equals(inputA.selectionEnd, 9);

    // Clicking on focusable directly will cause the element to be focused.
    clickOn(inputA);
    assert_innermost_active_element('shadowHost/inputA');
    inputA.setSelectionRange(1, 1);
    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost/inputA');
    assert_equals(inputA.selectionStart, 1, 'inputA selection start should be preserved.');
    assert_equals(inputA.selectionEnd, 1, 'inputA selection end should be preserved.');

    clickOn(inputB);
    assert_innermost_active_element('shadowHost/inputB');
    inputA.setSelectionRange(1, 1);
    clickOn(innerDiv);
    assert_innermost_active_element('shadowHost/inputB');
    assert_equals(inputB.selectionStart, 1, 'inputB selection start should be preserved.');
    assert_equals(inputB.selectionEnd, 1, 'inputB selection end should be preserved.');
}, 'click on inner div should focus inner focusable (with delegatesFocus = true).');
</script>