chromium/third_party/blink/web_tests/editing/selection/directionality-after-undo-replace.html

<!doctype html>
<script src="../../resources/ahem.js"></script>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../assert_selection.js"></script>
<script>
// This tests Blink preserves non-directional selection after unapplying
// replacement on Mac.
//
// This tests do following steps:
//  1. Select "world" by double-clicking the word
//  2. Replace "world" by a character by pressing a key
//  3. Undo
//  4. Extend selection to the left

const kStyle = [
    'font: 30px/1 monospace;',
].join('');

function doubleClick(selection) {
    if (!window.eventSender)
        throw 'This test requires eventSender.';
    const target = selection.document.getElementById('target');

    eventSender.leapForward(9999); // reset mouse button state
    eventSender.mouseMoveTo(
        selection.computeLeft(target) + target.offsetWidth / 2,
        selection.computeTop(target) + target.offsetHeight / 2);
    eventSender.mouseDown();
    eventSender.mouseUp();

    eventSender.leapForward(200);

    eventSender.mouseDown();
    eventSender.mouseUp();
}

const kSample = [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC wo<b id="target">r</b>ld XYZ',
            '</div>',
];

const steps = [
    {
        title: '1. Select "world" by double-clicking the word',
        action: doubleClick,
        expected: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC ^wo<b id="target">r</b>ld| XYZ',
            '</div>',
        ],
        win: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                // Windoews selects word with a trailing space.
                'ABC ^wo<b id="target">r</b>ld |XYZ',
            '</div>',
        ],
    },

    {
        title: '2. Replace "world" by a character by pressing a key',
        action: selection => {
            selection.document.execCommand('InsertText', false,  'a');
        },
        expected: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC a|\u00A0XYZ',
            '</div>',
        ],
        win: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC a|XYZ',
            '</div>',
        ],
    },

    {
        title: '3. Undo',
        action: selection => {
            selection.document.execCommand('Undo');
        },
        expected: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC ^wo<b id="target">r</b>ld| XYZ',
            '</div>',
        ],
        win: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC ^wo<b id="target">r</b>ld |XYZ',
            '</div>',
        ],
    },

    {
        title: '4. Extend selection to the left',
        action: selection => selection.modify('extend', 'left', 'character'),
        expected: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC ^wo<b id="target">r</b>l|d XYZ',
            '</div>',
        ],
        mac: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                // Mac keeps non-directional selection made by double click.
                'ABC| wo<b id="target">r</b>ld^ XYZ',
            '</div>',
        ],
        win: [
            `<style>${kStyle}</style>`,
            '<div contenteditable>',
                'ABC ^wo<b id="target">r</b>ld| XYZ',
            '</div>',
        ],
    },
];

for (const platform of ['android', 'mac', 'unix', 'win']) {
    if (window.internals) {
        internals.settings.setEditingBehavior(platform);
        internals.settings.setSelectTrailingWhitespaceEnabled(
            platform === 'win');
    }

    for (const step of steps) {
      if (platform in step)
        continue;
      step[platform] = step.expected;
    }

    for (let nth = 0; nth < steps.length; ++nth) {
        selection_test(
            kSample,
            selection => {
                for (const step of steps.slice(0, nth + 1))
                    step.action(selection);
            },
            steps[nth][platform],
            `${platform} ${steps[nth].title}`);
    }
}
</script>