Bug 1276972 - adding value and attributes caching tests. r=eeejay draft
authorYura Zenevich <yzenevich@mozilla.com>
Mon, 06 Jun 2016 10:29:24 -0400
changeset 375679 6e73b27072d50dbc25fd28172a0cb1027b01c431
parent 375659 0a3b6e2df6567d845f31c000c68dd67816c6153d
child 522941 99428afe3355eaa2f6131e9390b8525743eb2515
push id20353
push useryura.zenevich@gmail.com
push dateMon, 06 Jun 2016 14:29:54 +0000
reviewerseeejay
bugs1276972
milestone49.0a1
Bug 1276972 - adding value and attributes caching tests. r=eeejay MozReview-Commit-ID: BOXh17Ql1dW
accessible/tests/browser/.eslintrc
accessible/tests/browser/browser.ini
accessible/tests/browser/browser_caching_attributes.js
accessible/tests/browser/browser_caching_value.js
accessible/tests/browser/events.js
accessible/tests/mochitest/common.js
--- a/accessible/tests/browser/.eslintrc
+++ b/accessible/tests/browser/.eslintrc
@@ -6,20 +6,23 @@
   "globals": {
     // Content scripts have global 'content' object
     "content": true,
 
     // Defined in accessible/tests/mochitest/ common.js, name.js, states.js
     "prettyName": true,
     "statesToString": true,
     "eventTypeToString": true,
+    "testAttrs": true,
+    "testAbsentAttrs": true,
     "testName": true,
     "testDescr": true,
     "testStates": true,
     "testRelation": true,
+    "testValue": true,
     "testAccessibleTree": true,
     "isAccessible": true,
     "getAccessibleDOMNodeID": true,
 
     // Defined for all accessibility browser tests.
     "addAccessibleTask": true,
     "BrowserTestUtils": true,
     "ContentTask": true,
--- a/accessible/tests/browser/browser.ini
+++ b/accessible/tests/browser/browser.ini
@@ -9,21 +9,24 @@ support-files =
   doc_treeupdate_removal.xhtml
   doc_treeupdate_visibility.html
   doc_treeupdate_whitespace.html
   !/accessible/tests/mochitest/*.js
   !/accessible/tests/mochitest/letters.gif
   !/accessible/tests/mochitest/moz.png
 
 # Caching tests
+[browser_caching_attributes.js]
 [browser_caching_description.js]
 [browser_caching_name.js]
 skip-if = e10s
 [browser_caching_relations.js]
 [browser_caching_states.js]
+[browser_caching_value.js]
+skip-if = e10s # Bug 1276721: QueryInterface is not working with proxies.
 
 # Events tests
 [browser_events_caretmove.js]
 [browser_events_hide.js]
 [browser_events_show.js]
 [browser_events_statechange.js]
 [browser_events_textchange.js]
 
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_caching_attributes.js
@@ -0,0 +1,117 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+/* global EVENT_FOCUS */
+
+loadScripts({ name: 'attributes.js', dir: MOCHITESTS_DIR });
+
+/**
+ * Default textbox accessible attributes.
+ */
+const defaultAttributes = {
+  'margin-top': '0px',
+  'margin-right': '0px',
+  'margin-bottom': '0px',
+  'margin-left': '0px',
+  'text-align': 'start',
+  'text-indent': '0px',
+  'id': 'textbox',
+  'tag': 'input',
+  'display': 'inline'
+};
+
+/**
+ * Test data has the format of:
+ * {
+ *   desc        {String}       description for better logging
+ *   expected    {Object}       expected attributes for given accessibles
+ *   unexpected  {Object}       unexpected attributes for given accessibles
+ *
+ *   action      {?Function*}   an optional action that yields a change in
+ *                              attributes
+ *   attrs       {?Array}       an optional list of attributes to update
+ *   waitFor     {?Number}      an optional event to wait for
+ * }
+ */
+const attributesTests = [{
+  desc: 'Initiall accessible attributes',
+  expected: defaultAttributes,
+  unexpected: {
+    'line-number': '1',
+    'explicit-name': 'true',
+    'container-live': 'polite',
+    'live': 'polite'
+  }
+}, {
+  desc: '@line-number attribute is present when textbox is focused',
+  action: function*(browser) {
+    yield invokeFocus(browser, 'textbox');
+  },
+  waitFor: EVENT_FOCUS,
+  expected: Object.assign({}, defaultAttributes, { 'line-number': '1' }),
+  unexpected: {
+    'explicit-name': 'true',
+    'container-live': 'polite',
+    'live': 'polite'
+  }
+}, {
+  desc: '@aria-live sets container-live and live attributes',
+  attrs: [{
+    attr: 'aria-live',
+    value: 'polite'
+  }],
+  expected: Object.assign({}, defaultAttributes, {
+    'line-number': '1',
+    'container-live': 'polite',
+    'live': 'polite'
+  }),
+  unexpected: {
+    'explicit-name': 'true'
+  }
+}, {
+  desc: '@title attribute sets explicit-name attribute to true',
+  attrs: [{
+    attr: 'title',
+    value: 'textbox'
+  }],
+  expected: Object.assign({}, defaultAttributes, {
+    'line-number': '1',
+    'explicit-name': 'true',
+    'container-live': 'polite',
+    'live': 'polite'
+  }),
+  unexpected: {}
+}];
+
+/**
+ * Test caching of accessible object attributes
+ */
+addAccessibleTask(`
+  <input id="textbox" value="hello">`,
+  function* (browser, accDoc) {
+    let textbox = findAccessibleChildByID(accDoc, 'textbox');
+    for (let { desc, action, attrs, expected, waitFor, unexpected } of attributesTests) {
+      info(desc);
+      let onUpdate;
+
+      if (waitFor) {
+        onUpdate = waitForEvent(waitFor, 'textbox');
+      }
+
+      if (action) {
+        yield action(browser);
+      } else if (attrs) {
+        for (let { attr, value } of attrs) {
+          yield invokeSetAttribute(browser, 'textbox', attr, value);
+        }
+      }
+
+      yield onUpdate;
+      testAttrs(textbox, expected);
+      testAbsentAttrs(textbox, unexpected);
+    }
+  }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/browser_caching_value.js
@@ -0,0 +1,155 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict';
+
+/* global nsIAccessibleValue, EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE */
+
+loadScripts({ name: 'value.js', dir: MOCHITESTS_DIR });
+
+/**
+ * Test data has the format of:
+ * {
+ *   desc      {String}       description for better logging
+ *   id        {String}       given accessible DOMNode ID
+ *   expected  {String}       expected value for a given accessible
+ *   action    {?Function*}   an optional action that yields a value change
+ *   attrs     {?Array}       an optional list of attributes to update
+ *   waitFor   {?Number}      an optional value change event to wait for
+ * }
+ */
+const valueTests = [{
+  desc: 'Initially value is set to 1st element of select',
+  id: 'select',
+  expected: '1st'
+}, {
+  desc: 'Value should update to 3rd when 3 is pressed',
+  id: 'select',
+  action: function*(browser) {
+    yield invokeFocus(browser, 'select');
+    yield BrowserTestUtils.synthesizeKey('3', {}, browser);
+  },
+  waitFor: EVENT_TEXT_VALUE_CHANGE,
+  expected: '3rd'
+}, {
+  desc: 'Initially value is set to @aria-valuenow for slider',
+  id: 'slider',
+  expected: ['5', 5, 0, 7, 0]
+}, {
+  desc: 'Value should change when @aria-valuenow is updated',
+  id: 'slider',
+  attrs: [{
+    attr: 'aria-valuenow',
+    value: '6'
+  }],
+  waitFor: EVENT_VALUE_CHANGE,
+  expected: ['6', 6, 0, 7, 0]
+}, {
+  desc: 'Value should change when @aria-valuetext is set',
+  id: 'slider',
+  attrs: [{
+    attr: 'aria-valuetext',
+    value: 'plain'
+  }],
+  waitFor: EVENT_TEXT_VALUE_CHANGE,
+  expected: ['plain', 6, 0, 7, 0]
+}, {
+  desc: 'Value should change when @aria-valuetext is updated',
+  id: 'slider',
+  attrs: [{
+    attr: 'aria-valuetext',
+    value: 'hey!'
+  }],
+  waitFor: EVENT_TEXT_VALUE_CHANGE,
+  expected: ['hey!', 6, 0, 7, 0]
+}, {
+  desc: 'Value should change to @aria-valuetext when @aria-valuenow is removed',
+  id: 'slider',
+  attrs: [{
+    attr: 'aria-valuenow'
+  }],
+  expected: ['hey!', 0, 0, 7, 0]
+}, {
+  desc: 'Initially value is not set for combobox',
+  id: 'combobox',
+  expected: ''
+}, {
+  desc: 'Value should change when @value attribute is updated',
+  id: 'combobox',
+  attrs: [{
+    attr: 'value',
+    value: 'hello'
+  }],
+  waitFor: EVENT_TEXT_VALUE_CHANGE,
+  expected: 'hello'
+}, {
+  desc: 'Initially value corresponds to @value attribute for progress',
+  id: 'progress',
+  expected: '22%'
+}, {
+  desc: 'Value should change when @value attribute is updated',
+  id: 'progress',
+  attrs: [{
+    attr: 'value',
+    value: '50'
+  }],
+  waitFor: EVENT_VALUE_CHANGE,
+  expected: '50%'
+}, {
+  desc: 'Initially value corresponds to @value attribute for range',
+  id: 'range',
+  expected: '6'
+}, {
+  desc: 'Value should change when slider is moved',
+  id: 'range',
+  action: function*(browser) {
+    yield invokeFocus(browser, 'range');
+    yield BrowserTestUtils.synthesizeKey('VK_LEFT', {}, browser);
+  },
+  waitFor: EVENT_VALUE_CHANGE,
+  expected: '5'
+}];
+
+/**
+ * Test caching of accessible object values
+ */
+addAccessibleTask(`
+  <div id="slider" role="slider" aria-valuenow="5"
+       aria-valuemin="0" aria-valuemax="7">slider</div>
+  <select id="select">
+    <option>1st</option>
+    <option>2nd</option>
+    <option>3rd</option>
+  </select>
+  <input id="combobox" role="combobox" aria-autocomplete="inline">
+  <progress id="progress" value="22" max="100"></progress>
+  <input type="range" id="range" min="0" max="10" value="6">`,
+  function* (browser, accDoc) {
+    for (let { desc, id, action, attrs, expected, waitFor } of valueTests) {
+      info(desc);
+      let acc = findAccessibleChildByID(accDoc, id);
+      let onUpdate;
+
+      if (waitFor) {
+        onUpdate = waitForEvent(waitFor, id);
+      }
+
+      if (action) {
+        yield action(browser);
+      } else if (attrs) {
+        for (let { attr, value } of attrs) {
+          yield invokeSetAttribute(browser, id, attr, value);
+        }
+      }
+
+      yield onUpdate;
+      if (Array.isArray(expected)) {
+        acc.QueryInterface(nsIAccessibleValue);
+        testValue(acc, ...expected);
+      } else {
+        is(acc.value, expected, `Correct value for ${prettyName(acc)}`);
+      }
+    }
+  }
+);
--- a/accessible/tests/browser/events.js
+++ b/accessible/tests/browser/events.js
@@ -5,28 +5,32 @@
 'use strict';
 
 /* global nsIAccessibleEvent, nsIAccessibleDocument,
           nsIAccessibleStateChangeEvent, nsIAccessibleTextChangeEvent */
 
 /* exported EVENT_REORDER, EVENT_SHOW, EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED,
             EVENT_DOCUMENT_LOAD_COMPLETE, EVENT_HIDE, EVENT_TEXT_CARET_MOVED,
             EVENT_DESCRIPTION_CHANGE, EVENT_NAME_CHANGE, EVENT_STATE_CHANGE,
+            EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE, EVENT_FOCUS,
             waitForEvent, waitForMultipleEvents */
 
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
 const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
 const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
 const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
 const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED;
 const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED;
 const EVENT_DESCRIPTION_CHANGE = nsIAccessibleEvent.EVENT_DESCRIPTION_CHANGE;
 const EVENT_NAME_CHANGE = nsIAccessibleEvent.EVENT_NAME_CHANGE;
+const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE;
+const EVENT_TEXT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_TEXT_VALUE_CHANGE;
+const EVENT_FOCUS = nsIAccessibleEvent.EVENT_FOCUS;
 
 /**
  * Describe an event in string format.
  * @param  {nsIAccessibleEvent}  event  event to strigify
  */
 function eventToString(event) {
   let type = eventTypeToString(event.eventType);
   let info = `Event type: ${type}`;
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -286,16 +286,19 @@ function getAccessible(aAccOrElmOrID, aI
 
   if (!aInterfaces)
     return acc;
 
   if (!(aInterfaces instanceof Array))
     aInterfaces = [ aInterfaces ];
 
   for (var index = 0; index < aInterfaces.length; index++) {
+    if (acc instanceof aInterfaces[index]) {
+      continue;
+    }
     try {
       acc.QueryInterface(aInterfaces[index]);
     } catch (e) {
       if (!(aDoNotFailIf & DONOTFAIL_IF_NO_INTERFACE))
         ok(false, "Can't query " + aInterfaces[index] + " for " + aAccOrElmOrID);
 
       return null;
     }