| // 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 incrementSelectedIndex = |
| this.incrementSelectedIndex.bind(this, undefined, '#fruitSelect'); |
| mockFeedback.expectSpeech('apple', 'has pop up', 'Collapsed') |
| .expectBraille('apple btn +popup +') |
| .call(incrementSelectedIndex) |
| .expectSpeech('grape', /2 of 3/) |
| .expectBraille('grape mnuitm 2/3') |
| .call(incrementSelectedIndex) |
| .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('Button') |
| .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(); |
| }); |
| }); |
| |
| TEST_F('BackgroundTest', 'NameFromHeadingLink', function() { |
| var mockFeedback = this.createMockFeedback(); |
| this.runWithLoadedTree(function(root) {/*! |
| <p>before</p> |
| <h1><a href="google.com">go</a><p>here</p></h1> |
| */}, function(root) { |
| var link = root.find({role: RoleType.link}); |
| mockFeedback.call(link.focus.bind(link)) |
| .expectSpeech('go') |
| .expectSpeech('Link') |
| .expectSpeech('Heading 1') |
| .replay(); |
| }); |
| }); |
| |
| TEST_F('BackgroundTest', 'OptionChildIndexCount', function() { |
| var mockFeedback = this.createMockFeedback(); |
| this.runWithLoadedTree(function(root) {/*! |
| <div role="listbox"> |
| <p>Fruits</p> |
| <div role="option">apple</div> |
| <div role="option">banana</div> |
| </div> |
| */}, function(root) { |
| mockFeedback.call(doCmd('nextObject')) |
| .expectSpeech('Fruits') |
| .expectSpeech('with 2 items') |
| .expectSpeech('apple') |
| .expectSpeech(' 1 of 2 ') |
| .call(doCmd('nextObject')) |
| .expectSpeech('banana') |
| .expectSpeech(' 2 of 2 ') |
| .replay(); |
| }); |
| }); |
| |
| TEST_F('BackgroundTest', 'ListMarkerIsIgnored', function() { |
| var mockFeedback = this.createMockFeedback(); |
| this.runWithLoadedTree(function(root) {/*! |
| <ul><li>apple</ul> |
| */}, function(root) { |
| mockFeedback.call(doCmd('nextObject')) |
| .expectNextSpeechUtteranceIsNot('listMarker') |
| .expectSpeech('apple') |
| .replay(); |
| }); |
| }); |
| |
| TEST_F('BackgroundTest', 'SymetricComplexHeading', function() { |
| var mockFeedback = this.createMockFeedback(); |
| this.runWithLoadedTree(function(root) {/*! |
| <h4><p>NW</p><p>NE</p></h4> |
| <h4><p>SW</p><p>SE</p></h4> |
| */}, function(root) { |
| mockFeedback.call(doCmd('nextHeading')) |
| .expectNextSpeechUtteranceIsNot('NE') |
| .expectSpeech('NW') |
| .call(doCmd('previousHeading')) |
| .expectNextSpeechUtteranceIsNot('NE') |
| .expectSpeech('NW') |
| .replay(); |
| }); |
| }); |