Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2855)

Unified Diff: chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher_test.unitjs

Issue 595633002: Port event watcher ChromeVox tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@live_regions
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher_test.unitjs
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher_test.unitjs b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher_test.unitjs
new file mode 100644
index 0000000000000000000000000000000000000000..f9eac4dc678a22ace19154dd550448881421af8d
--- /dev/null
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher_test.unitjs
@@ -0,0 +1,850 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Include test fixture.
+GEN_INCLUDE(['../../testing/chromevox_unittest_base.js']);
+
+/**
+ * Test fixture.
+ * @constructor
+ * @extends {ChromeVoxUnitTestBase}
+ */
+function CvoxEventWatcherUnitTest() {}
+
+CvoxEventWatcherUnitTest.prototype = {
+ __proto__: ChromeVoxUnitTestBase.prototype,
+
+ /** @override */
+ closureModuleDeps: [
+ 'cvox.ChromeVoxTester',
+ 'cvox.SpokenListBuilder',
+ ],
+
+ /** @override */
+ setUp: function() {
+ cvox.ChromeVoxTester.setUp(document);
+ },
+
+ /** @override */
+ tearDown: function() {
+ cvox.ChromeVoxTester.tearDown(document);
+ },
+
+ /**
+ * Create mock event object.
+ * @param {Element} target The event target.
+ * @param {number=} opt_keyCode The event key code (i.e. 13 for Enter).
+ * @param {string=} opt_type The event type (i.e. 'keydown' or
+ * 'focus').
+ * @param {number=} opt_timeStamp The event timeStamp.
+ * @return {Event} The mock event.
+ * @suppress {invalidCasts}
+ */
+ createMockEvent: function(target, opt_keyCode, opt_type, opt_timeStamp) {
+ var mockEvent = {};
+ mockEvent.target = target;
+ if (opt_keyCode) {
+ mockEvent.keyCode = opt_keyCode;
+ }
+ if (opt_type) {
+ mockEvent.type = opt_type;
+ }
+ if (opt_timeStamp) {
+ mockEvent.timeStamp = opt_timeStamp;
+ }
+
+ return /** @type {Event} */ (mockEvent);
+ },
+
+ /**
+ * Simulate typing a key into an text field by modifying a given field and
+ * dispatching a keydown event to ChromeVoxEventWatcher. Allows modifying the
+ * selection so arrow keypresses can be simulated.
+ * @param {Element} textField The text field.
+ * @param {string} newValue The new value for the text field.
+ * @param {number} newSelStart The new selection start.
+ * @param {number} newSelEnd The new selection end.
+ * @param {number} keyCode The key code for the keydown event.
+ * @return {Element} The modified text field.
+ */
+ changeTextField: function(
+ textField, newValue, newSelStart, newSelEnd, keyCode) {
+ textField.value = newValue;
+ textField.selectionStart = newSelStart;
+ textField.selectionEnd = newSelEnd;
+
+ cvox.ChromeVoxEventWatcher.keyDownEventWatcher(
+ this.createMockEvent(textField, keyCode, 'keydown'));
+ return textField;
+ }
+};
+
+TEST_F('CvoxEventWatcherUnitTest', 'ButtonFocusFeedback', function() {
+ this.loadHtml('<div> <button id="alpha">Alpha</button> </div>');
+ this.setFocus('alpha');
+ this.waitForCalm(this.assertSpoken, 'Alpha Button');
+});
+
+/**
+ * Test feedback when focusing links backwards (like shift-tabbing).
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'FocusLinksBackwards', function() {
+ this.loadHtml('<div> <p>before</p>' +
+ '<p><a href="#" id="l1">1</a></p>' +
+ '<p><a href="#" id="l2">2</a></p>' +
+ '<p><a href="#" id="l3">3</a></p>' +
+ '</div>');
+
+ this.waitForCalm(this.setFocus, 'l1')
+ .waitForCalm(this.setFocus, 'l2')
+ .waitForCalm(this.setFocus, 'l3')
+ .waitForCalm(this.setFocus, 'l2')
+ .waitForCalm(this.setFocus, 'l1')
+ .waitForCalm(this.assertSpoken,
+ '1 Internal link 2 Internal link 3 Internal link ' +
+ '2 Internal link 1 Internal link');
+});
+
+/**
+ * Test feedback when an editable text field gets focus.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'TextFocusFeedback', function() {
+ this.loadHtml('<div>' +
+ '<label for="mytext">Label</label>' +
+ '<input id="mytext" value="Value" title="Title" />' +
+ '</div>');
+
+ this.setFocus('mytext');
+ this.waitForCalm(this.assertSpoken, 'Label Value Edit text');
+});
+
+/**
+ * Test feedback when a contenteditable field gets focus.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'ContentEditableFocusFeedback', function() {
+ this.loadHtml('<div>' +
+ '<label for="mytext">Label</label>' +
+ '<div id="mytext" contentEditable>This is editable</div>' +
+ '</div>');
+
+ this.setFocus('mytext');
+ this.waitForCalm(this.assertSpoken, 'Label This is editable Edit text');
+});
+
+/**
+ * Test feedback when an item in an dialog receives focus and then focus
+ * leaves the dialog.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'DialogFeedback', function() {
+ this.loadHtml('<div>' +
+ '<button id="show">Show</button>' +
+ '<div aria-label="compose message" role="dialog">' +
+ ' <button id="ok">OK</button>' +
+ ' <button id="cancel">Cancel</button>' +
+ '</div>' +
+ '</div>');
+
+ // Enter the dialog by focusing an element inside it.
+ this.setFocus('ok');
+
+ this.waitForCalm(this.assertSpoken,
+ 'Entered dialog compose message Dialog OK Button');
+
+ // After we've entered a dialog, temporarily moving focus away shouldn't
+ // have any effect if we move it right back. (Allow apps to trap focus.)
+ this.waitForCalm(function() {
+ this.setFocus('show')
+ .setFocus('ok');
+ });
+
+ this.waitForCalm(this.assertSpoken, 'OK Button');
+
+ // Now move focus away and leave it there.
+ this.waitForCalm(this.setFocus, 'show');
+ this.waitForCalm(this.assertSpoken, 'Exited dialog. Show Button');
+});
+
+/**
+ * Test feedback when an item in an alert dialog receives focus.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'AlertDialogFeedback', function() {
+ this.loadHtml('<div>' +
+ '<div role="alertdialog">' +
+ ' <p>Are you sure you want to install Windows?</p>' +
+ ' <button id="yes">Yes</button>' +
+ ' <button id="no">No</button>' +
+ '</div> </div>');
+
+ // Enter the dialog by focusing an element inside it.
+ this.setFocus('no');
+ this.waitForCalm(this.assertSpoken,
+ 'Entered dialog ' +
+ 'Are you sure you want to install Windows? Yes Button No Button ' +
+ 'No Button');
+});
+
+/**
+ * Test feedback when focus moves to two different items in a alertdialog
+ * quickly - make sure the notification that we entered the dialog
+ * isn't interrupted.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'DoubleFocusAlertDialogFeedback', function() {
+ this.loadHtml('<div>' +
+ '<div role="alertdialog">' +
+ ' <p>Are these the droids you\'re looking for?</p>' +
+ ' <button id="yes">Yes</button>' +
+ ' <button id="no">No</button>' +
+ '</div>' +
+ '<button id="outside">Outside</button>' +
+ '</div>');
+
+ // Enter the dialog by focusing an element inside it, but then the Jedi
+ // mind trick quickly changes the default answer.
+ this.setFocus('yes')
+ .setFocus('no');
+
+ this.waitForCalm(this.assertSpokenList,
+ this.spokenList()
+ .categoryFlush('Entered dialog')
+ .queue('Are these the droids you\'re looking for?')
+ .queue('Yes')
+ .queue('Button'));
+
+ // Unfocus the dialog so we don't effect other tests.
+ this.waitForCalm(this.setFocus, 'outside');
+ this.waitForCalm(this.assertSpoken, 'Exited dialog. Outside Button');
+});
+
+/**
+ * Test recovery when a dialog box closes and the user sends a tab event.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'CloseDialogTabRecovery', function() {
+ this.loadHtml('<div id="container">' +
+ '<p id="first">first node</p>' +
+ '<button id="button">valid button before</button>' +
+ '<p id="before">valid text before</p>' +
+ '<p id="dialog">invalid after click</p>' +
+ '<p id="last">valid text after</p>' +
+ '</div>');
+
+ var first = $('first');
+ var dialog = $('dialog');
+ var displayNone = function() {
+ dialog.style.display = 'none';
+ };
+
+ this.waitForCalm(cvox.ChromeVoxTester.syncToNode, first);
+ this.waitForCalm(cvox.ChromeVoxTester.setStrategy, 'lineardom');
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'valid button before Button');
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'valid text before');
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'invalid after click');
+
+ // Invalidate the dialog box.
+ this.waitForCalm(displayNone);
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'valid text after');
+});
+
+/**
+ * Test feedback when a list box with an active descendant receives focus.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'ListBoxFeedback', function() {
+ this.loadHtml('<div>' +
+ '<p id="before">My listbox</p>' +
+ '<div id="listbox" role="listbox" tabindex="0"' +
+ ' aria-activedescendant="red">' +
+ ' <div id="red" aria-selected="true" role="option">Red</div>' +
+ ' <div id="yellow" role="option">Yellow</div>' +
+ ' <div id="green" role="option">Green</div>' +
+ '</div>' +
+ '<p id="after">After</p>' +
+ '</div>');
+
+ // Focus the listbox.
+ this.setFocus('listbox');
+ this.waitForCalm(this.assertSpoken, 'Red List box Selected 1 of 3')
+ .waitForCalm(function() {
+ // Set the activeDescendant and fire a keydown event.
+ // TODO(dmazzoni): replace with a higher-level API that's
+ // less brittle.
+ var listbox = $('listbox');
+ listbox.setAttribute('aria-activeDescendant', 'yellow');
+ cvox.ChromeVoxEventWatcher.keyDownEventWatcher(/** @type {Event} */ (
+ { 'target': listbox,
+ 'type': 'keydown' }));
+ })
+ .waitForCalm(this.assertSpoken, 'Yellow 2 of 3');
+});
+
+/**
+ * Test feedback when the items of a list box receive focus.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'ListBoxOptionFeedback', function() {
+ this.loadHtml('<div>' +
+ '<p id="before">My listbox</p>' +
+ '<div id="listbox" role="listbox">' +
+ ' <div id="red" tabindex="0" aria-selected="true" role="option">' +
+ 'Red</div>' +
+ ' <div id="yellow" tabindex="-1" role="option">Yellow</div>' +
+ ' <div id="green" tabindex="-1" role="option">Green</div>' +
+ '</div>' +
+ '<p id="after">After</p>' +
+ '</div>');
+
+ // Focus the second item.
+ this.setFocus('yellow');
+
+ this.waitForCalm(this.assertSpoken, 'List box Yellow 2 of 3')
+ .waitForCalm(this.setFocus, 'red')
+ .waitForCalm(this.assertSpoken, 'Red Selected 1 of 3');
+});
+
+/**
+ * Test feedback when the list box is setting focus in response to arrow
+ * (or some other) keypress and the user is also using ChromeVox navigation.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'ListBoxOptionFeedbackWithFocus', function() {
+ this.loadHtml('<div>' +
+ '<p id="before">My listbox</p>' +
+ '<div id="listbox" role="listbox">' +
+ ' <div id="red" tabindex="0" aria-selected="true" role="option">' +
+ 'Red</div>' +
+ ' <div id="yellow" tabindex="-1" role="option">Yellow</div>' +
+ ' <div id="green" tabindex="-1" role="option">Green</div>' +
+ ' <div id="blue" tabindex="-1" role="option">Blue</div>' +
+ '</div>' +
+ '<p id="after">After</p>' +
+ '</div>');
+
+ // Simulate the user using ChromeVox navigation to move forward in the listbox
+ this.waitForCalm(cvox.ChromeVoxTester.setStrategy, 'lineardom');
+ this.waitForCalm(cvox.ChromeVoxTester.syncToFirstNode);
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'List box Red Selected 1 of 4');
+
+ // Simulate the listbox setting focus on items in the listbox in response to
+ // keypresses
+ this.waitForCalm(this.setFocus, 'yellow');
+ this.waitForCalm(this.assertSpoken, 'Yellow 2 of 4');
+
+ this.waitForCalm(this.setFocus, 'green');
+ this.waitForCalm(this.assertSpoken, 'Green 3 of 4');
+
+ // ChromeVox navigation again
+ this.waitForCalm(this.userCommand, 'forward');
+ this.waitForCalm(this.assertSpoken, 'Blue 4 of 4');
+});
+
+/**
+ * Test feedback when interacting with an editable text field.
+ * The low-level details are tested in editable_text_test.js, this is
+ * a higher-level test of how that code interacts with the event watcher.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'EditableText', function() {
+ cvox.ChromeVoxEditableTextBase.eventTypingEcho = false;
+ this.loadHtml('<div>' +
+ '<button id="before">Before</button>' +
+ '<label for="input">Query</label>' +
+ '<input id="input" value="abc">' +
+ '<p>After</p>' +
+ '</div>');
+
+ var before = $('before');
+ var input = $('input');
+
+ // Focus the button first.
+ before.focus();
+
+ // Then focus the text field.
+ input.focus();
+ input.setSelectionRange(3, 3);
+
+ this.waitForCalm(this.changeTextField, input, 'abcd', 3, 3, 68) // 'd'
+ .waitForCalm(this.changeTextField, input, 'abcde', 4, 4, 69) // 'e'
+ .waitForCalm(this.assertSpokenList,
+ this.spokenList()
+ .categoryFlush('Query')
+ .queue('abc')
+ .queue('Edit text')
+ .flush('d')
+ .flush('e'));
+});
+
+/**
+ * Test feedback when interacting with an editable text field that drives
+ * an listbox (to form an auto-complete combobox) but doesn't get updated.
+ * The low-level details are tested in editable_text_test.js, this is
+ * a higher-level test of how that code interacts with the event watcher.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'EditableTextListbox', function() {
+ this.loadHtml('<div>' +
+ '<button id="before">Before</button>' +
+ '<label for="input">Query</label>' +
+ '<input id="input" value="" role="combobox" aria-autocomplete="list"' +
+ ' aria-activedescendant>' +
+ '<div role="listbox">' +
+ ' <div id="option1" role="option">First pick</div>' +
+ ' <div id="option2" role="option">Second pick</div>' +
+ '</div>' +
+ '<p>After</p>' +
+ '</div>');
+
+ var before = $('before');
+ var input = $('input');
+
+ // Focus the text field.
+ this.waitForCalm(this.setFocus, 'input')
+ .waitForCalm(this.assertSpoken, 'Query Combo box Autocompletion list');
+
+ this.waitForCalm(function() {
+ input.setAttribute('aria-activedescendant', 'option1');
+ this.changeTextField(input, '', 0, 0, 40); // 'down'
+ })
+ .waitForCalm(this.assertSpoken, 'First pick 1 of 2');
+});
+
+/**
+ * Test feedback when interacting with an editable text field that drives
+ * an listbox (to form an auto-complete combobox) and *does* get updated.
+ * The low-level details are tested in editable_text_test.js, this is
+ * a higher-level test of how that code interacts with the event watcher.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'EditableTextListboxUpdatingInput', function() {
+ this.loadHtml('<div>' +
+ '<button id="before">Before</button>' +
+ '<label for="input">Query</label>' +
+ '<input id="input" value="" role="combobox" aria-autocomplete="list"' +
+ ' aria-activedescendant>' +
+ '<div role="listbox">' +
+ ' <div id="option1" role="option">First pick</div>' +
+ ' <div id="option2" role="option">Second pick</div>' +
+ '</div>' +
+ '<p>After</p>' +
+ '</div>');
+
+ var before = $('before');
+ var input = $('input');
+
+ // Focus the text field.
+ this.waitForCalm(this.setFocus, 'input')
+ .waitForCalm(this.assertSpoken, 'Query Combo box Autocompletion list');
+
+ this.waitForCalm(function() {
+ input.setAttribute('aria-activedescendant', 'option1');
+ this.changeTextField(input, 'First pick', 9, 9, 40); // 'down'
+ })
+ .waitForCalm(this.assertSpoken, 'First pick');
+});
+
+/**
+ * Tests navigating through a multiline text area.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'MultilineNavigation', function() {
+ this.loadHtml('<div> <textarea id="area">' +
+ 'one' +
+ '\n\n' +
+ 'two' +
+ '\n\n' +
+ 'three</textarea>' +
+ '</div>');
+
+ var area = $('area');
+
+ function setAreaCursor(pos) {
+ area.setSelectionRange(pos, pos);
+ cvox.ChromeVoxEventWatcher.keyDownEventWatcher(/** @type {Event} */ (
+ { 'target': area,
+ 'type': 'keydown' }));
+ }
+
+ area.focus();
+ this.waitForCalm(this.assertSpoken, 'one two three Text area')
+ .waitForCalm(setAreaCursor, 0)
+ // The cursor did not move, so don't say anything -- even though we
+ // did press a key.
+ .waitForCalm(this.assertSpoken, '')
+ .waitForCalm(setAreaCursor, 5) // in front on the 'two'
+ .waitForCalm(this.assertSpoken, 'two')
+ .waitForCalm(setAreaCursor, 10) // in front of the 'three'
+ .waitForCalm(this.assertSpoken, 'three')
+ .waitForCalm(setAreaCursor, 0) // back to the first line
+ .waitForCalm(this.assertSpoken, 'one')
+ .waitForCalm(setAreaCursor, 4) // on the first new line
+ .waitForCalm(this.assertSpoken, 'Blank')
+ .waitForCalm(setAreaCursor, 5)
+ .waitForCalm(this.assertSpoken, 'two')
+ .waitForCalm(setAreaCursor, 9)
+ .waitForCalm(this.assertSpoken, 'Blank')
+ .waitForCalm(setAreaCursor, 10)
+ .waitForCalm(this.assertSpoken, 'three');
+});
+
+TEST_F('CvoxEventWatcherUnitTest', 'ShouldWaitToProcess', function() {
+ // The focus event just happened, wait.
+ assertTrue(
+ cvox.ChromeVoxEventWatcherUtil.shouldWaitToProcess(100, 100, 100));
+ // The focus event just happened, but the first event is old, don't wait.
+ assertFalse(
+ cvox.ChromeVoxEventWatcherUtil.shouldWaitToProcess(100, 0, 100));
+ // The focus event is old, don't wait.
+ assertFalse(
+ cvox.ChromeVoxEventWatcherUtil.shouldWaitToProcess(0, 0, 100));
+});
+
+/**
+ * Test that no feedback is received for events that fire on elements
+ * that are hidden (or the descendant of a hidden element).
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'AriaHiddenFeedback', function() {
+ this.loadHtml('<div>' +
+ '<div>' +
+ ' <button id="button1">Button 1</button>' +
+ ' <button id="button2" aria-hidden="true">Button 2</button>' +
+ '</div>' +
+ '<div aria-hidden="true">' +
+ ' <h3>Random header</h3>' +
+ ' <div>' +
+ ' <button id="button3">Button 3</button>' +
+ ' </div>' +
+ ' <h3>Random header</h3>' +
+ '</div>' +
+ '<div>' +
+ ' <button id="button4">Button 4</button>' +
+ '</div>' +
+ '</div>');
+
+ this.setFocus('button1')
+ .waitForCalm(this.assertSpoken, 'Button 1 Button')
+ .waitForCalm(this.setFocus, 'button2')
+ .waitForCalm(this.assertSpoken, '')
+ .waitForCalm(this.setFocus, 'button3')
+ .waitForCalm(this.assertSpoken, '')
+ .waitForCalm(this.setFocus, 'button4')
+ .waitForCalm(this.assertSpoken, 'Button 4 Button');
+});
+
+/**
+ * Test that key down events don't cause excessive value and state announcements
+ * when arrowing around radiobuttons.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'RadioButtonAnnouncements', function() {
+ this.loadHtml(
+ '<input id="radio1" type="radio" aria-label="green" tabindex=0>' +
+ '<input id="radio2" type="radio" aria-label="blue" tabindex=0>');
+ function performKeyDown(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keydown', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ var radio1 = $('radio1');
+ radio1.focus();
+
+ // TODO(dtseng): Repeated actual spoken text here; this is most certainly a
+ // test framework bug.
+ this.waitForCalm(this.assertSpoken, 'green Radio button unselected')
+ .waitForCalm(performKeyDown, 'Right') // right arrow
+ // Moves to next radiobutton.
+ .waitForCalm(this.assertSpoken,
+ 'blue Radio button selected blue Radio button selected')
+ .waitForCalm(performKeyDown, 'Right') // right arrow
+ // Arrowed beyond end. Should be quiet.
+ .waitForCalm(this.assertSpoken, '');
+
+ this.waitForCalm(performKeyDown, 'Left') // left arrow
+ // Moves back to first radio.
+ .waitForCalm(this.assertSpoken,
+ 'green Radio button selected green Radio button selected')
+ .waitForCalm(performKeyDown, 'Left') // left arrow
+ // Arrowed beyond beginning. Should be quiet.
+ .waitForCalm(this.assertSpoken, '');
+});
+
+/**
+ * Test time widget.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'TimeWidget', function() {
+ var chromeVer = -1;
+ var userAgent = window.navigator.userAgent;
+ var startIndex = userAgent.indexOf('Chrome/');
+ if (startIndex != -1) {
+ userAgent = userAgent.substring(startIndex + 'Chrome/'.length);
+ }
+ var endIndex = userAgent.indexOf('.');
+ if (endIndex != -1) {
+ userAgent = userAgent.substring(0, endIndex);
+ }
+ // This test will only work on Chrome 23 and higher.
+ if (userAgent >= 23) {
+ this.loadHtml(
+ '<label for="timewidget">Set alarm for:</label>');
+ this.loadHtml(
+ '<input id="timewidget" type="time" value="12:00">');
+ var performKeyDown = function(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keydown', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+ var performKeyUp = function(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keyup', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ var timewidget = $('timewidget');
+ timewidget.focus();
+
+ this.waitForCalm(this.assertSpoken,
+ 'Set alarm for: 12:00 Set alarm for: 12 hours 00 minutes PM');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ '11 hours');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ '10 hours');
+
+ this.waitForCalm(performKeyDown, 'Right') // right arrow
+ .waitForCalm(performKeyUp, 'Right') // right arrow
+ .waitForCalm(performKeyDown, 'Up') // right arrow
+ .waitForCalm(performKeyUp, 'Up') // right arrow
+ .waitForCalm(this.assertSpoken,
+ '01 minutes');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ '00 minutes');
+
+ this.waitForCalm(performKeyDown, 'Right') // right arrow
+ .waitForCalm(performKeyUp, 'Right') // right arrow
+ .waitForCalm(performKeyDown, 'Up') // right arrow
+ .waitForCalm(performKeyUp, 'Up') // right arrow
+ .waitForCalm(this.assertSpoken,
+ 'AM');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ 'PM');
+ }
+});
+
+/**
+ * Test date widget.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'DateWidget', function() {
+ var chromeVer = -1;
+ var userAgent = window.navigator.userAgent;
+ var startIndex = userAgent.indexOf('Chrome/');
+ if (startIndex != -1) {
+ userAgent = userAgent.substring(startIndex + 'Chrome/'.length);
+ }
+ var endIndex = userAgent.indexOf('.');
+ if (endIndex != -1) {
+ userAgent = userAgent.substring(0, endIndex);
+ }
+ // This test will only work on Chrome 25 and higher.
+ if (userAgent >= 25) {
+ this.loadHtml(
+ '<label for="datewidget">Set birthdate:</label>');
+ this.loadHtml(
+ '<input id="datewidget" type="date" value="1998-09-04"/>');
+ var performKeyDown = function(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keydown', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+ var performKeyUp = function(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keyup', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ var datewidget = $('datewidget');
+ datewidget.focus();
+
+ this.waitForCalm(this.assertSpoken,
+ 'Set birthdate: 1998-09-04 Date control Set birthdate: September 4 1998');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ 'August');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ 'July');
+
+ this.waitForCalm(performKeyDown, 'Right') // right arrow
+ .waitForCalm(performKeyUp, 'Right') // right arrow
+ .waitForCalm(performKeyDown, 'Up') // right arrow
+ .waitForCalm(performKeyUp, 'Up') // right arrow
+ .waitForCalm(this.assertSpoken, '5');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ '4');
+
+ this.waitForCalm(performKeyDown, 'Right') // right arrow
+ .waitForCalm(performKeyUp, 'Right') // right arrow
+ .waitForCalm(performKeyDown, 'Up') // right arrow
+ .waitForCalm(performKeyUp, 'Up') // right arrow
+ .waitForCalm(this.assertSpoken,
+ '1999');
+
+ this.waitForCalm(performKeyDown, 'Down') // down arrow
+ .waitForCalm(performKeyUp, 'Down') // down arrow
+ .waitForCalm(this.assertSpoken,
+ '1998');
+ }
+});
+
+/**
+ * Test video widget.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'VideoWidget', function() {
+ this.loadHtml('<video id="chromevideo" poster="star.png" controls>' +
+ '<source src="Chrome_ImF.mp4" ' +
+ ' type=\'video/mp4; codecs="avc1.42E01E, mp4a.40.2"\' />' +
+ '<source src="Chrome_ImF.webm" ' +
+ ' type=\'video/webm; codecs="vp8, vorbis"\' />' +
+ '<source src="Chrome_ImF.ogv" ' +
+ ' type=\'video/ogg; codecs="theora, vorbis"\' />' +
+ '</video>');
+
+ function performKeyDown(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keydown', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ function performKeyUp(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keyup', true, true, window, dir, 0, false, false, false, false);
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ var self = this;
+ var videowidget = $('chromevideo');
+
+ videowidget.onload = function() {
+ videowidget.focus();
+ self.waitForCalm(performKeyDown, 'Enter')
+ .waitForCalm(performKeyUp, 'Enter')
+ .waitForCalm(self.assertEquals, videowidget.paused, false);
+
+ self.waitForCalm(performKeyDown, 'Right')
+ .waitForCalm(performKeyUp, 'Right')
+ .waitForCalm(self.assertEquals, videowidget.currentTime, 0);
+
+ self.waitForCalm(performKeyDown, 'Down')
+ .waitForCalm(performKeyUp, 'Down')
+ .waitForCalm(self.assertEquals, videowidget.volume, 0);
+ };
+});
+
+/**
+ * Test audio widget.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'AudioWidget', function() {
+ this.loadHtml(
+ '<audio id="chromeaudio" controls>' +
+ '<source src="http://www.html5rocks.com/en/tutorials/' +
+ 'audio/quick/test.mp3" type="audio/mpeg" />' +
+ '<source src="http://www.html5rocks.com/en/tutorials/' +
+ 'audio/quick/test.ogg" type="audio/ogg" />');
+
+ function performKeyDown(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keydown', true, true, window, dir, 0, false, false, false, false);
+
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ function performKeyUp(dir) {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keyup', true, true, window, dir, 0, false, false, false, false);
+ document.activeElement.dispatchEvent(evt);
+ };
+
+ var self = this;
+ var audiowidget = $('chromeaudio');
+
+ audiowidget.onload = function() {
+ audiowidget.focus();
+ self.waitForCalm(performKeyDown, 'Enter')
+ .waitForCalm(performKeyUp, 'Enter')
+ .waitForCalm(self.assertEquals, audiowidget.paused, false);
+
+ self.waitForCalm(performKeyDown, 'Right')
+ .waitForCalm(performKeyUp, 'Right')
+ .waitForCalm(self.assertEquals, audiowidget.currentTime, 0);
+
+ self.waitForCalm(performKeyDown, 'Down')
+ .waitForCalm(performKeyUp, 'Down')
+ .waitForCalm(self.assertEquals, audiowidget.volume, 0);
+ };
+});
+
+/**
+ * Test that ChromeVox speaks the correct state when a focused control
+ * changes as the result of a key up, not just key down.
+ */
+TEST_F('CvoxEventWatcherUnitTest', 'ToggleOnKeyUp', function() {
+ this.loadHtml('<div>' +
+ '<div tabIndex=0 id="pressable" role="button" aria-pressed="false">' +
+ 'Toggle' +
+ '</div>' +
+ '</div>');
+
+ // Focus on the button.
+ this.setFocus('pressable');
+ this.waitForCalm(this.assertSpoken, 'Toggle Button Not pressed');
+
+ function keyupSpace() {
+ var evt = document.createEvent('KeyboardEvent');
+ evt.initKeyboardEvent(
+ 'keyup', true, true, window, ' ', 0, false, false, false, false);
+ document.activeElement.dispatchEvent(evt);
+ }
+
+ function keyupSpaceAndMarkPressed() {
+ keyupSpace();
+ $('pressable').setAttribute('aria-pressed', 'true');
+ };
+
+ function keyupSpaceAndMarkNotPressed() {
+ keyupSpace();
+ $('pressable').setAttribute('aria-pressed', 'false');
+ };
+
+ this.waitForCalm(keyupSpaceAndMarkPressed)
+ .waitForCalm(this.assertSpoken, 'Pressed')
+ .waitForCalm(keyupSpaceAndMarkNotPressed)
+ .waitForCalm(this.assertSpoken, 'Not pressed');
+});

Powered by Google App Engine
This is Rietveld 408576698