Commit e85dbbe6 authored by Anastasia Helfinstein's avatar Anastasia Helfinstein Committed by Commit Bot

[Switch Access] Generalize text infrastructure

Generalize some helper functions within Switch Access tests, and clean
up tests.

AX-Relnotes: n/a.
Bug: None
Change-Id: I7c0ced18e600a8a641a959d8e958a724045b47a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2203403
Commit-Queue: Anastasia Helfinstein <anastasi@google.com>
Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#769509}
parent bb028891
......@@ -12,6 +12,19 @@ function assertUndefined(a) {
}
}
/**
* Asserts that a given argument's value is null or undefined.
* @param {object} obj The argument to check.
* @param {string=} opt_message Error message if the condition is not met.
*/
function assertNullOrUndefined(obj, opt_message) {
if (obj !== undefined && obj !== null) {
throw new Error(
'Must be null or undefined: ' + (opt_message || '') + '\n' +
'Actual: ' + obj);
}
}
/**
* Asserts that the argument is neither null nor undefined.
* @param {object} obj The argument to check.
......
......@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
GEN_INCLUDE([
'switch_access_e2e_test_base.js', '../chromevox/testing/assert_additions.js'
]);
GEN_INCLUDE(['switch_access_e2e_test_base.js']);
/**
* @constructor
......@@ -23,27 +21,6 @@ SwitchAccessNavigationManagerTest.prototype = {
/** @override */
setUp() {
MenuManager.initialize();
},
runAndSaveDesktop(website, callback) {
this.runWithLoadedTree(website, (desktop) => {
this.desktop = desktop;
callback(desktop);
});
},
findNodeById(id) {
const treeWalker = new AutomationTreeWalker(
this.desktop, constants.Dir.FORWARD,
{visit: (node) => node.htmlAttributes['id'] === id});
const result = treeWalker.next().node;
assertTrue(
result && id === result.htmlAttributes['id'],
'Could not find "' + id + '".');
assertTrue(
treeWalker.next().node == undefined,
'More than one node found with id "' + id + '".');
return result;
}
};
......@@ -81,7 +58,7 @@ TEST_F('SwitchAccessNavigationManagerTest', 'MoveTo', function() {
</div>
<button></button>
</div>`;
this.runAndSaveDesktop(website, (desktop) => {
this.runWithLoadedTree(website, (desktop) => {
const textFields =
desktop.findAll({role: chrome.automation.RoleType.TEXT_FIELD});
assertEquals(2, textFields.length, 'Should be exactly 2 text fields.');
......@@ -129,8 +106,8 @@ TEST_F('SwitchAccessNavigationManagerTest', 'MoveTo', function() {
this.navigator.moveTo_(group);
assertTrue(this.navigator.node_.isGroup(), 'Current node is not a group');
assertEquals(
this.navigator.node_.automationNode.htmlAttributes['id'], 'group',
assertTrue(
this.navigator.node_.isEquivalentTo(group),
'Did not find the right group');
});
});
......@@ -144,7 +121,7 @@ TEST_F('SwitchAccessNavigationManagerTest', 'JumpTo', function() {
<button></button>
<button></button>
</div>`;
this.runAndSaveDesktop(website, (desktop) => {
this.runWithLoadedTree(website, (desktop) => {
const textInput =
desktop.findAll({role: chrome.automation.RoleType.TEXT_FIELD})[1];
assertNotNullNorUndefined(textInput, 'Text field is undefined');
......@@ -211,7 +188,7 @@ TEST_F('SwitchAccessNavigationManagerTest', 'EnterGroup', function() {
<button></button>
</div>
<input type="range">`;
this.runAndSaveDesktop(website, (desktop) => {
this.runWithLoadedTree(website, (desktop) => {
const targetGroup = this.findNodeById('group');
this.navigator.moveTo_(targetGroup);
......@@ -242,7 +219,7 @@ TEST_F('SwitchAccessNavigationManagerTest', 'DISABLED_MoveForward', function() {
<button id="button2"></button>
<button id="button3"></button>
</div>`;
this.runAndSaveDesktop(website, (desktop) => {
this.runWithLoadedTree(website, (desktop) => {
this.navigator.moveTo_(this.findNodeById('button1'));
const button1 = this.navigator.node_;
assertFalse(
......@@ -297,7 +274,7 @@ TEST_F('SwitchAccessNavigationManagerTest', 'MoveBackward', function() {
<button id="button2"></button>
<button id="button3"></button>
</div>`;
this.runAndSaveDesktop(website, (desktop) => {
this.runWithLoadedTree(website, (desktop) => {
this.navigator.moveTo_(this.findNodeById('button1'));
const button1 = this.navigator.node_;
assertFalse(
......
......@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
GEN_INCLUDE(['../chromevox/testing/callback_helper.js']);
GEN_INCLUDE([
'../chromevox/testing/callback_helper.js',
'../chromevox/testing/assert_additions.js'
]);
/**
* Base class for browser tests for Switch Access.
......@@ -70,6 +73,46 @@ SwitchAccessE2ETest.prototype = {
return this.callbackHelper_.wrap(opt_callback);
},
/**
* @param {function(chrome.automation.AutomationNode): boolean} predicate A
* predicate that uniquely specifies one automation node.
* @param {string=} opt_nodeString A string specifying what node was being
* looked for.
* @return {!chrome.automation.AutomationNode}
*/
findNodeMatchingPredicate(predicate, opt_nodeString) {
const nodeString = opt_nodeString || 'node matching the predicate';
const treeWalker = new AutomationTreeWalker(
NavigationManager.desktopNode, constants.Dir.FORWARD,
{visit: predicate});
const node = treeWalker.next().node;
assertNotNullNorUndefined(node, 'Could not find ' + nodeString + '.');
assertNullOrUndefined(
treeWalker.next().node, 'Found more than one ' + nodeString + '.');
return node;
},
/**
* @param {string} id The HTML id of an element.
* @return {!chrome.automation.AutomationNode}
*/
findNodeById(id) {
const predicate = (node) => node.htmlAttributes.id === id;
const nodeString = 'node with id "' + id + '"';
return this.findNodeMatchingPredicate(predicate, nodeString);
},
/**
* @param {string} name The name of the node within the automation tree.
* @param {string} role The node's role.
* @return {!chrome.automation.AutomationNode}
*/
findNodeByNameAndRole(name, role) {
const predicate = (node) => node.name === name && node.role === role;
const nodeString = 'node with name "' + name + '" and role ' + role;
return this.findNodeMatchingPredicate(predicate, nodeString);
},
/**
* From chromevox_next_e2e_test_base.js
* Gets the desktop from the automation API and Launches a new tab with
......
......@@ -13,23 +13,7 @@ function SwitchAccessPredicateTest() {
}
SwitchAccessPredicateTest.prototype = {
__proto__: SwitchAccessE2ETest.prototype,
setDesktop(desktop) {
this.desktop = desktop;
},
getNodeByName(name) {
assertTrue(this.desktop != undefined, 'Desktop is undefined');
const node = new AutomationTreeWalker(
this.desktop, constants.Dir.FORWARD,
{visit: (n) => n.name === name})
.next()
.node;
assertTrue(node != null, 'Node is null');
return node;
}
__proto__: SwitchAccessE2ETest.prototype
};
function fakeLoc(x) {
......@@ -63,7 +47,7 @@ function getTree(desktop) {
})
.next()
.node;
assertTrue(root != null, 'Root is null');
assertNotNullNorUndefined(root, 'Root is missing');
const upper1 = root.firstChild;
assertTrue(upper1 && upper1.name === 'upper1', 'Upper1 not found');
......@@ -252,24 +236,23 @@ TEST_F('SwitchAccessPredicateTest', 'IsInterestingSubtree', function() {
TEST_F('SwitchAccessPredicateTest', 'IsActionable', function() {
const treeString =
`<button style="position:absolute; top:-100px;">button1</button>
<button disabled>button2</button>
`<button style="position:absolute; top:-100px;">offscreen</button>
<button disabled>disabled</button>
<a href="https://www.google.com/" aria-label="link1">link1</a>
<input type="text" aria-label="input1">input1</input>
<button>button3</button>
<input type="range" aria-label="slider" value=5 min=0 max=10>
<div aria-label="listitem" role="listitem" onclick="2+2"></div>
<div id="clickable" role="listitem" onclick="2+2"></div>
<div aria-label="div1"><p>p1</p></div>`;
this.runWithLoadedTree(treeString, (desktop) => {
this.setDesktop(desktop);
const button1 = this.getNodeByName('button1');
const offscreenButton = this.findNodeByNameAndRole('offscreen', 'button');
assertFalse(
SwitchAccessPredicate.isActionable(button1),
SwitchAccessPredicate.isActionable(offscreenButton),
'Offscreen objects should not be actionable');
const button2 = this.getNodeByName('button2');
const disabledButton = this.findNodeByNameAndRole('disabled', 'button');
assertFalse(
SwitchAccessPredicate.isActionable(button2),
SwitchAccessPredicate.isActionable(disabledButton),
'Disabled objects should not be actionable');
const rwas =
......@@ -280,37 +263,37 @@ TEST_F('SwitchAccessPredicateTest', 'IsActionable', function() {
'Root web area should not be directly actionable');
}
const link1 = this.getNodeByName('link1');
const link1 = this.findNodeByNameAndRole('link1', 'link');
assertTrue(
SwitchAccessPredicate.isActionable(link1),
'Links should be actionable');
const input1 = this.getNodeByName('input1');
const input1 = this.findNodeByNameAndRole('input1', 'textField');
assertTrue(
SwitchAccessPredicate.isActionable(input1),
'Inputs should be actionable');
const button3 = this.getNodeByName('button3');
const button3 = this.findNodeByNameAndRole('button3', 'button');
assertTrue(
SwitchAccessPredicate.isActionable(button3),
'Buttons should be actionable');
const slider = this.getNodeByName('slider');
const slider = this.findNodeByNameAndRole('slider', 'slider');
assertTrue(
SwitchAccessPredicate.isActionable(slider),
'Sliders should be actionable');
const listitem = this.getNodeByName('listitem');
const clickable = this.findNodeById('clickable');
assertTrue(
SwitchAccessPredicate.isActionable(listitem),
SwitchAccessPredicate.isActionable(clickable),
'Clickable list items should be actionable');
const div1 = this.getNodeByName('div1');
const div1 = this.findNodeByNameAndRole('div1', 'genericContainer');
assertFalse(
SwitchAccessPredicate.isActionable(div1),
'Divs should not generally be actionable');
const p1 = this.getNodeByName('p1');
const p1 = this.findNodeByNameAndRole('p1', 'staticText');
assertFalse(
SwitchAccessPredicate.isActionable(p1),
'Static text should not generally be actionable');
......@@ -318,8 +301,8 @@ TEST_F('SwitchAccessPredicateTest', 'IsActionable', function() {
});
TEST_F('SwitchAccessPredicateTest', 'IsActionableFocusableElements', function() {
const treeString = `<div aria-label="noChildren" tabindex=0></div>
<div aria-label="oneInterestingChild" tabindex=0>
const treeString = `<div id="noChildren" tabindex=0></div>
<div id="oneInterestingChild" tabindex=0>
<div>
<div>
<div>
......@@ -328,41 +311,39 @@ TEST_F('SwitchAccessPredicateTest', 'IsActionableFocusableElements', function()
</div>
</div>
</div>
<div aria-label="oneUninterestingChild" tabindex=0>
<div id="oneUninterestingChild" tabindex=0>
<p>p1</p>
</div>
<div aria-label="interestingChildren" tabindex=0>
<div id="interestingChildren" tabindex=0>
<button>button2</button>
<button>button3</button>
</div>
<div aria-label="uninterestingChildren" tabindex=0>
<div id="uninterestingChildren" tabindex=0>
<p>p2</p>
<p>p3</p>
</div>`;
this.runWithLoadedTree(treeString, (desktop) => {
this.setDesktop(desktop);
const noChildren = this.getNodeByName('noChildren');
const noChildren = this.findNodeById('noChildren');
assertTrue(
SwitchAccessPredicate.isActionable(noChildren),
'Focusable element with no children should be actionable');
const oneInterestingChild = this.getNodeByName('oneInterestingChild');
const oneInterestingChild = this.findNodeById('oneInterestingChild');
assertFalse(
SwitchAccessPredicate.isActionable(oneInterestingChild),
'Focusable element with an interesting child should not be actionable');
const interestingChildren = this.getNodeByName('interestingChildren');
const interestingChildren = this.findNodeById('interestingChildren');
assertFalse(
SwitchAccessPredicate.isActionable(interestingChildren),
'Focusable element with interesting children should not be actionable');
const oneUninterestingChild = this.getNodeByName('oneUninterestingChild');
const oneUninterestingChild = this.findNodeById('oneUninterestingChild');
assertTrue(
SwitchAccessPredicate.isActionable(oneUninterestingChild),
'Focusable element with one uninteresting child should be actionable');
const uninterestingChildren = this.getNodeByName('uninterestingChildren');
const uninterestingChildren = this.findNodeById('uninterestingChildren');
assertTrue(
SwitchAccessPredicate.isActionable(uninterestingChildren),
'Focusable element with uninteresting children should be actionable');
......
......@@ -55,7 +55,7 @@ function runTextNavigationTest(testHelper, textParams) {
textId, textContent, initialTextIndex, textCols, textWrap);
testHelper.runWithLoadedTree(website, function(desktop) {
const inputNode = findNodeById(desktop, textId);
const inputNode = this.findNodeById(textId);
assertNotEquals(inputNode, null);
setUpCursorChangeListener(
......@@ -114,7 +114,7 @@ function runTextSelectionTest(testHelper, textParams) {
}
testHelper.runWithLoadedTree(website, function(desktop) {
const inputNode = findNodeById(desktop, textId, testHelper);
const inputNode = this.findNodeById(textId);
assertNotEquals(inputNode, null);
checkNodeIsFocused(inputNode);
const callback = testHelper.newCallback(function() {
......@@ -156,26 +156,6 @@ function generateWebsiteWithTextArea(id, contents, textIndex, cols, wrap) {
return website;
}
/**
* Given the desktop node, returns the node with the given
* id.
* @param {!chrome.automation.AutomationNode} desktop
* @param {string} id
* @return {!chrome.automation.AutomationNode}
*/
function findNodeById(desktop, id) {
// The loop ensures that the page has loaded before trying to find the node.
let inputNode;
while (inputNode == null) {
inputNode = new AutomationTreeWalker(
desktop, constants.Dir.FORWARD,
{visit: (node) => node.htmlAttributes.id === id})
.next()
.node;
}
return inputNode;
}
/**
* Check that the node in the JS file matches the node in the test.
* The nodes can be assumed to be the same if their roles match as there is only
......@@ -344,7 +324,7 @@ TEST_F(
generateWebsiteWithTextArea('test', 'test123', 3, 20, 'hard');
this.runWithLoadedTree(website, function(desktop) {
const inputNode = findNodeById(desktop, 'test', this);
const inputNode = this.findNodeById('test');
assertNotEquals(inputNode, null);
checkNodeIsFocused(inputNode);
......@@ -365,7 +345,7 @@ TEST_F(
generateWebsiteWithTextArea('test', 'test 123', 6, 20, 'hard');
this.runWithLoadedTree(website, function(desktop) {
const inputNode = findNodeById(desktop, 'test', this);
const inputNode = this.findNodeById('test');
assertNotEquals(inputNode, null);
checkNodeIsFocused(inputNode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment