• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
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_system.h"
22 #include "extensions/common/permissions/permissions_data.h"
23 
24 #if defined(OS_WIN)
25 #include "ui/views/win/hwnd_util.h"
26 #endif
27 
28 namespace extensions {
29 namespace {
30 
31 // chrome.browserAction API tests that interact with the UI in such a way that
32 // they cannot be run concurrently (i.e. openPopup API tests that require the
33 // window be focused/active).
34 class BrowserActionInteractiveTest : public ExtensionApiTest {
35  public:
BrowserActionInteractiveTest()36   BrowserActionInteractiveTest() {}
~BrowserActionInteractiveTest()37   virtual ~BrowserActionInteractiveTest() {}
38 
39  protected:
40   // Function to control whether to run popup tests for the current platform.
41   // These tests require RunExtensionSubtest to work as expected and the browser
42   // window to able to be made active automatically. Returns false for platforms
43   // where these conditions are not met.
ShouldRunPopupTest()44   bool ShouldRunPopupTest() {
45     // TODO(justinlin): http://crbug.com/177163
46 #if defined(OS_WIN) && !defined(NDEBUG)
47     return false;
48 #elif defined(OS_MACOSX)
49     // TODO(justinlin): Browser window do not become active on Mac even when
50     // Activate() is called on them. Enable when/if it's possible to fix.
51     return false;
52 #else
53     return true;
54 #endif
55   }
56 
57   // Open an extension popup via the chrome.browserAction.openPopup API.
OpenExtensionPopupViaAPI()58   void OpenExtensionPopupViaAPI() {
59     // Setup the notification observer to wait for the popup to finish loading.
60     content::WindowedNotificationObserver frame_observer(
61         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
62         content::NotificationService::AllSources());
63     // Show first popup in first window and expect it to have loaded.
64     ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
65                                     "open_popup_succeeds.html")) << message_;
66     frame_observer.Wait();
67     EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
68   }
69 };
70 
71 // Tests opening a popup using the chrome.browserAction.openPopup API. This test
72 // opens a popup in the starting window, closes the popup, creates a new window
73 // and opens a popup in the new window. Both popups should succeed in opening.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,TestOpenPopup)74 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
75   if (!ShouldRunPopupTest())
76     return;
77 
78   BrowserActionTestUtil browserActionBar = BrowserActionTestUtil(browser());
79   // Setup extension message listener to wait for javascript to finish running.
80   ExtensionTestMessageListener listener("ready", true);
81   {
82     OpenExtensionPopupViaAPI();
83     EXPECT_TRUE(browserActionBar.HasPopup());
84     browserActionBar.HidePopup();
85   }
86 
87   EXPECT_TRUE(listener.WaitUntilSatisfied());
88   Browser* new_browser = NULL;
89   {
90     content::WindowedNotificationObserver frame_observer(
91         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
92         content::NotificationService::AllSources());
93     // Open a new window.
94     new_browser = chrome::FindBrowserWithWebContents(
95         browser()->OpenURL(content::OpenURLParams(
96             GURL("about:"), content::Referrer(), NEW_WINDOW,
97             content::PAGE_TRANSITION_TYPED, false)));
98 #if defined(OS_WIN)
99     // Hide all the buttons to test that it opens even when browser action is
100     // in the overflow bucket.
101     // TODO(justinlin): Implement for other platforms.
102     browserActionBar.SetIconVisibilityCount(0);
103 #endif
104     frame_observer.Wait();
105   }
106 
107   EXPECT_TRUE(new_browser != NULL);
108 
109 // Flaky on non-aura linux http://crbug.com/309749
110 #if !(defined(OS_LINUX) && !defined(USE_AURA))
111   ResultCatcher catcher;
112   {
113     content::WindowedNotificationObserver frame_observer(
114         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
115         content::NotificationService::AllSources());
116     // Show second popup in new window.
117     listener.Reply("");
118     frame_observer.Wait();
119     EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
120   }
121   ASSERT_TRUE(catcher.GetNextResult()) << message_;
122 #endif
123 }
124 
125 // Tests opening a popup in an incognito window.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,TestOpenPopupIncognito)126 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
127   if (!ShouldRunPopupTest())
128     return;
129 
130   content::WindowedNotificationObserver frame_observer(
131       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
132       content::NotificationService::AllSources());
133   ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
134                                   "open_popup_succeeds.html",
135                                   kFlagEnableIncognito | kFlagUseIncognito))
136       << message_;
137   frame_observer.Wait();
138   // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
139   // have popups if there is any popup open.
140 #if !(defined(OS_LINUX) && !defined(USE_AURA))
141   // Starting window does not have a popup.
142   EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
143 #endif
144   // Incognito window should have a popup.
145   EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance(
146       chrome::GetActiveDesktop())->GetLastActive()).HasPopup());
147 }
148 
149 #if defined(OS_LINUX)
150 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups
151 #else
152 #define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups
153 #endif
154 // Tests if there is already a popup open (by a user click or otherwise), that
155 // the openPopup API does not override it.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,MAYBE_TestOpenPopupDoesNotCloseOtherPopups)156 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
157                        MAYBE_TestOpenPopupDoesNotCloseOtherPopups) {
158   if (!ShouldRunPopupTest())
159     return;
160 
161   // Load a first extension that can open a popup.
162   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
163       "browser_action/popup")));
164   const Extension* extension = GetSingleLoadedExtension();
165   ASSERT_TRUE(extension) << message_;
166 
167   ExtensionTestMessageListener listener("ready", true);
168   // Load the test extension which will do nothing except notifyPass() to
169   // return control here.
170   ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
171                                   "open_popup_fails.html")) << message_;
172   EXPECT_TRUE(listener.WaitUntilSatisfied());
173 
174   content::WindowedNotificationObserver frame_observer(
175       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
176       content::NotificationService::AllSources());
177   // Open popup in the first extension.
178   BrowserActionTestUtil(browser()).Press(0);
179   frame_observer.Wait();
180   EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
181 
182   ResultCatcher catcher;
183   // Return control to javascript to validate that opening a popup fails now.
184   listener.Reply("");
185   ASSERT_TRUE(catcher.GetNextResult()) << message_;
186 }
187 
188 // Test that openPopup does not grant tab permissions like for browser action
189 // clicks if the activeTab permission is set.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,TestOpenPopupDoesNotGrantTabPermissions)190 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
191                        TestOpenPopupDoesNotGrantTabPermissions) {
192   if (!ShouldRunPopupTest())
193     return;
194 
195   OpenExtensionPopupViaAPI();
196   ExtensionService* service = extensions::ExtensionSystem::Get(
197       browser()->profile())->extension_service();
198   ASSERT_FALSE(
199       service->GetExtensionById(last_loaded_extension_id(), false)
200           ->permissions_data()
201           ->HasAPIPermissionForTab(
202               SessionID::IdForTab(
203                   browser()->tab_strip_model()->GetActiveWebContents()),
204               APIPermission::kTab));
205 }
206 
207 // Test that the extension popup is closed when the browser window is clicked.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,BrowserClickClosesPopup1)208 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup1) {
209   if (!ShouldRunPopupTest())
210     return;
211 
212   // Open an extension popup via the chrome.browserAction.openPopup API.
213   content::WindowedNotificationObserver frame_observer(
214       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
215       content::NotificationService::AllSources());
216   ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
217                                   "open_popup_succeeds.html")) << message_;
218   frame_observer.Wait();
219   EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
220 
221   // Click on the omnibox to close the extension popup.
222   ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
223   EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
224 }
225 
226 // Test that the extension popup is closed when the browser window is clicked.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,BrowserClickClosesPopup2)227 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup2) {
228   if (!ShouldRunPopupTest())
229     return;
230 
231   // Load a first extension that can open a popup.
232   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
233       "browser_action/popup")));
234   const Extension* extension = GetSingleLoadedExtension();
235   ASSERT_TRUE(extension) << message_;
236 
237   // Open an extension popup by clicking the browser action button.
238   content::WindowedNotificationObserver frame_observer(
239       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
240       content::NotificationService::AllSources());
241   BrowserActionTestUtil(browser()).Press(0);
242   frame_observer.Wait();
243   EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
244 
245   // Click on the omnibox to close the extension popup.
246   ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
247   EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
248 }
249 
250 // Test that the extension popup is closed on browser tab switches.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,TabSwitchClosesPopup)251 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
252   if (!ShouldRunPopupTest())
253     return;
254 
255   // Add a second tab to the browser and open an extension popup.
256   chrome::NewTab(browser());
257   ASSERT_EQ(2, browser()->tab_strip_model()->count());
258   OpenExtensionPopupViaAPI();
259 
260   // Press CTRL+TAB to change active tabs, the extension popup should close.
261   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
262       browser(), ui::VKEY_TAB, true, false, false, false));
263   EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
264 }
265 
266 #if defined(TOOLKIT_VIEWS)
267 // Test closing the browser while inspecting an extension popup with dev tools.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,CloseBrowserWithDevTools)268 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, CloseBrowserWithDevTools) {
269   if (!ShouldRunPopupTest())
270     return;
271 
272   // Load a first extension that can open a popup.
273   ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
274       "browser_action/popup")));
275   const Extension* extension = GetSingleLoadedExtension();
276   ASSERT_TRUE(extension) << message_;
277 
278   // Open an extension popup by clicking the browser action button.
279   content::WindowedNotificationObserver frame_observer(
280       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
281       content::NotificationService::AllSources());
282   BrowserActionTestUtil(browser()).InspectPopup(0);
283   frame_observer.Wait();
284   EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
285 
286   // Close the browser window, this should not cause a crash.
287   chrome::CloseWindow(browser());
288 }
289 #endif  // TOOLKIT_VIEWS
290 
291 #if defined(OS_WIN)
292 // Test that forcibly closing the browser and popup HWND does not cause a crash.
IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,DestroyHWNDDoesNotCrash)293 IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, DestroyHWNDDoesNotCrash) {
294   if (!ShouldRunPopupTest())
295     return;
296 
297   OpenExtensionPopupViaAPI();
298   BrowserActionTestUtil test_util(browser());
299   const gfx::NativeView view = test_util.GetPopupNativeView();
300   EXPECT_NE(static_cast<gfx::NativeView>(NULL), view);
301   const HWND hwnd = views::HWNDForNativeView(view);
302   EXPECT_EQ(hwnd,
303             views::HWNDForNativeView(browser()->window()->GetNativeWindow()));
304   EXPECT_EQ(TRUE, ::IsWindow(hwnd));
305 
306   // Create a new browser window to prevent the message loop from terminating.
307   Browser* new_browser = chrome::FindBrowserWithWebContents(
308       browser()->OpenURL(content::OpenURLParams(
309           GURL("about:"), content::Referrer(), NEW_WINDOW,
310           content::PAGE_TRANSITION_TYPED, false)));
311 
312   // Forcibly closing the browser HWND should not cause a crash.
313   EXPECT_EQ(TRUE, ::CloseWindow(hwnd));
314   EXPECT_EQ(TRUE, ::DestroyWindow(hwnd));
315   EXPECT_EQ(FALSE, ::IsWindow(hwnd));
316 }
317 #endif  // OS_WIN
318 
319 }  // namespace
320 }  // namespace extensions
321