chromium/third_party/blink/web_tests/fast/forms/time-multiple-fields/time-multiple-fields-keyboard-events.html

<!DOCTYPE html>
<html>
<head>
<script src="../../../resources/js-test.js"></script>
</head>
<body>
<p id="description"></p>
<p>
Please run this with DumpRenderTree.
</p>
Test following keys:
<ul>
    <li>Digit keys</li>
    <li>Left/Right - Move focus field inside element</li>
    <li>Up/Down - Increment/decrement value of focus field</li>
    <li>Tab - Move focus field</li>
    <li>Backspace - Make value empty</li>
</ul>
<input id="before">
<input id="input" type="time">
<input id="another">
<div id="console"></div>
<script>
description("Multiple fields UI of time input type with keyboard events");
if (window.internals)
    internals.runtimeFlags.langAttributeAwareFormControlUIEnabled = true;
var input = document.getElementById("input");

function shadowPseudoIdOfFocusedSubField(host)
{
    return internals.shadowPseudoId(internals.shadowRoot(host).activeElement);
}

function keyDown(key, modifiers)
{
    if (!window.eventSender)
        return;
    eventSender.keyDown(key, modifiers);
}

function beginTest(title, value)
{
    debug("== " + title + " ==");
    input.value = value;
    input.blur();
    input.focus();
}

var eventsCounter = {};
function countEvents(event)
{
    if (eventsCounter[event.type] === undefined)
        eventsCounter[event.type] = 0;
    eventsCounter[event.type]++;
}
input.addEventListener('input', countEvents, false);
input.addEventListener('change', countEvents, false);

beginTest('Digit keys');
keyDown('7'); // -> 07:[--] --
keyDown('5'); // -> 07:[05] --
input.className = "CLASS";
keyDown('6'); // -> 07:56 [--]
shouldBeUndefined('eventsCounter.input');
shouldBeUndefined('eventsCounter.change');
keyDown('A'); // -> 07:56 [AM]
shouldBeEqualToString('input.value', '07:56');
shouldBe('eventsCounter.input', '1');
shouldBe('eventsCounter.change', '1');

beginTest('Digit keys starting with zero');
keyDown('0'); // -> [00]:-- --
keyDown('2'); // -> 02:[--] --
keyDown('0'); // -> 02:[00] --
keyDown('3'); // -> 02:03 [--]
keyDown('P'); // -> 02:03 [PM]
shouldBeEqualToString('input.value', '14:03');

beginTest('Digit keys and backspace key','01:01');
keyDown('0'); // -> [00]:-- --
keyDown('Backspace'); // -> [--]:-- --
keyDown('5'); // -> 05:[--] --
keyDown('6'); // -> 05:06 [--]
keyDown('Backspace'); // -> 05:06 [--]
keyDown('P'); // -> 05:06 [PM]
shouldBeEqualToString('input.value', '17:06');

beginTest('Left/Right keys', '01:24');
keyDown('ArrowRight');
keyDown('5');
keyDown('ArrowLeft');
keyDown('6');
shouldBeEqualToString('input.value', '06:05');
keyDown('ArrowLeft');
keyDown('ArrowLeft');
keyDown('ArrowLeft');
shouldBeEqualToString('document.activeElement.id', 'input');

beginTest('Up/Down keys', '04:56');
keyDown('ArrowUp');
shouldBeEqualToString('input.value', '05:56');
keyDown('ArrowDown');
keyDown('ArrowDown');
shouldBeEqualToString('input.value', '03:56');

beginTest('Up/Down keys on empty value', '');
eventsCounter = {};
keyDown('ArrowUp');    // -> [01]:-- --
keyDown('ArrowUp');    // -> [02]:-- --
keyDown('ArrowRight'); // -> 02:[--] --
keyDown('ArrowDown');  // -> 02:[59] --
keyDown('ArrowDown');  // -> 02:[58] --
keyDown('ArrowRight'); // -> 02:58 [--]
shouldBeUndefined('eventsCounter.input');
shouldBeUndefined('eventsCounter.change');
keyDown('ArrowDown');  // -> 02:58 [PM]
shouldBeEqualToString('input.value', '14:58');
shouldBe('eventsCounter.input', '1');
shouldBe('eventsCounter.change', '1');

beginTest('Tab key', '03:00');
keyDown('\t');
keyDown('5');
shouldBeEqualToString('input.value', '03:05');
keyDown('\t', ['shiftKey']);
keyDown('7');
shouldBeEqualToString('input.value', '07:05');
keyDown('\t');
keyDown('\t');
keyDown('\t');  // Focused on dropdown
shouldBeEqualToString('document.activeElement.id', 'another');

beginTest('Tab navigation should skip disabled inputs', '');
before.focus();
input.disabled = true;
keyDown('\t');
shouldBeEqualToString('document.activeElement.id', 'another');
input.disabled = false;

beginTest('Tab navigation should not skip readonly inputs, but editing operations should be ignored.', '');
before.focus();
input.value = '01:01';
input.readOnly = true;
keyDown('\t');
shouldBeEqualToString('document.activeElement.id', 'input');
shouldBeEqualToString('shadowPseudoIdOfFocusedSubField(input)', '-webkit-datetime-edit-hour-field');
shouldBeEqualToString('keyDown("ArrowUp"); input.value', '01:01');
shouldBeEqualToString('keyDown("ArrowDown"); input.value', '01:01');
keyDown('ArrowRight');
shouldBeEqualToString('shadowPseudoIdOfFocusedSubField(input)', '-webkit-datetime-edit-minute-field');
shouldBeEqualToString('keyDown("3"); input.value', '01:01');
keyDown('\t');
shouldBeEqualToString('shadowPseudoIdOfFocusedSubField(input)', '-webkit-datetime-edit-ampm-field');
keyDown('ArrowLeft');
shouldBeEqualToString('shadowPseudoIdOfFocusedSubField(input)', '-webkit-datetime-edit-minute-field');
keyDown('\t');
keyDown('\t');
shouldBeEqualToString('document.activeElement.id', 'another');
input.readOnly = false;

beginTest('Shfit+Tab key', '03:00');
another.focus();
keyDown('\t', ['shiftKey']);  // Focused on previous input's drop down button.
keyDown('\t', ['shiftKey']);  // Focused on previous input's drop last field.
keyDown('P');
shouldBeEqualToString('input.value', '15:00');
keyDown('\t', ['shiftKey']);
keyDown('3');
shouldBeEqualToString('input.value', '15:03');
keyDown('\t', ['shiftKey']);
keyDown('\t', ['shiftKey']);
shouldBeEqualToString('document.activeElement.id', 'before');

beginTest('Up key on maximum value', '12:59:59.999');
keyDown('ArrowUp');
keyDown('\t');
keyDown('ArrowUp');
keyDown('\t');
keyDown('ArrowUp');
keyDown('\t');
keyDown('ArrowUp');
shouldBeEqualToString('input.value', '13:00:00.000');

beginTest('Down key on minimum value', '01:00');
input.step = 0.001;
keyDown('ArrowDown');
keyDown('\t');
keyDown('ArrowDown');
keyDown('\t');
keyDown('ArrowDown');
keyDown('\t');
keyDown('ArrowDown');
shouldBeEqualToString('input.value', '00:59:59.999');
input.step = 60;

beginTest('Backspace key', '12:34');
keyDown("Backspace");
shouldBeEqualToString('input.value', '');

beginTest('Delete key', '12:34');
keyDown("Delete");
shouldBeEqualToString('input.value', '');

beginTest('Typeahead', '12:34:56');
keyDown('ArrowRight');
keyDown('1');
shouldBeEqualToString('input.value', '12:01:56');
keyDown('ArrowRight');
keyDown('ArrowLeft');
keyDown('2');
shouldBeEqualToString('input.value', '12:02:56');

input.setAttribute("lang", "he-il");
beginTest('RTL focus navigation', '04:56');
debug('The tests in this block fail on platforms without the lang-attribute-aware-form-control-UI feature.');
keyDown('1'); //          -> [01]:56
shouldBeEqualToString('input.value', '01:56');
keyDown('\t'); //          -> 01:[56]
keyDown('2'); //          -> 01:[02]
shouldBeEqualToString('input.value', '01:02');
keyDown('\t', ['shiftKey']); // -> [01]:02
keyDown('3'); //          -> [03]:02
shouldBeEqualToString('input.value', '03:02');
input.removeAttribute("lang");

input.min = '23:00';
input.max = '01:00';
beginTest('Reversed range', '');
keyDown('1');          // -> [01]:-- --
keyDown('1');          // -> 11:[--] --
keyDown('3');          // -> 11:[03] --
keyDown('0');          // -> 11:30 [--]
keyDown('P');          // -> 11:30 [PM]
shouldBeEqualToString('input.value', '23:30');
keyDown('ArrowLeft');  // -> 11:[30] PM
keyDown('ArrowLeft');  // -> [11]:30 PM
keyDown('1');          // -> [01]:30 PM
keyDown('2');          // -> 12:[30] PM
keyDown('ArrowRight'); // -> 12:30 [PM]
keyDown('ArrowUp');    // -> 12:30 [AM]
shouldBeEqualToString('input.value', '00:30');
input.min = '';
input.max = '';

</script>
</body>
</html>