1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/accessible/tests/mochitest/states.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,254 @@ 1.4 +//////////////////////////////////////////////////////////////////////////////// 1.5 +// Helper functions for accessible states testing. 1.6 +// 1.7 +// requires: 1.8 +// common.js 1.9 +// role.js 1.10 +// 1.11 +//////////////////////////////////////////////////////////////////////////////// 1.12 + 1.13 +//////////////////////////////////////////////////////////////////////////////// 1.14 +// State constants 1.15 + 1.16 +// const STATE_BUSY is defined in common.js 1.17 +const STATE_CHECKED = nsIAccessibleStates.STATE_CHECKED; 1.18 +const STATE_CHECKABLE = nsIAccessibleStates.STATE_CHECKABLE; 1.19 +const STATE_COLLAPSED = nsIAccessibleStates.STATE_COLLAPSED; 1.20 +const STATE_DEFAULT = nsIAccessibleStates.STATE_DEFAULT; 1.21 +const STATE_EXPANDED = nsIAccessibleStates.STATE_EXPANDED; 1.22 +const STATE_EXTSELECTABLE = nsIAccessibleStates.STATE_EXTSELECTABLE; 1.23 +const STATE_FLOATING = nsIAccessibleStates.STATE_FLOATING; 1.24 +const STATE_FOCUSABLE = nsIAccessibleStates.STATE_FOCUSABLE; 1.25 +const STATE_FOCUSED = nsIAccessibleStates.STATE_FOCUSED; 1.26 +const STATE_HASPOPUP = nsIAccessibleStates.STATE_HASPOPUP; 1.27 +const STATE_INVALID = nsIAccessibleStates.STATE_INVALID; 1.28 +const STATE_INVISIBLE = nsIAccessibleStates.STATE_INVISIBLE; 1.29 +const STATE_LINKED = nsIAccessibleStates.STATE_LINKED; 1.30 +const STATE_MIXED = nsIAccessibleStates.STATE_MIXED; 1.31 +const STATE_MULTISELECTABLE = nsIAccessibleStates.STATE_MULTISELECTABLE; 1.32 +const STATE_OFFSCREEN = nsIAccessibleStates.STATE_OFFSCREEN; 1.33 +const STATE_PRESSED = nsIAccessibleStates.STATE_PRESSED; 1.34 +const STATE_PROTECTED = nsIAccessibleStates.STATE_PROTECTED; 1.35 +const STATE_READONLY = nsIAccessibleStates.STATE_READONLY; 1.36 +const STATE_REQUIRED = nsIAccessibleStates.STATE_REQUIRED; 1.37 +const STATE_SELECTABLE = nsIAccessibleStates.STATE_SELECTABLE; 1.38 +const STATE_SELECTED = nsIAccessibleStates.STATE_SELECTED; 1.39 +const STATE_TRAVERSED = nsIAccessibleStates.STATE_TRAVERSED; 1.40 +const STATE_UNAVAILABLE = nsIAccessibleStates.STATE_UNAVAILABLE; 1.41 + 1.42 +const EXT_STATE_ACTIVE = nsIAccessibleStates.EXT_STATE_ACTIVE; 1.43 +const EXT_STATE_DEFUNCT = nsIAccessibleStates.EXT_STATE_DEFUNCT; 1.44 +const EXT_STATE_EDITABLE = nsIAccessibleStates.EXT_STATE_EDITABLE; 1.45 +const EXT_STATE_ENABLED = nsIAccessibleStates.EXT_STATE_ENABLED; 1.46 +const EXT_STATE_EXPANDABLE = nsIAccessibleStates.EXT_STATE_EXPANDABLE; 1.47 +const EXT_STATE_HORIZONTAL = nsIAccessibleStates.EXT_STATE_HORIZONTAL; 1.48 +const EXT_STATE_MULTI_LINE = nsIAccessibleStates.EXT_STATE_MULTI_LINE; 1.49 +const EXT_STATE_PINNED = nsIAccessibleStates.EXT_STATE_PINNED; 1.50 +const EXT_STATE_SENSITIVE = nsIAccessibleStates.EXT_STATE_SENSITIVE; 1.51 +const EXT_STATE_SINGLE_LINE = nsIAccessibleStates.EXT_STATE_SINGLE_LINE; 1.52 +const EXT_STATE_STALE = nsIAccessibleStates.EXT_STATE_STALE; 1.53 +const EXT_STATE_SUPPORTS_AUTOCOMPLETION = 1.54 + nsIAccessibleStates.EXT_STATE_SUPPORTS_AUTOCOMPLETION; 1.55 +const EXT_STATE_VERTICAL = nsIAccessibleStates.EXT_STATE_VERTICAL; 1.56 + 1.57 +const kOrdinalState = 0; 1.58 +const kExtraState = 1; 1.59 + 1.60 +//////////////////////////////////////////////////////////////////////////////// 1.61 +// Test functions 1.62 + 1.63 +/** 1.64 + * Tests the states and extra states of the given accessible. 1.65 + * Also tests for unwanted states and extra states. 1.66 + * In addition, the function performs a few plausibility checks derived from the 1.67 + * sstates and extra states passed in. 1.68 + * 1.69 + * @param aAccOrElmOrID The accessible, DOM element or ID to be tested. 1.70 + * @param aState The state bits that are wanted. 1.71 + * @param aExtraState The extra state bits that are wanted. 1.72 + * @param aAbsentState State bits that are not wanted. 1.73 + * @param aAbsentExtraState Extra state bits that are not wanted. 1.74 + * @param aTestName The test name. 1.75 + */ 1.76 +function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState, 1.77 + aAbsentExtraState, aTestName) 1.78 +{ 1.79 + var [state, extraState] = getStates(aAccOrElmOrID); 1.80 + var role = getRole(aAccOrElmOrID); 1.81 + var id = prettyName(aAccOrElmOrID) + (aTestName ? " [" + aTestName + "]": ""); 1.82 + 1.83 + // Primary test. 1.84 + if (aState) { 1.85 + isState(state & aState, aState, false, 1.86 + "wrong state bits for " + id + "!"); 1.87 + } 1.88 + 1.89 + if (aExtraState) 1.90 + isState(extraState & aExtraState, aExtraState, true, 1.91 + "wrong extra state bits for " + id + "!"); 1.92 + 1.93 + if (aAbsentState) 1.94 + isState(state & aAbsentState, 0, false, 1.95 + "state bits should not be present in ID " + id + "!"); 1.96 + 1.97 + if (aAbsentExtraState) 1.98 + isState(extraState & aAbsentExtraState, 0, true, 1.99 + "extraState bits should not be present in ID " + id + "!"); 1.100 + 1.101 + // Additional test. 1.102 + 1.103 + // focused/focusable 1.104 + if (state & STATE_FOCUSED) 1.105 + isState(state & STATE_FOCUSABLE, STATE_FOCUSABLE, false, 1.106 + "Focussed " + id + " must be focusable!"); 1.107 + 1.108 + if (aAbsentState && (aAbsentState & STATE_FOCUSABLE)) { 1.109 + isState(state & STATE_FOCUSED, 0, false, 1.110 + "Not focusable " + id + " must be not focused!"); 1.111 + } 1.112 + 1.113 + // multiline/singleline 1.114 + if (extraState & EXT_STATE_MULTI_LINE) 1.115 + isState(extraState & EXT_STATE_SINGLE_LINE, 0, true, 1.116 + "Multiline " + id + " cannot be singleline!"); 1.117 + 1.118 + if (extraState & EXT_STATE_SINGLE_LINE) 1.119 + isState(extraState & EXT_STATE_MULTI_LINE, 0, true, 1.120 + "Singleline " + id + " cannot be multiline!"); 1.121 + 1.122 + // expanded/collapsed/expandable 1.123 + if (state & STATE_COLLAPSED || state & STATE_EXPANDED) 1.124 + isState(extraState & EXT_STATE_EXPANDABLE, EXT_STATE_EXPANDABLE, true, 1.125 + "Collapsed or expanded " + id + " must be expandable!"); 1.126 + 1.127 + if (state & STATE_COLLAPSED) 1.128 + isState(state & STATE_EXPANDED, 0, false, 1.129 + "Collapsed " + id + " cannot be expanded!"); 1.130 + 1.131 + if (state & STATE_EXPANDED) 1.132 + isState(state & STATE_COLLAPSED, 0, false, 1.133 + "Expanded " + id + " cannot be collapsed!"); 1.134 + 1.135 + if (aAbsentState && (extraState & EXT_STATE_EXPANDABLE)) { 1.136 + if (aAbsentState & STATE_EXPANDED) { 1.137 + isState(state & STATE_COLLAPSED, STATE_COLLAPSED, false, 1.138 + "Not expanded " + id + " must be collapsed!"); 1.139 + } else if (aAbsentState & STATE_COLLAPSED) { 1.140 + isState(state & STATE_EXPANDED, STATE_EXPANDED, false, 1.141 + "Not collapsed " + id + " must be expanded!"); 1.142 + } 1.143 + } 1.144 + 1.145 + // checked/mixed/checkable 1.146 + if (state & STATE_CHECKED || state & STATE_MIXED && 1.147 + role != ROLE_TOGGLE_BUTTON && role != ROLE_PROGRESSBAR) 1.148 + isState(state & STATE_CHECKABLE, STATE_CHECKABLE, false, 1.149 + "Checked or mixed element must be checkable!"); 1.150 + 1.151 + if (state & STATE_CHECKED) 1.152 + isState(state & STATE_MIXED, 0, false, 1.153 + "Checked element cannot be state mixed!"); 1.154 + 1.155 + if (state & STATE_MIXED) 1.156 + isState(state & STATE_CHECKED, 0, false, 1.157 + "Mixed element cannot be state checked!"); 1.158 + 1.159 + // selected/selectable 1.160 + if (state & STATE_SELECTED) { 1.161 + isState(state & STATE_SELECTABLE, STATE_SELECTABLE, false, 1.162 + "Selected element must be selectable!"); 1.163 + } 1.164 +} 1.165 + 1.166 +/** 1.167 + * Tests an acessible and its sub tree for the passed in state bits. 1.168 + * Used to make sure that states are propagated to descendants, for example the 1.169 + * STATE_UNAVAILABLE from a container to its children. 1.170 + * 1.171 + * @param aAccOrElmOrID The accessible, DOM element or ID to be tested. 1.172 + * @param aState The state bits that are wanted. 1.173 + * @param aExtraState The extra state bits that are wanted. 1.174 + * @param aAbsentState State bits that are not wanted. 1.175 + */ 1.176 +function testStatesInSubtree(aAccOrElmOrID, aState, aExtraState, aAbsentState) 1.177 +{ 1.178 + // test accessible and its subtree for propagated states. 1.179 + var acc = getAccessible(aAccOrElmOrID); 1.180 + if (!acc) 1.181 + return; 1.182 + 1.183 + if (getRole(acc) != ROLE_TEXT_LEAF) 1.184 + // Right now, text leafs don't get tested because the states are not being 1.185 + // propagated. 1.186 + testStates(acc, aState, aExtraState, aAbsentState); 1.187 + 1.188 + // Iterate over its children to see if the state got propagated. 1.189 + var children = null; 1.190 + try { 1.191 + children = acc.children; 1.192 + } catch(e) {} 1.193 + ok(children, "Could not get children for " + aAccOrElmOrID +"!"); 1.194 + 1.195 + if (children) { 1.196 + for (var i = 0; i < children.length; i++) { 1.197 + var childAcc = children.queryElementAt(i, nsIAccessible); 1.198 + testStatesInSubtree(childAcc, aState, aExtraState, aAbsentState); 1.199 + } 1.200 + } 1.201 +} 1.202 + 1.203 +function getStringStates(aAccOrElmOrID) 1.204 +{ 1.205 + var [state, extraState] = getStates(aAccOrElmOrID); 1.206 + return statesToString(state, extraState); 1.207 +} 1.208 + 1.209 +function getStates(aAccOrElmOrID) 1.210 +{ 1.211 + var acc = getAccessible(aAccOrElmOrID); 1.212 + if (!acc) 1.213 + return [0, 0]; 1.214 + 1.215 + var state = {}, extraState = {}; 1.216 + acc.getState(state, extraState); 1.217 + 1.218 + return [state.value, extraState.value]; 1.219 +} 1.220 + 1.221 +/** 1.222 + * Return true if the accessible has given states. 1.223 + */ 1.224 +function hasState(aAccOrElmOrID, aState, aExtraState) 1.225 +{ 1.226 + var [state, exstate] = getStates(aAccOrElmOrID); 1.227 + return (aState ? state & aState : true) && 1.228 + (aExtraState ? exstate & aExtraState : true); 1.229 +} 1.230 + 1.231 +//////////////////////////////////////////////////////////////////////////////// 1.232 +// Private implementation details 1.233 + 1.234 +/** 1.235 + * Analogy of SimpleTest.is function used to compare states. 1.236 + */ 1.237 +function isState(aState1, aState2, aIsExtraStates, aMsg) 1.238 +{ 1.239 + if (aState1 == aState2) { 1.240 + ok(true, aMsg); 1.241 + return; 1.242 + } 1.243 + 1.244 + var got = "0"; 1.245 + if (aState1) { 1.246 + got = statesToString(aIsExtraStates ? 0 : aState1, 1.247 + aIsExtraStates ? aState1 : 0); 1.248 + } 1.249 + 1.250 + var expected = "0"; 1.251 + if (aState2) { 1.252 + expected = statesToString(aIsExtraStates ? 0 : aState2, 1.253 + aIsExtraStates ? aState2 : 0); 1.254 + } 1.255 + 1.256 + ok(false, aMsg + "got '" + got + "', expected '" + expected + "'"); 1.257 +}