1# Copyright 2016 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6 7from autotest_lib.client.bin import test 8from autotest_lib.client.bin import utils 9from autotest_lib.client.common_lib import error 10from autotest_lib.client.cros.input_playback import input_playback 11 12 13class a11y_test_base(test.test): 14 """Base class for a11y tests.""" 15 version = 1 16 17 # ChromeVox extension id 18 _CHROMEVOX_ID = 'mndnfokpggljbaajbnioimlmbfngpief' 19 _CVOX_STATE_TIMEOUT = 40 20 _CVOX_INDICATOR_TIMEOUT = 40 21 22 23 def warmup(self): 24 """Test setup.""" 25 # Emulate a keyboard for later ChromeVox toggle (if needed). 26 # See input_playback. The keyboard is used to play back shortcuts. 27 self._player = input_playback.InputPlayback() 28 self._player.emulate(input_type='keyboard') 29 self._player.find_connected_inputs() 30 31 32 def _child_test_cleanup(self): 33 """Can be overwritten by child classes and run duing parent cleanup.""" 34 return 35 36 37 def cleanup(self): 38 self._player.close() 39 self._child_test_cleanup() 40 41 42 def _toggle_chromevox(self): 43 """Use keyboard shortcut and emulated keyboard to toggle ChromeVox.""" 44 self._player.blocking_playback_of_default_file( 45 input_type='keyboard', filename='keyboard_ctrl+alt+z') 46 47 48 def _search_shift_move(self, direction): 49 """Playback the keyboard movement shortcut for given direction. 50 51 @param direction: right, left, up, or down. 52 53 """ 54 assert direction in ['right', 'left', 'up', 'down'] 55 self._player.blocking_playback_of_default_file( 56 input_type='keyboard', 57 filename='keyboard_search+shift+%s' % direction) 58 59 60 def _tab_move(self, direction='forwards'): 61 """Playback a tab or shift+tab for the given direction. 62 63 @param direction: forwards or backwards. 64 65 """ 66 assert direction in ['forwards', 'backwards'] 67 is_forwards = direction is 'forwards' 68 filename = 'keyboard_tab' if is_forwards else 'keyboard_shift+tab' 69 self._player.blocking_playback_of_default_file( 70 input_type='keyboard', filename=filename) 71 72 73 def _set_feature(self, feature, value): 74 """Set given feature to given value using a11y API call. 75 76 Presupposes self._extension (with accessibilityFeatures enabled). 77 78 @param feature: string of accessibility feature to change. 79 @param value: boolean of expected value. 80 81 @raises: error.TestError if feature cannot be set. 82 83 """ 84 value_str = 'true' if value else 'false' 85 cmd = ('window.__result = null;\n' 86 'chrome.accessibilityFeatures.%s.set({value: %s});\n' 87 'chrome.accessibilityFeatures.%s.get({}, function(d) {' 88 'window.__result = d[\'value\']; });' % ( 89 feature, value_str, feature)) 90 self._extension.ExecuteJavaScript(cmd) 91 92 poll_cmd = 'window.__result == %s;' % value_str 93 utils.poll_for_condition( 94 lambda: self._extension.EvaluateJavaScript(poll_cmd), 95 exception = error.TestError( 96 'Timeout while trying to set %s to %s' % 97 (feature, value_str))) 98 99 100 def _get_chromevox_state(self): 101 """Return whether ChromeVox is enabled or not. 102 103 Presupposes self._extension (with management enabled). 104 105 @returns: value of management.get.enabled. 106 107 @raises: error.TestError if state cannot be determined. 108 109 """ 110 cmd = ('window.__enabled = null;\n' 111 'chrome.management.get(\'%s\', function(r) {' 112 'if (r) {window.__enabled = r[\'enabled\'];} ' 113 'else {window.__enabled = false;}});' % self._CHROMEVOX_ID) 114 self._extension.ExecuteJavaScript(cmd) 115 116 poll_cmd = 'window.__enabled != null;' 117 utils.poll_for_condition( 118 lambda: self._extension.EvaluateJavaScript(poll_cmd), 119 exception=error.TestError( 120 'ChromeVox: management.get.enabled was not set!')) 121 return self._extension.EvaluateJavaScript('window.__enabled') 122 123 124 def _confirm_chromevox_state(self, value): 125 """Fail test unless ChromeVox state is given value. 126 127 Presupposes self._extension (with management enabled). 128 129 @param value: True or False, whether ChromeVox should be enabled. 130 131 @raises: error.TestFail if actual state doesn't match expected. 132 133 """ 134 utils.poll_for_condition( 135 lambda: self._get_chromevox_state() == value, 136 exception=error.TestFail('ChromeVox: enabled state ' 137 'was not %s.' % value), 138 timeout=self._CVOX_STATE_TIMEOUT) 139 140 141 def _get_chromevox_indicator(self, tab): 142 """Return whether the orange ChromeVox highlight is present or not. 143 144 Looks for the orange highlight on the given tab. 145 146 @returns: whether 'cvox_indicator_container' is found on the page 147 148 """ 149 cmd = ('document.getElementsByClassName(' 150 ' "cvox_indicator_container").length > 0;') 151 return tab.EvaluateJavaScript(cmd) 152 153 154 def _confirm_chromevox_indicator(self, value): 155 """Fail test unless indicator state is given value. 156 157 Presupposes self._tab (the tab on which to check). 158 159 @param value: True or False, whether ChromeVox indicator should show. 160 161 @raises: error.TestFail if actual state doesn't match expected. 162 163 """ 164 utils.poll_for_condition( 165 lambda: self._get_chromevox_indicator(self._tab) == value, 166 exception=error.TestFail('ChromeVox: "Indicator present" ' 167 'was not %s.' % value), 168 timeout=self._CVOX_INDICATOR_TIMEOUT) 169 170 171 def _get_extension_path(self): 172 """Return the path to the default accessibility extension. 173 174 @returns: string of path to default extension. 175 176 """ 177 this_dir = os.path.dirname(__file__) 178 return os.path.join(this_dir, 'a11y_ext') 179