| <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> |
| <html> |
| <head> |
| <script src="../../resources/js-test-pre.js"></script> |
| <script src="../../resources/accessibility-helper.js"></script> |
| </head> |
| <body id="body" role="group"> |
| |
| <blockquote>first blockquote level 1</blockquote> |
| <blockquote>second blockquote level 1</blockquote> |
| <p style="color:black; font-family:sans-serif; font-weight:bold; text-decoration:underline;">sans-serif black bold text with underline</p> |
| <p style="color:blue; font-family:serif; font-style:italic;">serif blue italic text</p> |
| <form> |
| <input type="text" /><br /> |
| <input type="checkbox" value="Checkbox" /> checkbox<br /> |
| <input type="submit" value="Submit" /> |
| </form> |
| <img id="image" src="resources/cake.png" alt="Test"> |
| <h1>first heading level 1</h1> |
| <h1>second heading level 1</h1> |
| <h2>heading level 2</h2> |
| <h3>heading level 3</h3> |
| <h4>heading level 4</h4> |
| <h5>heading level 5</h5> |
| <h6>heading level 6</h6> |
| <p id="banner" role="banner">landmark</p> |
| <a href="#image">link</a> |
| <ol><li>list item</li></ol> |
| <p aria-live="polite">live region</p> |
| <ul role="radiogroup"><li role="radio">radio button</li></ul> |
| <table> |
| <thead><tr><td>first table heading level 1</td></tr></thead> |
| <tbody><tr><td>first table body level 1</td></tr></tbody> |
| </table> |
| <table> |
| <thead><tr><td>second table heading level 1</td></tr></thead> |
| <tbody><tr><td>second table body level 1</td></tr></tbody> |
| </table> |
| <ul role="tree"><li role="treeitem">tree item</li></ul> |
| |
| <h1>isVisible test start</h1> |
| <div id="group" style="overflow: scroll; width:100px; height:100px;"> |
| <button id="button">test button 1</button><BR> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| test test test test <br> |
| <button id="button">test button 2</button> |
| </div> |
| <button id="button">test button 3</button> |
| |
| |
| <p id="description"></p> |
| <div id="console"></div> |
| |
| <script> |
| description("This tests the ability to search for accessible elements by key or text."); |
| |
| if (window.accessibilityController) { |
| window.jsTestIsAsync = true; |
| |
| window.containerElement = accessibilityController.accessibleElementById("body"); |
| // Any element. |
| window.startElement = containerElement.childAtIndex(0); |
| window.resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXAnyTypeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXStaticText'"); |
| shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'"); |
| |
| // Same level blockquote. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBlockquoteSameLevelSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second blockquote level 1'"); |
| |
| // Blockquote. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBlockquoteSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second blockquote level 1'"); |
| |
| // Bold font. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXBoldFontSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: sans-serif black bold text with underline'"); |
| |
| // Button. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| |
| // Check box. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXCheckBoxSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXCheckBox'"); |
| |
| // Control. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXCheckBoxSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXCheckBox'"); |
| |
| // Different type element. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXDifferentTypeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXStaticText'"); |
| shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'"); |
| |
| // Font change. |
| startElement = containerElement.childAtIndex(2); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXFontChangeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: serif blue italic text'"); |
| |
| // Font color change. |
| startElement = containerElement.childAtIndex(2); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXFontColorChangeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: serif blue italic text'"); |
| |
| // Graphic. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXGraphicSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXImage'"); |
| |
| // Heading level 1. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel1SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: first heading level 1'"); |
| |
| // Heading level 2. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel2SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'"); |
| |
| // Heading level 3. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel3SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 3'"); |
| |
| // Heading level 4. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel4SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 4'"); |
| |
| // Heading level 5. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel5SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 5'"); |
| |
| // Heading level 6. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingLevel6SearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 6'"); |
| |
| // Same level heading. |
| startElement = containerElement.childAtIndex(6); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingSameLevelSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second heading level 1'"); |
| |
| // Heading. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXHeadingSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: first heading level 1'"); |
| |
| // Italic font. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXItalicFontSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: serif blue italic text'"); |
| |
| // Landmark. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXLandmarkSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.subrole", "'AXSubrole: AXLandmarkBanner'"); |
| |
| // Link. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXLinkSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXLink'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'"); |
| |
| // List. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXListSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXList'"); |
| |
| // Live Region. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXLiveRegionSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.stringAttributeValue('AXARIALive')", "'polite'"); |
| |
| // Misspelled word. |
| // FIXME: Handle this search key. |
| |
| // Outline. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXOutlineSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXOutline'"); |
| shouldBe("resultElement.childAtIndex(0).childAtIndex(0).stringValue", "'AXValue: tree item'"); |
| |
| // Plain text. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXPlainTextSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXStaticText'"); |
| shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'"); |
| |
| // Radio group. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXRadioGroupSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXRadioGroup'"); |
| |
| // Same type element. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXSameTypeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: second blockquote level 1'"); |
| |
| // Static text. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXStaticTextSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXStaticText'"); |
| shouldBe("resultElement.stringValue", "'AXValue: first blockquote level 1'"); |
| |
| // Style change. |
| startElement = containerElement.childAtIndex(2); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXStyleChangeSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: serif blue italic text'"); |
| |
| // Same level table. |
| startElement = containerElement.childAtIndex(18); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXTableSameLevelSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXTable'"); |
| shouldBe("resultElement.childAtIndex(0).childAtIndex(0).childAtIndex(0).stringValue", "'AXValue: second table heading level 1'"); |
| |
| // Table. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXTableSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXTable'"); |
| shouldBe("resultElement.childAtIndex(0).childAtIndex(0).childAtIndex(0).stringValue", "'AXValue: first table heading level 1'"); |
| |
| // Text field. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXTextFieldSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXTextField'"); |
| |
| // Underline. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXUnderlineSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXGroup'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: sans-serif black bold text with underline'"); |
| |
| // Unvisited link. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXUnvisitedLinkSearchKey", "", false); |
| shouldBe("resultElement.boolAttributeValue('AXVisited')", "false"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'"); |
| |
| // Previous text search. |
| startElement = containerElement.childAtIndex(10); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, false, "", "sans-serif black bold text with underline", false); |
| shouldBe("resultElement.role", "'AXRole: AXStaticText'"); |
| shouldBe("resultElement.stringValue", "'AXValue: sans-serif black bold text with underline'"); |
| |
| // Execute a search for the next heading level 2 or the next link. |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'"); |
| |
| // After finding the heading, execute the search again and we should find the link. |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false); |
| shouldBe("resultElement.role", "'AXRole: AXLink'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: link'"); |
| |
| // From the link, execute the search in reverse and we should land back on the heading. |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, false, ["AXHeadingLevel2SearchKey", "AXLinkSearchKey"], "", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: heading level 2'"); |
| |
| // Now, we need to test isVisible. Save off the first object |
| startElement = containerElement.childAtIndex(0); |
| |
| // Scroll all the way to the bottom of the content |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "test button 3", false); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 3'"); |
| setTimeout(async function() { |
| resultElement.scrollToMakeVisible(); |
| await waitFor(() => { |
| return resultElement.isOnScreen; |
| }); |
| |
| // find the start of the isVisible test section |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "", "isVisible test start", false); |
| shouldBe("resultElement.role", "'AXRole: AXHeading'"); |
| shouldBe("resultElement.childAtIndex(0).stringValue", "'AXValue: isVisible test start'"); |
| |
| // save away the "isVisible test start" heading as the start element |
| startElement = resultElement; |
| |
| // If we don't care about visible only, then we should easily find 3 buttons |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 1'"); |
| |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 2'"); |
| |
| // save away testButton2 so we can make it visible later |
| window.testButton2 = resultElement; |
| |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", false); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 3'"); |
| |
| // if we care about visible only, then we should not find "test button 2" |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 1'"); |
| |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 3'"); |
| |
| // now, scroll to the second button, and confirm that we don't see the first button |
| testButton2.scrollToMakeVisible(); |
| await waitFor(() => { |
| return testButton2.isOnScreen; |
| }); |
| |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 2'"); |
| |
| resultElement = containerElement.uiElementForSearchPredicate(resultElement, true, "AXButtonSearchKey", "", true); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 3'"); |
| |
| // Now since the page is scrolled to the bottom, the first visible button should be #2 |
| startElement = containerElement.childAtIndex(0); |
| resultElement = containerElement.uiElementForSearchPredicate(startElement, true, "AXButtonSearchKey", "", true); |
| shouldBe("resultElement.role", "'AXRole: AXButton'"); |
| shouldBe("resultElement.title", "'AXTitle: test button 2'"); |
| |
| finishJSTest(); |
| }, 0); |
| } |
| </script> |
| <script src="../../resources/js-test-post.js"></script> |
| </body> |
| </html> |