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 def _chromevox_move(self, direction): 48 """Use ChromeVox move commands (search + arrow key). 49 50 @param direction: The direction in which to move, e.g. 'down'. 51 52 """ 53 self._player.blocking_playback_of_default_file( 54 input_type='keyboard', 55 filename='keyboard_search+%s' % direction) 56 57 def _set_feature(self, feature, value): 58 """Set given feature to given value using a11y API call. 59 60 Presupposes self._extension (with accessibilityFeatures enabled). 61 62 @param feature: string of accessibility feature to change. 63 @param value: boolean of expected value. 64 65 @raises: error.TestError if feature cannot be set. 66 67 """ 68 value_str = 'true' if value else 'false' 69 cmd = ('window.__result = null;\n' 70 'chrome.accessibilityFeatures.%s.set({value: %s});\n' 71 'chrome.accessibilityFeatures.%s.get({}, function(d) {' 72 'window.__result = d[\'value\']; });' % ( 73 feature, value_str, feature)) 74 self._extension.ExecuteJavaScript(cmd) 75 76 poll_cmd = 'window.__result == %s;' % value_str 77 utils.poll_for_condition( 78 lambda: self._extension.EvaluateJavaScript(poll_cmd), 79 exception = error.TestError( 80 'Timeout while trying to set %s to %s' % 81 (feature, value_str))) 82 83 84 def _get_chromevox_state(self): 85 """Return whether ChromeVox is enabled or not. 86 87 Presupposes self._extension (with management enabled). 88 89 @returns: value of management.get.enabled. 90 91 @raises: error.TestError if state cannot be determined. 92 93 """ 94 cmd = ('window.__enabled = null;\n' 95 'chrome.management.get(\'%s\', function(r) {' 96 'if (r) {window.__enabled = r[\'enabled\'];} ' 97 'else {window.__enabled = false;}});' % self._CHROMEVOX_ID) 98 self._extension.ExecuteJavaScript(cmd) 99 100 poll_cmd = 'window.__enabled != null;' 101 utils.poll_for_condition( 102 lambda: self._extension.EvaluateJavaScript(poll_cmd), 103 exception=error.TestError( 104 'ChromeVox: management.get.enabled was not set!')) 105 return self._extension.EvaluateJavaScript('window.__enabled') 106 107 108 def _confirm_chromevox_state(self, value): 109 """Fail test unless ChromeVox state is given value. 110 111 Presupposes self._extension (with management enabled). 112 113 @param value: True or False, whether ChromeVox should be enabled. 114 115 @raises: error.TestFail if actual state doesn't match expected. 116 117 """ 118 utils.poll_for_condition( 119 lambda: self._get_chromevox_state() == value, 120 exception=error.TestFail('ChromeVox: enabled state ' 121 'was not %s.' % value), 122 timeout=self._CVOX_STATE_TIMEOUT) 123 124 125 def _get_extension_path(self): 126 """Return the path to the default accessibility extension. 127 128 @returns: string of path to default extension. 129 130 """ 131 this_dir = os.path.dirname(__file__) 132 return os.path.join(this_dir, 'a11y_ext') 133