1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright 2014 The Chromium Authors. All rights reserved. 2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Use of this source code is governed by a BSD-style license that can be 3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// found in the LICENSE file. 4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "base/files/file_path.h" 6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "base/path_service.h" 7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "base/strings/string_number_conversions.h" 8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/extensions/api/automation_internal/automation_util.h" 9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/extensions/chrome_extension_function.h" 10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/extensions/extension_apitest.h" 11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/browser/ui/tabs/tab_strip_model.h" 12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/common/chrome_paths.h" 13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/common/chrome_switches.h" 14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/common/extensions/api/automation_internal.h" 15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "chrome/test/base/ui_test_utils.h" 16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/browser/ax_event_notification_details.h" 17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/browser/render_widget_host.h" 18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/browser/render_widget_host_view.h" 19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "content/public/browser/web_contents.h" 20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "extensions/test/extension_test_message_listener.h" 21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "net/dns/mock_host_resolver.h" 22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "net/test/embedded_test_server/embedded_test_server.h" 23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "testing/gtest/include/gtest/gtest.h" 24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/accessibility/ax_node.h" 25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/accessibility/ax_serializable_tree.h" 26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/accessibility/ax_tree.h" 27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/accessibility/ax_tree_serializer.h" 28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "ui/accessibility/tree_generator.h" 29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace extensions { 31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 32c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace { 33c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathstatic const char kDomain[] = "a.com"; 34c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathstatic const char kSitesDir[] = "automation/sites"; 35c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathstatic const char kGotTree[] = "got_tree"; 36c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} // anonymous namespace 37c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 38c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathclass AutomationApiTest : public ExtensionApiTest { 39c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath protected: 40c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath GURL GetURLForPath(const std::string& host, const std::string& path) { 41c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath std::string port = base::IntToString(embedded_test_server()->port()); 42c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath GURL::Replacements replacements; 43c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath replacements.SetHostStr(host); 44c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath replacements.SetPortStr(port); 45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath GURL url = 46c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath embedded_test_server()->GetURL(path).ReplaceComponents(replacements); 47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return url; 48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez void StartEmbeddedTestServer() { 51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::FilePath test_data; 52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data)); 53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath embedded_test_server()->ServeFilesFromDirectory( 54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath test_data.AppendASCII("extensions/api_test") 55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath .AppendASCII(kSitesDir)); 56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(ExtensionApiTest::StartEmbeddedTestServer()); 57c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath host_resolver()->AddRule("*", embedded_test_server()->base_url().host()); 58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void LoadPage() { 61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath StartEmbeddedTestServer(); 62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath const GURL url = GetURLForPath(kDomain, "/index.html"); 63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui_test_utils::NavigateToURL(browser(), url); 64c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath public: 67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}; 71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(AutomationApiTest, TestRendererAccessibilityEnabled) { 73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath LoadPage(); 74c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_EQ(1, browser()->tab_strip_model()->count()); 76c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath content::WebContents* const tab = 77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath browser()->tab_strip_model()->GetWebContentsAt(0); 78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_FALSE(tab->IsFullAccessibilityModeForTesting()); 79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_FALSE(tab->IsTreeOnlyAccessibilityModeForTesting()); 80c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 81c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::FilePath extension_path = 82c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath test_data_dir_.AppendASCII("automation/tests/basic"); 83c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ExtensionTestMessageListener got_tree(kGotTree, false /* no reply */); 847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez LoadExtension(extension_path); 85c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(got_tree.WaitUntilSatisfied()); 86c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_FALSE(tab->IsFullAccessibilityModeForTesting()); 88c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(tab->IsTreeOnlyAccessibilityModeForTesting()); 89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(AutomationApiTest, SanityCheck) { 92c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath StartEmbeddedTestServer(); 93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "sanity_check.html")) 94c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath << message_; 957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, Unit) { 987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/unit", "unit.html")) 99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath << message_; 1007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, GetTreeByTabId) { 1037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 1047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "tab_id.html")) 1057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 1067faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1077faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1087faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, Events) { 1097faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 1107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "events.html")) 1117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 113c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, Actions) { 115c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath StartEmbeddedTestServer(); 116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "actions.html")) 117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath << message_; 118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 120c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(AutomationApiTest, Location) { 121c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath StartEmbeddedTestServer(); 122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "location.html")) 1237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 1247faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 125c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 126c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(AutomationApiTest, TabsAutomationBooleanPermissions) { 1277faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 1287faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest( 129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath "automation/tests/tabs_automation_boolean", "permissions.html")) 130c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath << message_; 131c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 133c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIN_PROC_BROWSER_TEST_F(AutomationApiTest, TabsAutomationBooleanActions) { 1347faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(RunExtensionSubtest( 1367faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez "automation/tests/tabs_automation_boolean", "actions.html")) 137c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath << message_; 138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 139c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 1407faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, TabsAutomationHostsPermissions) { 1417faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ASSERT_TRUE(RunExtensionSubtest( 1437faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez "automation/tests/tabs_automation_hosts", "permissions.html")) 1447faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 1457faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1477faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#if defined(OS_CHROMEOS) 1487faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, Desktop) { 1497faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/desktop", "desktop.html")) 1507faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 1517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1527faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1537faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopNotRequested) { 1547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", 1557faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez "desktop_not_requested.html")) << message_; 1567faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1577faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopActions) { 1597faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/desktop", "actions.html")) 1607faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 161c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 1627faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#else 1637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, DesktopNotSupported) { 1647faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/desktop", 1657faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez "desktop_not_supported.html")) << message_; 1667faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1677faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#endif 1687faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1697faaa9f3f0df9d23790277834d426c3d992ac3baCarlos HernandezIN_PROC_BROWSER_TEST_F(AutomationApiTest, CloseTab) { 1707faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez StartEmbeddedTestServer(); 1717faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ASSERT_TRUE(RunExtensionSubtest("automation/tests/tabs", "close_tab.html")) 1727faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez << message_; 1737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 1747faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1757faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstatic const int kPid = 1; 1767faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstatic const int kTab0Rid = 1; 1777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstatic const int kTab1Rid = 2; 1787faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1797faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezusing content::BrowserContext; 1807faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1817faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztypedef ui::AXTreeSerializer<const ui::AXNode*> TreeSerializer; 1827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandeztypedef ui::AXTreeSource<const ui::AXNode*> TreeSource; 1837faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1847faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#define AX_EVENT_ASSERT_EQUAL ui::AX_EVENT_LOAD_COMPLETE 1857faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#define AX_EVENT_ASSERT_NOT_EQUAL ui::AX_EVENT_ACTIVEDESCENDANTCHANGED 1867faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#define AX_EVENT_IGNORE ui::AX_EVENT_CHILDREN_CHANGED 1877faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#define AX_EVENT_TEST_COMPLETE ui::AX_EVENT_BLUR 1887faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 1897faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// This test is based on ui/accessibility/ax_generated_tree_unittest.cc 1907faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// However, because the tree updates need to be sent to the extension, we can't 1917faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// use a straightforward set of nested loops as that test does, so this class 1927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// keeps track of where we're up to in our imaginary loops, while the extension 1937faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// function classes below do the work of actually incrementing the state when 1947faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// appropriate. 1957faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// The actual deserialization and comparison happens in the API bindings and the 1967faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// test extension respectively: see 1977faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// c/t/data/extensions/api_test/automation/tests/generated/generated_trees.js 1987faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezclass TreeSerializationState { 1997faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez public: 2007faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez TreeSerializationState() 2017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#ifdef NDEBUG 2027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez : tree_size(3), 2037faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#else 2047faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez : tree_size(2), 2057faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez#endif 206c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath generator(tree_size), 207c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath num_trees(generator.UniqueTreeCount()), 208c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath tree0_version(0), 209c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath tree1_version(0) { 2107faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez } 211c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 212c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Serializes tree and sends it as an accessibility event to the extension. 213c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendDataForTree(const ui::AXTree* tree, 2147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez TreeSerializer* serializer, 215c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int routing_id, 216c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath BrowserContext* browser_context) { 2177faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ui::AXTreeUpdate update; 218c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath serializer->SerializeChanges(tree->GetRoot(), &update); 219c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendUpdate(update, 2207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ui::AX_EVENT_LAYOUT_COMPLETE, 221c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath tree->GetRoot()->id(), 222c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath routing_id, 2237faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez browser_context); 224c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 2257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez 226c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Sends the given AXTreeUpdate to the extension as an accessibility event. 227c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendUpdate(ui::AXTreeUpdate update, 228c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXEvent event, 229c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int node_id, 230c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int routing_id, 231c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath BrowserContext* browser_context) { 232c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath content::AXEventNotificationDetails detail(update.node_id_to_clear, 233c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath update.nodes, 234c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath event, 235c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath node_id, 236c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath kPid, 237c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath routing_id); 238c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath std::vector<content::AXEventNotificationDetails> details; 239c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath details.push_back(detail); 240c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath automation_util::DispatchAccessibilityEventsToAutomation( 241c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath details, browser_context, gfx::Vector2d()); 242c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 243c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 244c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Notify the extension bindings to destroy the tree for the given tab 245c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // (identified by routing_id) 246c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void SendTreeDestroyedEvent(int routing_id, BrowserContext* browser_context) { 247c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath automation_util::DispatchTreeDestroyedEventToAutomation( 248c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath kPid, routing_id, browser_context); 249c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 250c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 2517faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez // Reset tree0 to a new generated tree based on tree0_version, reset 252c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tree0_source accordingly. 253c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void ResetTree0() { 2547faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez tree0.reset(new ui::AXSerializableTree); 255c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath tree0_source.reset(tree0->CreateTreeSource()); 256c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath generator.BuildUniqueTree(tree0_version, tree0.get()); 257c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (!serializer0.get()) 2587faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez serializer0.reset(new TreeSerializer(tree0_source.get())); 259c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 260c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 2617faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez // Reset tree0, set up serializer0, send down the initial tree data to create 262c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // the tree in the extension 263c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void InitializeTree0(BrowserContext* browser_context) { 264c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ResetTree0(); 265c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath serializer0->ChangeTreeSourceForTesting(tree0_source.get()); 266c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath serializer0->Reset(); 267c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendDataForTree(tree0.get(), serializer0.get(), kTab0Rid, browser_context); 268c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 269c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 270c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Reset tree1 to a new generated tree based on tree1_version, reset 271c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tree1_source accordingly. 272c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void ResetTree1() { 2737faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez tree1.reset(new ui::AXSerializableTree); 274c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath tree1_source.reset(tree1->CreateTreeSource()); 275c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath generator.BuildUniqueTree(tree1_version, tree1.get()); 276c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (!serializer1.get()) 2777faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez serializer1.reset(new TreeSerializer(tree1_source.get())); 278c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 279c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 280c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Reset tree1, set up serializer1, send down the initial tree data to create 281c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // the tree in the extension 282c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath void InitializeTree1(BrowserContext* browser_context) { 283c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ResetTree1(); 284c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath serializer1->ChangeTreeSourceForTesting(tree1_source.get()); 285c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath serializer1->Reset(); 286c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath SendDataForTree(tree1.get(), serializer1.get(), kTab1Rid, browser_context); 287c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 288c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 289c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath const int tree_size; 290c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath const ui::TreeGenerator generator; 291c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 292c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // The loop variables: comments indicate which variables in 293c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // ax_generated_tree_unittest they correspond to. 294c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath const int num_trees; // n 295c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int tree0_version; // i 296c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int tree1_version; // j 297c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int starting_node; // k 298c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 299c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Tree infrastructure; tree0 and tree1 need to be regenerated whenever 300c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tree0_version and tree1_version change, respectively; tree0_source and 301c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tree1_source need to be reset whenever that happens. 302c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath scoped_ptr<ui::AXSerializableTree> tree0, tree1; 303c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath scoped_ptr<TreeSource> tree0_source, tree1_source; 304c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath scoped_ptr<TreeSerializer> serializer0, serializer1; 305c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 306c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // Whether tree0 needs to be destroyed after the extension has performed its 307c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // checks 308c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath bool destroy_tree0; 309c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}; 310c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 3117faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezstatic TreeSerializationState state; 312c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 3137faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// Override for chrome.automationInternal.enableTab 3147faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// This fakes out the process and routing IDs for two "tabs", which contain the 315c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// source and target trees, respectively, and sends down the current tree for 3167faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// the requested tab - tab 1 always has tree1, and tab 0 starts with tree0 317c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// and then has a series of updates intended to translate tree0 to tree1. 318c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Once all the updates have been sent, the extension asserts that both trees 3197faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// are equivalent, and then one or both of the trees are reset to a new version. 3207faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandezclass FakeAutomationInternalEnableTabFunction 3217faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez : public UIThreadExtensionFunction { 322c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath public: 323c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath FakeAutomationInternalEnableTabFunction() {} 324c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 3257faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez ExtensionFunction::ResponseAction Run() OVERRIDE { 326c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath using api::automation_internal::EnableTab::Params; 327c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath scoped_ptr<Params> params(Params::Create(*args_)); 328c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath EXTENSION_FUNCTION_VALIDATE(params.get()); 329c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (!params->tab_id.get()) 330c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return RespondNow(Error("tab_id not specified")); 331c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int tab_id = *params->tab_id; 332c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (tab_id == 0) { 333c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tab 0 <--> tree0 334c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::MessageLoop::current()->PostTask( 335c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath FROM_HERE, 336c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::Bind(&TreeSerializationState::InitializeTree0, 337c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::Unretained(&state), 3387faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez base::Unretained(browser_context()))); 339c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return RespondNow( 340c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ArgumentList(api::automation_internal::EnableTab::Results::Create( 341c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath kPid, kTab0Rid))); 342c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 343c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath if (tab_id == 1) { 344c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath // tab 1 <--> tree1 345c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::MessageLoop::current()->PostTask( 3467faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez FROM_HERE, 347c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::Bind(&TreeSerializationState::InitializeTree1, 348c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::Unretained(&state), 349c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath base::Unretained(browser_context()))); 350c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return RespondNow( 351c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ArgumentList(api::automation_internal::EnableTab::Results::Create( 352c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath kPid, kTab1Rid))); 353c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 354c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return RespondNow(Error("Unrecognised tab_id")); 355c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 356c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}; 357c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 358c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Factory method for use in OverrideFunction() 359c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathExtensionFunction* FakeAutomationInternalEnableTabFunctionFactory() { 360c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath return new FakeAutomationInternalEnableTabFunction(); 361c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 362c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 3637faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// Helper method to serialize a series of updates via source_serializer to 364c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// transform the tree which source_serializer was initialized from into 365c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// target_tree, and then trigger the test code to assert the two tabs contain 366c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// the same tree. 367c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid TransformTree(TreeSerializer* source_serializer, 368c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXTree* target_tree, 369c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath TreeSource* target_tree_source, 370c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath content::BrowserContext* browser_context) { 371c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath source_serializer->ChangeTreeSourceForTesting(target_tree_source); 372c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath for (int node_delta = 0; node_delta < state.tree_size; ++node_delta) { 373c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath int id = 1 + (state.starting_node + node_delta) % state.tree_size; 374c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXTreeUpdate update; 375c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath source_serializer->SerializeChanges(target_tree->GetFromId(id), &update); 376c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath bool is_last_update = node_delta == state.tree_size - 1; 377c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXEvent event = 378c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath is_last_update ? AX_EVENT_ASSERT_EQUAL : AX_EVENT_IGNORE; 379c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath state.SendUpdate( 380c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath update, event, target_tree->GetRoot()->id(), kTab0Rid, browser_context); 381c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath } 3827faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez} 383c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 384c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Helper method to send a no-op tree update to tab 0 with the given event. 385c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid SendEvent(ui::AXEvent event, content::BrowserContext* browser_context) { 386c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXTreeUpdate update; 387c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath ui::AXNode* root = state.tree0->GetRoot(); 388c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath state.serializer0->SerializeChanges(root, &update); 389c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath state.SendUpdate(update, event, root->id(), kTab0Rid, browser_context); 390c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} 391c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath 3927faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// Override for chrome.automationInternal.performAction 393c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This is used as a synchronization mechanism; the general flow is: 394c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 1. The extension requests tree0 and tree1 (on tab 0 and tab 1 respectively) 395c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 2. FakeAutomationInternalEnableTabFunction sends down the trees 396c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 3. When the callback for getTree(0) fires, the extension calls doDefault() on 397c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// the root node of tree0, which calls into this class's Run() method. 398c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// 4. In the normal case, we're in the "inner loop" (iterating over 399c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// starting_node). For each value of starting_node, we do the following: 400c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// a. Serialize a sequence of updates which should transform tree0 into 4017faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// tree1. Each of these updates is sent as a childrenChanged event, 4027faaa9f3f0df9d23790277834d426c3d992ac3baCarlos Hernandez// except for the last which is sent as a loadComplete event. 403c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// b. state.destroy_tree0 is set to true 404c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// c. state.starting_node gets incremented 405c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// d. The loadComplete event triggers an assertion in the extension. 406// e. The extension performs another doDefault() on the root node of the 407// tree. 408// f. This time, we send a destroy event to tab0, so that the tree can be 409// reset. 410// g. The extension is notified of the tree's destruction and requests the 411// tree for tab 0 again, returning to step 2. 412// 5. When starting_node exceeds state.tree_size, we increment tree0_version if 413// it would not exceed state.num_trees, or increment tree1_version and reset 414// tree0_version to 0 otherwise, and reset starting_node to 0. 415// Then we reset one or both trees as appropriate, and send down destroyed 416// events similarly, causing the extension to re-request the tree and going 417// back to step 2 again. 418// 6. When tree1_version has gone through all possible values, we send a blur 419// event, signaling the extension to call chrome.test.succeed() and finish 420// the test. 421class FakeAutomationInternalPerformActionFunction 422 : public UIThreadExtensionFunction { 423 public: 424 FakeAutomationInternalPerformActionFunction() {} 425 426 ExtensionFunction::ResponseAction Run() OVERRIDE { 427 if (state.destroy_tree0) { 428 // Step 4.f: tell the extension to destroy the tree and re-request it. 429 state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); 430 state.destroy_tree0 = false; 431 return RespondNow(NoArguments()); 432 } 433 434 TreeSerializer* serializer0 = state.serializer0.get(); 435 if (state.starting_node < state.tree_size) { 436 // As a sanity check, if the trees are not equal, assert that they are not 437 // equal before serializing changes. 438 if (state.tree0_version != state.tree1_version) 439 SendEvent(AX_EVENT_ASSERT_NOT_EQUAL, browser_context()); 440 441 // Step 4.a: pretend that tree0 turned into tree1, and serialize 442 // a sequence of updates to tab 0 to match. 443 TransformTree(serializer0, 444 state.tree1.get(), 445 state.tree1_source.get(), 446 browser_context()); 447 448 // Step 4.b: remember that we need to tell the extension to destroy and 449 // re-request the tree on the next action. 450 state.destroy_tree0 = true; 451 452 // Step 4.c: increment starting_node. 453 state.starting_node++; 454 } else if (state.tree0_version < state.num_trees - 1) { 455 // Step 5: Increment tree0_version and reset starting_node 456 state.tree0_version++; 457 state.starting_node = 0; 458 459 // Step 5: Reset tree0 and tell the extension to destroy and re-request it 460 state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); 461 } else if (state.tree1_version < state.num_trees - 1) { 462 // Step 5: Increment tree1_version and reset tree0_version and 463 // starting_node 464 state.tree1_version++; 465 state.tree0_version = 0; 466 state.starting_node = 0; 467 468 // Step 5: Reset tree0 and tell the extension to destroy and re-request it 469 state.SendTreeDestroyedEvent(kTab0Rid, browser_context()); 470 471 // Step 5: Reset tree1 and tell the extension to destroy and re-request it 472 state.SendTreeDestroyedEvent(kTab1Rid, browser_context()); 473 } else { 474 // Step 6: Send a TEST_COMPLETE (blur) event to signal the extension to 475 // call chrome.test.succeed(). 476 SendEvent(AX_EVENT_TEST_COMPLETE, browser_context()); 477 } 478 479 return RespondNow(NoArguments()); 480 } 481}; 482 483// Factory method for use in OverrideFunction() 484ExtensionFunction* FakeAutomationInternalPerformActionFunctionFactory() { 485 return new FakeAutomationInternalPerformActionFunction(); 486} 487 488// http://crbug.com/396353 489IN_PROC_BROWSER_TEST_F(AutomationApiTest, DISABLED_GeneratedTree) { 490 ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( 491 "automationInternal.enableTab", 492 FakeAutomationInternalEnableTabFunctionFactory)); 493 ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( 494 "automationInternal.performAction", 495 FakeAutomationInternalPerformActionFunctionFactory)); 496 ASSERT_TRUE(RunExtensionSubtest("automation/tests/generated", 497 "generated_trees.html")) << message_; 498} 499 500} // namespace extensions 501