// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/i18n/rtl.h" #include "base/json/json_value_serializer.h" #include "base/md5.h" #include "base/memory/scoped_ptr.h" #include "base/scoped_temp_dir.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/sys_info.h" #include "base/test/test_timeouts.h" #include "base/utf_string_conversions.h" #include "build/build_config.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/ui/view_ids.h" #include "chrome/common/automation_messages.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/url_constants.h" #include "chrome/test/automation/automation_proxy_uitest.h" #include "chrome/test/automation/browser_proxy.h" #include "chrome/test/automation/proxy_launcher.h" #include "chrome/test/automation/tab_proxy.h" #include "chrome/test/automation/window_proxy.h" #include "chrome/test/base/ui_test_utils.h" #include "chrome/test/ui/ui_test.h" #include "content/browser/net/url_request_slow_http_job.h" #include "net/base/host_port_pair.h" #include "net/base/net_util.h" #include "net/test/test_server.h" #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING #include "testing/gmock_mutant.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_types.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/rect.h" using ui_test_utils::TimedMessageLoopRunner; using testing::CreateFunctor; using testing::StrEq; using testing::_; // Replace the default automation proxy with our mock client. class ExternalTabUITestMockLauncher : public ProxyLauncher { public: explicit ExternalTabUITestMockLauncher(ExternalTabUITestMockClient **mock) : mock_(mock) { channel_id_ = AutomationProxy::GenerateChannelID(); } AutomationProxy* CreateAutomationProxy(int execution_timeout) { *mock_ = new ExternalTabUITestMockClient(execution_timeout); (*mock_)->InitializeChannel(channel_id_, false); return *mock_; } bool InitializeConnection( const LaunchState& state, bool wait_for_initial_loads) OVERRIDE WARN_UNUSED_RESULT { bool launch_browser_and_server = LaunchBrowserAndServer(state, wait_for_initial_loads); EXPECT_TRUE(launch_browser_and_server); return launch_browser_and_server; } void TerminateConnection() { CloseBrowserAndServer(); } std::string PrefixedChannelID() const { return channel_id_; } private: ExternalTabUITestMockClient **mock_; std::string channel_id_; // Channel id of automation proxy. }; class AutomationProxyTest : public UITest { protected: AutomationProxyTest() { dom_automation_enabled_ = true; launch_arguments_.AppendSwitchASCII(switches::kLang, "en-US"); } }; TEST_F(AutomationProxyTest, GetBrowserWindowCount) { int window_count = 0; EXPECT_TRUE(automation()->GetBrowserWindowCount(&window_count)); EXPECT_EQ(1, window_count); #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) ASSERT_FALSE(automation()->GetBrowserWindowCount(NULL)); #endif } TEST_F(AutomationProxyTest, GetBrowserWindow) { { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); } { scoped_refptr window(automation()->GetBrowserWindow(-1)); ASSERT_FALSE(window.get()); } { scoped_refptr window(automation()->GetBrowserWindow(1)); ASSERT_FALSE(window.get()); } }; #if defined(OS_MACOSX) // Missing automation provider support: http://crbug.com/45892 #define MAYBE_WindowGetViewBounds FAILS_WindowGetViewBounds #else #define MAYBE_WindowGetViewBounds WindowGetViewBounds #endif TEST_F(AutomationProxyVisibleTest, MAYBE_WindowGetViewBounds) { { scoped_refptr browser(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser.get()); scoped_refptr window(browser->GetWindow()); ASSERT_TRUE(window.get()); scoped_refptr tab1(browser->GetTab(0)); ASSERT_TRUE(tab1.get()); GURL tab1_url; ASSERT_TRUE(tab1->GetCurrentURL(&tab1_url)); // Add another tab so we can simulate dragging. ASSERT_TRUE(browser->AppendTab(GURL(chrome::kChromeUIVersionURL))); scoped_refptr tab2(browser->GetTab(1)); ASSERT_TRUE(tab2.get()); GURL tab2_url; ASSERT_TRUE(tab2->GetCurrentURL(&tab2_url)); EXPECT_NE(tab1_url.spec(), tab2_url.spec()); gfx::Rect bounds; ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_0, &bounds, false)); EXPECT_GT(bounds.width(), 0); EXPECT_GT(bounds.height(), 0); gfx::Rect bounds2; ASSERT_TRUE(window->GetViewBounds(VIEW_ID_TAB_LAST, &bounds2, false)); EXPECT_GT(bounds2.x(), 0); EXPECT_GT(bounds2.width(), 0); EXPECT_GT(bounds2.height(), 0); // The tab logic is mirrored in RTL locales, so what is to the right in // LTR locales is now on the left with RTL ones. string16 browser_locale; EXPECT_TRUE(automation()->GetBrowserLocale(&browser_locale)); const std::string& locale_utf8 = UTF16ToUTF8(browser_locale); if (base::i18n::GetTextDirectionForLocale(locale_utf8.c_str()) == base::i18n::RIGHT_TO_LEFT) { EXPECT_LT(bounds2.x(), bounds.x()); } else { EXPECT_GT(bounds2.x(), bounds.x()); } EXPECT_EQ(bounds2.y(), bounds.y()); // Sometimes tests start the browser in full screen mode. Don't check the // location bar in such a case. bool fullscreen = false; if (browser->IsFullscreen(&fullscreen) && !fullscreen) { gfx::Rect urlbar_bounds; ASSERT_TRUE(window->GetViewBounds(VIEW_ID_LOCATION_BAR, &urlbar_bounds, false)); EXPECT_GT(urlbar_bounds.x(), 0); EXPECT_GT(urlbar_bounds.y(), 0); EXPECT_GT(urlbar_bounds.width(), 0); EXPECT_GT(urlbar_bounds.height(), 0); } /* TODO(beng): uncomment this section or move to interactive_ui_tests post haste! // Now that we know where the tabs are, let's try dragging one. POINT start; POINT end; start.x = bounds.x() + bounds.width() / 2; start.y = bounds.y() + bounds.height() / 2; end.x = start.x + 2 * bounds.width() / 3; end.y = start.y; ASSERT_TRUE(browser->SimulateDrag(start, end, ui::EF_LEFT_BUTTON_DOWN)); // Check to see that the drag event successfully swapped the two tabs. tab1 = browser->GetTab(0); ASSERT_TRUE(tab1.get()); GURL tab1_new_url; ASSERT_TRUE(tab1->GetCurrentURL(&tab1_new_url)); tab2 = browser->GetTab(1); ASSERT_TRUE(tab2.get()); GURL tab2_new_url; ASSERT_TRUE(tab2->GetCurrentURL(&tab2_new_url)); EXPECT_EQ(tab1_url.spec(), tab2_new_url.spec()); EXPECT_EQ(tab2_url.spec(), tab1_new_url.spec()); */ } } TEST_F(AutomationProxyTest, GetTabCount) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); int tab_count = 0; ASSERT_TRUE(window->GetTabCount(&tab_count)); ASSERT_EQ(1, tab_count); } TEST_F(AutomationProxyTest, GetActiveTabIndex) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); int active_tab_index = -1; ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(0, active_tab_index); } TEST_F(AutomationProxyVisibleTest, AppendTab) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); int original_tab_count; ASSERT_TRUE(window->GetTabCount(&original_tab_count)); ASSERT_EQ(1, original_tab_count); // By default there are 2 tabs opened. int original_active_tab_index; ASSERT_TRUE(window->GetActiveTabIndex(&original_active_tab_index)); ASSERT_EQ(0, original_active_tab_index); // By default 0-th tab is active ASSERT_TRUE(window->AppendTab(GURL("about:blank"))); int tab_count; ASSERT_TRUE(window->GetTabCount(&tab_count)); ASSERT_EQ(original_tab_count + 1, tab_count); int active_tab_index = -1; ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(tab_count - 1, active_tab_index); ASSERT_NE(original_active_tab_index, active_tab_index); FilePath filename(test_data_directory_); filename = filename.AppendASCII("title2.html"); ASSERT_TRUE(window->AppendTab(net::FilePathToFileURL(filename))); int appended_tab_index; // Append tab will also be active tab ASSERT_TRUE(window->GetActiveTabIndex(&appended_tab_index)); scoped_refptr tab(window->GetTab(appended_tab_index)); ASSERT_TRUE(tab.get()); std::wstring title; ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); } TEST_F(AutomationProxyTest, ActivateTab) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); ASSERT_TRUE(window->AppendTab(GURL("about:blank"))); ASSERT_TRUE(window->ActivateTab(1)); int active_tab_index = -1; ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(1, active_tab_index); ASSERT_TRUE(window->ActivateTab(0)); ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(0, active_tab_index); } TEST_F(AutomationProxyTest, GetTab) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); { scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring title; ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"about:blank", title.c_str()); } { ASSERT_FALSE(window->GetTab(-1)); } { scoped_refptr tab(window->GetTab(1)); ASSERT_FALSE(tab.get()); } }; TEST_F(AutomationProxyTest, NavigateToURL) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring title; ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"about:blank", title.c_str()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("title2.html"); ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(net::FilePathToFileURL(filename))); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); // TODO(vibhor) : Add a test using testserver. } TEST_F(AutomationProxyTest, GoBackForward) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring title; ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"about:blank", title.c_str()); ASSERT_FALSE(tab->GoBack()); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"about:blank", title.c_str()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("title2.html"); ASSERT_TRUE(tab->NavigateToURL(net::FilePathToFileURL(filename))); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); ASSERT_TRUE(tab->GoBack()); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"about:blank", title.c_str()); ASSERT_TRUE(tab->GoForward()); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); ASSERT_FALSE(tab->GoForward()); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); } TEST_F(AutomationProxyTest, GetCurrentURL) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); GURL url; ASSERT_TRUE(tab->GetCurrentURL(&url)); ASSERT_STREQ("about:blank", url.spec().c_str()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("cookie1.html"); GURL newurl = net::FilePathToFileURL(filename); ASSERT_TRUE(tab->NavigateToURL(newurl)); ASSERT_TRUE(tab->GetCurrentURL(&url)); // compare canonical urls... ASSERT_STREQ(newurl.spec().c_str(), url.spec().c_str()); } class AutomationProxyTest2 : public AutomationProxyVisibleTest { protected: AutomationProxyTest2() { document1_= test_data_directory_.AppendASCII("title1.html"); document2_ = test_data_directory_.AppendASCII("title2.html"); launch_arguments_ = CommandLine(CommandLine::NO_PROGRAM); launch_arguments_.AppendArgPath(document1_); launch_arguments_.AppendArgPath(document2_); } FilePath document1_; FilePath document2_; }; TEST_F(AutomationProxyTest2, GetActiveTabIndex) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); int active_tab_index = -1; ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(0, active_tab_index); ASSERT_TRUE(window->ActivateTab(1)); ASSERT_TRUE(window->GetActiveTabIndex(&active_tab_index)); ASSERT_EQ(1, active_tab_index); } // http://crbug.com/98071 #if defined(OS_MACOSX) #define MAYBE_GetTabTitle FLAKY_GetTabTitle #else #define MAYBE_GetTabTitle GetTabTitle #endif TEST_F(AutomationProxyTest2, MAYBE_GetTabTitle) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring title; ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"title1.html", title.c_str()); tab = window->GetTab(1); ASSERT_TRUE(tab.get()); ASSERT_TRUE(tab->GetTabTitle(&title)); ASSERT_STREQ(L"Title Of Awesomeness", title.c_str()); } TEST_F(AutomationProxyTest, Cookies) { GURL url("http://mojo.jojo.google.com"); std::string value_result; scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); // test setting the cookie: ASSERT_TRUE(tab->SetCookie(url, "foo=baz")); ASSERT_TRUE(tab->GetCookieByName(url, "foo", &value_result)); ASSERT_FALSE(value_result.empty()); ASSERT_STREQ("baz", value_result.c_str()); // test clearing the cookie: ASSERT_TRUE(tab->SetCookie(url, "foo=")); ASSERT_TRUE(tab->GetCookieByName(url, "foo", &value_result)); ASSERT_TRUE(value_result.empty()); // now, test that we can get multiple cookies: ASSERT_TRUE(tab->SetCookie(url, "foo1=baz1")); ASSERT_TRUE(tab->SetCookie(url, "foo2=baz2")); ASSERT_TRUE(tab->GetCookies(url, &value_result)); ASSERT_FALSE(value_result.empty()); EXPECT_TRUE(value_result.find("foo1=baz1") != std::string::npos); EXPECT_TRUE(value_result.find("foo2=baz2") != std::string::npos); // test deleting cookie ASSERT_TRUE(tab->SetCookie(url, "foo3=deleteme")); ASSERT_TRUE(tab->GetCookieByName(url, "foo3", &value_result)); ASSERT_FALSE(value_result.empty()); ASSERT_STREQ("deleteme", value_result.c_str()); ASSERT_TRUE(tab->DeleteCookie(url, "foo3")); } TEST_F(AutomationProxyTest, NavigateToURLAsync) { AutomationProxy* automation_object = automation(); scoped_refptr window(automation_object->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("cookie1.html"); GURL newurl = net::FilePathToFileURL(filename); ASSERT_TRUE(tab->NavigateToURLAsync(newurl)); std::string value = WaitUntilCookieNonEmpty( tab.get(), newurl, "foo", TestTimeouts::action_max_timeout_ms()); ASSERT_STREQ("baz", value.c_str()); } TEST_F(AutomationProxyTest, AcceleratorNewTab) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); int tab_count = -1; ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB)); ASSERT_TRUE(window->GetTabCount(&tab_count)); EXPECT_EQ(2, tab_count); scoped_refptr tab(window->GetTab(1)); ASSERT_TRUE(tab.get()); } TEST_F(AutomationProxyTest, AcceleratorDownloads) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); ASSERT_TRUE(window->RunCommand(IDC_SHOW_DOWNLOADS)); // We expect the RunCommand above to wait until the title is updated. EXPECT_EQ(L"Downloads", GetActiveTabTitle()); } TEST_F(AutomationProxyTest, AcceleratorExtensions) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); ASSERT_TRUE(window->RunCommand(IDC_MANAGE_EXTENSIONS)); EXPECT_EQ("chrome://settings/extensions", GetActiveTabURL().spec()); } TEST_F(AutomationProxyTest, AcceleratorHistory) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); ASSERT_TRUE(window->RunCommand(IDC_SHOW_HISTORY)); // We expect the RunCommand above to wait until the title is updated. EXPECT_EQ(L"History", GetActiveTabTitle()); } class AutomationProxyTest4 : public UITest { protected: AutomationProxyTest4() : UITest() { dom_automation_enabled_ = true; } }; std::wstring CreateJSString(const std::wstring& value) { std::wstring jscript; base::SStringPrintf(&jscript, L"window.domAutomationController.send(%ls);", value.c_str()); return jscript; } TEST_F(AutomationProxyTest4, StringValueIsEchoedByDomAutomationController) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring expected(L"string"); std::wstring jscript = CreateJSString(L"\"" + expected + L"\""); std::wstring actual; ASSERT_TRUE(tab->ExecuteAndExtractString(L"", jscript, &actual)); ASSERT_STREQ(expected.c_str(), actual.c_str()); } std::wstring BooleanToString(bool bool_value) { Value* value = Value::CreateBooleanValue(bool_value); std::string json_string; JSONStringValueSerializer serializer(&json_string); serializer.Serialize(*value); return UTF8ToWide(json_string); } TEST_F(AutomationProxyTest4, BooleanValueIsEchoedByDomAutomationController) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); bool expected = true; std::wstring jscript = CreateJSString(BooleanToString(expected)); bool actual = false; ASSERT_TRUE(tab->ExecuteAndExtractBool(L"", jscript, &actual)); ASSERT_EQ(expected, actual); } TEST_F(AutomationProxyTest4, NumberValueIsEchoedByDomAutomationController) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); int expected = 1; int actual = 0; std::wstring expected_string; base::SStringPrintf(&expected_string, L"%d", expected); std::wstring jscript = CreateJSString(expected_string); ASSERT_TRUE(tab->ExecuteAndExtractInt(L"", jscript, &actual)); ASSERT_EQ(expected, actual); } // TODO(vibhor): Add a test for ExecuteAndExtractValue() for JSON Dictionary // type value class AutomationProxyTest3 : public UITest { protected: AutomationProxyTest3() : UITest() { document1_ = test_data_directory_; document1_ = document1_.AppendASCII("frame_dom_access"); document1_ = document1_.AppendASCII("frame_dom_access.html"); dom_automation_enabled_ = true; launch_arguments_ = CommandLine(CommandLine::NO_PROGRAM); launch_arguments_.AppendArgPath(document1_); } FilePath document1_; }; std::wstring CreateJSStringForDOMQuery(const std::wstring& id) { std::wstring jscript(L"window.domAutomationController"); base::StringAppendF(&jscript, L".send(document.getElementById('%ls').nodeName);", id.c_str()); return jscript; } TEST_F(AutomationProxyTest3, FrameDocumentCanBeAccessed) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); std::wstring actual; std::wstring xpath1 = L""; // top level frame std::wstring jscript1 = CreateJSStringForDOMQuery(L"myinput"); ASSERT_TRUE(tab->ExecuteAndExtractString(xpath1, jscript1, &actual)); ASSERT_EQ(L"INPUT", actual); std::wstring xpath2 = L"/html/body/iframe"; std::wstring jscript2 = CreateJSStringForDOMQuery(L"myspan"); ASSERT_TRUE(tab->ExecuteAndExtractString(xpath2, jscript2, &actual)); ASSERT_EQ(L"SPAN", actual); std::wstring xpath3 = L"/html/body/iframe\n/html/body/iframe"; std::wstring jscript3 = CreateJSStringForDOMQuery(L"mydiv"); ASSERT_TRUE(tab->ExecuteAndExtractString(xpath3, jscript3, &actual)); ASSERT_EQ(L"DIV", actual); } // Flaky, http://crbug.com/70937 TEST_F(AutomationProxyTest, FLAKY_BlockedPopupTest) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("constrained_files"); filename = filename.AppendASCII("constrained_window.html"); ASSERT_TRUE(tab->NavigateToURL(net::FilePathToFileURL(filename))); ASSERT_TRUE(tab->WaitForBlockedPopupCountToChangeTo( 2, TestTimeouts::action_max_timeout_ms())); } // TODO(port): Remove HWND if possible #if defined(OS_WIN) const char simple_data_url[] = "data:text/html,External tab test" "A simple page for testing a floating/invisible tab
" ""; ExternalTabUITestMockClient::ExternalTabUITestMockClient(int execution_timeout) : AutomationProxy(execution_timeout, false), host_window_style_(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE), host_window_(NULL) { } ExternalTabUITestMockClient::~ExternalTabUITestMockClient() { EXPECT_TRUE(host_window_ == NULL); } void ExternalTabUITestMockClient::ReplyStarted( const AutomationURLResponse* response, int tab_handle, int request_id) { AutomationProxy::Send(new AutomationMsg_RequestStarted(tab_handle, request_id, *response)); } void ExternalTabUITestMockClient::ReplyData( const std::string* data, int tab_handle, int request_id) { AutomationProxy::Send(new AutomationMsg_RequestData(tab_handle, request_id, *data)); } void ExternalTabUITestMockClient::ReplyEOF(int tab_handle, int request_id) { ReplyEnd(net::URLRequestStatus(), tab_handle, request_id); } void ExternalTabUITestMockClient::ReplyEnd(const net::URLRequestStatus& status, int tab_handle, int request_id) { AutomationProxy::Send(new AutomationMsg_RequestEnd(tab_handle, request_id, status)); } void ExternalTabUITestMockClient::Reply404(int tab_handle, int request_id) { AutomationURLResponse notfound; notfound.headers = "HTTP/1.1 404\r\n\r\n"; notfound.content_length = 0; notfound.redirect_status = 0; ReplyStarted(¬found, tab_handle, request_id); ReplyEOF(tab_handle, request_id); } void ExternalTabUITestMockClient::ServeHTMLData(int tab_handle, const GURL& url, const std::string& data) { EXPECT_CALL(*this, OnRequestStart(tab_handle, testing::AllOf( testing::Field(&AutomationURLRequest::url, url.spec()), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(this, &ExternalTabUITestMockClient::ReplyStarted, &GetHttp200Response())))); EXPECT_CALL(*this, OnRequestRead(tab_handle, testing::Gt(0))) .Times(2) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(this, &ExternalTabUITestMockClient::ReplyData, &data)))) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(this, &ExternalTabUITestMockClient::ReplyEOF)))); } void ExternalTabUITestMockClient::IgnoreFaviconNetworkRequest() { // Ignore favicon.ico EXPECT_CALL(*this, OnRequestStart(_, testing::AllOf( testing::Field(&AutomationURLRequest::url, testing::EndsWith("favicon.ico")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(testing::AnyNumber()) .WillRepeatedly(testing::WithArgs<0, 0>(testing::Invoke( CreateFunctor(this, &ExternalTabUITestMockClient::ReplyEnd, net::URLRequestStatus(net::URLRequestStatus::FAILED, 0))))); } void ExternalTabUITestMockClient::InvalidateHandle( const IPC::Message& message) { void* iter = NULL; int handle; ASSERT_TRUE(message.ReadInt(&iter, &handle)); // Call base class AutomationProxy::InvalidateHandle(message); HandleClosed(handle); } // static ExternalTabSettings ExternalTabUITestMockClient::GetDefaultSettings() { ExternalTabSettings settings; settings.parent = NULL; settings.style = WS_CHILD | WS_VISIBLE; settings.is_incognito = false; settings.load_requests_via_automation = true; settings.handle_top_level_requests = true; settings.infobars_enabled = false; settings.route_all_top_level_navigations = false; return settings; } // static AutomationURLResponse ExternalTabUITestMockClient::GetHttp200Response() { AutomationURLResponse response; response.headers = "HTTP/0.9 200\r\n\r\n"; response.content_length = 0; response.redirect_status = 0; return response; } bool ExternalTabUITestMockClient::OnMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExternalTabUITestMockClient, msg) IPC_MESSAGE_HANDLER(AutomationMsg_DidNavigate, OnDidNavigate) IPC_MESSAGE_HANDLER(AutomationMsg_ForwardMessageToExternalHost, OnForwardMessageToExternalHost) IPC_MESSAGE_HANDLER(AutomationMsg_RequestStart, OnRequestStart) IPC_MESSAGE_HANDLER(AutomationMsg_RequestRead, OnRequestRead) IPC_MESSAGE_HANDLER(AutomationMsg_RequestEnd, OnRequestEnd) IPC_MESSAGE_HANDLER(AutomationMsg_SetCookieAsync, OnSetCookieAsync) IPC_MESSAGE_HANDLER(AutomationMsg_TabLoaded, OnLoad) IPC_MESSAGE_HANDLER(AutomationMsg_AttachExternalTab, OnAttachExternalTab) IPC_MESSAGE_HANDLER(AutomationMsg_OpenURL, OnOpenURL) IPC_MESSAGE_HANDLER(AutomationMsg_NavigationStateChanged, OnNavigationStateChanged) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } scoped_refptr ExternalTabUITestMockClient::CreateHostWindowAndTab( const ExternalTabSettings& settings) { EXPECT_THAT(settings.parent, testing::IsNull()); host_window_ = CreateWindowW(L"Button", NULL, host_window_style_, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); EXPECT_THAT(host_window_, testing::Truly(::IsWindow)); RECT client_area = {0}; ::GetClientRect(host_window_, &client_area); ExternalTabSettings s = settings; s.parent = host_window_; s.dimensions = client_area; HWND container_wnd = NULL; HWND tab_wnd = NULL; scoped_refptr tab(CreateExternalTab(s, &container_wnd, &tab_wnd)); EXPECT_TRUE(tab != NULL); EXPECT_NE(FALSE, ::IsWindow(container_wnd)); EXPECT_NE(FALSE, ::IsWindow(tab_wnd)); return tab; } scoped_refptr ExternalTabUITestMockClient::CreateTabWithUrl( const GURL& initial_url) { ExternalTabSettings settings = GetDefaultSettings(); settings.initial_url = initial_url; return CreateHostWindowAndTab(settings); } void ExternalTabUITestMockClient::NavigateInExternalTab(int tab_handle, const GURL& url, const GURL& referrer /* = GURL()*/) { channel_->ChannelProxy::Send(new AutomationMsg_NavigateInExternalTab( tab_handle, url, referrer, NULL)); } void ExternalTabUITestMockClient::ConnectToExternalTab(gfx::NativeWindow parent, const AttachExternalTabParams& attach_params) { gfx::NativeWindow tab_container = NULL; gfx::NativeWindow tab_window = NULL; int tab_handle = 0; int session_id = -1; IPC::SyncMessage* message = new AutomationMsg_ConnectExternalTab( attach_params.cookie, true, NULL, &tab_container, &tab_window, &tab_handle, &session_id); channel_->Send(message); RECT rect; ::GetClientRect(parent, &rect); Reposition_Params params; params.window = tab_container; params.flags = SWP_NOZORDER | SWP_SHOWWINDOW; params.width = rect.right - rect.left; params.height = rect.bottom - rect.top; params.set_parent = true; params.parent_window = parent; channel_->Send(new AutomationMsg_TabReposition(tab_handle, params)); ::ShowWindow(parent, SW_SHOWNORMAL); } void ExternalTabUITestMockClient::NavigateThroughUserGesture() { ASSERT_THAT(host_window_, testing::Truly(::IsWindow)); HWND tab_container = ::GetWindow(host_window_, GW_CHILD); ASSERT_THAT(tab_container, testing::Truly(::IsWindow)); HWND tab = ::GetWindow(tab_container, GW_CHILD); ASSERT_THAT(tab, testing::Truly(::IsWindow)); HWND renderer_window = ::GetWindow(tab, GW_CHILD); ASSERT_THAT(renderer_window, testing::Truly(::IsWindow)); ::SetFocus(renderer_window); ::PostMessage(renderer_window, WM_KEYDOWN, VK_TAB, 0); ::PostMessage(renderer_window, WM_KEYUP, VK_TAB, 0); ::PostMessage(renderer_window, WM_KEYDOWN, VK_RETURN, 0); ::PostMessage(renderer_window, WM_KEYUP, VK_RETURN, 0); } void ExternalTabUITestMockClient::DestroyHostWindow() { ::DestroyWindow(host_window_); host_window_ = NULL; } bool ExternalTabUITestMockClient::HostWindowExists() { return (host_window_ != NULL) && ::IsWindow(host_window_); } // Handy macro #define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\ CreateFunctor(loop, &TimedMessageLoopRunner::Quit)) #define QUIT_LOOP_SOON(loop, ms) testing::InvokeWithoutArgs(\ CreateFunctor(loop, &TimedMessageLoopRunner::QuitAfter, ms)) template T** ReceivePointer(scoped_ptr& p) { // NOLINT return reinterpret_cast(&p); } template T** ReceivePointer(scoped_refptr& p) { // NOLINT return reinterpret_cast(&p); } ExternalTabUITest::ExternalTabUITest() : UITest(MessageLoop::TYPE_UI) {} // Replace the default automation proxy with our mock client. ProxyLauncher* ExternalTabUITest::CreateProxyLauncher() { return new ExternalTabUITestMockLauncher(&mock_); } // Create with specifying a url // Flaky, http://crbug.com/32293 TEST_F(ExternalTabUITest, FLAKY_CreateExternalTab1) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnDidNavigate(testing::_)) .Times(1) .WillOnce(testing::InvokeWithoutArgs(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)); EXPECT_CALL(*mock_, HandleClosed(1)) .Times(1) .WillOnce(QUIT_LOOP(&loop)); tab = mock_->CreateTabWithUrl(GURL(simple_data_url)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // Create with empty url and then navigate // Flaky, http://crbug.com/32293 TEST_F(ExternalTabUITest, FLAKY_CreateExternalTab2) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnDidNavigate(testing::_)) .Times(1) .WillOnce(testing::InvokeWithoutArgs(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)); EXPECT_CALL(*mock_, HandleClosed(1)) .Times(1) .WillOnce(QUIT_LOOP(&loop)); tab = mock_->CreateTabWithUrl(GURL()); mock_->NavigateInExternalTab(tab->handle(), GURL(simple_data_url)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // FLAKY: http://crbug.com/60409 TEST_F(ExternalTabUITest, FLAKY_IncognitoMode) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); GURL url("http://anatomyofmelancholy.net"); std::string cookie = "robert=burton; expires=Thu, 13 Oct 2011 05:04:03 UTC;"; EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); ExternalTabSettings incognito = ExternalTabUITestMockClient::GetDefaultSettings(); incognito.is_incognito = true; // SetCookie is a sync call and deadlock can happen if window is visible, // since it shares same thread with AutomationProxy. mock_->host_window_style_ &= ~WS_VISIBLE; tab = mock_->CreateHostWindowAndTab(incognito); std::string value_result; EXPECT_TRUE(tab->SetCookie(url, cookie)); EXPECT_TRUE(tab->GetCookieByName(url, "robert", &value_result)); EXPECT_EQ("burton", value_result); mock_->DestroyHostWindow(); CloseBrowserAndServer(); tab = NULL; value_result.clear(); clear_profile_ = false; LaunchBrowserAndServer(); // SetCookie is a sync call and deadlock can happen if window is visible, // since it shares same thread with AutomationProxy. mock_->host_window_style_ &= ~WS_VISIBLE; tab = mock_->CreateTabWithUrl(GURL()); EXPECT_TRUE(tab->GetCookieByName(url, "robert", &value_result)); EXPECT_EQ("", value_result); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); mock_->DestroyHostWindow(); CloseBrowserAndServer(); tab = NULL; } // FLAKY: http://crbug.com/44617 TEST_F(ExternalTabUITest, FLAKY_TabPostMessage) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); std::string content = "data:text/html," "external tab test
" ""; EXPECT_CALL(*mock_, OnDidNavigate(testing::_)) .Times(1) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor( ReceivePointer(tab), &TabProxy::HandleMessageFromExternalHost, std::string("Hello from gtest"), std::string("null"), std::string("*")))); EXPECT_CALL(*mock_, OnForwardMessageToExternalHost( testing::StrEq("Hello from gtest"), testing::_, testing::_)) .Times(1) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)), QUIT_LOOP_SOON(&loop, 50))); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); tab = mock_->CreateTabWithUrl(GURL(content)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // Flaky: http://crbug.com/62143 TEST_F(ExternalTabUITest, FLAKY_PostMessageTarget) { net::TestServer test_server( net::TestServer::TYPE_HTTP, FilePath(FILE_PATH_LITERAL("chrome/test/data/external_tab"))); ASSERT_TRUE(test_server.Start()); scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); std::string kTestMessage("Hello from gtest"); std::string kTestOrigin("http://www.external.tab"); EXPECT_CALL(*mock_, OnDidNavigate(testing::_)) .Times(1) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor( ReceivePointer(tab), &TabProxy::HandleMessageFromExternalHost, kTestMessage, kTestOrigin, std::string("http://localhost:1337/")))); EXPECT_CALL(*mock_, OnForwardMessageToExternalHost( testing::StrEq(kTestMessage), testing::_, testing::StrEq(GURL(kTestOrigin).GetOrigin().spec()))) .Times(1) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)), QUIT_LOOP_SOON(&loop, 50))); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); ExternalTabSettings s = ExternalTabUITestMockClient::GetDefaultSettings(); s.load_requests_via_automation = false; s.initial_url = GURL("http://localhost:1337/files/post_message.html"); tab = mock_->CreateHostWindowAndTab(s); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // Disabled, http://crbug.com/42545. TEST_F(ExternalTabUITest, DISABLED_HostNetworkStack) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); std::string url = "http://placetogo.org"; testing::InSequence sequence; EXPECT_CALL(*mock_, OnRequestStart(2, testing::AllOf( testing::Field(&AutomationURLRequest::url, StrEq(url + "/")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) // We can simply do CreateFunctor(1, 2, &GetHttp200Response()) since we // know the tab handle and request id, but using WithArgs<> is much more // fancy :) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyStarted, &ExternalTabUITestMockClient::GetHttp200Response())))); // Return some trivial page, that have a link to a "logo.gif" image const std::string data = "Hello" ""; EXPECT_CALL(*mock_, OnRequestRead(2, testing::Gt(0))) .Times(2) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyData, &data, 1, 2))) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyEOF)))); // Expect navigation is ok. EXPECT_CALL(*mock_, OnDidNavigate(testing::Field(&NavigationInfo::url, GURL(url)))) .Times(1); // Expect GET request for logo.gif EXPECT_CALL(*mock_, OnRequestStart(3, testing::AllOf( testing::Field(&AutomationURLRequest::url, StrEq(url + "/logo.gif")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::Reply404, 1, 3))); EXPECT_CALL(*mock_, OnRequestRead(3, testing::Gt(0))) .Times(1); // Chrome makes a brave request for favicon.ico EXPECT_CALL(*mock_, OnRequestStart(4, testing::AllOf( testing::Field(&AutomationURLRequest::url, StrEq(url + "/favicon.ico")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::Reply404, 1, 4)), testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)))); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); EXPECT_CALL(*mock_, OnRequestRead(4, testing::Gt(0))) .Times(1) .WillOnce(QUIT_LOOP_SOON(&loop, 300)); tab = mock_->CreateTabWithUrl(GURL(url)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // Disabled, http://crbug.com/61023. TEST_F(ExternalTabUITest, DISABLED_HostNetworkStackAbortRequest) { scoped_refptr tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); std::string url = "http://placetogo.org"; testing::InSequence sequence; EXPECT_CALL(*mock_, OnRequestStart(2, testing::AllOf( testing::Field(&AutomationURLRequest::url, StrEq(url + "/")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) // We can simply do CreateFunctor(1, 2, &GetHttp200Response()) since we // know the tab handle and request id, but using WithArgs<> is much more // fancy :) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyStarted, &ExternalTabUITestMockClient::GetHttp200Response())))); // Return some trivial page, that have a link to a "logo.gif" image const std::string data = "Hello"; EXPECT_CALL(*mock_, OnRequestRead(2, testing::Gt(0))) .Times(2) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyData, &data, 1, 2))) .WillOnce(testing::WithArgs<0, 0>( testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::DestroyHostWindow)))); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); EXPECT_CALL(*mock_, OnRequestEnd(2, testing::_)) .Times(1) .WillOnce(QUIT_LOOP_SOON(&loop, 300)); tab = mock_->CreateTabWithUrl(GURL(url)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); } // Disabled, http://crbug.com/61023. TEST_F(ExternalTabUITest, DISABLED_HostNetworkStackUnresponsiveRenderer) { scoped_refptr<TabProxy> tab; TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnLoad(_)).Times(testing::AnyNumber()); std::string url = "http://placetogo.org"; EXPECT_CALL(*mock_, OnRequestStart(3, testing::_)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(testing::AnyNumber()); testing::InSequence sequence; EXPECT_CALL(*mock_, OnRequestStart(2, testing::AllOf( testing::Field(&AutomationURLRequest::url, StrEq(url + "/")), testing::Field(&AutomationURLRequest::method, StrEq("GET"))))) .Times(1) // We can simply do CreateFunctor(1, 2, &GetHttp200Response()) since we // know the tab handle and request id, but using WithArgs<> is much more // fancy :) .WillOnce(testing::WithArgs<0, 0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyStarted, &ExternalTabUITestMockClient::GetHttp200Response())))); const std::string head = "<html><title>Hello"; const std::string data = "" "" "" "" "" "" "" "" "" "" "" "" "" "
MonthSavings
January$100
February$100
March$100
April$100
May$100
June$100
July$100
Aug$100
Sept$100
Oct$100
Nov$100
Dec$100
"; const std::string tail = ""; EXPECT_CALL(*mock_, OnRequestRead(2, testing::Gt(0))) .Times(1) .WillOnce(testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyData, &head, 1, 2))); EXPECT_CALL(*mock_, OnRequestRead(2, testing::Gt(0))) .Times(100) .WillRepeatedly(testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyData, &data, 1, 2))); EXPECT_CALL(*mock_, OnRequestRead(2, testing::Gt(0))) .Times(testing::AnyNumber()) .WillOnce(testing::DoAll( testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyData, &tail, 1, 2)), testing::InvokeWithoutArgs(CreateFunctor(mock_, &ExternalTabUITestMockClient::ReplyEOF, 1, 2)), QUIT_LOOP_SOON(&loop, 300))); EXPECT_CALL(*mock_, HandleClosed(1)).Times(1); tab = mock_->CreateTabWithUrl(GURL(url)); loop.RunFor(TestTimeouts::action_max_timeout_ms()); mock_->DestroyHostWindow(); } class ExternalTabUITestPopupEnabled : public ExternalTabUITest { public: ExternalTabUITestPopupEnabled() { launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking); } }; #if defined(OS_WIN) // http://crbug.com/61023 - Fails on one popular operating system. #define MAYBE_WindowDotOpen DISABLED_WindowDotOpen #define MAYBE_UserGestureTargetBlank DISABLED_UserGestureTargetBlank #else #define MAYBE_WindowDotOpen WindowDotOpen #define MAYBE_UserGestureTargetBlank UserGestureTargetBlank #endif // Testing AutomationMsg_AttachExternalTab callback from Chrome. // Open a popup window with window.open() call. The created popup window opens // another popup window (again using window.open() call). TEST_F(ExternalTabUITestPopupEnabled, MAYBE_WindowDotOpen) { TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); mock_->IgnoreFaviconNetworkRequest(); // Ignore navigation state changes. EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(testing::AnyNumber()); GURL main_url("http://placetogo.com/"); std::string main_html = "Main."; mock_->ServeHTMLData(1, main_url, main_html); EXPECT_CALL(*mock_, OnLoad(_)).Times(1); GURL popup1_url("http://placetogo.com/popup1.html"); std::string popup1_html = "Popup1."; mock_->ServeHTMLData(2, popup1_url, popup1_html); EXPECT_CALL(*mock_, OnLoad(_)).Times(1); GURL popup2_url("http://placetogo.com/popup2.html"); std::string popup2_html = "Popup2."; mock_->ServeHTMLData(3, popup2_url, popup2_html); EXPECT_CALL(*mock_, OnLoad(_)).Times(1) .WillOnce(QUIT_LOOP_SOON(&loop, 500)); DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN; HWND popup1_host = CreateWindowW(L"Button", L"popup1_host", style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); HWND popup2_host = CreateWindowW(L"Button", L"popup2_host", style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); EXPECT_CALL(*mock_, OnAttachExternalTab(_)) .Times(1) .WillOnce(testing::WithArgs<0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ConnectToExternalTab, popup1_host)))); EXPECT_CALL(*mock_, OnAttachExternalTab(_)) .Times(1) .WillOnce(testing::WithArgs<0>(testing::Invoke(CreateFunctor(mock_, &ExternalTabUITestMockClient::ConnectToExternalTab, popup2_host)))); mock_->CreateTabWithUrl(main_url); loop.RunFor(TestTimeouts::action_max_timeout_ms()); EXPECT_CALL(*mock_, HandleClosed(1)); EXPECT_CALL(*mock_, HandleClosed(2)); EXPECT_CALL(*mock_, HandleClosed(3)); mock_->DestroyHostWindow(); ::DestroyWindow(popup1_host); ::DestroyWindow(popup2_host); } // Open a new window by simulating a user gesture through keyboard. TEST_F(ExternalTabUITestPopupEnabled, MAYBE_UserGestureTargetBlank) { TimedMessageLoopRunner loop(MessageLoop::current()); ASSERT_THAT(mock_, testing::NotNull()); mock_->IgnoreFaviconNetworkRequest(); // Ignore navigation state changes. EXPECT_CALL(*mock_, OnNavigationStateChanged(_, _)) .Times(testing::AnyNumber()); EXPECT_CALL(*mock_, OnDidNavigate(_)).Times(testing::AnyNumber()); GURL main_url("http://placetogo.com/"); std::string main_html = "Hello" "Link"; mock_->ServeHTMLData(1, main_url, main_html); HWND foo_host = CreateWindowW(L"Button", L"foo_host", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL); testing::InSequence s; EXPECT_CALL(*mock_, OnLoad(_)) .WillOnce(testing::InvokeWithoutArgs(testing::CreateFunctor(mock_, &ExternalTabUITestMockClient::NavigateThroughUserGesture))); EXPECT_CALL(*mock_, OnAttachExternalTab(_)) .Times(1) .WillOnce(QUIT_LOOP_SOON(&loop, 500)); mock_->CreateTabWithUrl(main_url); loop.RunFor(TestTimeouts::action_max_timeout_ms()); EXPECT_CALL(*mock_, HandleClosed(1)); ::DestroyWindow(foo_host); mock_->DestroyHostWindow(); } #endif // defined(OS_WIN) // Flaky especially on Windows. See crbug.com/25039. TEST_F(AutomationProxyTest, FLAKY_AppModalDialogTest) { scoped_refptr browser(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser.get()); scoped_refptr tab(browser->GetTab(0)); ASSERT_TRUE(tab.get()); bool modal_dialog_showing = false; ui::DialogButton button = ui::DIALOG_BUTTON_NONE; EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_FALSE(modal_dialog_showing); EXPECT_EQ(ui::DIALOG_BUTTON_NONE, button); // Show a simple alert. std::string content = "data:text/html," ""; ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(GURL(content))); EXPECT_TRUE(automation()->WaitForAppModalDialog()); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_TRUE(modal_dialog_showing); EXPECT_EQ(ui::DIALOG_BUTTON_OK, button); // Test that clicking missing button fails graciously and does not close the // dialog. EXPECT_FALSE(automation()->ClickAppModalDialogButton( ui::DIALOG_BUTTON_CANCEL)); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_TRUE(modal_dialog_showing); // Now click OK, that should close the dialog. EXPECT_TRUE(automation()->ClickAppModalDialogButton( ui::DIALOG_BUTTON_OK)); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_FALSE(modal_dialog_showing); // Show a confirm dialog. content = "data:text/html," ""; ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(GURL(content))); EXPECT_TRUE(automation()->WaitForAppModalDialog()); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_TRUE(modal_dialog_showing); EXPECT_EQ(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, button); // Click OK. EXPECT_TRUE(automation()->ClickAppModalDialogButton(ui::DIALOG_BUTTON_OK)); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_FALSE(modal_dialog_showing); int result = -1; EXPECT_TRUE(tab->ExecuteAndExtractInt( std::wstring(), L"window.domAutomationController.send(result);", &result)); EXPECT_EQ(0, result); // Try again. ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(GURL(content))); EXPECT_TRUE(automation()->WaitForAppModalDialog()); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_TRUE(modal_dialog_showing); EXPECT_EQ(ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL, button); // Click Cancel this time. EXPECT_TRUE(automation()->ClickAppModalDialogButton( ui::DIALOG_BUTTON_CANCEL)); EXPECT_TRUE(automation()->GetShowingAppModalDialog(&modal_dialog_showing, &button)); EXPECT_FALSE(modal_dialog_showing); EXPECT_TRUE(tab->ExecuteAndExtractInt( std::wstring(), L"window.domAutomationController.send(result);", &result)); EXPECT_EQ(1, result); } class AutomationProxyTest5 : public UITest { protected: AutomationProxyTest5() { show_window_ = true; dom_automation_enabled_ = true; // We need to disable popup blocking to ensure that the RenderView // instance for the popup actually closes. launch_arguments_.AppendSwitch(switches::kDisablePopupBlocking); } }; TEST_F(AutomationProxyTest5, TestLifetimeOfDomAutomationController) { scoped_refptr window(automation()->GetBrowserWindow(0)); ASSERT_TRUE(window.get()); scoped_refptr tab(window->GetTab(0)); ASSERT_TRUE(tab.get()); FilePath filename(test_data_directory_); filename = filename.AppendASCII("dom_automation_test_with_popup.html"); ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(net::FilePathToFileURL(filename))); // Allow some time for the popup to show up and close. base::PlatformThread::Sleep(TestTimeouts::action_timeout_ms()); std::wstring expected(L"string"); std::wstring jscript = CreateJSString(L"\"" + expected + L"\""); std::wstring actual; ASSERT_TRUE(tab->ExecuteAndExtractString(L"", jscript, &actual)); ASSERT_EQ(expected, actual); } class AutomationProxySnapshotTest : public UITest { protected: AutomationProxySnapshotTest() { dom_automation_enabled_ = true; if (!snapshot_dir_.CreateUniqueTempDir()) ADD_FAILURE() << "Unable to create temporary directory"; else snapshot_path_ = snapshot_dir_.path().AppendASCII("snapshot.png"); } // Asserts that the given png file can be read and decoded into the given // bitmap. void AssertReadPNG(const FilePath& filename, std::string* data) { ASSERT_TRUE(file_util::PathExists(filename)); int64 size64; ASSERT_TRUE(file_util::GetFileSize(filename, &size64)); // Check that the file is not too big to read in (less than 100 MB). ASSERT_LT(size64, 1024 * 1024 * 100); // Read and decode image. int size = static_cast(size64); data->resize(size); int bytes_read = file_util::ReadFile(filename, &(*data)[0], size); ASSERT_EQ(size, bytes_read); } // Returns the file path for the directory for these tests appended with // the given relative path. FilePath GetTestFilePath(const std::string& relative_path) { FilePath filename(test_data_directory_); return filename.AppendASCII("automation_proxy_snapshot") .AppendASCII(relative_path); } GURL GetTestUrl(const std::string& relative_path, const std::string& query) { FilePath file_path = GetTestFilePath(relative_path); return ui_test_utils::GetFileUrlWithQuery(file_path, query); } FilePath snapshot_path_; ScopedTempDir snapshot_dir_; }; // Tests that taking a snapshot when the content is larger than the view // produces a snapshot equal to the content size. TEST_F(AutomationProxySnapshotTest, ContentLargerThanView) { const char kReferenceMd5[] = "3d594850fd25cb116338cb3610afe18e"; scoped_refptr browser(automation()->GetBrowserWindow(0)); ASSERT_TRUE(browser.get()); scoped_refptr tab(browser->GetTab(0)); ASSERT_TRUE(tab.get()); ASSERT_EQ(AUTOMATION_MSG_NAVIGATION_SUCCESS, tab->NavigateToURL(GetTestUrl("set_size.html", "2000,2500"))); ASSERT_TRUE(tab->CaptureEntirePageAsPNG(snapshot_path_)); std::string data; ASSERT_NO_FATAL_FAILURE(AssertReadPNG(snapshot_path_, &data)); EXPECT_STREQ(kReferenceMd5, base::MD5String(data).c_str()); if (CommandLine::ForCurrentProcess()->HasSwitch("dump-test-image")) { FilePath path(FILE_PATH_LITERAL("snapshot.png")); EXPECT_EQ(file_util::WriteFile(path, &data[0], data.length()), static_cast(data.length())); } }