blob: 461306c2dda7822f0b63d892c755d1ed671171ae [file] [log] [blame]
// Copyright 2014 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_next_e2e_test_base.js',
'../../testing/assert_additions.js']);
GEN_INCLUDE(['../../testing/mock_feedback.js']);
/**
* Test fixture for Background.
* @constructor
* @extends {ChromeVoxNextE2ETest}
*/
function BackgroundTest() {
ChromeVoxNextE2ETest.call(this);
}
BackgroundTest.prototype = {
__proto__: ChromeVoxNextE2ETest.prototype,
/** @override */
setUp: function() {
global.backgroundObj.forceChromeVoxNextActive();
window.RoleType = chrome.automation.RoleType;
window.doCmd = this.doCmd;
},
/**
* @return {!MockFeedback}
*/
createMockFeedback: function() {
var mockFeedback = new MockFeedback(this.newCallback(),
this.newCallback.bind(this));
mockFeedback.install();
return mockFeedback;
},
/**
* Create a function which perform the command |cmd|.
* @param {string} cmd
* @return {function() : void}
*/
doCmd: function(cmd) {
return function() {
global.backgroundObj.onGotCommand(cmd);
};
},
linksAndHeadingsDoc: function() {/*!
<p>start</p>
<a href='#a'>alpha</a>
<a href='#b'>beta</a>
<p>
<h1>charlie</h1>
<a href='foo'>delta</a>
</p>
<a href='#bar'>echo</a>
<h2>foxtraut</h2>
<p>end<span>of test</span></p>
*/},
formsDoc: function() {/*!
<select id="fruitSelect">
<option>apple</option>
<option>grape</option>
<option> banana</option>
</select>
*/},
iframesDoc: function() {/*!
<p>start</p>
<button>Before</button>
<iframe srcdoc="<button>Inside</button><h1>Inside</h1>"></iframe>
<button>After</button>
*/},
disappearingObjectDoc: function() {/*!
<p>start</p>
<article>
<p>Before1</p>
<p>Before2</p>
<p>Before3</p>
</article>
<article>
<p id="disappearing">Disappearing</p>
</article>
<article>
<p>After1</p>
<p>After2</p>
<p>After3</p>
</article>
</div>
<div id="live" aria-live="polite"></div>
<div id="delete" role="button">Delete</div>
<script>
document.getElementById('delete').addEventListener('click', function() {
var d = document.getElementById('disappearing');
d.parentElement.removeChild(d);
document.getElementById('live').innerText = 'Deleted';
});
</script>
*/},
};
/** Tests that ChromeVox classic is in this context. */
SYNC_TEST_F('BackgroundTest', 'ClassicNamespaces', function() {
assertEquals('object', typeof(cvox));
assertEquals('function', typeof(cvox.ChromeVoxBackground));
});
/** Tests that ChromeVox next is in this context. */
SYNC_TEST_F('BackgroundTest', 'NextNamespaces', function() {
assertEquals('function', typeof(Background));
});
/** Tests consistency of navigating forward and backward. */
TEST_F('BackgroundTest', 'ForwardBackwardNavigation', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
mockFeedback.expectSpeech('start').expectBraille('start');
mockFeedback.call(doCmd('nextLink'))
.expectSpeech('alpha', 'Link')
.expectBraille('alpha lnk');
mockFeedback.call(doCmd('nextLink'))
.expectSpeech('beta', 'Link')
.expectBraille('beta lnk');
mockFeedback.call(doCmd('nextLink'))
.expectSpeech('delta', 'Link')
.expectBraille('delta lnk');
mockFeedback.call(doCmd('previousLink'))
.expectSpeech('beta', 'Link')
.expectBraille('beta lnk');
mockFeedback.call(doCmd('nextHeading'))
.expectSpeech('charlie', 'Heading 1')
.expectBraille('charlie h1');
mockFeedback.call(doCmd('nextHeading'))
.expectSpeech('foxtraut', 'Heading 2')
.expectBraille('foxtraut h2');
mockFeedback.call(doCmd('previousHeading'))
.expectSpeech('charlie', 'Heading 1')
.expectBraille('charlie h1');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('delta', 'Link')
.expectBraille('delta lnk');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('echo', 'Link')
.expectBraille('echo lnk');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('foxtraut', 'Heading 2')
.expectBraille('foxtraut h2');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('end')
.expectBraille('end');
mockFeedback.call(doCmd('previousObject'))
.expectSpeech('foxtraut', 'Heading 2')
.expectBraille('foxtraut h2');
mockFeedback.call(doCmd('nextLine'))
.expectSpeech('end', 'of test')
.expectBraille('end of test');
mockFeedback.call(doCmd('jumpToTop'))
.expectSpeech('start')
.expectBraille('start');
mockFeedback.call(doCmd('jumpToBottom'))
.expectSpeech('of test')
.expectBraille('of test');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'CaretNavigation', function() {
// TODO(plundblad): Add braille expectaions when crbug.com/523285 is fixed.
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
mockFeedback.expectSpeech('start');
mockFeedback.call(doCmd('nextCharacter'))
.expectSpeech('t');
mockFeedback.call(doCmd('nextCharacter'))
.expectSpeech('a');
mockFeedback.call(doCmd('nextWord'))
.expectSpeech('alpha', 'Link');
mockFeedback.call(doCmd('nextWord'))
.expectSpeech('beta', 'Link');
mockFeedback.call(doCmd('nextWord'))
.expectSpeech('charlie', 'Heading 1');
mockFeedback.call(doCmd('nextLine'))
.expectSpeech('delta', 'Link');
mockFeedback.call(doCmd('nextLine'))
.expectSpeech('echo', 'Link');
mockFeedback.call(doCmd('nextLine'))
.expectSpeech('foxtraut', 'Heading 2');
mockFeedback.call(doCmd('nextLine'))
.expectSpeech('end', 'of test');
mockFeedback.call(doCmd('nextCharacter'))
.expectSpeech('n');
mockFeedback.call(doCmd('previousCharacter'))
.expectSpeech('e');
mockFeedback.call(doCmd('previousCharacter'))
.expectSpeech('t', 'Heading 2');
mockFeedback.call(doCmd('previousWord'))
.expectSpeech('foxtraut');
mockFeedback.call(doCmd('previousWord'))
.expectSpeech('echo', 'Link');
mockFeedback.call(doCmd('previousCharacter'))
.expectSpeech('a', 'Link');
mockFeedback.call(doCmd('previousCharacter'))
.expectSpeech('t');
mockFeedback.call(doCmd('nextWord'))
.expectSpeech('echo', 'Link');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'SelectSingleBasic', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.formsDoc, function() {
var sendDownToSelect =
this.sendKeyToElement.bind(this, undefined, 'ArrowDown', '#fruitSelect');
mockFeedback.expectSpeech('apple', 'has pop up', 'Collapsed')
.expectBraille('apple btn +popup +')
.call(sendDownToSelect)
.expectSpeech('grape', /2 of 3/)
.expectBraille('grape mnuitm 2/3')
.call(sendDownToSelect)
.expectSpeech('banana', /3 of 3/)
.expectBraille('banana mnuitm 3/3');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'ContinuousRead', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
mockFeedback.expectSpeech('start')
.call(doCmd('readFromHere'))
.expectSpeech(
'start',
'alpha', 'Link',
'beta', 'Link',
'charlie', 'Heading 1');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'InitialFocus', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree('<a href="a">a</a>',
function(rootNode) {
mockFeedback.expectSpeech('data:text/html,<!doctype html>' +
'<a href="a">a</a>')
.expectSpeech('a')
.expectSpeech('Link');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'AriaLabel', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree('<a aria-label="foo" href="a">a</a>',
function(rootNode) {
rootNode.find({role: RoleType.link}).focus();
mockFeedback.expectSpeech('foo')
.expectSpeech('Link')
.expectBraille('foo lnk');
mockFeedback.replay();
}
);
});
TEST_F('BackgroundTest', 'ShowContextMenu', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree('<a href="a">a</a>',
function(rootNode) {
mockFeedback.expectSpeech(/menu opened/)
.call(function() {
// When shown, the context menu pushes a new message loop so test
// messages sent to the browser do not get processed. Ensure we
// exit the context menu here.
go.showContextMenu();
});
mockFeedback.replay();
var go = rootNode.find({ role: RoleType.link });
this.listenOnce(go, 'focus', function(e) {
doCmd('contextMenu')();
}.bind(this), true);
go.focus();
}.bind(this));
});
TEST_F('BackgroundTest', 'BrailleRouting', function() {
var mockFeedback = this.createMockFeedback();
var route = function(position) {
assertTrue(global.backgroundObj.onBrailleKeyEvent(
{command: cvox.BrailleKeyCommand.ROUTING,
displayPosition: position},
mockFeedback.lastMatchedBraille));
};
this.runWithLoadedTree(
function() {/*!
<p>start</p>
<button id="btn1">Click me</button>
<p>Some text</p>
<button id="btn2">Focus me</button>
<p>Some more text</p>
<input type="text" id ="text" value="Edit me">
<script>
document.getElementById('btn1').addEventListener('click', function() {
document.getElementById('btn2').focus();
}, false);
</script>
*/},
function(rootNode) {
var button1 = rootNode.find({role: RoleType.button,
attributes: { name: 'Click me' }});
var textField = rootNode.find(
{role: RoleType.textField});
mockFeedback.expectBraille('start')
.call(button1.focus.bind(button1))
.expectBraille(/^Click me btn/)
.call(route.bind(null, 5))
.expectBraille(/Focus me btn/)
.call(textField.focus.bind(textField))
.expectBraille('Edit me ed', {startIndex: 0})
.call(route.bind(null, 3))
.expectBraille('Edit me ed', {startIndex: 3})
.call(function() {
assertEquals(3, textField.textSelStart);
});
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'FocusInputElement', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(
function() {/*!
<input id="name" value="Lancelot">
<input id="quest" value="Grail">
<input id="color" value="Blue">
*/},
function(rootNode) {
var name = rootNode.find({ attributes: { value: 'Lancelot' } });
var quest = rootNode.find({ attributes: { value: 'Grail' } });
var color = rootNode.find({ attributes: { value: 'Blue' } });
mockFeedback.call(quest.focus.bind(quest))
.expectSpeech('Grail', 'Edit text')
.call(color.focus.bind(color))
.expectSpeech('Blue', 'Edit text')
.call(name.focus.bind(name))
.expectNextSpeechUtteranceIsNot('Blue')
.expectSpeech('Lancelot', 'Edit text');
mockFeedback.replay();
}.bind(this));
});
TEST_F('BackgroundTest', 'UseEditableState', function() {
this.runWithLoadedTree(
function() {/*!
<input type="text"></input>
<p tabindex=0>hi</p>
*/},
function(rootNode) {
var assertExists = this.newCallback(function (evt) {
assertNotNullNorUndefined(
global.desktopAutomationHandler.textEditHandler_);
evt.stopPropagation();
});
var assertDoesntExist = this.newCallback(function (evt) {
assertTrue(!global.desktopAutomationHandler.editableTextHandler_);
evt.stopPropagation();
});
var editable = rootNode.find({ role: RoleType.textField });
var nonEditable = rootNode.find({ role: RoleType.paragraph });
this.listenOnce(editable, 'focus', assertExists);
this.listenOnce(nonEditable, 'focus', assertDoesntExist);
editable.focus();
nonEditable.focus();
}.bind(this));
});
TEST_F('BackgroundTest', 'EarconsForControls', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(
function() {/*!
<p>Initial focus will be on something that's not a control.</p>
<a href="#">MyLink</a>
<button>MyButton</button>
<input type=checkbox>
<input type=checkbox checked>
<input>
<select multiple><option>1</option></select>
<select><option>2</option></select>
<input type=range value=5>
*/},
function(rootNode) {
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('MyLink')
.expectEarcon(cvox.Earcon.LINK)
.call(doCmd('nextObject'))
.expectSpeech('MyButton')
.expectEarcon(cvox.Earcon.BUTTON)
.call(doCmd('nextObject'))
.expectSpeech('Check box')
.expectEarcon(cvox.Earcon.CHECK_OFF)
.call(doCmd('nextObject'))
.expectSpeech('Check box')
.expectEarcon(cvox.Earcon.CHECK_ON)
.call(doCmd('nextObject'))
.expectSpeech('Edit text')
.expectEarcon(cvox.Earcon.EDITABLE_TEXT)
.call(doCmd('nextObject'))
.expectSpeech('List box')
.expectEarcon(cvox.Earcon.LISTBOX)
.call(doCmd('nextObject'))
.expectSpeech('Button', 'has pop up')
.expectEarcon(cvox.Earcon.POP_UP_BUTTON)
.call(doCmd('nextObject'))
.expectSpeech(/slider/)
.expectEarcon(cvox.Earcon.SLIDER);
mockFeedback.replay();
}.bind(this));
});
TEST_F('BackgroundTest', 'ToggleChromeVoxVersion', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.linksAndHeadingsDoc, function() {
var gotCmd = global.backgroundObj.onGotCommand;
// The command came from the background keyboard handler.
var togglerFromBackground = gotCmd.bind(gotCmd, 'toggleChromeVoxVersion');
// The command came from a content script.
var togglerFromContent = gotCmd.bind(gotCmd, 'toggleChromeVoxVersion',
true);
mockFeedback.call(togglerFromBackground)
.expectSpeech('classic')
.call(togglerFromContent)
.expectSpeech('next')
.call(togglerFromBackground)
.expectSpeech('classic');
mockFeedback.replay();
});
});
SYNC_TEST_F('BackgroundTest', 'GlobsToRegExp', function() {
assertEquals('/^()$/', Background.globsToRegExp_([]).toString());
assertEquals(
'/^(http:\\/\\/host\\/path\\+here)$/',
Background.globsToRegExp_(['http://host/path+here']).toString());
assertEquals(
'/^(url1.*|u.l2|.*url3)$/',
Background.globsToRegExp_(['url1*', 'u?l2', '*url3']).toString());
});
TEST_F('BackgroundTest', 'ActiveOrInactive', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<a href="a">a</a>
<button>b</button>
<input type="text"></input>
*/},
function(rootNode) {
var focusButton = function() {
rootNode.find({role: RoleType.button}).focus();
};
var on = function() { cvox.ChromeVox.isActive = true; };
var off = function() { cvox.ChromeVox.isActive = false; };
function focusThen(toFocus, then) {
toFocus.addEventListener('focus', function innerFocus(e) {
if (e.target != toFocus)
return;
rootNode.removeEventListener('focus', innerFocus, true);
then && then();
}, true);
toFocus.focus();
}
mockFeedback.call(focusButton)
.expectSpeech('b').expectSpeech('Button')
.call(off)
.call(focusThen.bind(this, rootNode.find(
{ role: RoleType.link }), on))
.call(focusThen.bind(this, rootNode.find(
{ role: RoleType.textField })))
.expectNextSpeechUtteranceIsNot('a')
.expectSpeech('Edit text');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'ModeSwitching', function() {
this.runWithLoadedTree('<button></button>', function(root) {
var fakeDesktop = {};
fakeDesktop.role = 'desktop';
fakeDesktop.root = fakeDesktop;
var fakeWebRoot = {};
fakeWebRoot.root = fakeWebRoot;
fakeWebRoot.parent = fakeDesktop;
fakeWebRoot.role = 'rootWebArea';
var fakeSubRoot = {};
fakeSubRoot.root = fakeSubRoot;
fakeSubRoot.parent = fakeWebRoot;
fakeSubRoot.role = 'rootWebArea';
// Tests default to force next mode.
assertEquals('force_next', global.backgroundObj.mode);
// Force next mode stays set regardless of where the range lands.
fakeWebRoot.docUrl = 'http://google.com';
global.backgroundObj.refreshMode(fakeWebRoot);
assertEquals('force_next', global.backgroundObj.mode);
// Empty urls occur before document load or when root is desktop.
fakeWebRoot.docUrl = '';
global.backgroundObj.refreshMode(fakeWebRoot);
assertEquals('force_next', global.backgroundObj.mode);
// Verify compat -> classic switching.
global.backgroundObj.setMode('compat');
fakeWebRoot.docUrl = 'http://google.com';
global.backgroundObj.refreshMode(fakeWebRoot);
assertEquals('classic', global.backgroundObj.mode);
// Ensure we switch to compat if our current range has focused
// state set and is not in web content.
assertTrue(root.parent.state.focused);
global.backgroundObj.setCurrentRange(cursors.Range.fromNode(root.parent));
global.backgroundObj.refreshMode(root.parent);
assertEquals('compat', global.backgroundObj.mode);
// And back to classic.
global.backgroundObj.setCurrentRange(cursors.Range.fromNode(root));
global.backgroundObj.refreshMode(fakeWebRoot);
assertEquals('classic', global.backgroundObj.mode);
// Now, try refreshing mode (which we call after tab switching) with a range
// that's not actually focused.
assertEquals(undefined, root.parent.parent.state.focused);
global.backgroundObj.setCurrentRange(cursors.Range.fromNode(root.parent.parent));
global.backgroundObj.refreshMode(root.parent.parent);
assertEquals('classic', global.backgroundObj.mode);
// Now, verify mode refreshes uses the top level root.
fakeWebRoot.docUrl = 'http://google.com/#chromevox_next_test';
fakeSubRoot.docUrl = 'http://chromevox.com';
global.backgroundObj.refreshMode(fakeSubRoot);
assertEquals('next', global.backgroundObj.mode);
}.bind(this));
});
TEST_F('BackgroundTest', 'FocusIframe', function() {
this.runWithLoadedTree( function() {/*!
<iframe tabindex=0 src="data:text/html,<p>Inside</p>"></iframe>
<button>outside</button>
*/}, function(root) {
var iframe = root.find({role: RoleType.iframe});
var button = root.find({role: RoleType.button});
assertEquals('iframe', iframe.role);
assertEquals('button', button.role);
var didFocus = false;
iframe.focus = function() {
didFocus = true;
};
var b = global.backgroundObj;
b.currentRange_ = cursors.Range.fromNode(button);
b.onGotCommand('previousElement');
assertFalse(didFocus);
}.bind(this));
});
TEST_F('BackgroundTest', 'NoisySlider', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree( function() {/*!
<button id="go">go</button>
<div id="slider" tabindex=0 role="slider"></div>
<script>
function update() {
var s = document.getElementById('slider');
s.setAttribute('aria-valuetext', 'noisy');
setTimeout(update, 500);
}
update();
</script>
*/}, function(root) {
var go = root.find({role: RoleType.button});
var slider = root.find({role: RoleType.slider});
var focusButton = go.focus.bind(go);
var focusSlider = slider.focus.bind(slider);
mockFeedback.call(focusButton)
.expectNextSpeechUtteranceIsNot('noisy')
.call(focusSlider)
.expectSpeech('noisy')
.expectSpeech('noisy')
.replay();
}.bind(this));
});
TEST_F('BackgroundTest', 'Checkbox', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<div id="go" role="checkbox">go</div>
<script>
var go = document.getElementById('go');
var isChecked = true;
go.addEventListener('click', function(e) {
if (isChecked)
go.setAttribute('aria-checked', true);
else
go.removeAttribute('aria-checked');
isChecked = !isChecked;
});
</script>
*/}, function(root) {
var cbx = root.find({role: RoleType.checkBox});
var click = cbx.doDefault.bind(cbx);
mockFeedback.call(click)
.expectSpeech('go')
.expectSpeech('Check box')
.expectSpeech('checked')
.call(click)
.expectSpeech('go')
.expectSpeech('Check box')
.expectSpeech('not checked')
.replay();
});
});
/** Tests navigating into and out of iframes using nextButton */
TEST_F('BackgroundTest', 'ForwardNavigationThroughIframeButtons', function() {
var mockFeedback = this.createMockFeedback();
var running = false;
var runTestIfIframeIsLoaded = function(rootNode) {
if (running)
return;
// Return if the iframe hasn't loaded yet.
var iframe = rootNode.find({role: RoleType.iframe});
var childDoc = iframe.firstChild;
if (!childDoc || childDoc.children.length == 0)
return;
running = true;
var beforeButton = rootNode.find({role: RoleType.button,
name: 'Before'});
beforeButton.focus();
mockFeedback.expectSpeech('Before', 'Button');
mockFeedback.call(doCmd('nextButton'))
.expectSpeech('Inside', 'Button');
mockFeedback.call(doCmd('nextButton'))
.expectSpeech('After', 'Button');
mockFeedback.call(doCmd('previousButton'))
.expectSpeech('Inside', 'Button');
mockFeedback.call(doCmd('previousButton'))
.expectSpeech('Before', 'Button');
mockFeedback.replay();
}.bind(this);
this.runWithLoadedTree(this.iframesDoc, function(rootNode) {
chrome.automation.getDesktop(function(desktopNode) {
runTestIfIframeIsLoaded(rootNode);
desktopNode.addEventListener('loadComplete', function(evt) {
runTestIfIframeIsLoaded(rootNode);
}, true);
});
});
});
/** Tests navigating into and out of iframes using nextObject */
TEST_F('BackgroundTest', 'ForwardObjectNavigationThroughIframes', function() {
var mockFeedback = this.createMockFeedback();
var running = false;
var runTestIfIframeIsLoaded = function(rootNode) {
if (running)
return;
// Return if the iframe hasn't loaded yet.
var iframe = rootNode.find({role: 'iframe'});
var childDoc = iframe.firstChild;
if (!childDoc || childDoc.children.length == 0)
return;
running = true;
var beforeButton = rootNode.find({role: RoleType.button,
name: 'Before'});
beforeButton.focus();
mockFeedback.expectSpeech('Before', 'Button');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('Inside', 'Button');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('Inside', 'Heading 1');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('After', 'Button');
mockFeedback.call(doCmd('previousObject'))
.expectSpeech('Inside', 'Heading 1');
mockFeedback.call(doCmd('previousObject'))
.expectSpeech('Inside', 'Button');
mockFeedback.call(doCmd('previousObject'))
.expectSpeech('Before', 'Button');
mockFeedback.replay();
}.bind(this);
this.runWithLoadedTree(this.iframesDoc, function(rootNode) {
chrome.automation.getDesktop(function(desktopNode) {
runTestIfIframeIsLoaded(rootNode);
desktopNode.addEventListener('loadComplete', function(evt) {
runTestIfIframeIsLoaded(rootNode);
}, true);
});
});
});
TEST_F('BackgroundTest', 'SelectOptionSelected', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<select>
<option>apple
<option>banana
<option>grapefruit
</select>
*/}, function(root) {
var select = root.find({role: RoleType.popUpButton});
var clickSelect = select.doDefault.bind(select);
var lastOption = select.lastChild.lastChild;
var selectLastOption = lastOption.doDefault.bind(lastOption);
mockFeedback.call(clickSelect)
.expectSpeech('apple')
.expectSpeech('Button')
.call(selectLastOption)
.expectNextSpeechUtteranceIsNot('apple')
.expectSpeech('grapefruit')
.replay();
});
});
TEST_F('BackgroundTest', 'ToggleButton', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<div aria-pressed="true" role="button">ok</div>
<div aria-pressed="false" role="button">cancel</div>
<div aria-pressed role="button">close</div>
*/}, function(root) {
var b = global.backgroundObj;
var move = b.onGotCommand.bind(b, 'nextObject');
mockFeedback.call(move)
.expectSpeech('ok')
.expectSpeech('Button')
.expectSpeech('Pressed')
.call(move)
.expectSpeech('cancel')
.expectSpeech('Button')
.expectSpeech('Not pressed')
.call(move)
.expectSpeech('close')
.expectSpeech('Button')
.replay();
});
});
TEST_F('BackgroundTest', 'EditText', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<input type="text"></input>
<input role="combobox" type="text"></input>
*/}, function(root) {
var nextEditText = doCmd('nextEditText');
var previousEditText = doCmd('previousEditText');
mockFeedback.call(nextEditText)
.expectSpeech('Combo box')
.call(previousEditText)
.expectSpeech('Edit text')
.replay();
});
});
TEST_F('BackgroundTest', 'BackwardForwardSync', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function() {/*!
<div role="group" tabindex=0><input type="text"></input></div>
<ul>
<li tabindex=0>
<button>ok</button>
</li>
</ul>
*/}, function(root) {
var listItem = root.find({role: RoleType.listItem});
mockFeedback.call(listItem.focus.bind(listItem))
.expectSpeech('List item')
.call(this.doCmd('nextObject'))
.expectSpeech('•')
.call(this.doCmd('previousObject'))
.expectSpeech('List item')
.call(this.doCmd('nextObject'))
.expectSpeech('•')
.call(this.doCmd('previousObject'))
.expectSpeech('List item')
.call(this.doCmd('previousObject'))
.expectSpeech('Edit text')
.call(this.doCmd('previousObject'))
.expectSpeech('Group')
.replay();
});
});
/** Tests that navigation works when the current object disappears. */
TEST_F('BackgroundTest', 'DisappearingObject', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(this.disappearingObjectDoc, function(rootNode) {
var deleteButton = rootNode.find({role: RoleType.button,
attributes: { name: 'Delete' }});
var pressDelete = deleteButton.doDefault.bind(deleteButton);
mockFeedback.expectSpeech('start').expectBraille('start');
mockFeedback.call(doCmd('nextObject'))
.expectSpeech('Before1')
.call(doCmd('nextObject'))
.expectSpeech('Before2')
.call(doCmd('nextObject'))
.expectSpeech('Before3')
.call(doCmd('nextObject'))
.expectSpeech('Disappearing')
.call(pressDelete)
.expectSpeech('Deleted')
.call(doCmd('nextObject'))
.expectSpeech('After1')
.call(doCmd('nextObject'))
.expectSpeech('After2')
.call(doCmd('previousObject'))
.expectSpeech('After1')
.call(doCmd('previousObject'))
.expectSpeech('Before3');
mockFeedback.replay();
});
});
TEST_F('BackgroundTest', 'ButtonNameValueDescription', function() {
var mockFeedback = this.createMockFeedback();
this.runWithLoadedTree(function(root) {/*!
<input type="submit" aria-label="foo" value="foo"></input>
*/}, function(root) {
var btn = root.find({role: RoleType.button});
mockFeedback.call(btn.focus.bind(btn))
.expectSpeech('foo')
.expectSpeech('Button')
.replay();
});
});