1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/accessibility/accessibility_content_browsertest.h"
6 
7 #include <string>
8 
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/accessibility/browser_accessibility.h"
11 #include "content/browser/accessibility/browser_accessibility_manager.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/public/test/accessibility_notification_waiter.h"
14 #include "content/public/test/content_browser_test_utils.h"
15 #include "content/shell/browser/shell.h"
16 #include "net/base/escape.h"
17 #include "net/test/embedded_test_server/embedded_test_server.h"
18 
19 namespace content {
20 
LoadInitialAccessibilityTreeFromUrl(const GURL & url,ui::AXMode accessibility_mode)21 void AccessibilityContentBrowserTest::LoadInitialAccessibilityTreeFromUrl(
22     const GURL& url,
23     ui::AXMode accessibility_mode) {
24   AccessibilityNotificationWaiter waiter(GetWebContentsAndAssertNonNull(),
25                                          accessibility_mode,
26                                          ax::mojom::Event::kLoadComplete);
27   EXPECT_TRUE(NavigateToURL(shell(), url));
28   waiter.WaitForNotification();
29 }
30 
31 void AccessibilityContentBrowserTest::
LoadInitialAccessibilityTreeFromHtmlFilePath(const std::string & html_file_path,ui::AXMode accessibility_mode)32     LoadInitialAccessibilityTreeFromHtmlFilePath(
33         const std::string& html_file_path,
34         ui::AXMode accessibility_mode) {
35   if (!embedded_test_server()->Started())
36     ASSERT_TRUE(embedded_test_server()->Start());
37   ASSERT_TRUE(embedded_test_server()->Started());
38   LoadInitialAccessibilityTreeFromUrl(
39       embedded_test_server()->GetURL(html_file_path), accessibility_mode);
40 }
41 
LoadInitialAccessibilityTreeFromHtml(const std::string & html,ui::AXMode accessibility_mode)42 void AccessibilityContentBrowserTest::LoadInitialAccessibilityTreeFromHtml(
43     const std::string& html,
44     ui::AXMode accessibility_mode) {
45   LoadInitialAccessibilityTreeFromUrl(
46       GURL("data:text/html," + net::EscapeQueryParamValue(html, false)),
47       accessibility_mode);
48 }
49 
GetWebContentsAndAssertNonNull() const50 WebContents* AccessibilityContentBrowserTest::GetWebContentsAndAssertNonNull()
51     const {
52   // Perform the null pointer validation inside a void function to allow for a
53   // return type.
54   auto GetWebContentsAndAssertNonNull = [this](WebContents** result) {
55     WebContents* web_contents = shell()->web_contents();
56     ASSERT_NE(nullptr, web_contents);
57     *result = web_contents;
58   };
59 
60   WebContents* web_contents;
61   GetWebContentsAndAssertNonNull(&web_contents);
62   return web_contents;
63 }
64 
65 WebContentsImpl*
GetWebContentsImplAndAssertNonNull() const66 AccessibilityContentBrowserTest::GetWebContentsImplAndAssertNonNull() const {
67   return static_cast<WebContentsImpl*>(GetWebContentsAndAssertNonNull());
68 }
69 
70 BrowserAccessibilityManager*
GetManagerAndAssertNonNull() const71 AccessibilityContentBrowserTest::GetManagerAndAssertNonNull() const {
72   // Perform the null pointer validation inside a void function to allow for a
73   // return type.
74   auto GetManagerAndAssertNonNull =
75       [this](BrowserAccessibilityManager** result) {
76         BrowserAccessibilityManager* browser_accessibility_manager =
77             GetWebContentsImplAndAssertNonNull()
78                 ->GetRootBrowserAccessibilityManager();
79         ASSERT_NE(nullptr, browser_accessibility_manager);
80         *result = browser_accessibility_manager;
81       };
82 
83   BrowserAccessibilityManager* browser_accessibility_manager;
84   GetManagerAndAssertNonNull(&browser_accessibility_manager);
85   return browser_accessibility_manager;
86 }
87 
GetRootAndAssertNonNull() const88 BrowserAccessibility* AccessibilityContentBrowserTest::GetRootAndAssertNonNull()
89     const {
90   // Perform the null pointer validation inside a void function to allow for a
91   // return type.
92   auto GetRootAndAssertNonNull = [this](BrowserAccessibility** result) {
93     BrowserAccessibility* root_browser_accessibility =
94         GetManagerAndAssertNonNull()->GetRoot();
95     ASSERT_NE(nullptr, result);
96     *result = root_browser_accessibility;
97   };
98 
99   BrowserAccessibility* root_browser_accessibility;
100   GetRootAndAssertNonNull(&root_browser_accessibility);
101   return root_browser_accessibility;
102 }
103 
FindNode(const ax::mojom::Role role,const std::string & name_or_value) const104 BrowserAccessibility* AccessibilityContentBrowserTest::FindNode(
105     const ax::mojom::Role role,
106     const std::string& name_or_value) const {
107   return FindNodeInSubtree(GetRootAndAssertNonNull(), role, name_or_value);
108 }
109 
FindNodeInSubtree(BrowserAccessibility * node,const ax::mojom::Role role,const std::string & name_or_value) const110 BrowserAccessibility* AccessibilityContentBrowserTest::FindNodeInSubtree(
111     BrowserAccessibility* node,
112     const ax::mojom::Role role,
113     const std::string& name_or_value) const {
114   const std::string& name =
115       node->GetStringAttribute(ax::mojom::StringAttribute::kName);
116   // Note that in the case of a text field,
117   // "BrowserAccessibility::GetValueForControl" has the added functionality of
118   // computing the value of an ARIA text box from its inner text.
119   //
120   // <div contenteditable="true" role="textbox">Hello world.</div>
121   // Will expose no HTML value attribute, but some screen readers, such as Jaws,
122   // VoiceOver and Talkback, require one to be computed.
123   const std::string value = base::UTF16ToUTF8(node->GetValueForControl());
124   if (node->GetRole() == role &&
125       (name == name_or_value || value == name_or_value)) {
126     return node;
127   }
128 
129   for (uint32_t i = 0; i < node->PlatformChildCount(); ++i) {
130     BrowserAccessibility* result =
131         FindNodeInSubtree(node->PlatformGetChild(i), role, name_or_value);
132     if (result)
133       return result;
134   }
135 
136   return nullptr;
137 }
138 
139 }  // namespace content
140