Commit 33913132 authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Port live region ChromeVox tests.

This is 10/11 tests from upstream. All uses of setTimeout were removed to hopefully eliminate any flakiness.

Fixes bug where live region removals weren't spoken.

BUG=371692

Review URL: https://codereview.chromium.org/582123002

Cr-Commit-Position: refs/heads/master@{#296015}
parent 0e01f814
......@@ -344,16 +344,18 @@ cvox.LiveRegions.announceChange = function(
}
var navDescriptions = cvox.LiveRegions.getNavDescriptionsRecursive(node);
if (navDescriptions.length == 0) {
return;
}
if (isRemoval) {
navDescriptions = [cvox.DescriptionUtil.getDescriptionFromAncestors(
[node], true, cvox.ChromeVox.verbosity)];
navDescriptions = [new cvox.NavDescription({
context: cvox.ChromeVox.msgs.getMsg('live_regions_removed'), text: ''
})].concat(navDescriptions);
}
if (navDescriptions.length == 0) {
return;
}
// Don't announce alerts on page load if their text and values consist of
// just whitespace.
var deltaTime = new Date() - cvox.LiveRegions.pageLoadTime;
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Include test fixture.
GEN_INCLUDE(['../../testing/chromevox_unittest_base.js']);
/**
* Test fixture.
* @constructor
* @extends {ChromeVoxUnitTestBase}
*/
function CvoxLiveRegionsUnitTest() {}
CvoxLiveRegionsUnitTest.prototype = {
__proto__: ChromeVoxUnitTestBase.prototype,
/** @override */
isAsync: true,
/** @override */
closureModuleDeps: [
'cvox.ChromeVoxTester',
'cvox.SpokenListBuilder',
],
/** @override */
setUp: function() {
cvox.ChromeVoxTester.setUp(document);
},
/** @override */
tearDown: function() {
cvox.ChromeVoxTester.tearDown(document);
}
};
TEST_F('CvoxLiveRegionsUnitTest', 'InsertNonLiveRegion', function() {
var region = document.createElement('div');
region.innerHTML = '<div role="button">Alpha</div>';
document.body.appendChild(region);
this.waitForCalm(function() {
assertEquals(0, cvox.ChromeVoxTester.getUtteranceList().length);
testDone();
});
});
/**
* Test inserting an 'alert' live region.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'InsertAlertLiveRegion', function() {
var region = document.createElement('div');
region.innerHTML = '<div role="alert">Alpha</div>';
document.body.appendChild(region);
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('Alpha', utterances[0]);
assertEquals('Alert', utterances[1]);
testDone();
});
});
/**
* Test making text appear inside an 'alert' live region by setting its
* display to something other than 'none'.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'RevealAlertLiveRegion', function() {
this.loadDoc(function() {/*!
<div role="alert">
<style>
.invisible {
display: none;
}
</style>
<div id="mymessage" class="invisible">
I just appeared!
</div>
</div>
*/});
$('mymessage').className = '';
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('I just appeared!', utterances[0]);
testDone();
});
});
/**
* Test inserting a 'polite' live region.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'InsertPoliteLiveRegion', function() {
var region = document.createElement('div');
region.innerHTML = '<div aria-live="polite">Beta</div>';
document.body.appendChild(region);
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('Beta', utterances[0]);
testDone();
});
});
/**
* Test modifying an existing status live region.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'ModifyStatusLiveRegion', function() {
var region = document.createElement('div');
region.innerHTML = '<div id="status" role="status">Gamma</div>';
document.body.appendChild(region);
this.waitForCalm(function() {
$('status').innerText = 'Delta';
// Wait for this to make it through the event queue and
// trigger the live region change announcement.
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('Delta', utterances[utterances.length - 1]);
testDone();
});
});
});
/**
* Test adding element to a atomic and non-atomic live regions.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'AddToLiveRegion', function() {
this.loadDoc(function() {/*!
<div>
<div id="non_atomic_buddylist" aria-live="polite">
<div>Larry</div>
<div>Sergey</div>
</div>
<div id="atomic_buddylist" aria-live="polite" aria-atomic="true">
<div>Larry</div>
<div>Sergey</div>
</div>
</div>
*/});
this.waitForCalm(function() {
var eric1 = document.createElement('div');
eric1.innerHTML = 'Eric';
$('non_atomic_buddylist').appendChild(eric1);
var eric2 = document.createElement('div');
eric2.innerHTML = 'Eric';
$('atomic_buddylist').appendChild(eric2);
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('Eric', utterances[utterances.length - 2]);
assertEquals('Larry Sergey Eric', utterances[utterances.length - 1]);
testDone();
});
});
});
/**
* Test removing elements from live regions.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'RemoveFromLiveRegion', function() {
this.loadDoc(function() {/*!
<div>
<div id="buddylist2" aria-relevant="removals">
<div id="jack">Jack</div>
<div id="janet">Janet</div>
<div id="chrissy">Chrissy</div>
</div>
</div>
*/});
$('buddylist2').setAttribute('aria-live', 'polite');
$('buddylist2').removeChild($('jack'));
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals(3, utterances.length);
assertEquals('removed:', utterances[0]);
assertEquals('', utterances[1]);
assertEquals('Jack', utterances[2]);
testDone();
});
});
/**
* Test live region that's a progress bar through the event watcher.
*/
TEST_F('CvoxLiveRegionsUnitTest', 'ProgressBarLiveRegionEvents', function() {
this.loadDoc(function() {/*!
<div id="progress" role="progressbar" aria-live="polite" aria-valuenow="1">
<div id="ptext">
1% complete.
</div>
</div>
*/});
$('progress').setAttribute('aria-valuenow', '2');
$('ptext').innerText = '2% complete';
this.waitForCalm(function() {
var utterances = cvox.ChromeVoxTester.getUtteranceList();
assertEquals('Progress bar 2', utterances[utterances.length - 1]);
testDone();
});
});
/**
* Test 'alert' live region inserted as a result of focus change, like
* when there's an error message when filling out a form.
* @export
*/
TEST_F('CvoxLiveRegionsUnitTest', 'FocusTriggeredAlertLiveRegion', function() {
this.loadDoc(function() {/*!
<form id="form">
<label>
Name
<input id="name">
</label>
<label>
Address
<input id="address">
</label>
</form>
*/});
// Suppress EventWatcher's artificial limit on the number of DOM subtree
// modified events that can happen in a row.
cvox.ChromeVoxEventWatcher.SUBTREE_MODIFIED_BURST_COUNT_LIMIT_ = 999;
var form = $('form');
var name = $('name');
var address = $('address');
name.addEventListener(
'blur',
function() {
var region = document.createElement('div');
region.innerHTML = '<div role="alert">Not a valid name!</div>';
form.appendChild(region);
}, false);
this.waitForCalm(function() { name.focus(); })
.waitForCalm(function() { address.focus(); })
.waitForCalm(this.assertSpokenList,
new cvox.SpokenListBuilder()
.categoryFlush('Name')
.queue('Edit text')
.categoryFlush('Address')
.queue('Edit text')
.categoryFlush('Not a valid name!')
.queue('Alert'))
.waitForCalm(testDone);
});
......@@ -52,8 +52,8 @@
'<(test_api_js)',
'<(js2gtest)',
'<(chromevox_test_deps_js_file)',
'testing/chromevox_unittest_base.js',
'testing/assert_additions.js',
'testing/chromevox_unittest_base.js',
],
'outputs': [
'<(INTERMEDIATE_DIR)/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)-gen.cc',
......@@ -140,6 +140,7 @@
'common/page_selection_test.unitjs',
'common/selection_util_test.unitjs',
'common/spannable_test.unitjs',
'chromevox/injected/live_regions_test.unitjs',
'host/chrome/braille_display_manager_test.unitjs',
'host/chrome/braille_input_handler_test.unitjs',
'host/chrome/braille_integration_test.unitjs',
......
......@@ -119,5 +119,53 @@ ChromeVoxUnitTestBase.prototype = {
return commentEncodedHtml.toString().
replace(/^[^\/]+\/\*!?/, '').
replace(/\*\/[^\/]+$/, '');
},
/**
* Waits for the queued events in ChromeVoxEventWatcher to be
* handled, then calls a callback function with provided arguments
* in the test case scope. Very useful for asserting the results of events.
*
* @param {function()} func A function to call when ChromeVox is ready.
* @param {*} var_args Additional arguments to pass through to the function.
* @return {ChromeVoxUnitTestBase} this.
*/
waitForCalm: function(func, var_args) {
var me = this;
var calmArguments = Array.prototype.slice.call(arguments);
calmArguments.shift();
cvox.ChromeVoxEventWatcher.addReadyCallback(function() {
func.apply(me, calmArguments);
});
return this; // for chaining.
},
/**
* Asserts a list of utterances are in the correct queue mode.
* @param {cvox.SpokenListBuilder|Array} expectedList A list
* of [text, queueMode] tuples OR a SpokenListBuilder with the expected
* utterances.
* @return {ChromeVoxUnitTestBase} this.
*/
assertSpokenList: function(expectedList) {
if (expectedList instanceof cvox.SpokenListBuilder) {
expectedList = expectedList.build();
}
var ulist = cvox.ChromeVoxTester.testTts().getUtteranceInfoList();
for (var i = 0; i < expectedList.length; i++) {
var text = expectedList[i][0];
var queueMode = expectedList[i][1];
this.assertSingleUtterance_(text, queueMode,
ulist[i].text, ulist[i].queueMode);
}
cvox.ChromeVoxTester.clearUtterances();
return this; // for chaining.
},
assertSingleUtterance_: function(
expectedText, expectedQueueMode, text, queueMode) {
assertEquals(expectedQueueMode, queueMode);
assertEquals(expectedText, text);
}
};
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview The spoken list builder. Used in test cases.
*/
goog.provide('cvox.SpokenListBuilder');
/**
* Builds a spoken list.
* @constructor
*/
cvox.SpokenListBuilder = function() {
this.list_ = [];
};
/**
* Adds an expected flushed utterance to the builder.
* @param {string} expectedText The expected text.
* @return {cvox.SpokenListBuilder} this.
*/
cvox.SpokenListBuilder.prototype.flush = function(expectedText) {
this.list_.push([expectedText, cvox.AbstractTts.QUEUE_MODE_FLUSH]);
return this; // for chaining
};
/**
* Adds an expected queued utterance to the builder.
* @param {string} expectedText The expected text.
* @return {cvox.SpokenListBuilder} this.
*/
cvox.SpokenListBuilder.prototype.queue = function(expectedText) {
this.list_.push([expectedText, cvox.AbstractTts.QUEUE_MODE_QUEUE]);
return this; // for chaining
};
/**
* Adds an expected category-flush utterance to the builder.
* @param {string} expectedText The expected text.
* @return {cvox.SpokenListBuilder} this.
*/
cvox.SpokenListBuilder.prototype.categoryFlush = function(expectedText) {
this.list_.push([expectedText, cvox.AbstractTts.QUEUE_MODE_CATEGORY_FLUSH]);
return this; // for chaining
};
/**
* Builds the list.
* @return {Array} The array of utterances.
*/
cvox.SpokenListBuilder.prototype.build = function() {
return this.list_;
};
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