summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/input-events/input-events-typing.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/input-events/input-events-typing.html')
-rw-r--r--testing/web-platform/tests/input-events/input-events-typing.html285
1 files changed, 285 insertions, 0 deletions
diff --git a/testing/web-platform/tests/input-events/input-events-typing.html b/testing/web-platform/tests/input-events/input-events-typing.html
new file mode 100644
index 0000000000..a894beea9b
--- /dev/null
+++ b/testing/web-platform/tests/input-events/input-events-typing.html
@@ -0,0 +1,285 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Input Event typing tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<div id="rich" contenteditable></div>
+<textarea id="plain"></textarea>
+<script>
+let inputEventsLog = [];
+const rich = document.getElementById('rich');
+const plain = document.getElementById('plain');
+
+function log(event) {
+ const clone = new event.constructor(event.type, event);
+ clone.state = rich.innerHTML;
+ inputEventsLog.push(clone);
+}
+
+function resetRich() {
+ inputEventsLog = [];
+ rich.innerHTML = '';
+}
+
+rich.addEventListener('beforeinput', log);
+rich.addEventListener('input', log);
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ const message = 'Hello';
+ await test_driver.send_keys(rich, message);
+ // 10 events (5 beforeinput + 5 input events)
+ assert_equals(inputEventsLog.length, 10);
+ for (let i = 0; i < inputEventsLog.length; i += 2) {
+ const beforeInputEvent = inputEventsLog[i];
+ const inputEvent = inputEventsLog[i + 1];
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'insertText');
+ assert_equals(inputEvent.inputType, 'insertText');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+ assert_equals(inputEvent.data, message[i / 2]);
+ assert_equals(beforeInputEvent.state + message[i / 2], inputEvent.state);
+ }
+}, 'It triggers beforeinput and input events on text typing');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ await test_driver.send_keys(rich, "\uE006"); // Return
+
+ assert_equals(inputEventsLog.length, 2);
+ const beforeInputEvent = inputEventsLog[0];
+ const inputEvent = inputEventsLog[1];
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'insertParagraph');
+ assert_equals(inputEvent.inputType, 'insertParagraph');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing RETURN');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ await new test_driver.Actions()
+ .keyDown('\uE008') // Shift
+ .keyDown('\uE006') // Return
+ .keyUp('\uE006')
+ .keyUp('\uE008')
+ .send();
+
+ assert_equals(inputEventsLog.length, 2);
+ const [beforeInputEvent, inputEvent] = inputEventsLog;
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'insertLineBreak');
+ assert_equals(inputEvent.inputType, 'insertLineBreak');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing Shift+RETURN');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.innerHTML = '<p>Preexisting <i id="caret">c</i>ontent</p>';
+ const caret = document.querySelector('#caret');
+ await test_driver.click(caret);
+ await test_driver.send_keys(caret, "\uE017"); // Delete
+
+ assert_equals(inputEventsLog.length, 2);
+ const [beforeInputEvent, inputEvent] = inputEventsLog;
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'deleteContentForward');
+ assert_equals(inputEvent.inputType, 'deleteContentForward');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing DELETE with pre-existing content');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ await test_driver.send_keys(rich, "\uE017"); // Delete
+ assert_equals(inputEventsLog.length, 2);
+ const [beforeInputEvent, inputEvent] = inputEventsLog;
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'deleteContentForward');
+ assert_equals(inputEvent.inputType, 'deleteContentForward');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing DELETE with no pre-existing content');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.innerHTML = '<p>Preexisting <i id="caret">c</i>ontent</p>';
+
+ await test_driver.click(document.querySelector('#caret'));
+ await test_driver.send_keys(rich, "\uE003"); // Back Space
+
+ assert_equals(inputEventsLog.length, 2);
+ const [beforeInputEvent, inputEvent] = inputEventsLog;
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'deleteContentBackward');
+ assert_equals(inputEvent.inputType, 'deleteContentBackward');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing BACK_SPACE with pre-existing content');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ await test_driver.send_keys(rich, "\uE003"); // Back Space
+
+ assert_equals(inputEventsLog.length, 2);
+ const [beforeInputEvent, inputEvent] = inputEventsLog;
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, 'deleteContentBackward');
+ assert_equals(inputEvent.inputType, 'deleteContentBackward');
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+}, 'It triggers beforeinput and input events on typing BACK_SPACE with no pre-existing content');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ await test_driver.send_keys(rich, "hello");
+
+ // Decide whether to use Key.COMMAND (mac) or Key.CONTROL (everything else)
+ const modifierKey = navigator.platform === "MacIntel" ? '\u2318' : '\uE009';
+
+ // Undo
+ await new test_driver.Actions()
+ .keyDown(modifierKey)
+ .keyDown('z')
+ .keyUp('z')
+ .keyUp(modifierKey)
+ .send();
+ // Redo
+ await new test_driver.Actions()
+ .keyDown(modifierKey)
+ .keyDown('\uE008') // Shift
+ .keyDown('z')
+ .keyUp('z')
+ .keyUp('\uE008')
+ .keyUp(modifierKey)
+ .send();
+
+ // Ignore the initial typing of 'hello'
+ const historyInputEventsLog = inputEventsLog.slice(10);
+
+ assert_equals(historyInputEventsLog.length, 4);
+ const inputTypes = ['historyUndo', 'historyRedo'];
+ for (let i = 0; i < historyInputEventsLog.length; i += 2) {
+ // We are increaisng i by 2 as there should always be matching beforeinput and input events.
+ const beforeInputEvent = historyInputEventsLog[i];
+ const inputEvent = historyInputEventsLog[i + 1];
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, inputTypes[i / 2]);
+ assert_equals(inputEvent.inputType, inputTypes[i / 2]);
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+ }
+}, 'It triggers beforeinput and input events on typing Undo and Redo key combinations with an existing history');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ rich.focus();
+ // Decide whether to use Key.COMMAND (mac) or Key.CONTROL (everything else)
+ const modifierKey = navigator.platform === "MacIntel" ? '\u2318' : '\uE009';
+
+ // Undo
+ await new test_driver.Actions()
+ .keyDown(modifierKey)
+ .keyDown('z')
+ .keyUp('z')
+ .keyUp(modifierKey)
+ .send();
+ // Redo
+ await new test_driver.Actions()
+ .keyDown(modifierKey)
+ .keyDown('\uE008') // Shift
+ .keyDown('z')
+ .keyUp('z')
+ .keyUp('\uE008')
+ .keyUp(modifierKey)
+ .send();
+
+ assert_equals(inputEventsLog.length, 4);
+ const inputTypes = ['historyUndo', 'historyRedo'];
+ for (let i = 0; i < inputEventsLog.length; i += 2) {
+ const beforeInputEvent = inputEventsLog[i];
+ const inputEvent = inputEventsLog[i + 1];
+ assert_equals(beforeInputEvent.type, 'beforeinput');
+ assert_equals(inputEvent.type, 'input');
+ assert_equals(beforeInputEvent.inputType, inputTypes[i / 2]);
+ assert_equals(inputEvent.inputType, inputTypes[i / 2]);
+ assert_equals(beforeInputEvent.data, inputEvent.data);
+ }
+}, 'It triggers beforeinput and input events on typing Undo and Redo key combinations without an existing history');
+
+promise_test(async function() {
+ this.add_cleanup(resetRich);
+ const expectedResult = [
+ // Pressing 'a'.
+ 'plain-keydown-a',
+ 'plain-keypress-a',
+ 'plain-beforeinput-a-null',
+ 'plain-input-a-null',
+ 'plain-keyup-a',
+ // Pressing Shift-'b'.
+ 'plain-keydown-B',
+ 'plain-keypress-B',
+ 'plain-beforeinput-B-null',
+ 'plain-input-B-null',
+ 'plain-keyup-B',
+ // Pressing 'c'.
+ 'rich-keydown-c',
+ 'rich-keypress-c',
+ 'rich-beforeinput-c-null',
+ 'rich-input-c-null',
+ 'rich-keyup-c',
+ // Pressing Shift-'d'.
+ 'rich-keydown-D',
+ 'rich-keypress-D',
+ 'rich-beforeinput-D-null',
+ 'rich-input-D-null',
+ 'rich-keyup-D',
+ ];
+ const result = [];
+
+ for (const eventType of ['beforeinput', 'input', 'keydown', 'keypress', 'keyup']) {
+ const listener = event => {
+ if (event.key === 'Shift') return;
+ const eventInfo = [event.target.id, event.type, event.data || event.key];
+ if (event instanceof InputEvent) eventInfo.push(String(event.dataTransfer));
+ result.push(eventInfo.join('-'));
+ }
+ rich.addEventListener(eventType, listener);
+ plain.addEventListener(eventType, listener);
+ }
+
+ plain.focus();
+ await new test_driver.Actions()
+ .keyDown('a')
+ .keyUp('a')
+ .keyDown('\uE008') // Shift
+ .keyDown('b')
+ .keyUp('b')
+ .keyUp('\uE008')
+ .send();
+
+ rich.focus();
+ await new test_driver.Actions()
+ .keyDown('c')
+ .keyUp('c')
+ .keyDown('\uE008') // Shift
+ .keyDown('d')
+ .keyUp('d')
+ .keyUp('\uE008')
+ .send();
+
+ assert_equals(expectedResult.length, result.length);
+ expectedResult.forEach((er, index) => assert_equals(er, result[index]));
+}, 'InputEvents have correct data/order when typing on textarea and contenteditable');
+</script>