1 // Copyright (c) 2012 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 "build/build_config.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/browser_action_test_util.h"
9 #include "chrome/browser/extensions/extension_action.h"
10 #include "chrome/browser/extensions/extension_action_icon_factory.h"
11 #include "chrome/browser/extensions/extension_action_manager.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/extension_tab_util.h"
15 #include "chrome/browser/extensions/extension_toolbar_model.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_commands.h"
19 #include "chrome/browser/ui/browser_window.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "extensions/browser/extension_system.h"
27 #include "extensions/common/feature_switch.h"
28 #include "grit/theme_resources.h"
29 #include "ui/base/resource/resource_bundle.h"
30 #include "ui/gfx/image/image_skia.h"
31 #include "ui/gfx/image/image_skia_operations.h"
32 #include "ui/gfx/rect.h"
33 #include "ui/gfx/size.h"
34 #include "ui/gfx/skia_util.h"
36 using content::WebContents
;
38 namespace extensions
{
41 const char kEmptyImageDataError
[] =
42 "The imageData property must contain an ImageData object or dictionary "
43 "of ImageData objects.";
44 const char kEmptyPathError
[] = "The path property must not be empty.";
46 // Views implementation of browser action button will return icon whose
47 // background will be set.
48 gfx::ImageSkia
AddBackgroundForViews(const gfx::ImageSkia
& icon
) {
49 #if defined(TOOLKIT_VIEWS)
50 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
51 gfx::ImageSkia bg
= *rb
.GetImageSkiaNamed(IDR_BROWSER_ACTION
);
52 return gfx::ImageSkiaOperations::CreateSuperimposedImage(bg
, icon
);
58 bool ImagesAreEqualAtScale(const gfx::ImageSkia
& i1
,
59 const gfx::ImageSkia
& i2
,
61 SkBitmap bitmap1
= i1
.GetRepresentation(scale
).sk_bitmap();
62 SkBitmap bitmap2
= i2
.GetRepresentation(scale
).sk_bitmap();
63 return gfx::BitmapsAreEqual(bitmap1
, bitmap2
);
66 class BrowserActionApiTest
: public ExtensionApiTest
{
68 BrowserActionApiTest() {}
69 virtual ~BrowserActionApiTest() {}
72 BrowserActionTestUtil
GetBrowserActionsBar() {
73 return BrowserActionTestUtil(browser());
76 bool OpenPopup(int index
) {
77 ResultCatcher catcher
;
78 content::WindowedNotificationObserver
popup_observer(
79 content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME
,
80 content::NotificationService::AllSources());
81 GetBrowserActionsBar().Press(index
);
82 popup_observer
.Wait();
83 EXPECT_TRUE(catcher
.GetNextResult()) << catcher
.message();
84 return GetBrowserActionsBar().HasPopup();
87 ExtensionAction
* GetBrowserAction(const Extension
& extension
) {
88 return ExtensionActionManager::Get(browser()->profile())->
89 GetBrowserAction(extension
);
93 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, Basic
) {
94 ASSERT_TRUE(test_server()->Start());
95 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_
;
96 const Extension
* extension
= GetSingleLoadedExtension();
97 ASSERT_TRUE(extension
) << message_
;
99 // Test that there is a browser action in the toolbar.
100 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
102 // Tell the extension to update the browser action state.
103 ResultCatcher catcher
;
104 ui_test_utils::NavigateToURL(browser(),
105 GURL(extension
->GetResourceURL("update.html")));
106 ASSERT_TRUE(catcher
.GetNextResult()) << catcher
.message();
108 // Test that we received the changes.
109 ExtensionAction
* action
= GetBrowserAction(*extension
);
110 ASSERT_EQ("Modified", action
->GetTitle(ExtensionAction::kDefaultTabId
));
111 ASSERT_EQ("badge", action
->GetBadgeText(ExtensionAction::kDefaultTabId
));
112 ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255),
113 action
->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId
));
115 // Simulate the browser action being clicked.
116 ui_test_utils::NavigateToURL(browser(),
117 test_server()->GetURL("files/extensions/test_file.txt"));
119 ExtensionToolbarModel
* toolbar_model
= ExtensionToolbarModel::Get(
120 browser()->profile());
121 toolbar_model
->ExecuteBrowserAction(extension
, browser(), NULL
, true);
123 ASSERT_TRUE(catcher
.GetNextResult()) << catcher
.message();
126 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, DynamicBrowserAction
) {
127 ASSERT_TRUE(RunExtensionTest("browser_action/no_icon")) << message_
;
128 const Extension
* extension
= GetSingleLoadedExtension();
129 ASSERT_TRUE(extension
) << message_
;
131 #if defined (OS_MACOSX)
132 // We need this on mac so we don't loose 2x representations from browser icon
133 // in transformations gfx::ImageSkia -> NSImage -> gfx::ImageSkia.
134 std::vector
<ui::ScaleFactor
> supported_scale_factors
;
135 supported_scale_factors
.push_back(ui::SCALE_FACTOR_100P
);
136 supported_scale_factors
.push_back(ui::SCALE_FACTOR_200P
);
137 ui::SetSupportedScaleFactors(supported_scale_factors
);
140 // We should not be creating icons asynchronously, so we don't need an
142 ExtensionActionIconFactory
icon_factory(
145 GetBrowserAction(*extension
),
147 // Test that there is a browser action in the toolbar.
148 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
149 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0));
151 gfx::Image action_icon
= icon_factory
.GetIcon(0);
152 uint32_t action_icon_last_id
= action_icon
.ToSkBitmap()->getGenerationID();
154 // Let's check that |GetIcon| doesn't always return bitmap with new id.
155 ASSERT_EQ(action_icon_last_id
,
156 icon_factory
.GetIcon(0).ToSkBitmap()->getGenerationID());
158 uint32_t action_icon_current_id
= 0;
160 ResultCatcher catcher
;
162 // Tell the extension to update the icon using ImageData object.
163 GetBrowserActionsBar().Press(0);
164 ASSERT_TRUE(catcher
.GetNextResult());
166 action_icon
= icon_factory
.GetIcon(0);
168 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
169 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
170 action_icon_last_id
= action_icon_current_id
;
172 EXPECT_FALSE(action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
175 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
176 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
179 // Tell the extension to update the icon using path.
180 GetBrowserActionsBar().Press(0);
181 ASSERT_TRUE(catcher
.GetNextResult());
183 action_icon
= icon_factory
.GetIcon(0);
185 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
186 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
187 action_icon_last_id
= action_icon_current_id
;
190 action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
193 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
194 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
197 // Tell the extension to update the icon using dictionary of ImageData
199 GetBrowserActionsBar().Press(0);
200 ASSERT_TRUE(catcher
.GetNextResult());
202 action_icon
= icon_factory
.GetIcon(0);
204 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
205 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
206 action_icon_last_id
= action_icon_current_id
;
208 EXPECT_TRUE(action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
211 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
212 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
215 // Tell the extension to update the icon using dictionary of paths.
216 GetBrowserActionsBar().Press(0);
217 ASSERT_TRUE(catcher
.GetNextResult());
219 action_icon
= icon_factory
.GetIcon(0);
221 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
222 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
223 action_icon_last_id
= action_icon_current_id
;
225 EXPECT_TRUE(action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
228 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
229 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
232 // Tell the extension to update the icon using dictionary of ImageData
233 // objects, but setting only size 19.
234 GetBrowserActionsBar().Press(0);
235 ASSERT_TRUE(catcher
.GetNextResult());
237 action_icon
= icon_factory
.GetIcon(0);
239 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
240 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
241 action_icon_last_id
= action_icon_current_id
;
243 EXPECT_FALSE(action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
246 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
247 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
250 // Tell the extension to update the icon using dictionary of paths, but
251 // setting only size 19.
252 GetBrowserActionsBar().Press(0);
253 ASSERT_TRUE(catcher
.GetNextResult());
255 action_icon
= icon_factory
.GetIcon(0);
257 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
258 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
259 action_icon_last_id
= action_icon_current_id
;
261 EXPECT_FALSE(action_icon
.ToImageSkia()->HasRepresentation(2.0f
));
264 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon
.ToImageSkia()),
265 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
268 // Tell the extension to update the icon using dictionary of ImageData
269 // objects, but setting only size 38.
270 GetBrowserActionsBar().Press(0);
271 ASSERT_TRUE(catcher
.GetNextResult());
273 action_icon
= icon_factory
.GetIcon(0);
275 const gfx::ImageSkia
* action_icon_skia
= action_icon
.ToImageSkia();
277 EXPECT_FALSE(action_icon_skia
->HasRepresentation(1.0f
));
278 EXPECT_TRUE(action_icon_skia
->HasRepresentation(2.0f
));
280 action_icon_current_id
= action_icon
.ToSkBitmap()->getGenerationID();
281 EXPECT_GT(action_icon_current_id
, action_icon_last_id
);
282 action_icon_last_id
= action_icon_current_id
;
284 EXPECT_TRUE(gfx::BitmapsAreEqual(
285 *action_icon
.ToSkBitmap(),
286 action_icon_skia
->GetRepresentation(2.0f
).sk_bitmap()));
289 ImagesAreEqualAtScale(AddBackgroundForViews(*action_icon_skia
),
290 *GetBrowserActionsBar().GetIcon(0).ToImageSkia(),
293 // Try setting icon with empty dictionary of ImageData objects.
294 GetBrowserActionsBar().Press(0);
295 ASSERT_FALSE(catcher
.GetNextResult());
296 EXPECT_EQ(kEmptyImageDataError
, catcher
.message());
298 // Try setting icon with empty dictionary of path objects.
299 GetBrowserActionsBar().Press(0);
300 ASSERT_FALSE(catcher
.GetNextResult());
301 EXPECT_EQ(kEmptyPathError
, catcher
.message());
304 // This test is flaky as per http://crbug.com/74557.
305 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
,
306 DISABLED_TabSpecificBrowserActionState
) {
307 ASSERT_TRUE(RunExtensionTest("browser_action/tab_specific_state")) <<
309 const Extension
* extension
= GetSingleLoadedExtension();
310 ASSERT_TRUE(extension
) << message_
;
312 // Test that there is a browser action in the toolbar and that it has an icon.
313 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
314 EXPECT_TRUE(GetBrowserActionsBar().HasIcon(0));
316 // Execute the action, its title should change.
317 ResultCatcher catcher
;
318 GetBrowserActionsBar().Press(0);
319 ASSERT_TRUE(catcher
.GetNextResult());
320 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0));
322 // Open a new tab, the title should go back.
323 chrome::NewTab(browser());
324 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0));
326 // Go back to first tab, changed title should reappear.
327 browser()->tab_strip_model()->ActivateTabAt(0, true);
328 EXPECT_EQ("Showing icon 2", GetBrowserActionsBar().GetTooltip(0));
330 // Reload that tab, default title should come back.
331 ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
332 EXPECT_EQ("hi!", GetBrowserActionsBar().GetTooltip(0));
335 // http://code.google.com/p/chromium/issues/detail?id=70829
336 // Mac used to be ok, but then mac 10.5 started failing too. =(
337 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, DISABLED_BrowserActionPopup
) {
339 LoadExtension(test_data_dir_
.AppendASCII("browser_action/popup")));
340 BrowserActionTestUtil actions_bar
= GetBrowserActionsBar();
341 const Extension
* extension
= GetSingleLoadedExtension();
342 ASSERT_TRUE(extension
) << message_
;
344 // The extension's popup's size grows by |growFactor| each click.
345 const int growFactor
= 500;
346 gfx::Size minSize
= BrowserActionTestUtil::GetMinPopupSize();
347 gfx::Size middleSize
= gfx::Size(growFactor
, growFactor
);
348 gfx::Size maxSize
= BrowserActionTestUtil::GetMaxPopupSize();
350 // Ensure that two clicks will exceed the maximum allowed size.
351 ASSERT_GT(minSize
.height() + growFactor
* 2, maxSize
.height());
352 ASSERT_GT(minSize
.width() + growFactor
* 2, maxSize
.width());
354 // Simulate a click on the browser action and verify the size of the resulting
355 // popup. The first one tries to be 0x0, so it should be the min values.
356 ASSERT_TRUE(OpenPopup(0));
357 EXPECT_EQ(minSize
, actions_bar
.GetPopupBounds().size());
358 EXPECT_TRUE(actions_bar
.HidePopup());
360 ASSERT_TRUE(OpenPopup(0));
361 EXPECT_EQ(middleSize
, actions_bar
.GetPopupBounds().size());
362 EXPECT_TRUE(actions_bar
.HidePopup());
364 // One more time, but this time it should be constrained by the max values.
365 ASSERT_TRUE(OpenPopup(0));
366 EXPECT_EQ(maxSize
, actions_bar
.GetPopupBounds().size());
367 EXPECT_TRUE(actions_bar
.HidePopup());
370 // Test that calling chrome.browserAction.setPopup() can enable and change
372 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, BrowserActionAddPopup
) {
373 ASSERT_TRUE(RunExtensionTest("browser_action/add_popup")) << message_
;
374 const Extension
* extension
= GetSingleLoadedExtension();
375 ASSERT_TRUE(extension
) << message_
;
377 int tab_id
= ExtensionTabUtil::GetTabId(
378 browser()->tab_strip_model()->GetActiveWebContents());
380 ExtensionAction
* browser_action
= GetBrowserAction(*extension
);
381 ASSERT_TRUE(browser_action
)
382 << "Browser action test extension should have a browser action.";
384 ASSERT_FALSE(browser_action
->HasPopup(tab_id
));
385 ASSERT_FALSE(browser_action
->HasPopup(ExtensionAction::kDefaultTabId
));
387 // Simulate a click on the browser action icon. The onClicked handler
390 ResultCatcher catcher
;
391 GetBrowserActionsBar().Press(0);
392 ASSERT_TRUE(catcher
.GetNextResult());
395 // The call to setPopup in background.html set a tab id, so the
396 // current tab's setting should have changed, but the default setting
397 // should not have changed.
398 ASSERT_TRUE(browser_action
->HasPopup(tab_id
))
399 << "Clicking on the browser action should have caused a popup to "
401 ASSERT_FALSE(browser_action
->HasPopup(ExtensionAction::kDefaultTabId
))
402 << "Clicking on the browser action should not have set a default "
405 ASSERT_STREQ("/a_popup.html",
406 browser_action
->GetPopupUrl(tab_id
).path().c_str());
408 // Now change the popup from a_popup.html to another_popup.html by loading
409 // a page which removes the popup using chrome.browserAction.setPopup().
411 ResultCatcher catcher
;
412 ui_test_utils::NavigateToURL(
414 GURL(extension
->GetResourceURL("change_popup.html")));
415 ASSERT_TRUE(catcher
.GetNextResult());
418 // The call to setPopup in change_popup.html did not use a tab id,
419 // so the default setting should have changed as well as the current tab.
420 ASSERT_TRUE(browser_action
->HasPopup(tab_id
));
421 ASSERT_TRUE(browser_action
->HasPopup(ExtensionAction::kDefaultTabId
));
422 ASSERT_STREQ("/another_popup.html",
423 browser_action
->GetPopupUrl(tab_id
).path().c_str());
426 // Test that calling chrome.browserAction.setPopup() can remove a popup.
427 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, BrowserActionRemovePopup
) {
428 // Load the extension, which has a browser action with a default popup.
429 ASSERT_TRUE(RunExtensionTest("browser_action/remove_popup")) << message_
;
430 const Extension
* extension
= GetSingleLoadedExtension();
431 ASSERT_TRUE(extension
) << message_
;
433 int tab_id
= ExtensionTabUtil::GetTabId(
434 browser()->tab_strip_model()->GetActiveWebContents());
436 ExtensionAction
* browser_action
= GetBrowserAction(*extension
);
437 ASSERT_TRUE(browser_action
)
438 << "Browser action test extension should have a browser action.";
440 ASSERT_TRUE(browser_action
->HasPopup(tab_id
))
441 << "Expect a browser action popup before the test removes it.";
442 ASSERT_TRUE(browser_action
->HasPopup(ExtensionAction::kDefaultTabId
))
443 << "Expect a browser action popup is the default for all tabs.";
445 // Load a page which removes the popup using chrome.browserAction.setPopup().
447 ResultCatcher catcher
;
448 ui_test_utils::NavigateToURL(
450 GURL(extension
->GetResourceURL("remove_popup.html")));
451 ASSERT_TRUE(catcher
.GetNextResult());
454 ASSERT_FALSE(browser_action
->HasPopup(tab_id
))
455 << "Browser action popup should have been removed.";
456 ASSERT_TRUE(browser_action
->HasPopup(ExtensionAction::kDefaultTabId
))
457 << "Browser action popup default should not be changed by setting "
458 << "a specific tab id.";
461 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, IncognitoBasic
) {
462 ASSERT_TRUE(test_server()->Start());
464 ASSERT_TRUE(RunExtensionTest("browser_action/basics")) << message_
;
465 const Extension
* extension
= GetSingleLoadedExtension();
466 ASSERT_TRUE(extension
) << message_
;
468 // Test that there is a browser action in the toolbar.
469 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
471 // Open an incognito window and test that the browser action isn't there by
473 Profile
* incognito_profile
= browser()->profile()->GetOffTheRecordProfile();
474 Browser
* incognito_browser
=
475 new Browser(Browser::CreateParams(incognito_profile
,
476 browser()->host_desktop_type()));
479 BrowserActionTestUtil(incognito_browser
).NumberOfBrowserActions());
481 // Now enable the extension in incognito mode, and test that the browser
482 // action shows up. Note that we don't update the existing window at the
483 // moment, so we just create a new one.
484 extensions::ExtensionPrefs::Get(browser()->profile())
485 ->SetIsIncognitoEnabled(extension
->id(), true);
487 chrome::CloseWindow(incognito_browser
);
489 new Browser(Browser::CreateParams(incognito_profile
,
490 browser()->host_desktop_type()));
492 BrowserActionTestUtil(incognito_browser
).NumberOfBrowserActions());
494 // TODO(mpcomplete): simulate a click and have it do the right thing in
498 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, IncognitoDragging
) {
499 ExtensionService
* service
= extensions::ExtensionSystem::Get(
500 browser()->profile())->extension_service();
502 // The tooltips for each respective browser action.
503 const char kTooltipA
[] = "Alpha";
504 const char kTooltipB
[] = "Beta";
505 const char kTooltipC
[] = "Gamma";
507 const size_t size_before
= service
->extensions()->size();
509 base::FilePath test_dir
= test_data_dir_
.AppendASCII("browser_action");
510 const Extension
* extension_a
= InstallExtension(
511 test_dir
.AppendASCII("empty_browser_action_alpha.crx"), 1);
512 const Extension
* extension_b
= InstallExtension(
513 test_dir
.AppendASCII("empty_browser_action_beta.crx"), 1);
514 const Extension
* extension_c
= InstallExtension(
515 test_dir
.AppendASCII("empty_browser_action_gamma.crx"), 1);
516 ASSERT_TRUE(extension_a
);
517 ASSERT_TRUE(extension_b
);
518 ASSERT_TRUE(extension_c
);
520 // Test that there are 3 browser actions in the toolbar.
521 ASSERT_EQ(size_before
+ 3, service
->extensions()->size());
522 ASSERT_EQ(3, GetBrowserActionsBar().NumberOfBrowserActions());
524 // Now enable 2 of the extensions in incognito mode, and test that the browser
526 extensions::ExtensionPrefs
* prefs
=
527 extensions::ExtensionPrefs::Get(browser()->profile());
528 prefs
->SetIsIncognitoEnabled(extension_a
->id(), true);
529 prefs
->SetIsIncognitoEnabled(extension_c
->id(), true);
531 Profile
* incognito_profile
= browser()->profile()->GetOffTheRecordProfile();
532 Browser
* incognito_browser
=
533 new Browser(Browser::CreateParams(incognito_profile
,
534 browser()->host_desktop_type()));
535 BrowserActionTestUtil
incognito_bar(incognito_browser
);
537 // Navigate just to have a tab in this window, otherwise wonky things happen.
538 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
540 ASSERT_EQ(2, incognito_bar
.NumberOfBrowserActions());
542 // Ensure that the browser actions are in the right order (ABC).
543 EXPECT_EQ(kTooltipA
, GetBrowserActionsBar().GetTooltip(0));
544 EXPECT_EQ(kTooltipB
, GetBrowserActionsBar().GetTooltip(1));
545 EXPECT_EQ(kTooltipC
, GetBrowserActionsBar().GetTooltip(2));
547 EXPECT_EQ(kTooltipA
, incognito_bar
.GetTooltip(0));
548 EXPECT_EQ(kTooltipC
, incognito_bar
.GetTooltip(1));
550 // Now rearrange them and ensure that they are rearranged correctly in both
551 // regular and incognito mode.
554 ExtensionToolbarModel
* toolbar_model
= ExtensionToolbarModel::Get(
555 browser()->profile());
556 toolbar_model
->MoveBrowserAction(extension_c
, 0);
558 EXPECT_EQ(kTooltipC
, GetBrowserActionsBar().GetTooltip(0));
559 EXPECT_EQ(kTooltipA
, GetBrowserActionsBar().GetTooltip(1));
560 EXPECT_EQ(kTooltipB
, GetBrowserActionsBar().GetTooltip(2));
562 EXPECT_EQ(kTooltipC
, incognito_bar
.GetTooltip(0));
563 EXPECT_EQ(kTooltipA
, incognito_bar
.GetTooltip(1));
566 toolbar_model
->MoveBrowserAction(extension_b
, 1);
568 EXPECT_EQ(kTooltipC
, GetBrowserActionsBar().GetTooltip(0));
569 EXPECT_EQ(kTooltipB
, GetBrowserActionsBar().GetTooltip(1));
570 EXPECT_EQ(kTooltipA
, GetBrowserActionsBar().GetTooltip(2));
572 EXPECT_EQ(kTooltipC
, incognito_bar
.GetTooltip(0));
573 EXPECT_EQ(kTooltipA
, incognito_bar
.GetTooltip(1));
576 // Tests that events are dispatched to the correct profile for split mode
578 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, IncognitoSplit
) {
579 ResultCatcher catcher
;
580 const Extension
* extension
= LoadExtensionWithFlags(
581 test_data_dir_
.AppendASCII("browser_action/split_mode"),
582 kFlagEnableIncognito
);
583 ASSERT_TRUE(extension
) << message_
;
585 // Open an incognito window.
586 Profile
* incognito_profile
= browser()->profile()->GetOffTheRecordProfile();
587 Browser
* incognito_browser
=
588 new Browser(Browser::CreateParams(incognito_profile
,
589 browser()->host_desktop_type()));
590 // Navigate just to have a tab in this window, otherwise wonky things happen.
591 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
593 BrowserActionTestUtil(incognito_browser
).NumberOfBrowserActions());
595 // A click in the regular profile should open a tab in the regular profile.
596 ExtensionToolbarModel
* toolbar_model
= ExtensionToolbarModel::Get(
597 browser()->profile());
598 toolbar_model
->ExecuteBrowserAction(extension
, browser(), NULL
, true);
599 ASSERT_TRUE(catcher
.GetNextResult()) << catcher
.message();
601 // A click in the incognito profile should open a tab in the
602 // incognito profile.
603 toolbar_model
->ExecuteBrowserAction(extension
, incognito_browser
, NULL
, true);
604 ASSERT_TRUE(catcher
.GetNextResult()) << catcher
.message();
607 // Disabled because of failures (crashes) on ASAN bot.
608 // See http://crbug.com/98861.
609 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, DISABLED_CloseBackgroundPage
) {
610 ASSERT_TRUE(LoadExtension(
611 test_data_dir_
.AppendASCII("browser_action/close_background")));
612 const Extension
* extension
= GetSingleLoadedExtension();
614 // There is a background page and a browser action with no badge text.
615 extensions::ProcessManager
* manager
=
616 extensions::ExtensionSystem::Get(browser()->profile())->process_manager();
617 ASSERT_TRUE(manager
->GetBackgroundHostForExtension(extension
->id()));
618 ExtensionAction
* action
= GetBrowserAction(*extension
);
619 ASSERT_EQ("", action
->GetBadgeText(ExtensionAction::kDefaultTabId
));
621 content::WindowedNotificationObserver
host_destroyed_observer(
622 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
623 content::NotificationService::AllSources());
625 // Click the browser action.
626 ExtensionToolbarModel
* toolbar_model
= ExtensionToolbarModel::Get(
627 browser()->profile());
628 toolbar_model
->ExecuteBrowserAction(extension
, browser(), NULL
, true);
630 // It can take a moment for the background page to actually get destroyed
631 // so we wait for the notification before checking that it's really gone
632 // and the badge text has been set.
633 host_destroyed_observer
.Wait();
634 ASSERT_FALSE(manager
->GetBackgroundHostForExtension(extension
->id()));
635 ASSERT_EQ("X", action
->GetBadgeText(ExtensionAction::kDefaultTabId
));
638 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, BadgeBackgroundColor
) {
639 ASSERT_TRUE(test_server()->Start());
640 ASSERT_TRUE(RunExtensionTest("browser_action/color")) << message_
;
641 const Extension
* extension
= GetSingleLoadedExtension();
642 ASSERT_TRUE(extension
) << message_
;
644 // Test that there is a browser action in the toolbar.
645 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
647 // Test that CSS values (#FF0000) set color correctly.
648 ExtensionAction
* action
= GetBrowserAction(*extension
);
649 ASSERT_EQ(SkColorSetARGB(255, 255, 0, 0),
650 action
->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId
));
652 // Tell the extension to update the browser action state.
653 ResultCatcher catcher
;
654 ui_test_utils::NavigateToURL(browser(),
655 GURL(extension
->GetResourceURL("update.html")));
656 ASSERT_TRUE(catcher
.GetNextResult());
658 // Test that CSS values (#0F0) set color correctly.
659 ASSERT_EQ(SkColorSetARGB(255, 0, 255, 0),
660 action
->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId
));
662 ui_test_utils::NavigateToURL(browser(),
663 GURL(extension
->GetResourceURL("update2.html")));
664 ASSERT_TRUE(catcher
.GetNextResult());
666 // Test that array values set color correctly.
667 ASSERT_EQ(SkColorSetARGB(255, 255, 255, 255),
668 action
->GetBadgeBackgroundColor(ExtensionAction::kDefaultTabId
));
671 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, Getters
) {
672 ASSERT_TRUE(RunExtensionTest("browser_action/getters")) << message_
;
673 const Extension
* extension
= GetSingleLoadedExtension();
674 ASSERT_TRUE(extension
) << message_
;
676 // Test that there is a browser action in the toolbar.
677 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
679 // Test the getters for defaults.
680 ResultCatcher catcher
;
681 ui_test_utils::NavigateToURL(browser(),
682 GURL(extension
->GetResourceURL("update.html")));
683 ASSERT_TRUE(catcher
.GetNextResult());
685 // Test the getters for a specific tab.
686 ui_test_utils::NavigateToURL(browser(),
687 GURL(extension
->GetResourceURL("update2.html")));
688 ASSERT_TRUE(catcher
.GetNextResult());
691 // Verify triggering browser action.
692 IN_PROC_BROWSER_TEST_F(BrowserActionApiTest
, TestTriggerBrowserAction
) {
693 ASSERT_TRUE(test_server()->Start());
695 ASSERT_TRUE(RunExtensionTest("trigger_actions/browser_action")) << message_
;
696 const Extension
* extension
= GetSingleLoadedExtension();
697 ASSERT_TRUE(extension
) << message_
;
699 // Test that there is a browser action in the toolbar.
700 ASSERT_EQ(1, GetBrowserActionsBar().NumberOfBrowserActions());
702 ui_test_utils::NavigateToURL(
704 test_server()->GetURL("files/simple.html"));
706 ExtensionAction
* browser_action
= GetBrowserAction(*extension
);
707 EXPECT_TRUE(browser_action
!= NULL
);
709 // Simulate a click on the browser action icon.
711 ResultCatcher catcher
;
712 GetBrowserActionsBar().Press(0);
713 EXPECT_TRUE(catcher
.GetNextResult());
717 browser()->tab_strip_model()->GetActiveWebContents();
718 EXPECT_TRUE(tab
!= NULL
);
720 // Verify that the browser action turned the background color red.
721 const std::string script
=
722 "window.domAutomationController.send(document.body.style."
725 EXPECT_TRUE(content::ExecuteScriptAndExtractString(tab
, script
, &result
));
726 EXPECT_EQ(result
, "red");
730 } // namespace extensions