Chromium Code Reviews| Index: content/browser/accessibility/dump_accessibility_browsertest_base.cc |
| diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc |
| index b5dd3296ef3106a32025b15a1a7cf93b335578a6..29bc7cc9d196948bb8dd64795b2e1edf0e5ff5e1 100644 |
| --- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc |
| +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc |
| @@ -26,10 +26,15 @@ |
| #include "content/public/common/content_paths.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/common/url_constants.h" |
| +#include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| +#include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/test/accessibility_browser_test_utils.h" |
| +#include "content/test/content_browser_test_utils_internal.h" |
| +#include "net/dns/mock_host_resolver.h" |
| +#include "net/test/embedded_test_server/embedded_test_server.h" |
| namespace content { |
| @@ -40,6 +45,46 @@ const char kMarkSkipFile[] = "#<skip"; |
| const char kMarkEndOfFile[] = "<-- End-of-file -->"; |
| const char kSignalDiff[] = "*"; |
| +// Helper function to be used with FrameTree::ForEach, so that |
| +// AccessibilityNotificationWaiter can listen for accessibility |
| +// events in all frames. |
| +bool ListenToFrame(AccessibilityNotificationWaiter* waiter, |
| + FrameTreeNode* frame_tree_node) { |
| + waiter->ListenToAdditionalFrame(frame_tree_node->current_frame_host()); |
| + return true; |
| +} |
| + |
| +// Helper function to be used with FrameTree::ForEach, to get the |
| +// url of all frames. |
| +bool GetFrameUrl(std::vector<std::string>* all_frame_urls, |
| + FrameTreeNode* frame_tree_node) { |
| + all_frame_urls->push_back(frame_tree_node->current_url().spec()); |
| + return true; |
| +} |
| + |
| +// Searches recursively and returns true if an accessibility node is found |
| +// that represents a fully loaded web document with the given url. |
| +bool AccessibilityTreeContainsLoadedDocWithUrl(BrowserAccessibility* node, |
| + const std::string& url) { |
| + if ((node->GetRole() == ui::AX_ROLE_WEB_AREA || |
| + node->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA) && |
| + node->GetStringAttribute(ui::AX_ATTR_URL) == url) { |
| + // If possible, ensure the doc has finished loading. That's currently |
| + // not possible with same-process iframes until http://crbug.com/532249 |
|
nasko
2016/01/08 22:57:45
nit: httpS ;)
dmazzoni
2016/01/11 19:04:41
Done.
|
| + // is fixed. |
| + return (node->manager()->GetTreeData().url != url || |
| + node->manager()->GetTreeData().loaded); |
| + } |
| + |
| + for (unsigned i = 0; i < node->PlatformChildCount(); i++) { |
| + if (AccessibilityTreeContainsLoadedDocWithUrl( |
| + node->PlatformGetChild(i), url)) { |
| + return true; |
| + } |
| + } |
| + return false; |
| +} |
| + |
| } // namespace |
| typedef AccessibilityTreeFormatter::Filter Filter; |
| @@ -50,6 +95,17 @@ DumpAccessibilityTestBase::DumpAccessibilityTestBase() { |
| DumpAccessibilityTestBase::~DumpAccessibilityTestBase() { |
| } |
| +void DumpAccessibilityTestBase::SetUpCommandLine( |
| + base::CommandLine* command_line) { |
| + IsolateAllSitesForTesting(command_line); |
| +} |
| + |
| +void DumpAccessibilityTestBase::SetUpOnMainThread() { |
| + host_resolver()->AddRule("*", "127.0.0.1"); |
| + ASSERT_TRUE(embedded_test_server()->Start()); |
| + SetupCrossSiteRedirector(embedded_test_server()); |
| +} |
| + |
| base::string16 |
| DumpAccessibilityTestBase::DumpUnfilteredAccessibilityTreeAsString() { |
| scoped_ptr<AccessibilityTreeFormatter> formatter( |
| @@ -95,7 +151,7 @@ std::vector<int> DumpAccessibilityTestBase::DiffLines( |
| void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( |
| const std::string& test_html, |
| std::vector<Filter>* filters, |
| - std::string* wait_for) { |
| + std::vector<std::string>* wait_for) { |
| for (const std::string& line : |
| base::SplitString(test_html, "\n", base::TRIM_WHITESPACE, |
| base::SPLIT_WANT_ALL)) { |
| @@ -120,7 +176,7 @@ void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives( |
| Filter::DENY)); |
| } else if (base::StartsWith(line, wait_str, |
| base::CompareCase::SENSITIVE)) { |
| - *wait_for = line.substr(wait_str.size()); |
| + wait_for->push_back(line.substr(wait_str.size())); |
| } |
| } |
| } |
| @@ -147,6 +203,10 @@ void DumpAccessibilityTestBase::RunTest( |
| void DumpAccessibilityTestBase::RunTestForPlatform( |
| const base::FilePath file_path, const char* file_dir) { |
| + WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( |
| + shell()->web_contents()); |
| + web_contents->AddAccessibilityMode(AccessibilityModeComplete); |
| + |
| formatter_.reset(CreateAccessibilityTreeFormatter()); |
| // Disable the "hot tracked" state (set when the mouse is hovering over |
| @@ -193,42 +253,73 @@ void DumpAccessibilityTestBase::RunTestForPlatform( |
| } |
| // Parse filters and other directives in the test file. |
| - std::string wait_for; |
| + std::vector<std::string> wait_for; |
| AddDefaultFilters(&filters_); |
| ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for); |
| // Load the page. |
| - base::string16 html_contents16; |
| - html_contents16 = base::UTF8ToUTF16(html_contents); |
| - GURL url = GetTestUrl(file_dir, file_path.BaseName().MaybeAsASCII().c_str()); |
| - |
| - // If there's a @WAIT-FOR directive, set up an accessibility notification |
| - // waiter that returns on any event; we'll stop when we get the text we're |
| - // waiting for, or time out. Otherwise just wait specifically for |
| - // the "load complete" event. |
| - scoped_ptr<AccessibilityNotificationWaiter> waiter; |
| - if (!wait_for.empty()) { |
| - waiter.reset(new AccessibilityNotificationWaiter( |
| - shell(), AccessibilityModeComplete, ui::AX_EVENT_NONE)); |
| - } else { |
| - waiter.reset(new AccessibilityNotificationWaiter( |
| - shell(), AccessibilityModeComplete, ui::AX_EVENT_LOAD_COMPLETE)); |
| - } |
| + GURL url(embedded_test_server()->GetURL( |
| + "/" + std::string(file_dir) + "/" + file_path.BaseName().MaybeAsASCII())); |
| // Load the test html. |
| NavigateToURL(shell(), url); |
| - // Wait for notifications. If there's a @WAIT-FOR directive, break when |
| - // the text we're waiting for appears in the dump, otherwise break after |
| - // the first notification, which will be a load complete. |
| - do { |
| - waiter->WaitForNotification(); |
| - if (!wait_for.empty()) { |
| - base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString(); |
| - if (base::UTF16ToUTF8(tree_dump).find(wait_for) != std::string::npos) |
| - wait_for.clear(); |
| + // Get the url of every frame in the frame tree. |
| + FrameTree* frame_tree = web_contents->GetFrameTree(); |
| + std::vector<std::string> all_frame_urls; |
| + frame_tree->ForEach(base::Bind(GetFrameUrl, &all_frame_urls)); |
| + |
| + // Wait for the accessibility tree to fully load for all frames, |
| + // by searching for the WEB_AREA node in the accessibility tree |
| + // with the url of each frame in our frame tree. Note that this |
| + // doesn't support cases where there are two iframes with the |
| + // exact same url. If all frames haven't loaded yet, set up a |
| + // listener for accessibility events on any frame and block |
| + // until the next one is received. |
| + // |
| + // If the original page has a @WAIT-FOR directive, don't break until |
| + // the text we're waiting for appears in the full text dump of the |
| + // accessibility tree, either. |
| + for (;;) { |
| + VLOG(1) << "Top of loop"; |
| + RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>( |
| + web_contents->GetMainFrame()); |
| + BrowserAccessibility* accessibility_root = |
| + main_frame->browser_accessibility_manager()->GetRoot(); |
| + |
| + // Check to see if all frames have loaded. |
| + bool all_frames_loaded = true; |
| + for (const auto& url : all_frame_urls) { |
| + if (!AccessibilityTreeContainsLoadedDocWithUrl(accessibility_root, url)) { |
| + VLOG(1) << "Still waiting on this frame to load: " << url; |
| + all_frames_loaded = false; |
| + break; |
| + } |
| + } |
| + |
| + // Check to see if the @WAIT-FOR text has appeared yet. |
| + bool all_wait_for_strings_found = true; |
| + base::string16 tree_dump = DumpUnfilteredAccessibilityTreeAsString(); |
| + for (const auto& str : wait_for) { |
| + if (base::UTF16ToUTF8(tree_dump).find(str) == std::string::npos) { |
| + VLOG(1) << "Still waiting on this text to be found: " << str; |
| + all_wait_for_strings_found = false; |
| + break; |
| + } |
| } |
| - } while (!wait_for.empty()); |
| + |
| + // If all frames have loaded and the @WAIT-FOR text has appeared, |
| + // we're done. |
| + if (all_frames_loaded && all_wait_for_strings_found) |
| + break; |
| + |
| + // Block until the next accessibility notification in any frame. |
| + VLOG(1) << "Waiting until the next accessibility event"; |
| + AccessibilityNotificationWaiter accessibility_waiter(main_frame, |
| + ui::AX_EVENT_NONE); |
| + frame_tree->ForEach(base::Bind(ListenToFrame, &accessibility_waiter)); |
| + accessibility_waiter.WaitForNotification(); |
| + } |
| // Call the subclass to dump the output. |
| std::vector<std::string> actual_lines = Dump(); |