Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(682)

Side by Side Diff: content/browser/accessibility/dump_accessibility_browsertest_base.cc

Issue 1552683002: Enable DumpAccessibilityTree tests to use cross-process iframes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebaseline last Android test Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h" 5 #include "content/browser/accessibility/dump_accessibility_browsertest_base.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/path_service.h" 12 #include "base/path_service.h"
13 #include "base/strings/string16.h" 13 #include "base/strings/string16.h"
14 #include "base/strings/string_split.h" 14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "build/build_config.h" 18 #include "build/build_config.h"
19 #include "content/browser/accessibility/accessibility_tree_formatter.h" 19 #include "content/browser/accessibility/accessibility_tree_formatter.h"
20 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h" 20 #include "content/browser/accessibility/accessibility_tree_formatter_blink.h"
21 #include "content/browser/accessibility/browser_accessibility.h" 21 #include "content/browser/accessibility/browser_accessibility.h"
22 #include "content/browser/accessibility/browser_accessibility_manager.h" 22 #include "content/browser/accessibility/browser_accessibility_manager.h"
23 #include "content/browser/accessibility/browser_accessibility_state_impl.h" 23 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
24 #include "content/browser/web_contents/web_contents_impl.h" 24 #include "content/browser/web_contents/web_contents_impl.h"
25 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents.h"
26 #include "content/public/common/content_paths.h" 26 #include "content/public/common/content_paths.h"
27 #include "content/public/common/content_switches.h" 27 #include "content/public/common/content_switches.h"
28 #include "content/public/common/url_constants.h" 28 #include "content/public/common/url_constants.h"
29 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/content_browser_test.h" 30 #include "content/public/test/content_browser_test.h"
30 #include "content/public/test/content_browser_test_utils.h" 31 #include "content/public/test/content_browser_test_utils.h"
32 #include "content/public/test/test_utils.h"
31 #include "content/shell/browser/shell.h" 33 #include "content/shell/browser/shell.h"
32 #include "content/test/accessibility_browser_test_utils.h" 34 #include "content/test/accessibility_browser_test_utils.h"
35 #include "content/test/content_browser_test_utils_internal.h"
36 #include "net/dns/mock_host_resolver.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
33 38
34 namespace content { 39 namespace content {
35 40
36 namespace { 41 namespace {
37 42
38 const char kCommentToken = '#'; 43 const char kCommentToken = '#';
39 const char kMarkSkipFile[] = "#<skip"; 44 const char kMarkSkipFile[] = "#<skip";
40 const char kMarkEndOfFile[] = "<-- End-of-file -->"; 45 const char kMarkEndOfFile[] = "<-- End-of-file -->";
41 const char kSignalDiff[] = "*"; 46 const char kSignalDiff[] = "*";
42 47
48 // Helper function to be used with FrameTree::ForEach, so that
49 // AccessibilityNotificationWaiter can listen for accessibility
50 // events in all frames.
51 bool ListenToFrame(AccessibilityNotificationWaiter* waiter,
52 FrameTreeNode* frame_tree_node) {
53 waiter->ListenToAdditionalFrame(frame_tree_node->current_frame_host());
54 return true;
55 }
56
57 // Helper function to be used with FrameTree::ForEach, to get the
58 // url of all frames.
59 //
60 // Ignore about:blank urls because of the case where a parent frame A
61 // has a child iframe B and it writes to the document using
62 // contentDocument.open() on the child frame B.
63 //
64 // In this scenario, B's contentWindow.location.href matches A's url,
65 // but B's url in the browser frame tree is still "about:blank".
66 bool GetFrameUrl(std::vector<std::string>* all_frame_urls,
67 FrameTreeNode* frame_tree_node) {
68 std::string url = frame_tree_node->current_url().spec();
69 if (url != url::kAboutBlankURL)
70 all_frame_urls->push_back(url);
71 return true;
72 }
73
74 // Searches recursively and returns true if an accessibility node is found
75 // that represents a fully loaded web document with the given url.
76 bool AccessibilityTreeContainsLoadedDocWithUrl(BrowserAccessibility* node,
77 const std::string& url) {
78 if ((node->GetRole() == ui::AX_ROLE_WEB_AREA ||
79 node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) &&
80 node->GetStringAttribute(ui::AX_ATTR_URL) == url) {
81 // If possible, ensure the doc has finished loading. That's currently
82 // not possible with same-process iframes until https://crbug.com/532249
83 // is fixed.
84 return (node->manager()->GetTreeData().url != url ||
85 node->manager()->GetTreeData().loaded);
86 }
87
88 for (unsigned i = 0; i < node->PlatformChildCount(); i++) {
89 if (AccessibilityTreeContainsLoadedDocWithUrl(
90 node->PlatformGetChild(i), url)) {
91 return true;
92 }
93 }
94 return false;
95 }
96
43 } // namespace 97 } // namespace
44 98
45 typedef AccessibilityTreeFormatter::Filter Filter; 99 typedef AccessibilityTreeFormatter::Filter Filter;
46 100
47 DumpAccessibilityTestBase::DumpAccessibilityTestBase() { 101 DumpAccessibilityTestBase::DumpAccessibilityTestBase() {
48 } 102 }
49 103
50 DumpAccessibilityTestBase::~DumpAccessibilityTestBase() { 104 DumpAccessibilityTestBase::~DumpAccessibilityTestBase() {
51 } 105 }
52 106
107 void DumpAccessibilityTestBase::SetUpCommandLine(
108 base::CommandLine* command_line) {
109 IsolateAllSitesForTesting(command_line);
110 }
111
112 void DumpAccessibilityTestBase::SetUpOnMainThread() {
113 host_resolver()->AddRule("*", "127.0.0.1");
114 ASSERT_TRUE(embedded_test_server()->Start());
115 SetupCrossSiteRedirector(embedded_test_server());
116 }
117
53 base::string16 118 base::string16
54 DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() { 119 DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() {
55 scoped_ptr<AccessibilityTreeFormatter> formatter( 120 scoped_ptr<AccessibilityTreeFormatter> formatter(
56 CreateAccessibilityTreeFormatter()); 121 CreateAccessibilityTreeFormatter());
57 std::vector<Filter> filters; 122 std::vector<Filter> filters;
58 filters.push_back(Filter(base::ASCIIToUTF16("*"), Filter::ALLOW)); 123 filters.push_back(Filter(base::ASCIIToUTF16("*"), Filter::ALLOW));
59 formatter->SetFilters(filters); 124 formatter->SetFilters(filters);
60 formatter->set_show_ids(true); 125 formatter->set_show_ids(true);
61 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( 126 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
62 shell()->web_contents()); 127 shell()->web_contents());
(...skipping 25 matching lines...) Expand all
88 ++j; 153 ++j;
89 } 154 }
90 155
91 // Actual file has been fully checked. 156 // Actual file has been fully checked.
92 return diff_lines; 157 return diff_lines;
93 } 158 }
94 159
95 void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( 160 void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives(
96 const std::string& test_html, 161 const std::string& test_html,
97 std::vector<Filter>* filters, 162 std::vector<Filter>* filters,
98 std::string* wait_for) { 163 std::vector<std::string>* wait_for) {
99 for (const std::string& line : 164 for (const std::string& line :
100 base::SplitString(test_html, "\n", base::TRIM_WHITESPACE, 165 base::SplitString(test_html, "\n", base::TRIM_WHITESPACE,
101 base::SPLIT_WANT_ALL)) { 166 base::SPLIT_WANT_ALL)) {
102 const std::string& allow_empty_str = formatter_->GetAllowEmptyString(); 167 const std::string& allow_empty_str = formatter_->GetAllowEmptyString();
103 const std::string& allow_str = formatter_->GetAllowString(); 168 const std::string& allow_str = formatter_->GetAllowString();
104 const std::string& deny_str = formatter_->GetDenyString(); 169 const std::string& deny_str = formatter_->GetDenyString();
105 const std::string& wait_str = "@WAIT-FOR:"; 170 const std::string& wait_str = "@WAIT-FOR:";
106 if (base::StartsWith(line, allow_empty_str, 171 if (base::StartsWith(line, allow_empty_str,
107 base::CompareCase::SENSITIVE)) { 172 base::CompareCase::SENSITIVE)) {
108 filters->push_back( 173 filters->push_back(
109 Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())), 174 Filter(base::UTF8ToUTF16(line.substr(allow_empty_str.size())),
110 Filter::ALLOW_EMPTY)); 175 Filter::ALLOW_EMPTY));
111 } else if (base::StartsWith(line, allow_str, 176 } else if (base::StartsWith(line, allow_str,
112 base::CompareCase::SENSITIVE)) { 177 base::CompareCase::SENSITIVE)) {
113 filters->push_back(Filter(base::UTF8ToUTF16( 178 filters->push_back(Filter(base::UTF8ToUTF16(
114 line.substr(allow_str.size())), 179 line.substr(allow_str.size())),
115 Filter::ALLOW)); 180 Filter::ALLOW));
116 } else if (base::StartsWith(line, deny_str, 181 } else if (base::StartsWith(line, deny_str,
117 base::CompareCase::SENSITIVE)) { 182 base::CompareCase::SENSITIVE)) {
118 filters->push_back(Filter(base::UTF8ToUTF16( 183 filters->push_back(Filter(base::UTF8ToUTF16(
119 line.substr(deny_str.size())), 184 line.substr(deny_str.size())),
120 Filter::DENY)); 185 Filter::DENY));
121 } else if (base::StartsWith(line, wait_str, 186 } else if (base::StartsWith(line, wait_str,
122 base::CompareCase::SENSITIVE)) { 187 base::CompareCase::SENSITIVE)) {
123 *wait_for = line.substr(wait_str.size()); 188 wait_for->push_back(line.substr(wait_str.size()));
124 } 189 }
125 } 190 }
126 } 191 }
127 192
128 AccessibilityTreeFormatter* 193 AccessibilityTreeFormatter*
129 DumpAccessibilityTestBase::CreateAccessibilityTreeFormatter() { 194 DumpAccessibilityTestBase::CreateAccessibilityTreeFormatter() {
130 if (is_blink_pass_) 195 if (is_blink_pass_)
131 return new AccessibilityTreeFormatterBlink(); 196 return new AccessibilityTreeFormatterBlink();
132 else 197 else
133 return AccessibilityTreeFormatter::Create(); 198 return AccessibilityTreeFormatter::Create();
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 // normalize by deleting all \r from the file (if any) to leave only \n. 251 // normalize by deleting all \r from the file (if any) to leave only \n.
187 std::string expected_contents; 252 std::string expected_contents;
188 base::RemoveChars(expected_contents_raw, "\r", &expected_contents); 253 base::RemoveChars(expected_contents_raw, "\r", &expected_contents);
189 254
190 if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) { 255 if (!expected_contents.compare(0, strlen(kMarkSkipFile), kMarkSkipFile)) {
191 LOG(INFO) << "Skipping this test on this platform."; 256 LOG(INFO) << "Skipping this test on this platform.";
192 return; 257 return;
193 } 258 }
194 259
195 // Parse filters and other directives in the test file. 260 // Parse filters and other directives in the test file.
196 std::string wait_for; 261 std::vector<std::string> wait_for;
197 AddDefaultFilters(&filters_); 262 AddDefaultFilters(&filters_);
198 ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for); 263 ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for);
199 264
200 // Load the page. 265 // Load the test html and wait for the "load complete" AX event.
201 base::string16 html_contents16; 266 GURL url(embedded_test_server()->GetURL(
202 html_contents16 = base::UTF8ToUTF16(html_contents); 267 "/" + std::string(file_dir) + "/" + file_path.BaseName().MaybeAsASCII()));
203 GURL url = GetTestUrl(file_dir, file_path.BaseName().MaybeAsASCII().c_str()); 268 AccessibilityNotificationWaiter accessibility_waiter(
269 shell(),
270 AccessibilityModeComplete,
271 ui::AX_EVENT_LOAD_COMPLETE);
272 NavigateToURL(shell(), url);
273 accessibility_waiter.WaitForNotification();
204 274
205 // If there's a @WAIT-FOR directive, set up an accessibility notification 275 // Get the url of every frame in the frame tree.
206 // waiter that returns on any event; we'll stop when we get the text we're 276 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
207 // waiting for, or time out. Otherwise just wait specifically for 277 shell()->web_contents());
208 // the "load complete" event. 278 FrameTree* frame_tree = web_contents->GetFrameTree();
209 scoped_ptr<AccessibilityNotificationWaiter> waiter; 279 std::vector<std::string> all_frame_urls;
210 if (!wait_for.empty()) { 280 frame_tree->ForEach(base::Bind(GetFrameUrl, &all_frame_urls));
211 waiter.reset(new AccessibilityNotificationWaiter( 281
212 shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE)); 282 // Wait for the accessibility tree to fully load for all frames,
213 } else { 283 // by searching for the WEB_AREA node in the accessibility tree
214 waiter.reset(new AccessibilityNotificationWaiter( 284 // with the url of each frame in our frame tree. Note that this
215 shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE)); 285 // doesn't support cases where there are two iframes with the
286 // exact same url. If all frames haven't loaded yet, set up a
287 // listener for accessibility events on any frame and block
288 // until the next one is received.
289 //
290 // If the original page has a @WAIT-FOR directive, don't break until
291 // the text we're waiting for appears in the full text dump of the
292 // accessibility tree, either.
293 for (;;) {
294 VLOG(1) << "Top of loop";
295 RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
296 web_contents->GetMainFrame());
297 BrowserAccessibilityManager* manager =
298 main_frame->browser_accessibility_manager();
299 if (manager) {
300 BrowserAccessibility* accessibility_root =
301 manager->GetRoot();
302
303 // Check to see if all frames have loaded.
304 bool all_frames_loaded = true;
305 for (const auto& url : all_frame_urls) {
306 if (!AccessibilityTreeContainsLoadedDocWithUrl(
307 accessibility_root, url)) {
308 VLOG(1) << "Still waiting on this frame to load: " << url;
309 all_frames_loaded = false;
310 break;
311 }
312 }
313
314 // Check to see if the @WAIT-FOR text has appeared yet.
315 bool all_wait_for_strings_found = true;
316 base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString();
317 for (const auto& str : wait_for) {
318 if (base::UTF16ToUTF8(tree_dump).find(str) == std::string::npos) {
319 VLOG(1) << "Still waiting on this text to be found: " << str;
320 all_wait_for_strings_found = false;
321 break;
322 }
323 }
324
325 // If all frames have loaded and the @WAIT-FOR text has appeared,
326 // we're done.
327 if (all_frames_loaded && all_wait_for_strings_found)
328 break;
329 }
330
331 // Block until the next accessibility notification in any frame.
332 VLOG(1) << "Waiting until the next accessibility event";
333 AccessibilityNotificationWaiter accessibility_waiter(main_frame,
334 ui::AX_EVENT_NONE);
335 frame_tree->ForEach(base::Bind(ListenToFrame, &accessibility_waiter));
336 accessibility_waiter.WaitForNotification();
216 } 337 }
217 338
218 // Load the test html.
219 NavigateToURL(shell(), url);
220
221 // Wait for notifications. If there's a @WAIT-FOR directive, break when
222 // the text we're waiting for appears in the dump, otherwise break after
223 // the first notification, which will be a load complete.
224 do {
225 waiter->WaitForNotification();
226 if (!wait_for.empty()) {
227 base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString();
228 if (base::UTF16ToUTF8(tree_dump).find(wait_for) != std::string::npos)
229 wait_for.clear();
230 }
231 } while (!wait_for.empty());
232
233 // Call the subclass to dump the output. 339 // Call the subclass to dump the output.
234 std::vector<std::string> actual_lines = Dump(); 340 std::vector<std::string> actual_lines = Dump();
235 341
236 // Perform a diff (or write the initial baseline). 342 // Perform a diff (or write the initial baseline).
237 std::vector<std::string> expected_lines = base::SplitString( 343 std::vector<std::string> expected_lines = base::SplitString(
238 expected_contents, "\n", base::KEEP_WHITESPACE, 344 expected_contents, "\n", base::KEEP_WHITESPACE,
239 base::SPLIT_WANT_NONEMPTY); 345 base::SPLIT_WANT_NONEMPTY);
240 // Marking the end of the file with a line of text ensures that 346 // Marking the end of the file with a line of text ensures that
241 // file length differences are found. 347 // file length differences are found.
242 expected_lines.push_back(kMarkEndOfFile); 348 expected_lines.push_back(kMarkEndOfFile);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 expected_file, actual_contents.c_str(), actual_contents.size())); 384 expected_file, actual_contents.c_str(), actual_contents.size()));
279 LOG(INFO) << "Wrote expectations to: " 385 LOG(INFO) << "Wrote expectations to: "
280 << expected_file.LossyDisplayName(); 386 << expected_file.LossyDisplayName();
281 } 387 }
282 } else { 388 } else {
283 LOG(INFO) << "Test output matches expectations."; 389 LOG(INFO) << "Test output matches expectations.";
284 } 390 }
285 } 391 }
286 392
287 } // namespace content 393 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698