1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/browser_action_test_util.h"
6 #include "chrome/browser/extensions/extension_action.h"
7 #include "chrome/browser/extensions/extension_action_manager.h"
8 #include "chrome/browser/extensions/extension_apitest.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_tab_util.h"
11 #include "chrome/browser/sessions/session_tab_helper.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/browser_finder.h"
15 #include "chrome/browser/ui/browser_list.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/test/base/interactive_test_utils.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/notification_service.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/common/permissions/permissions_data.h"
26 #include "extensions/test/extension_test_message_listener.h"
27 #include "extensions/test/result_catcher.h"
30 #include "ui/views/win/hwnd_util.h"
33 namespace extensions {
36 // chrome.browserAction API tests that interact with the UI in such a way that
37 // they cannot be run concurrently (i.e. openPopup API tests that require the
38 // window be focused/active).
39 class BrowserActionInteractiveTest : public ExtensionApiTest {
41 BrowserActionInteractiveTest() {}
42 ~BrowserActionInteractiveTest() override {}
45 // Function to control whether to run popup tests for the current platform.
46 // These tests require RunExtensionSubtest to work as expected and the browser
47 // window to able to be made active automatically. Returns false for platforms
48 // where these conditions are not met.
49 bool ShouldRunPopupTest() {
50 // TODO(justinlin): http://crbug.com/177163
51 #if defined(OS_WIN) && !defined(NDEBUG)
53 #elif defined(OS_MACOSX)
54 // TODO(justinlin): Browser window do not become active on Mac even when
55 // Activate() is called on them. Enable when/if it's possible to fix.
62 // Open an extension popup via the chrome.browserAction.openPopup API.
63 void OpenExtensionPopupViaAPI() {
64 // Setup the notification observer to wait for the popup to finish loading.
65 content::WindowedNotificationObserver frame_observer(
66 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
67 content::NotificationService::AllSources());
68 // Show first popup in first window and expect it to have loaded.
69 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
70 "open_popup_succeeds.html")) << message_;
71 frame_observer.Wait();
72 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
76 // Tests opening a popup using the chrome.browserAction.openPopup API. This test
77 // opens a popup in the starting window, closes the popup, creates a new window
78 // and opens a popup in the new window. Both popups should succeed in opening.
79 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
80 if (!ShouldRunPopupTest())
83 BrowserActionTestUtil browserActionBar = BrowserActionTestUtil(browser());
84 // Setup extension message listener to wait for javascript to finish running.
85 ExtensionTestMessageListener listener("ready", true);
87 OpenExtensionPopupViaAPI();
88 EXPECT_TRUE(browserActionBar.HasPopup());
89 browserActionBar.HidePopup();
92 EXPECT_TRUE(listener.WaitUntilSatisfied());
93 Browser* new_browser = NULL;
95 content::WindowedNotificationObserver frame_observer(
96 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
97 content::NotificationService::AllSources());
99 new_browser = chrome::FindBrowserWithWebContents(
100 browser()->OpenURL(content::OpenURLParams(
101 GURL("about:"), content::Referrer(), NEW_WINDOW,
102 ui::PAGE_TRANSITION_TYPED, false)));
104 // Hide all the buttons to test that it opens even when browser action is
105 // in the overflow bucket.
106 // TODO(justinlin): Implement for other platforms.
107 browserActionBar.SetIconVisibilityCount(0);
109 frame_observer.Wait();
112 EXPECT_TRUE(new_browser != NULL);
114 // Flaky on non-aura linux http://crbug.com/309749
115 #if !(defined(OS_LINUX) && !defined(USE_AURA))
116 ResultCatcher catcher;
118 content::WindowedNotificationObserver frame_observer(
119 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
120 content::NotificationService::AllSources());
121 // Show second popup in new window.
123 frame_observer.Wait();
124 EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
126 ASSERT_TRUE(catcher.GetNextResult()) << message_;
130 // Tests opening a popup in an incognito window.
131 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
132 if (!ShouldRunPopupTest())
135 content::WindowedNotificationObserver frame_observer(
136 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
137 content::NotificationService::AllSources());
138 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
139 "open_popup_succeeds.html",
140 kFlagEnableIncognito | kFlagUseIncognito))
142 frame_observer.Wait();
143 // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
144 // have popups if there is any popup open.
145 #if !(defined(OS_LINUX) && !defined(USE_AURA))
146 // Starting window does not have a popup.
147 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
149 // Incognito window should have a popup.
150 EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance(
151 chrome::GetActiveDesktop())->GetLastActive()).HasPopup());
154 #if defined(OS_LINUX)
155 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups
157 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups
159 // Tests if there is already a popup open (by a user click or otherwise), that
160 // the openPopup API does not override it.
161 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
162 MAYBE_TestOpenPopupDoesNotCloseOtherPopups) {
163 if (!ShouldRunPopupTest())
166 // Load a first extension that can open a popup.
167 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
168 "browser_action/popup")));
169 const Extension* extension = GetSingleLoadedExtension();
170 ASSERT_TRUE(extension) << message_;
172 ExtensionTestMessageListener listener("ready", true);
173 // Load the test extension which will do nothing except notifyPass() to
174 // return control here.
175 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
176 "open_popup_fails.html")) << message_;
177 EXPECT_TRUE(listener.WaitUntilSatisfied());
179 content::WindowedNotificationObserver frame_observer(
180 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
181 content::NotificationService::AllSources());
182 // Open popup in the first extension.
183 BrowserActionTestUtil(browser()).Press(0);
184 frame_observer.Wait();
185 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
187 ResultCatcher catcher;
188 // Return control to javascript to validate that opening a popup fails now.
190 ASSERT_TRUE(catcher.GetNextResult()) << message_;
193 // Test that openPopup does not grant tab permissions like for browser action
194 // clicks if the activeTab permission is set.
195 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
196 TestOpenPopupDoesNotGrantTabPermissions) {
197 if (!ShouldRunPopupTest())
200 OpenExtensionPopupViaAPI();
201 ExtensionService* service = extensions::ExtensionSystem::Get(
202 browser()->profile())->extension_service();
204 service->GetExtensionById(last_loaded_extension_id(), false)
206 ->HasAPIPermissionForTab(
207 SessionTabHelper::IdForTab(
208 browser()->tab_strip_model()->GetActiveWebContents()),
209 APIPermission::kTab));
212 // Test that the extension popup is closed when the browser window is clicked.
213 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup1) {
214 if (!ShouldRunPopupTest())
217 // Open an extension popup via the chrome.browserAction.openPopup API.
218 content::WindowedNotificationObserver frame_observer(
219 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
220 content::NotificationService::AllSources());
221 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
222 "open_popup_succeeds.html")) << message_;
223 frame_observer.Wait();
224 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
226 // Click on the omnibox to close the extension popup.
227 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
228 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
231 // Test that the extension popup is closed when the browser window is clicked.
232 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup2) {
233 if (!ShouldRunPopupTest())
236 // Load a first extension that can open a popup.
237 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
238 "browser_action/popup")));
239 const Extension* extension = GetSingleLoadedExtension();
240 ASSERT_TRUE(extension) << message_;
242 // Open an extension popup by clicking the browser action button.
243 content::WindowedNotificationObserver frame_observer(
244 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
245 content::NotificationService::AllSources());
246 BrowserActionTestUtil(browser()).Press(0);
247 frame_observer.Wait();
248 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
250 // Click on the omnibox to close the extension popup.
251 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
252 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
255 // Test that the extension popup is closed on browser tab switches.
256 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
257 if (!ShouldRunPopupTest())
260 // Add a second tab to the browser and open an extension popup.
261 chrome::NewTab(browser());
262 ASSERT_EQ(2, browser()->tab_strip_model()->count());
263 OpenExtensionPopupViaAPI();
265 // Press CTRL+TAB to change active tabs, the extension popup should close.
266 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
267 browser(), ui::VKEY_TAB, true, false, false, false));
268 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
271 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
272 DeleteBrowserActionWithPopupOpen) {
273 if (!ShouldRunPopupTest())
276 // First, we open a popup.
277 OpenExtensionPopupViaAPI();
278 BrowserActionTestUtil browser_action_test_util(browser());
279 EXPECT_TRUE(browser_action_test_util.HasPopup());
281 // Then, find the extension that created it.
282 content::WebContents* active_web_contents =
283 browser()->tab_strip_model()->GetActiveWebContents();
284 ASSERT_TRUE(active_web_contents);
285 GURL url = active_web_contents->GetLastCommittedURL();
286 const Extension* extension = ExtensionRegistry::Get(browser()->profile())->
287 enabled_extensions().GetExtensionOrAppByURL(url);
288 ASSERT_TRUE(extension);
290 // Finally, uninstall the extension, which causes the view to be deleted and
291 // the popup to go away. This should not crash.
292 UninstallExtension(extension->id());
293 EXPECT_FALSE(browser_action_test_util.HasPopup());
296 #if defined(TOOLKIT_VIEWS)
297 // Test closing the browser while inspecting an extension popup with dev tools.
298 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, CloseBrowserWithDevTools) {
299 if (!ShouldRunPopupTest())
302 // Load a first extension that can open a popup.
303 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
304 "browser_action/popup")));
305 const Extension* extension = GetSingleLoadedExtension();
306 ASSERT_TRUE(extension) << message_;
308 // Open an extension popup by clicking the browser action button.
309 content::WindowedNotificationObserver frame_observer(
310 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
311 content::NotificationService::AllSources());
312 BrowserActionTestUtil(browser()).InspectPopup(0);
313 frame_observer.Wait();
314 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
316 // Close the browser window, this should not cause a crash.
317 chrome::CloseWindow(browser());
319 #endif // TOOLKIT_VIEWS
322 // Test that forcibly closing the browser and popup HWND does not cause a crash.
323 // http://crbug.com/400646
324 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
325 DISABLED_DestroyHWNDDoesNotCrash) {
326 if (!ShouldRunPopupTest())
329 OpenExtensionPopupViaAPI();
330 BrowserActionTestUtil test_util(browser());
331 const gfx::NativeView view = test_util.GetPopupNativeView();
332 EXPECT_NE(static_cast<gfx::NativeView>(NULL), view);
333 const HWND hwnd = views::HWNDForNativeView(view);
335 views::HWNDForNativeView(browser()->window()->GetNativeWindow()));
336 EXPECT_EQ(TRUE, ::IsWindow(hwnd));
338 // Create a new browser window to prevent the message loop from terminating.
339 Browser* new_browser = chrome::FindBrowserWithWebContents(
340 browser()->OpenURL(content::OpenURLParams(
341 GURL("about:"), content::Referrer(), NEW_WINDOW,
342 ui::PAGE_TRANSITION_TYPED, false)));
344 // Forcibly closing the browser HWND should not cause a crash.
345 EXPECT_EQ(TRUE, ::CloseWindow(hwnd));
346 EXPECT_EQ(TRUE, ::DestroyWindow(hwnd));
347 EXPECT_EQ(FALSE, ::IsWindow(hwnd));
352 } // namespace extensions