| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| GEN_INCLUDE(['../select_to_speak/mv3/select_to_speak_e2e_test_base.js']); |
| |
| /** |
| * Test fixture for paragraph_utils.js. |
| */ |
| SelectToSpeakParagraphUnitTest = class extends SelectToSpeakE2ETest {}; |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'GetFirstBlockAncestor', function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph = {role: 'paragraph', parent: root, root}; |
| const text1 = |
| {role: 'staticText', parent: paragraph, display: 'block', root}; |
| const text2 = {role: 'staticText', parent: root, root}; |
| const text3 = {role: 'inlineTextBox', parent: text1, root}; |
| const div = |
| {role: 'genericContainer', parent: paragraph, display: 'block', root}; |
| const text4 = {role: 'staticText', parent: div, root}; |
| assertEquals(paragraph, ParagraphUtils.getFirstBlockAncestor(text1)); |
| assertEquals(root, ParagraphUtils.getFirstBlockAncestor(text2)); |
| assertEquals(paragraph, ParagraphUtils.getFirstBlockAncestor(text3)); |
| assertEquals(div, ParagraphUtils.getFirstBlockAncestor(text4)); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'SVGRootIsBlockAncestor', function() { |
| const root = {role: 'rootWebArea'}; |
| const svgRoot = {role: 'svgRoot', parent: root, root}; |
| const text1 = {role: 'staticText', parent: svgRoot, root}; |
| const inline1 = {role: 'inlineTextBox', parent: text1, root}; |
| const text2 = {role: 'staticText', parent: svgRoot, root}; |
| const inline2 = {role: 'inlineTextBox', parent: text2, root}; |
| assertEquals(svgRoot, ParagraphUtils.getFirstBlockAncestor(text1)); |
| assertEquals(svgRoot, ParagraphUtils.getFirstBlockAncestor(inline1)); |
| assertEquals(svgRoot, ParagraphUtils.getFirstBlockAncestor(inline2)); |
| assertTrue(ParagraphUtils.inSameParagraph(inline1, inline2)); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'ParagraphInSVGIsBlock', function() { |
| // This represents how Google Docs renders Canvas accessibility as of |
| // October 24 2022. |
| const root = {role: 'rootWebArea'}; |
| const svgRoot = {role: 'svgRoot', parent: root, root}; |
| const group1 = {role: 'paragraph', parent: svgRoot, root}; |
| const text1 = {role: 'graphicsSymbol', parent: group1, root}; |
| const text2 = {role: 'graphicsSymbol', parent: group1, root}; |
| const group2 = {role: 'paragraph', parent: svgRoot, root}; |
| const text3 = {role: 'graphicsSymbol', parent: group2, root}; |
| assertEquals(group1, ParagraphUtils.getFirstBlockAncestor(text1)); |
| assertEquals(group1, ParagraphUtils.getFirstBlockAncestor(text2)); |
| assertEquals(group2, ParagraphUtils.getFirstBlockAncestor(text3)); |
| assertTrue(ParagraphUtils.inSameParagraph(text1, text2)); |
| assertFalse(ParagraphUtils.inSameParagraph(text1, text3)); |
| }); |
| |
| AX_TEST_F('SelectToSpeakParagraphUnitTest', 'InSameParagraph', function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph1 = |
| {role: 'paragraph', display: 'block', parent: 'rootWebArea', root}; |
| const text1 = {role: 'staticText', parent: paragraph1, root}; |
| const text2 = {role: 'staticText', parent: paragraph1, root}; |
| const paragraph2 = |
| {role: 'paragraph', display: 'block', parent: 'rootWebArea', root}; |
| const text3 = {role: 'staticText', parent: paragraph2, root}; |
| assertTrue(ParagraphUtils.inSameParagraph(text1, text2)); |
| assertFalse(ParagraphUtils.inSameParagraph(text1, text3)); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BlockDivBreaksSameParagraph', |
| function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph1 = |
| {role: 'paragraph', display: 'block', parent: 'rootWebArea', root}; |
| const text1 = {role: 'staticText', parent: paragraph1, root}; |
| const text2 = {role: 'image', parent: paragraph1, display: 'block', root}; |
| const text3 = |
| {role: 'image', parent: paragraph1, display: 'inline', root}; |
| const text4 = {role: 'staticText', parent: paragraph1, root}; |
| assertFalse(ParagraphUtils.inSameParagraph(text1, text2)); |
| assertFalse(ParagraphUtils.inSameParagraph(text2, text3)); |
| assertTrue(ParagraphUtils.inSameParagraph(text3, text4)); |
| }); |
| |
| AX_TEST_F('SelectToSpeakParagraphUnitTest', 'IsWhitespace', function() { |
| assertTrue(ParagraphUtils.isWhitespace('')); |
| assertTrue(ParagraphUtils.isWhitespace(' ')); |
| assertTrue(ParagraphUtils.isWhitespace(' \n \t ')); |
| assertTrue(ParagraphUtils.isWhitespace()); |
| assertFalse(ParagraphUtils.isWhitespace('cats')); |
| assertFalse(ParagraphUtils.isWhitespace(' cats ')); |
| }); |
| |
| AX_TEST_F('SelectToSpeakParagraphUnitTest', 'GetNodeName', function() { |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'staticText', name: 'cat'}), 'cat'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'inlineTextBox', name: 'cat'}), 'cat'); |
| assertEquals(ParagraphUtils.getNodeName({name: 'cat'}), 'cat'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'radioButton', name: 'cat'}), |
| 'cat unselected'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'checkBox', name: 'cat'}), |
| 'cat unchecked'); |
| assertEquals( |
| ParagraphUtils.getNodeName( |
| {role: 'checkBox', checked: 'true', name: 'cat'}), |
| 'cat checked'); |
| assertEquals(ParagraphUtils.getNodeName({role: 'radioButton'}), 'unselected'); |
| assertEquals(ParagraphUtils.getNodeName({role: 'checkBox'}), 'unchecked'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'radioButton', checked: 'true'}), |
| 'selected'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'checkBox', checked: 'true'}), |
| 'checked'); |
| assertEquals( |
| ParagraphUtils.getNodeName( |
| {role: 'radioButton', checked: 'true', name: 'cat'}), |
| 'cat selected'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'checkBox', checked: 'mixed'}), |
| 'partially checked'); |
| assertEquals( |
| ParagraphUtils.getNodeName({role: 'radioButton', checked: 'mixed'}), |
| 'partially selected'); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'GetStartCharIndexInParent', function() { |
| const staticText = { |
| role: 'staticText', |
| name: 'My name is Bond, James Bond', |
| }; |
| const inline1 = { |
| role: 'inlineTextBox', |
| name: 'My name is ', |
| indexInParent: 0, |
| parent: staticText, |
| }; |
| const inline2 = { |
| role: 'inlineTextBox', |
| name: 'Bond, ', |
| indexInParent: 1, |
| parent: staticText, |
| }; |
| const inline3 = { |
| role: 'inlineTextBox', |
| name: 'James Bond', |
| indexInParent: 2, |
| parent: staticText, |
| }; |
| staticText.children = [inline1, inline2, inline3]; |
| assertEquals(ParagraphUtils.getStartCharIndexInParent(inline1), 0); |
| assertEquals(ParagraphUtils.getStartCharIndexInParent(inline2), 11); |
| assertEquals(ParagraphUtils.getStartCharIndexInParent(inline3), 17); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'FindInlineTextNodeByCharIndex', |
| function() { |
| const staticText = { |
| role: 'staticText', |
| name: 'My name is Bond, James Bond', |
| }; |
| const inline1 = {role: 'inlineTextBox', name: 'My name is '}; |
| const inline2 = {role: 'inlineTextBox', name: 'Bond, '}; |
| const inline3 = {role: 'inlineTextBox', name: 'James Bond'}; |
| staticText.children = [inline1, inline2, inline3]; |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 0), |
| inline1); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 10), |
| inline1); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 11), |
| inline2); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 16), |
| inline2); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 17), |
| inline3); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 50), |
| inline3); |
| staticText.children = []; |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeByCharacterIndex(staticText, 10), |
| null); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'FindInlineTextNodeIndexByCharIndex', |
| function() { |
| const staticText = { |
| role: 'staticText', |
| name: 'My name is Bond, James Bond', |
| }; |
| const inline1 = {role: 'inlineTextBox', name: 'My name is '}; |
| const inline2 = {role: 'inlineTextBox', name: 'Bond, '}; |
| const inline3 = {role: 'inlineTextBox', name: 'James Bond'}; |
| staticText.children = [inline1, inline2, inline3]; |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex(staticText, 0), |
| 0); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 10), |
| 0); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 11), |
| 1); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 16), |
| 1); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 17), |
| 2); |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 50), |
| 2); |
| staticText.children = []; |
| assertEquals( |
| ParagraphUtils.findInlineTextNodeIndexByCharacterIndex( |
| staticText, 10), |
| -1); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtNewParagraph', |
| function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph1 = |
| {role: 'paragraph', display: 'block', parent: root, root}; |
| const text1 = |
| {role: 'staticText', parent: paragraph1, name: 'text1', root}; |
| const text2 = |
| {role: 'staticText', parent: paragraph1, name: 'text2', root}; |
| const paragraph2 = |
| {role: 'paragraph', display: 'block', parent: root, root}; |
| const text3 = |
| {role: 'staticText', parent: paragraph2, name: 'text3', root}; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 0, {splitOnLanguage: false}); |
| assertEquals('text1 text2 ', result.text); |
| assertEquals(1, result.endIndex); |
| assertEquals(2, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(text2, result.nodes[1].node); |
| assertEquals(paragraph1, result.blockParent); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupAcrossParagraphs', |
| function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph1 = |
| {role: 'paragraph', display: 'block', parent: root, root}; |
| const text1 = |
| {role: 'staticText', parent: paragraph1, name: 'text1', root}; |
| const text2 = |
| {role: 'staticText', parent: paragraph1, name: 'text2', root}; |
| const paragraph2 = |
| {role: 'paragraph', display: 'block', parent: root, root}; |
| const text3 = |
| {role: 'staticText', parent: paragraph2, name: 'text3', root}; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 0, {splitOnParagraph: false}); |
| assertEquals('text1 text2 text3 ', result.text); |
| assertEquals(2, result.endIndex); |
| assertEquals(3, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(text2, result.nodes[1].node); |
| assertEquals(12, result.nodes[2].startChar); |
| assertEquals(text3, result.nodes[2].node); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupStopsAtLanguageBoundary', |
| function() { |
| const splitOnLanguage = true; |
| |
| // When the detectedLanguage changes from en-US to fr-FR we expect to |
| // break the NodeGroup. |
| const root = {role: 'rootWebArea'}; |
| const text1 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text1', |
| root, |
| detectedLanguage: 'en-US', |
| }; |
| const text2 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text2', |
| root, |
| detectedLanguage: 'en-US', |
| }; |
| const text3 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text3', |
| root, |
| detectedLanguage: 'fr-FR', |
| }; |
| |
| const result1 = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 0, {splitOnLanguage}); |
| assertEquals('text1 text2 ', result1.text); |
| assertEquals(1, result1.endIndex); |
| assertEquals(2, result1.nodes.length); |
| assertEquals(0, result1.nodes[0].startChar); |
| assertEquals(text1, result1.nodes[0].node); |
| assertEquals(6, result1.nodes[1].startChar); |
| assertEquals(text2, result1.nodes[1].node); |
| assertEquals('en-US', result1.detectedLanguage); |
| |
| const result2 = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 2, {splitOnLanguage}); |
| assertEquals('text3 ', result2.text); |
| assertEquals(2, result2.endIndex); |
| assertEquals(1, result2.nodes.length); |
| assertEquals(0, result2.nodes[0].startChar); |
| assertEquals(text3, result2.nodes[0].node); |
| assertEquals('fr-FR', result2.detectedLanguage); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', |
| 'BuildNodeGroupStopsAtLanguageBoundaryAllUndefined', function() { |
| const splitOnLanguage = true; |
| |
| // If no detectedLanguage is defined then we should not split at all.... |
| const root = {role: 'rootWebArea'}; |
| const text1 = {role: 'staticText', parent: root, name: 'text1', root}; |
| const text2 = {role: 'staticText', parent: root, name: 'text2', root}; |
| const text3 = {role: 'staticText', parent: root, name: 'text3', root}; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 0, {splitOnLanguage}); |
| assertEquals('text1 text2 text3 ', result.text); |
| assertEquals(2, result.endIndex); |
| assertEquals(3, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(text2, result.nodes[1].node); |
| assertEquals(12, result.nodes[2].startChar); |
| assertEquals(text3, result.nodes[2].node); |
| assertEquals(undefined, result.detectedLanguage); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', |
| 'BuildNodeGroupStopsAtLanguageBoundaryLastNode', function() { |
| const splitOnLanguage = true; |
| |
| // our NodeGroup should get the first defined detectedLanguage |
| const root = {role: 'rootWebArea'}; |
| const text1 = {role: 'staticText', parent: root, name: 'text1', root}; |
| const text2 = {role: 'staticText', parent: root, name: 'text2', root}; |
| const text3 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text3', |
| root, |
| detectedLanguage: 'fr-FR', |
| }; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3], 0, {splitOnLanguage}); |
| assertEquals('text1 text2 text3 ', result.text); |
| assertEquals(2, result.endIndex); |
| assertEquals(3, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(text2, result.nodes[1].node); |
| assertEquals(12, result.nodes[2].startChar); |
| assertEquals(text3, result.nodes[2].node); |
| assertEquals('fr-FR', result.detectedLanguage); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupSplitOnLanguageDisabled', |
| function() { |
| // Test behaviour with splitOnLanguage disabled. This is to show that we |
| // haven't introduced an obvious regression. |
| const splitOnLanguage = false; |
| |
| const root = {role: 'rootWebArea'}; |
| const text1 = {role: 'staticText', parent: root, name: 'text1', root}; |
| const text2 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text2', |
| root, |
| detectedLanguage: 'en-US', |
| }; |
| const text3 = {role: 'staticText', parent: root, name: 'text3', root}; |
| const text4 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text4', |
| root, |
| detectedLanguage: 'fr-FR', |
| }; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3, text4], 0, {splitOnLanguage}); |
| assertEquals('text1 text2 text3 text4 ', result.text); |
| assertEquals(3, result.endIndex); |
| assertEquals(4, result.nodes.length); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(text4, result.nodes[3].node); |
| assertEquals(undefined, result.detectedLanguage); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', |
| 'BuildNodeGroupStopsAtLanguageBoundarySomeUndefined', function() { |
| const splitOnLanguage = true; |
| |
| // We never want to break up a NodeGroup based on an undefined |
| // detectedLanguage, instead we allow an undefined detectedLanguage to |
| // match any other language. The language for the NodeGroup will be |
| // determined by the first defined detectedLanguage. |
| const root = {role: 'rootWebArea'}; |
| const text1 = {role: 'staticText', parent: root, name: 'text1', root}; |
| const text2 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text2', |
| root, |
| detectedLanguage: 'en-US', |
| }; |
| const text3 = {role: 'staticText', parent: root, name: 'text3', root}; |
| const text4 = { |
| role: 'staticText', |
| parent: root, |
| name: 'text4', |
| root, |
| detectedLanguage: 'fr-FR', |
| }; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, text3, text4], 0, {splitOnLanguage}); |
| assertEquals('text1 text2 text3 ', result.text); |
| assertEquals(2, result.endIndex); |
| assertEquals(3, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(text2, result.nodes[1].node); |
| assertEquals(12, result.nodes[2].startChar); |
| assertEquals(text3, result.nodes[2].node); |
| assertEquals('en-US', result.detectedLanguage); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupIncludesLinks', |
| function() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph1 = |
| {role: 'paragraph', display: 'block', parent: root, root}; |
| const text1 = |
| {role: 'staticText', parent: paragraph1, name: 'text1', root}; |
| // Whitespace-only nodes should be ignored. |
| const text2 = {role: 'staticText', parent: paragraph1, name: '\n', root}; |
| const link = {role: 'link', parent: paragraph1, root}; |
| const linkText = |
| {role: 'staticText', parent: link, name: 'linkText', root}; |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2, linkText], 0, {splitOnLanguage: false}); |
| assertEquals('text1 linkText ', result.text); |
| assertEquals(2, result.endIndex); |
| assertEquals(2, result.nodes.length); |
| assertEquals(0, result.nodes[0].startChar); |
| assertEquals(text1, result.nodes[0].node); |
| assertEquals(6, result.nodes[1].startChar); |
| assertEquals(linkText, result.nodes[1].node); |
| assertEquals(paragraph1, result.blockParent); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupNativeTextBox', |
| function() { |
| const root = {role: 'desktop'}; |
| const parent = {role: 'pane', parent: root, root}; |
| const searchBar = { |
| role: 'textField', |
| name: 'Address and search bar', |
| value: 'http://www.google.com', |
| children: [], |
| }; |
| let result = ParagraphUtils.buildNodeGroup([searchBar], 0); |
| assertEquals('http://www.google.com ', result.text); |
| |
| // If there is no value, it should use the name. |
| searchBar.value = ''; |
| result = ParagraphUtils.buildNodeGroup( |
| [searchBar], 0, {splitOnLanguage: false}); |
| assertEquals('Address and search bar ', result.text); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupWithSvg', function() { |
| const root = {role: 'rootWebArea'}; |
| const svgRoot = {role: 'svgRoot', parent: root, root}; |
| const text1 = {role: 'staticText', parent: svgRoot, root, name: 'Hello,'}; |
| const inline1 = |
| {role: 'inlineTextBox', parent: text1, root, name: 'Hello,'}; |
| const text2 = {role: 'staticText', parent: svgRoot, root, name: 'world!'}; |
| const inline2 = |
| {role: 'inlineTextBox', parent: text2, root, name: 'world!'}; |
| |
| const result = ParagraphUtils.buildNodeGroup( |
| [inline1, inline2], 0, {splitOnLanguage: false}); |
| assertEquals('Hello, world! ', result.text); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildNodeGroupWithAndroidClickable', |
| function() { |
| const root = {role: 'application'}; |
| const listRoot = {role: 'list', parent: root, root}; |
| const clickableContainer = |
| {role: 'genericContainer', parent: listRoot, root, clickable: true}; |
| const text1 = |
| {role: 'staticText', parent: clickableContainer, root, name: 'text1'}; |
| const text2 = |
| {role: 'staticText', parent: clickableContainer, root, name: 'text2'}; |
| |
| const result = ParagraphUtils.buildNodeGroup( |
| [text1, text2], 0, {splitOnLanguage: false}); |
| assertEquals('text1 text2 ', result.text); |
| assertEquals(clickableContainer, result.blockParent); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', |
| 'BuildNodeGroupWithMultipleAndroidClickables', function() { |
| const root = {role: 'application'}; |
| const container = {role: 'genericContainer', parent: root, root}; |
| const button1 = { |
| role: 'button', |
| parent: container, |
| root, |
| clickable: true, |
| name: 'button1', |
| }; |
| const button2 = { |
| role: 'button', |
| parent: container, |
| root, |
| clickable: true, |
| name: 'button2', |
| }; |
| |
| const result = ParagraphUtils.buildNodeGroup( |
| [button1, button2], 0, {splitOnLanguage: false}); |
| assertEquals('button1 ', result.text); |
| assertEquals(button1, result.blockParent); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'findNodeFromNodeGroupByCharIndex', |
| function() { |
| // The array has four inline text nodes and one static text node. |
| const nodeGroup = |
| ParagraphUtils.buildNodeGroup(generateNodesForParagraph(), 0); |
| // Start index = 0 |
| const firstInline = 'The first'; |
| // Start index = 9 |
| const secondInline = ' sentence.'; |
| // Start index = 20 |
| const thirdInline = 'The second'; |
| // Start index = 30 |
| const fourthInline = ' sentence is longer.'; |
| // Start index = 51 |
| const thirdStatic = 'No child sentence.'; |
| |
| let result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 0 /* charIndex */); |
| assertEquals(result.node.name, firstInline); |
| assertEquals(result.offset, 0); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 3 /* charIndex */); |
| assertEquals(result.node.name, firstInline); |
| assertEquals(result.offset, 3); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 10 /* charIndex */); |
| assertEquals(result.node.name, secondInline); |
| assertEquals(result.offset, 1); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 20 /* charIndex */); |
| assertEquals(result.node.name, thirdInline); |
| assertEquals(result.offset, 0); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 33 /* charIndex */); |
| assertEquals(result.node.name, fourthInline); |
| assertEquals(result.offset, 3); |
| |
| // Pointing to the gap between the fourthInline and thirdStatic. |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 50 /* charIndex */); |
| assertEquals(result.node.name, thirdStatic); |
| assertEquals(result.offset, 0); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 51 /* charIndex */); |
| assertEquals(result.node.name, thirdStatic); |
| assertEquals(result.offset, 0); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 52 /* charIndex */); |
| assertEquals(result.node.name, thirdStatic); |
| assertEquals(result.offset, 1); |
| |
| result = ParagraphUtils.findNodeFromNodeGroupByCharIndex( |
| nodeGroup, 100 /* charIndex */); |
| assertEquals(result.node, null); |
| }); |
| |
| AX_TEST_F( |
| 'SelectToSpeakParagraphUnitTest', 'BuildSingleNodeGroupWithOffset', |
| function() { |
| // The array has four inline text nodes and one static text node. |
| // Their starting indexes are 0, 9, 20, 30, and 51. |
| const nodes = generateNodesForParagraph(); |
| // Start index = 0 |
| const firstInline = 'The first'; |
| // Start index = 9 |
| const secondInline = ' sentence.'; |
| const firstSentence = firstInline + secondInline + ' '; |
| // Start index = 20 |
| const thirdInline = 'The second'; |
| // Start index = 30 |
| const fourthInline = ' sentence is longer.'; |
| const secondSentence = thirdInline + fourthInline + ' '; |
| // Start index = 51 |
| const thirdStatic = 'No child sentence.'; |
| const thirdSentence = thirdStatic + ' '; |
| |
| let nodeGroup; |
| let startIndexInGroup; |
| let endIndexInGroup; |
| ({nodeGroup, startIndexInGroup, endIndexInGroup} = |
| ParagraphUtils.buildSingleNodeGroupWithOffset(nodes)); |
| assertEquals( |
| nodeGroup.text, firstSentence + secondSentence + thirdSentence); |
| assertEquals(startIndexInGroup, undefined); |
| assertEquals(endIndexInGroup, undefined); |
| |
| ({nodeGroup, startIndexInGroup, endIndexInGroup} = |
| ParagraphUtils.buildSingleNodeGroupWithOffset( |
| nodes, 5 /* startIndex */)); |
| assertEquals( |
| nodeGroup.text, firstSentence + secondSentence + thirdSentence); |
| assertEquals(startIndexInGroup, 5); |
| assertEquals(endIndexInGroup, undefined); |
| |
| ({nodeGroup, startIndexInGroup, endIndexInGroup} = |
| ParagraphUtils.buildSingleNodeGroupWithOffset( |
| nodes.slice(1), 0 /* startIndex */)); |
| assertEquals( |
| nodeGroup.text, firstSentence + secondSentence + thirdSentence); |
| assertEquals(startIndexInGroup, 9); |
| assertEquals(endIndexInGroup, undefined); |
| |
| ({nodeGroup, startIndexInGroup, endIndexInGroup} = |
| ParagraphUtils.buildSingleNodeGroupWithOffset( |
| nodes.slice(2, 5), 1 /* startIndex */, 1 /* endIndex */)); |
| assertEquals(nodeGroup.text, secondSentence + thirdSentence); |
| assertEquals(startIndexInGroup, 1); |
| assertEquals(endIndexInGroup, 32); |
| |
| ({nodeGroup, startIndexInGroup, endIndexInGroup} = |
| ParagraphUtils.buildSingleNodeGroupWithOffset( |
| nodes.slice(4, 5), undefined, 5 /* endIndex */)); |
| assertEquals(nodeGroup.text, thirdSentence); |
| assertEquals(startIndexInGroup, undefined); |
| assertEquals(endIndexInGroup, 5); |
| }); |
| |
| /** |
| * Creates an array of nodes that represents a paragraph. |
| * @return {Array<AutomationNode>} |
| */ |
| function generateNodesForParagraph() { |
| const root = {role: 'rootWebArea'}; |
| const paragraph = {role: 'paragraph', display: 'block', parent: root, root}; |
| const text1 = { |
| name: 'The first sentence.', |
| role: 'staticText', |
| parent: paragraph, |
| }; |
| const inlineText1 = { |
| role: 'inlineTextBox', |
| name: 'The first', |
| indexInParent: 0, |
| parent: text1, |
| }; |
| const inlineText2 = { |
| role: 'inlineTextBox', |
| name: ' sentence.', |
| indexInParent: 1, |
| parent: text1, |
| }; |
| text1.children = [inlineText1, inlineText2]; |
| |
| const text2 = { |
| name: 'The second sentence is longer.', |
| role: 'staticText', |
| parent: paragraph, |
| }; |
| const inlineText3 = { |
| role: 'inlineTextBox', |
| name: 'The second', |
| indexInParent: 0, |
| parent: text2, |
| }; |
| const inlineText4 = { |
| role: 'inlineTextBox', |
| name: ' sentence is longer.', |
| indexInParent: 1, |
| parent: text2, |
| }; |
| text2.children = [inlineText3, inlineText4]; |
| |
| const text3 = { |
| name: 'No child sentence.', |
| role: 'staticText', |
| parent: paragraph, |
| }; |
| |
| return [inlineText1, inlineText2, inlineText3, inlineText4, text3]; |
| } |