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/extensions/extension_test_message_listener.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"
28 #include "ui/views/win/hwnd_util.h"
31 namespace extensions {
34 // chrome.browserAction API tests that interact with the UI in such a way that
35 // they cannot be run concurrently (i.e. openPopup API tests that require the
36 // window be focused/active).
37 class BrowserActionInteractiveTest : public ExtensionApiTest {
39 BrowserActionInteractiveTest() {}
40 virtual ~BrowserActionInteractiveTest() {}
43 // Function to control whether to run popup tests for the current platform.
44 // These tests require RunExtensionSubtest to work as expected and the browser
45 // window to able to be made active automatically. Returns false for platforms
46 // where these conditions are not met.
47 bool ShouldRunPopupTest() {
48 // TODO(justinlin): http://crbug.com/177163
49 #if defined(OS_WIN) && !defined(NDEBUG)
51 #elif defined(OS_MACOSX)
52 // TODO(justinlin): Browser window do not become active on Mac even when
53 // Activate() is called on them. Enable when/if it's possible to fix.
60 // Open an extension popup via the chrome.browserAction.openPopup API.
61 void OpenExtensionPopupViaAPI() {
62 // Setup the notification observer to wait for the popup to finish loading.
63 content::WindowedNotificationObserver frame_observer(
64 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
65 content::NotificationService::AllSources());
66 // Show first popup in first window and expect it to have loaded.
67 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
68 "open_popup_succeeds.html")) << message_;
69 frame_observer.Wait();
70 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
74 // Tests opening a popup using the chrome.browserAction.openPopup API. This test
75 // opens a popup in the starting window, closes the popup, creates a new window
76 // and opens a popup in the new window. Both popups should succeed in opening.
77 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
78 if (!ShouldRunPopupTest())
81 BrowserActionTestUtil browserActionBar = BrowserActionTestUtil(browser());
82 // Setup extension message listener to wait for javascript to finish running.
83 ExtensionTestMessageListener listener("ready", true);
85 OpenExtensionPopupViaAPI();
86 EXPECT_TRUE(browserActionBar.HasPopup());
87 browserActionBar.HidePopup();
90 EXPECT_TRUE(listener.WaitUntilSatisfied());
91 Browser* new_browser = NULL;
93 content::WindowedNotificationObserver frame_observer(
94 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
95 content::NotificationService::AllSources());
97 new_browser = chrome::FindBrowserWithWebContents(
98 browser()->OpenURL(content::OpenURLParams(
99 GURL("about:"), content::Referrer(), NEW_WINDOW,
100 content::PAGE_TRANSITION_TYPED, false)));
102 // Hide all the buttons to test that it opens even when browser action is
103 // in the overflow bucket.
104 // TODO(justinlin): Implement for other platforms.
105 browserActionBar.SetIconVisibilityCount(0);
107 frame_observer.Wait();
110 EXPECT_TRUE(new_browser != NULL);
112 // Flaky on non-aura linux http://crbug.com/309749
113 #if !(defined(OS_LINUX) && !defined(USE_AURA))
114 ResultCatcher catcher;
116 content::WindowedNotificationObserver frame_observer(
117 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
118 content::NotificationService::AllSources());
119 // Show second popup in new window.
121 frame_observer.Wait();
122 EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
124 ASSERT_TRUE(catcher.GetNextResult()) << message_;
128 // Tests opening a popup in an incognito window.
129 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
130 if (!ShouldRunPopupTest())
133 content::WindowedNotificationObserver frame_observer(
134 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
135 content::NotificationService::AllSources());
136 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
137 "open_popup_succeeds.html",
138 kFlagEnableIncognito | kFlagUseIncognito))
140 frame_observer.Wait();
141 // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
142 // have popups if there is any popup open.
143 #if !(defined(OS_LINUX) && !defined(USE_AURA))
144 // Starting window does not have a popup.
145 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
147 // Incognito window should have a popup.
148 EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance(
149 chrome::GetActiveDesktop())->GetLastActive()).HasPopup());
152 #if defined(OS_LINUX)
153 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups
155 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups
157 // Tests if there is already a popup open (by a user click or otherwise), that
158 // the openPopup API does not override it.
159 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
160 MAYBE_TestOpenPopupDoesNotCloseOtherPopups) {
161 if (!ShouldRunPopupTest())
164 // Load a first extension that can open a popup.
165 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
166 "browser_action/popup")));
167 const Extension* extension = GetSingleLoadedExtension();
168 ASSERT_TRUE(extension) << message_;
170 ExtensionTestMessageListener listener("ready", true);
171 // Load the test extension which will do nothing except notifyPass() to
172 // return control here.
173 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
174 "open_popup_fails.html")) << message_;
175 EXPECT_TRUE(listener.WaitUntilSatisfied());
177 content::WindowedNotificationObserver frame_observer(
178 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
179 content::NotificationService::AllSources());
180 // Open popup in the first extension.
181 BrowserActionTestUtil(browser()).Press(0);
182 frame_observer.Wait();
183 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
185 ResultCatcher catcher;
186 // Return control to javascript to validate that opening a popup fails now.
188 ASSERT_TRUE(catcher.GetNextResult()) << message_;
191 // Test that openPopup does not grant tab permissions like for browser action
192 // clicks if the activeTab permission is set.
193 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
194 TestOpenPopupDoesNotGrantTabPermissions) {
195 if (!ShouldRunPopupTest())
198 OpenExtensionPopupViaAPI();
199 ExtensionService* service = extensions::ExtensionSystem::Get(
200 browser()->profile())->extension_service();
202 service->GetExtensionById(last_loaded_extension_id(), false)
204 ->HasAPIPermissionForTab(
206 browser()->tab_strip_model()->GetActiveWebContents()),
207 APIPermission::kTab));
210 // Test that the extension popup is closed when the browser window is clicked.
211 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup1) {
212 if (!ShouldRunPopupTest())
215 // Open an extension popup via the chrome.browserAction.openPopup API.
216 content::WindowedNotificationObserver frame_observer(
217 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
218 content::NotificationService::AllSources());
219 ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
220 "open_popup_succeeds.html")) << message_;
221 frame_observer.Wait();
222 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
224 // Click on the omnibox to close the extension popup.
225 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
226 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
229 // Test that the extension popup is closed when the browser window is clicked.
230 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup2) {
231 if (!ShouldRunPopupTest())
234 // Load a first extension that can open a popup.
235 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
236 "browser_action/popup")));
237 const Extension* extension = GetSingleLoadedExtension();
238 ASSERT_TRUE(extension) << message_;
240 // Open an extension popup by clicking the browser action button.
241 content::WindowedNotificationObserver frame_observer(
242 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
243 content::NotificationService::AllSources());
244 BrowserActionTestUtil(browser()).Press(0);
245 frame_observer.Wait();
246 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
248 // Click on the omnibox to close the extension popup.
249 ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
250 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
253 // Test that the extension popup is closed on browser tab switches.
254 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
255 if (!ShouldRunPopupTest())
258 // Add a second tab to the browser and open an extension popup.
259 chrome::NewTab(browser());
260 ASSERT_EQ(2, browser()->tab_strip_model()->count());
261 OpenExtensionPopupViaAPI();
263 // Press CTRL+TAB to change active tabs, the extension popup should close.
264 ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
265 browser(), ui::VKEY_TAB, true, false, false, false));
266 EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
269 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
270 DeleteBrowserActionWithPopupOpen) {
271 if (!ShouldRunPopupTest())
274 // First, we open a popup.
275 OpenExtensionPopupViaAPI();
276 BrowserActionTestUtil browser_action_test_util(browser());
277 EXPECT_TRUE(browser_action_test_util.HasPopup());
279 // Then, find the extension that created it.
280 content::WebContents* active_web_contents =
281 browser()->tab_strip_model()->GetActiveWebContents();
282 ASSERT_TRUE(active_web_contents);
283 GURL url = active_web_contents->GetLastCommittedURL();
284 const Extension* extension = ExtensionRegistry::Get(browser()->profile())->
285 enabled_extensions().GetExtensionOrAppByURL(url);
286 ASSERT_TRUE(extension);
288 // Finally, uninstall the extension, which causes the view to be deleted and
289 // the popup to go away. This should not crash.
290 UninstallExtension(extension->id());
291 EXPECT_FALSE(browser_action_test_util.HasPopup());
294 #if defined(TOOLKIT_VIEWS)
295 // Test closing the browser while inspecting an extension popup with dev tools.
296 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, CloseBrowserWithDevTools) {
297 if (!ShouldRunPopupTest())
300 // Load a first extension that can open a popup.
301 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
302 "browser_action/popup")));
303 const Extension* extension = GetSingleLoadedExtension();
304 ASSERT_TRUE(extension) << message_;
306 // Open an extension popup by clicking the browser action button.
307 content::WindowedNotificationObserver frame_observer(
308 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
309 content::NotificationService::AllSources());
310 BrowserActionTestUtil(browser()).InspectPopup(0);
311 frame_observer.Wait();
312 EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
314 // Close the browser window, this should not cause a crash.
315 chrome::CloseWindow(browser());
317 #endif // TOOLKIT_VIEWS
320 // Test that forcibly closing the browser and popup HWND does not cause a crash.
321 // http://crbug.com/400646
322 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
323 DISABLED_DestroyHWNDDoesNotCrash) {
324 if (!ShouldRunPopupTest())
327 OpenExtensionPopupViaAPI();
328 BrowserActionTestUtil test_util(browser());
329 const gfx::NativeView view = test_util.GetPopupNativeView();
330 EXPECT_NE(static_cast<gfx::NativeView>(NULL), view);
331 const HWND hwnd = views::HWNDForNativeView(view);
333 views::HWNDForNativeView(browser()->window()->GetNativeWindow()));
334 EXPECT_EQ(TRUE, ::IsWindow(hwnd));
336 // Create a new browser window to prevent the message loop from terminating.
337 Browser* new_browser = chrome::FindBrowserWithWebContents(
338 browser()->OpenURL(content::OpenURLParams(
339 GURL("about:"), content::Referrer(), NEW_WINDOW,
340 content::PAGE_TRANSITION_TYPED, false)));
342 // Forcibly closing the browser HWND should not cause a crash.
343 EXPECT_EQ(TRUE, ::CloseWindow(hwnd));
344 EXPECT_EQ(TRUE, ::DestroyWindow(hwnd));
345 EXPECT_EQ(FALSE, ::IsWindow(hwnd));
350 } // namespace extensions