chromium/third_party/blink/web_tests/accessibility/contenteditable-selection.html

<!DOCTYPE html>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>

<div id="main" role="main">

    <div id="contenteditable-textbox" role="textbox" contenteditable="true">
        <div id="contenteditable-line1">Line 1</div>
        <textarea id="contenteditable-line2" rows="1" cols="40">Line 2</textarea>
    </div>

    <div id="contenteditable-div" contenteditable>
        <p id="paragraph1">Line 1<br>Line 2</p>
        <p id="paragraph2">Line 3</p>
    </div>

</div>

<script>
    test(() =>
    {
        let selection = window.getSelection();
        let selectionRange = document.createRange();
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;

        let textbox = document.getElementById("contenteditable-textbox");
        let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");

        // Select the entire contents of the outer ARIA textbox.
        // These include another ARIA textbox and a textarea node
        // taking up three lines.
        textbox.focus();
        selectionRange.selectNodeContents(textbox);
        selection.removeAllRanges();
        selection.addRange(selectionRange);

        assert_equals(textboxAccessible.selectionAnchorObject, textboxAccessible);
        assert_equals(textboxAccessible.selectionAnchorOffset, 0);
        assert_equals(textboxAccessible.selectionFocusObject, textboxAccessible);
        // Two nodes have been selected: the two text fields  inside the outer one.
        assert_equals(textboxAccessible.selectionFocusOffset, 2);

        // Selection offsets should be the same when retrieved from the parent object.
        assert_equals(mainAccessible.selectionAnchorObject, textboxAccessible);
        assert_equals(mainAccessible.selectionAnchorOffset, 0);
        assert_equals(mainAccessible.selectionFocusObject, textboxAccessible);
        assert_equals(mainAccessible.selectionFocusOffset, 2);

        assert_equals(rootAccessible.selectionAnchorObject, textboxAccessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 0);
        assert_equals(rootAccessible.selectionFocusObject, textboxAccessible);
        assert_equals(rootAccessible.selectionFocusOffset, 2);
    }, "Test selectNodeContents on an ARIA textbox.");

    test(() =>
    {
        let selection = window.getSelection();
        let selectionRange = document.createRange();
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;

        let contenteditable = document.getElementById("contenteditable-div");
        let line1 = document.getElementById("paragraph1").firstChild;
        let line3 = document.getElementById("paragraph2").firstChild;
        let contenteditableAccessible = accessibilityController.accessibleElementById("contenteditable-div");

        // Select the entire contents of the second content editable.
        contenteditable.focus();
        selectionRange.selectNodeContents(contenteditable);
        selection.removeAllRanges();
        selection.addRange(selectionRange);

        assert_equals(contenteditableAccessible.selectionAnchorObject, contenteditableAccessible);
        assert_equals(contenteditableAccessible.selectionAnchorOffset, 0);
        assert_equals(contenteditableAccessible.selectionFocusObject, contenteditableAccessible);
        assert_equals(contenteditableAccessible.selectionFocusOffset, 2);

        assert_equals(mainAccessible.selectionAnchorObject, contenteditableAccessible);
        assert_equals(mainAccessible.selectionAnchorOffset, 0);
        assert_equals(mainAccessible.selectionFocusObject, contenteditableAccessible);
        assert_equals(mainAccessible.selectionFocusOffset, 2);

        assert_equals(rootAccessible.selectionAnchorObject, contenteditableAccessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 0);
        assert_equals(rootAccessible.selectionFocusObject, contenteditableAccessible);
        assert_equals(rootAccessible.selectionFocusOffset, 2);
    }, "Test selectNodeContents on a contenteditable.");

    test(() =>
    {
        let selection = window.getSelection();
        let selectionRange = document.createRange();
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;
        let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
        let line1 = document.getElementById("contenteditable-line1");
        let line1Accessible = accessibilityController.accessibleElementById("contenteditable-line1");
        let line1TextAccessible = line1Accessible.childAtIndex(0);

        // Select only the first line of the ARIA textbox.
        selectionRange.setStart(line1.firstChild, 0);
        selectionRange.setEnd(line1.firstChild, 6);
        selection.removeAllRanges();
        selection.addRange(selectionRange);

        assert_equals(textboxAccessible.selectionAnchorObject, line1TextAccessible);
        assert_equals(textboxAccessible.selectionAnchorOffset, 0);
        assert_equals(textboxAccessible.selectionFocusObject, line1TextAccessible);
        assert_equals(textboxAccessible.selectionFocusOffset, 6);

        assert_equals(mainAccessible.selectionAnchorObject, line1TextAccessible);
        assert_equals(mainAccessible.selectionAnchorOffset, 0);
        assert_equals(mainAccessible.selectionFocusObject, line1TextAccessible);
        assert_equals(mainAccessible.selectionFocusOffset, 6);

        assert_equals(rootAccessible.selectionAnchorObject, line1TextAccessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 0);
        assert_equals(rootAccessible.selectionFocusObject, line1TextAccessible);
        assert_equals(rootAccessible.selectionFocusOffset, 6);
    }, "The effects of the setStart and setEnd methods should be reflected in the accessibility API.");

    test(() =>
    {
        let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
        let rootAccessible = accessibilityController.rootElement;
        let line2 = document.getElementById("contenteditable-line2");
        let line2Accessible = accessibilityController.accessibleElementById("contenteditable-line2");

        line2.focus();

        // The selection should have been removed from the line1 div
        // due to the focus being moved.
        assert_equals(textboxAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(textboxAccessible.selectionAnchorOffset, 0);
        assert_equals(textboxAccessible.selectionFocusObject, line2Accessible);
        assert_equals(textboxAccessible.selectionFocusOffset, 0);

        assert_equals(rootAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 0);
        assert_equals(rootAccessible.selectionFocusObject, line2Accessible);
        assert_equals(rootAccessible.selectionFocusOffset, 0);
    }, "Verify that changing the focus removes the selection.");

    test(() =>
    {
        let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;
        let line2Accessible = accessibilityController.accessibleElementById("contenteditable-line2");
        let line2 = document.getElementById("contenteditable-line2");

        // Select only the second line of the ARIA textbox, that is,
        // the one found in the textarea.
        line2.setSelectionRange(0, line2.textLength);

        assert_equals(line2Accessible.selectionAnchorOffset, 0);
        assert_equals(line2Accessible.selectionFocusOffset, line2.textLength);

        assert_equals(textboxAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(textboxAccessible.selectionAnchorOffset, 0);
        assert_equals(textboxAccessible.selectionFocusObject, line2Accessible);
        assert_equals(textboxAccessible.selectionFocusOffset, line2.textLength);

        assert_equals(mainAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(mainAccessible.selectionAnchorOffset, 0);
        assert_equals(mainAccessible.selectionFocusObject, line2Accessible);
        assert_equals(mainAccessible.selectionFocusOffset, line2.textLength);

        assert_equals(rootAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 0);
        assert_equals(rootAccessible.selectionFocusObject, line2Accessible);
        assert_equals(rootAccessible.selectionFocusOffset, line2.textLength);
    }, "The effects of the textarea.setSelectionRange method should be reflected in the accessibility API.");

    test(() =>
    {
        let textboxAccessible = accessibilityController.accessibleElementById("contenteditable-textbox");
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;
        let line2Accessible = accessibilityController.accessibleElementById("contenteditable-line2");

        // Selection can also be set via the accessibility API.
        line2Accessible.setSelectedTextRange(2, 3);

        assert_equals(line2Accessible.selectionAnchorObject, line2Accessible);
        assert_equals(line2Accessible.selectionAnchorOffset, 2);
        assert_equals(line2Accessible.selectionFocusObject, line2Accessible);
        assert_equals(line2Accessible.selectionFocusOffset, 5);

        assert_equals(textboxAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(textboxAccessible.selectionAnchorOffset, 2);
        assert_equals(textboxAccessible.selectionFocusObject, line2Accessible);
        assert_equals(textboxAccessible.selectionFocusOffset, 5);

        assert_equals(mainAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(mainAccessible.selectionAnchorOffset, 2);
        assert_equals(mainAccessible.selectionFocusObject, line2Accessible);
        assert_equals(mainAccessible.selectionFocusOffset, 5);

        assert_equals(rootAccessible.selectionAnchorObject, line2Accessible);
        assert_equals(rootAccessible.selectionAnchorOffset, 2);
        assert_equals(rootAccessible.selectionFocusObject, line2Accessible);
        assert_equals(rootAccessible.selectionFocusOffset, 5);
    }, "Test the setSelectedTextRange accessibility API function.");

    test(() =>
    {
        let selection = window.getSelection();
        let selectionRange = document.createRange();
        let mainAccessible = accessibilityController.accessibleElementById("main");
        let rootAccessible = accessibilityController.rootElement;

        let contenteditable = document.getElementById("contenteditable-div");
        let line1 = document.getElementById("paragraph1").firstChild;
        let line2 = document.getElementById("paragraph1").lastChild;
        let line3 = document.getElementById("paragraph2").firstChild;
        let contenteditableLines = [ line1, line2, line3 ];

        let contenteditableAccessible = accessibilityController.accessibleElementById("contenteditable-div");
        let paragraph1Accessible = accessibilityController.accessibleElementById("paragraph1");
        let paragraph2Accessible = accessibilityController.accessibleElementById("paragraph2");
        let line1Accessible = paragraph1Accessible.childAtIndex(0);
        let line2Accessible = paragraph1Accessible.childAtIndex(2);
        let line3Accessible = paragraph2Accessible.childAtIndex(0);
        let expectations = [
          [  line1Accessible, 0, paragraph1Accessible, 1 ],
          [ line2Accessible, 0, paragraph1Accessible, 3 ],
          [ line3Accessible, 0, paragraph2Accessible, 1 ],
        ];

        // Select entire lines in the second content editable.
        for (let testCase = 0; testCase < 2; ++testCase) {
            for (let i = 0; i < contenteditableLines.length; ++i) {
                selectionRange.selectNode(contenteditableLines[i]);
                selection.removeAllRanges();
                selection.addRange(selectionRange);

                assert_equals(contenteditableAccessible.selectionAnchorObject, expectations[i][0]);
                assert_equals(contenteditableAccessible.selectionAnchorOffset, expectations[i][1]);
                assert_equals(contenteditableAccessible.selectionFocusObject, expectations[i][2]);
                assert_equals(contenteditableAccessible.selectionFocusOffset, expectations[i][3]);

                assert_equals(mainAccessible.selectionAnchorObject, expectations[i][0]);
                assert_equals(mainAccessible.selectionAnchorOffset, expectations[i][1]);
                assert_equals(mainAccessible.selectionFocusObject, expectations[i][2]);
                assert_equals(mainAccessible.selectionFocusOffset, expectations[i][3]);

                assert_equals(rootAccessible.selectionAnchorObject, expectations[i][0]);
                assert_equals(rootAccessible.selectionAnchorOffset, expectations[i][1]);
                assert_equals(rootAccessible.selectionFocusObject, expectations[i][2]);
                assert_equals(rootAccessible.selectionFocusOffset, expectations[i][3]);
            }

            // For a sanity check, try the same test with contenteditable="false".
            contenteditable.contenteditable = false;
        }

    }, "The effects of the selectNode method should be reflected in the accessibility API.");
</script>