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_system.h"
11#include "chrome/browser/extensions/extension_tab_util.h"
12#include "chrome/browser/extensions/extension_test_message_listener.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/tabs/tab_strip_model.h"
17#include "chrome/test/base/interactive_test_utils.h"
18#include "chrome/test/base/ui_test_utils.h"
19#include "content/public/browser/notification_service.h"
20#include "content/public/browser/web_contents.h"
21#include "extensions/common/permissions/permissions_data.h"
22
23namespace extensions {
24namespace {
25
26// chrome.browserAction API tests that interact with the UI in such a way that
27// they cannot be run concurrently (i.e. openPopup API tests that require the
28// window be focused/active).
29class BrowserActionInteractiveTest : public ExtensionApiTest {
30 public:
31  BrowserActionInteractiveTest() {}
32  virtual ~BrowserActionInteractiveTest() {}
33
34 protected:
35  // Function to control whether to run popup tests for the current platform.
36  // These tests require RunExtensionSubtest to work as expected and the browser
37  // window to able to be made active automatically. Returns false for platforms
38  // where these conditions are not met.
39  bool ShouldRunPopupTest() {
40    // TODO(justinlin): http://crbug.com/177163
41#if defined(OS_WIN) && !defined(NDEBUG)
42    return false;
43#elif defined(OS_MACOSX)
44    // TODO(justinlin): Browser window do not become active on Mac even when
45    // Activate() is called on them. Enable when/if it's possible to fix.
46    return false;
47#else
48    return true;
49#endif
50  }
51};
52
53// Tests opening a popup using the chrome.browserAction.openPopup API. This test
54// opens a popup in the starting window, closes the popup, creates a new window
55// and opens a popup in the new window. Both popups should succeed in opening.
56IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopup) {
57  if (!ShouldRunPopupTest())
58    return;
59
60  BrowserActionTestUtil browserActionBar = BrowserActionTestUtil(browser());
61  // Setup extension message listener to wait for javascript to finish running.
62  ExtensionTestMessageListener listener("ready", true);
63  {
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(browserActionBar.HasPopup());
73    browserActionBar.HidePopup();
74  }
75
76  EXPECT_TRUE(listener.WaitUntilSatisfied());
77  Browser* new_browser = NULL;
78  {
79    content::WindowedNotificationObserver frame_observer(
80        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
81        content::NotificationService::AllSources());
82    // Open a new window.
83    new_browser = chrome::FindBrowserWithWebContents(
84        browser()->OpenURL(content::OpenURLParams(
85            GURL("about:"), content::Referrer(), NEW_WINDOW,
86            content::PAGE_TRANSITION_TYPED, false)));
87#if defined(OS_WIN)
88    // Hide all the buttons to test that it opens even when browser action is
89    // in the overflow bucket.
90    // TODO(justinlin): Implement for other platforms.
91    browserActionBar.SetIconVisibilityCount(0);
92#endif
93    frame_observer.Wait();
94  }
95
96  EXPECT_TRUE(new_browser != NULL);
97
98// Flaky on non-aura linux http://crbug.com/309749
99#if !(defined(OS_LINUX) && !defined(USE_AURA))
100  ResultCatcher catcher;
101  {
102    content::WindowedNotificationObserver frame_observer(
103        content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
104        content::NotificationService::AllSources());
105    // Show second popup in new window.
106    listener.Reply("");
107    frame_observer.Wait();
108    EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup());
109  }
110  ASSERT_TRUE(catcher.GetNextResult()) << message_;
111#endif
112}
113
114// Tests opening a popup in an incognito window.
115IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TestOpenPopupIncognito) {
116  if (!ShouldRunPopupTest())
117    return;
118
119  content::WindowedNotificationObserver frame_observer(
120      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
121      content::NotificationService::AllSources());
122  ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
123                                  "open_popup_succeeds.html",
124                                  kFlagEnableIncognito | kFlagUseIncognito))
125      << message_;
126  frame_observer.Wait();
127  // Non-Aura Linux uses a singleton for the popup, so it looks like all windows
128  // have popups if there is any popup open.
129#if !(defined(OS_LINUX) && !defined(USE_AURA))
130  // Starting window does not have a popup.
131  EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
132#endif
133  // Incognito window should have a popup.
134  EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance(
135      chrome::GetActiveDesktop())->GetLastActive()).HasPopup());
136}
137
138#if defined(OS_LINUX)
139#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups DISABLED_TestOpenPopupDoesNotCloseOtherPopups
140#else
141#define MAYBE_TestOpenPopupDoesNotCloseOtherPopups TestOpenPopupDoesNotCloseOtherPopups
142#endif
143// Tests if there is already a popup open (by a user click or otherwise), that
144// the openPopup API does not override it.
145IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
146                       MAYBE_TestOpenPopupDoesNotCloseOtherPopups) {
147  if (!ShouldRunPopupTest())
148    return;
149
150  // Load a first extension that can open a popup.
151  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
152      "browser_action/popup")));
153  const Extension* extension = GetSingleLoadedExtension();
154  ASSERT_TRUE(extension) << message_;
155
156  ExtensionTestMessageListener listener("ready", true);
157  // Load the test extension which will do nothing except notifyPass() to
158  // return control here.
159  ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
160                                  "open_popup_fails.html")) << message_;
161  EXPECT_TRUE(listener.WaitUntilSatisfied());
162
163  content::WindowedNotificationObserver frame_observer(
164      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
165      content::NotificationService::AllSources());
166  // Open popup in the first extension.
167  BrowserActionTestUtil(browser()).Press(0);
168  frame_observer.Wait();
169  EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
170
171  ResultCatcher catcher;
172  // Return control to javascript to validate that opening a popup fails now.
173  listener.Reply("");
174  ASSERT_TRUE(catcher.GetNextResult()) << message_;
175}
176
177// Test that openPopup does not grant tab permissions like for browser action
178// clicks if the activeTab permission is set.
179IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest,
180                       TestOpenPopupDoesNotGrantTabPermissions) {
181  if (!ShouldRunPopupTest())
182    return;
183
184  content::WindowedNotificationObserver frame_observer(
185      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
186      content::NotificationService::AllSources());
187  ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
188                                  "open_popup_succeeds.html")) << message_;
189  frame_observer.Wait();
190
191  ExtensionService* service = extensions::ExtensionSystem::Get(
192      browser()->profile())->extension_service();
193  ASSERT_FALSE(PermissionsData::HasAPIPermissionForTab(
194      service->GetExtensionById(last_loaded_extension_id(), false),
195      SessionID::IdForTab(browser()->tab_strip_model()->GetActiveWebContents()),
196      APIPermission::kTab));
197}
198
199// Test that the extension popup is closed when the browser window is clicked.
200IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup1) {
201  if (!ShouldRunPopupTest())
202    return;
203
204  // Open an extension popup via the chrome.browserAction.openPopup API.
205  content::WindowedNotificationObserver frame_observer(
206      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
207      content::NotificationService::AllSources());
208  ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
209                                  "open_popup_succeeds.html")) << message_;
210  frame_observer.Wait();
211  EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
212
213  // Click on the omnibox to close the extension popup.
214  ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
215  EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
216}
217
218// Test that the extension popup is closed when the browser window is clicked.
219IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, BrowserClickClosesPopup2) {
220  if (!ShouldRunPopupTest())
221    return;
222
223  // Load a first extension that can open a popup.
224  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(
225      "browser_action/popup")));
226  const Extension* extension = GetSingleLoadedExtension();
227  ASSERT_TRUE(extension) << message_;
228
229  // Open an extension popup by clicking the browser action button.
230  content::WindowedNotificationObserver frame_observer(
231      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
232      content::NotificationService::AllSources());
233  BrowserActionTestUtil(browser()).Press(0);
234  frame_observer.Wait();
235  EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
236
237  // Click on the omnibox to close the extension popup.
238  ui_test_utils::ClickOnView(browser(), VIEW_ID_OMNIBOX);
239  EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup());
240}
241
242// Test that the extension popup is closed on browser tab switches.
243IN_PROC_BROWSER_TEST_F(BrowserActionInteractiveTest, TabSwitchClosesPopup) {
244  if (!ShouldRunPopupTest())
245    return;
246
247  // Add a second tab to the browser.
248  chrome::NewTab(browser());
249  ASSERT_EQ(2, browser()->tab_strip_model()->count());
250
251  // Open an extension popup via the chrome.browserAction.openPopup API.
252  content::WindowedNotificationObserver frame_observer(
253      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
254      content::NotificationService::AllSources());
255  ASSERT_TRUE(RunExtensionSubtest("browser_action/open_popup",
256                                  "open_popup_succeeds.html")) << message_;
257  frame_observer.Wait();
258  EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup());
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}  // namespace
267}  // namespace extensions
268