accessible/tests/mochitest/states.js

changeset 0
6474c204b198
     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 +}

mercurial