1 // Copyright 2014 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 "base/files/file_util.h"
6 #include "base/macros.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
11 #include "chrome/browser/extensions/extension_action_manager.h"
12 #include "chrome/browser/extensions/extension_action_test_util.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/extensions/extension_service_test_base.h"
15 #include "chrome/browser/extensions/extension_util.h"
16 #include "chrome/browser/extensions/test_extension_dir.h"
17 #include "chrome/browser/extensions/test_extension_system.h"
18 #include "chrome/browser/extensions/unpacked_installer.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/sessions/session_tab_helper.h"
21 #include "chrome/browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h"
22 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h"
23 #include "chrome/browser/ui/toolbar/mock_component_toolbar_actions_factory.h"
24 #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
25 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h"
26 #include "chrome/common/extensions/api/extension_action/action_info.h"
27 #include "components/crx_file/id_util.h"
28 #include "content/public/test/test_renderer_host.h"
29 #include "content/public/test/web_contents_tester.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/pref_names.h"
34 #include "extensions/browser/test_extension_registry_observer.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/extension_builder.h"
37 #include "extensions/common/feature_switch.h"
38 #include "extensions/common/value_builder.h"
42 // A simple observer that tracks the number of times certain events occur.
43 class ToolbarActionsModelTestObserver
: public ToolbarActionsModel::Observer
{
45 explicit ToolbarActionsModelTestObserver(ToolbarActionsModel
* model
);
46 ~ToolbarActionsModelTestObserver() override
;
48 size_t inserted_count() const { return inserted_count_
; }
49 size_t removed_count() const { return removed_count_
; }
50 size_t moved_count() const { return moved_count_
; }
51 int highlight_mode_count() const { return highlight_mode_count_
; }
52 size_t initialized_count() const { return initialized_count_
; }
55 // ToolbarActionsModel::Observer:
56 void OnToolbarActionAdded(const std::string
& id
, int index
) override
{
60 void OnToolbarActionRemoved(const std::string
& id
) override
{
64 void OnToolbarActionMoved(const std::string
& id
, int index
) override
{
68 void OnToolbarActionUpdated(const std::string
& id
) override
{}
70 void OnToolbarVisibleCountChanged() override
{}
72 void OnToolbarHighlightModeChanged(bool is_highlighting
) override
{
73 // Add one if highlighting, subtract one if not.
74 highlight_mode_count_
+= is_highlighting
? 1 : -1;
77 void OnToolbarModelInitialized() override
{ ++initialized_count_
; }
79 ToolbarActionsModel
* model_
;
81 size_t inserted_count_
;
82 size_t removed_count_
;
84 // Int because it could become negative (if something goes wrong).
85 int highlight_mode_count_
;
86 size_t initialized_count_
;
88 DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModelTestObserver
);
91 ToolbarActionsModelTestObserver::ToolbarActionsModelTestObserver(
92 ToolbarActionsModel
* model
)
97 highlight_mode_count_(0),
98 initialized_count_(0) {
99 model_
->AddObserver(this);
102 ToolbarActionsModelTestObserver::~ToolbarActionsModelTestObserver() {
103 model_
->RemoveObserver(this);
108 class ToolbarActionsModelUnitTest
109 : public extensions::ExtensionServiceTestBase
{
111 ToolbarActionsModelUnitTest() {}
112 ~ToolbarActionsModelUnitTest() override
{}
115 // Initialize the ExtensionService, ToolbarActionsModel, and
119 void TearDown() override
;
121 // Adds or removes the given |extension| and verify success.
122 testing::AssertionResult
AddExtension(
123 const scoped_refptr
<const extensions::Extension
>& extension
)
125 testing::AssertionResult
RemoveExtension(
126 const scoped_refptr
<const extensions::Extension
>& extension
)
129 // Adds three extensions, all with browser actions.
130 testing::AssertionResult
AddBrowserActionExtensions() WARN_UNUSED_RESULT
;
132 // Adds three extensions, one each for browser action, page action, and no
133 // action, and are added in that order.
134 testing::AssertionResult
AddActionExtensions() WARN_UNUSED_RESULT
;
136 // Returns the action's id at the given index in the toolbar model, or empty
137 // if one does not exist.
138 // If |model| is specified, it is used. Otherwise, this defaults to
140 const std::string
GetActionIdAtIndex(size_t index
,
141 const ToolbarActionsModel
* model
) const;
142 const std::string
GetActionIdAtIndex(size_t index
) const;
144 void SetMockActionsFactory(MockComponentToolbarActionsFactory
* factory
);
146 ToolbarActionsModel
* toolbar_model() { return toolbar_model_
; }
148 const ToolbarActionsModelTestObserver
* observer() const {
149 return model_observer_
.get();
151 size_t num_toolbar_items() const {
152 return toolbar_model_
->toolbar_items().size();
154 const extensions::Extension
* browser_action_a() const {
155 return browser_action_a_
.get();
157 const extensions::Extension
* browser_action_b() const {
158 return browser_action_b_
.get();
160 const extensions::Extension
* browser_action_c() const {
161 return browser_action_c_
.get();
163 const extensions::Extension
* browser_action() const {
164 return browser_action_extension_
.get();
166 const extensions::Extension
* page_action() const {
167 return page_action_extension_
.get();
169 const extensions::Extension
* no_action() const {
170 return no_action_extension_
.get();
173 // The mock component action will be referred to as "MCA" below.
174 const char* component_action_id() {
175 return ComponentToolbarActionsFactory::kActionIdForTesting
;
179 // Verifies that all extensions in |extensions| are added successfully.
180 testing::AssertionResult
AddAndVerifyExtensions(
181 const extensions::ExtensionList
& extensions
);
183 // The toolbar model associated with the testing profile.
184 ToolbarActionsModel
* toolbar_model_
;
186 // The test observer to track events. Must come after toolbar_model_ so that
187 // it is destroyed and removes itself as an observer first.
188 scoped_ptr
<ToolbarActionsModelTestObserver
> model_observer_
;
190 // Sample extensions with only browser actions.
191 scoped_refptr
<const extensions::Extension
> browser_action_a_
;
192 scoped_refptr
<const extensions::Extension
> browser_action_b_
;
193 scoped_refptr
<const extensions::Extension
> browser_action_c_
;
195 // Sample extensions with different kinds of actions.
196 scoped_refptr
<const extensions::Extension
> browser_action_extension_
;
197 scoped_refptr
<const extensions::Extension
> page_action_extension_
;
198 scoped_refptr
<const extensions::Extension
> no_action_extension_
;
200 scoped_ptr
<MockComponentToolbarActionsFactory
> mock_actions_factory_
;
202 DISALLOW_COPY_AND_ASSIGN(ToolbarActionsModelUnitTest
);
205 void ToolbarActionsModelUnitTest::Init() {
206 InitializeEmptyExtensionService();
208 extensions::extension_action_test_util::CreateToolbarModelForProfile(
210 model_observer_
.reset(new ToolbarActionsModelTestObserver(toolbar_model_
));
213 void ToolbarActionsModelUnitTest::TearDown() {
214 model_observer_
.reset();
215 extensions::ExtensionServiceTestBase::TearDown();
218 testing::AssertionResult
ToolbarActionsModelUnitTest::AddExtension(
219 const scoped_refptr
<const extensions::Extension
>& extension
) {
220 if (registry()->enabled_extensions().GetByID(extension
->id())) {
221 return testing::AssertionFailure() << "Extension " << extension
->name()
222 << " already installed!";
224 service()->AddExtension(extension
.get());
225 if (!registry()->enabled_extensions().GetByID(extension
->id())) {
226 return testing::AssertionFailure() << "Failed to install extension: "
227 << extension
->name();
229 return testing::AssertionSuccess();
232 testing::AssertionResult
ToolbarActionsModelUnitTest::RemoveExtension(
233 const scoped_refptr
<const extensions::Extension
>& extension
) {
234 if (!registry()->enabled_extensions().GetByID(extension
->id())) {
235 return testing::AssertionFailure() << "Extension " << extension
->name()
236 << " not installed!";
238 service()->UnloadExtension(extension
->id(),
239 extensions::UnloadedExtensionInfo::REASON_DISABLE
);
240 if (registry()->enabled_extensions().GetByID(extension
->id())) {
241 return testing::AssertionFailure() << "Failed to unload extension: "
242 << extension
->name();
244 return testing::AssertionSuccess();
247 testing::AssertionResult
ToolbarActionsModelUnitTest::AddActionExtensions() {
248 browser_action_extension_
=
249 extensions::extension_action_test_util::CreateActionExtension(
251 extensions::extension_action_test_util::BROWSER_ACTION
);
252 page_action_extension_
=
253 extensions::extension_action_test_util::CreateActionExtension(
254 "page_action", extensions::extension_action_test_util::PAGE_ACTION
);
255 no_action_extension_
=
256 extensions::extension_action_test_util::CreateActionExtension(
257 "no_action", extensions::extension_action_test_util::NO_ACTION
);
259 extensions::ExtensionList extensions
;
260 extensions
.push_back(browser_action_extension_
);
261 extensions
.push_back(page_action_extension_
);
262 extensions
.push_back(no_action_extension_
);
264 return AddAndVerifyExtensions(extensions
);
267 testing::AssertionResult
268 ToolbarActionsModelUnitTest::AddBrowserActionExtensions() {
270 extensions::extension_action_test_util::CreateActionExtension(
272 extensions::extension_action_test_util::BROWSER_ACTION
);
274 extensions::extension_action_test_util::CreateActionExtension(
276 extensions::extension_action_test_util::BROWSER_ACTION
);
278 extensions::extension_action_test_util::CreateActionExtension(
280 extensions::extension_action_test_util::BROWSER_ACTION
);
282 extensions::ExtensionList extensions
;
283 extensions
.push_back(browser_action_a_
);
284 extensions
.push_back(browser_action_b_
);
285 extensions
.push_back(browser_action_c_
);
287 return AddAndVerifyExtensions(extensions
);
290 const std::string
ToolbarActionsModelUnitTest::GetActionIdAtIndex(
292 const ToolbarActionsModel
* model
) const {
293 return index
< model
->toolbar_items().size()
294 ? model
->toolbar_items()[index
].id
298 const std::string
ToolbarActionsModelUnitTest::GetActionIdAtIndex(
299 size_t index
) const {
300 return GetActionIdAtIndex(index
, toolbar_model_
);
303 testing::AssertionResult
ToolbarActionsModelUnitTest::AddAndVerifyExtensions(
304 const extensions::ExtensionList
& extensions
) {
305 for (extensions::ExtensionList::const_iterator iter
= extensions
.begin();
306 iter
!= extensions
.end(); ++iter
) {
307 if (!AddExtension(*iter
)) {
308 return testing::AssertionFailure() << "Failed to install extension: "
312 return testing::AssertionSuccess();
315 void ToolbarActionsModelUnitTest::SetMockActionsFactory(
316 MockComponentToolbarActionsFactory
* factory
) {
317 mock_actions_factory_
.reset(factory
);
320 // A basic test for component actions and extensions with browser actions
321 // showing up in the toolbar.
322 TEST_F(ToolbarActionsModelUnitTest
, BasicToolbarActionsModelTest
) {
325 // Load an extension with no browser action.
326 scoped_refptr
<const extensions::Extension
> extension1
=
327 extensions::extension_action_test_util::CreateActionExtension(
328 "no_action", extensions::extension_action_test_util::NO_ACTION
);
329 ASSERT_TRUE(AddExtension(extension1
));
331 // This extension should not be in the model (has no browser action).
332 EXPECT_EQ(0u, observer()->inserted_count());
333 EXPECT_EQ(0u, num_toolbar_items());
334 EXPECT_EQ(std::string(), GetActionIdAtIndex(0u));
336 // Load an extension with a browser action.
337 scoped_refptr
<const extensions::Extension
> extension2
=
338 extensions::extension_action_test_util::CreateActionExtension(
340 extensions::extension_action_test_util::BROWSER_ACTION
);
341 ASSERT_TRUE(AddExtension(extension2
));
343 // We should now find our extension in the model.
344 EXPECT_EQ(1u, observer()->inserted_count());
345 EXPECT_EQ(1u, num_toolbar_items());
346 EXPECT_EQ(extension2
->id(), GetActionIdAtIndex(0u));
348 // Should be a no-op, but still fires the events.
349 toolbar_model()->MoveActionIcon(extension2
->id(), 0);
350 EXPECT_EQ(1u, observer()->moved_count());
351 EXPECT_EQ(1u, num_toolbar_items());
352 EXPECT_EQ(extension2
->id(), GetActionIdAtIndex(0u));
354 // Remove the extension and verify.
355 ASSERT_TRUE(RemoveExtension(extension2
));
356 EXPECT_EQ(1u, observer()->removed_count());
357 EXPECT_EQ(0u, num_toolbar_items());
358 EXPECT_EQ(std::string(), GetActionIdAtIndex(0u));
361 // Test various different reorderings, removals, and reinsertions.
362 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarReorderAndReinsert
) {
365 // Add the three browser action extensions.
366 ASSERT_TRUE(AddBrowserActionExtensions());
368 // Verify the three actions are in the model in the proper order.
369 EXPECT_EQ(3u, num_toolbar_items());
370 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
371 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
372 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
374 // Order is now A, B, C. Let's put C first.
375 toolbar_model()->MoveActionIcon(browser_action_c()->id(), 0);
376 EXPECT_EQ(1u, observer()->moved_count());
377 EXPECT_EQ(3u, num_toolbar_items());
378 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
379 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
380 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
382 // Order is now C, A, B. Let's put A last.
383 toolbar_model()->MoveActionIcon(browser_action_a()->id(), 2);
384 EXPECT_EQ(2u, observer()->moved_count());
385 EXPECT_EQ(3u, num_toolbar_items());
386 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
387 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
388 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
390 // Order is now C, B, A. Let's remove B.
391 ASSERT_TRUE(RemoveExtension(browser_action_b()));
392 EXPECT_EQ(1u, observer()->removed_count());
393 EXPECT_EQ(2u, num_toolbar_items());
394 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
395 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
397 // Load extension B again.
398 ASSERT_TRUE(AddExtension(browser_action_b()));
400 // Extension B loaded again.
401 EXPECT_EQ(4u, observer()->inserted_count());
402 EXPECT_EQ(3u, num_toolbar_items());
403 // Make sure it gets its old spot in the list.
404 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
407 ASSERT_TRUE(RemoveExtension(browser_action_b()));
408 EXPECT_EQ(2u, observer()->removed_count());
409 EXPECT_EQ(2u, num_toolbar_items());
411 // Order is now C, A. Flip it.
412 toolbar_model()->MoveActionIcon(browser_action_a()->id(), 0);
413 EXPECT_EQ(3u, observer()->moved_count());
414 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
415 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
417 // Move A to the location it already occupies.
418 toolbar_model()->MoveActionIcon(browser_action_a()->id(), 0);
419 EXPECT_EQ(4u, observer()->moved_count());
420 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
421 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
423 // Order is now A, C.
424 ASSERT_TRUE(RemoveExtension(browser_action_c()));
425 EXPECT_EQ(3u, observer()->removed_count());
426 EXPECT_EQ(1u, num_toolbar_items());
427 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
429 // Load extension C again.
430 ASSERT_TRUE(AddExtension(browser_action_c()));
432 // Extension C loaded again.
433 EXPECT_EQ(5u, observer()->inserted_count());
434 EXPECT_EQ(2u, num_toolbar_items());
435 // Make sure it gets its old spot in the list (at the very end).
436 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
439 // Test that order persists after unloading and disabling, but not across
441 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarUnloadDisableAndUninstall
) {
444 // Add the three browser action extensions.
445 ASSERT_TRUE(AddBrowserActionExtensions());
447 // Verify the three actions are in the model in the proper order: A, B, C.
448 EXPECT_EQ(3u, num_toolbar_items());
449 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
450 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
451 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
453 // Unload B, then C, then A, and then reload C, then A, then B.
454 ASSERT_TRUE(RemoveExtension(browser_action_b()));
455 ASSERT_TRUE(RemoveExtension(browser_action_c()));
456 ASSERT_TRUE(RemoveExtension(browser_action_a()));
457 EXPECT_EQ(0u, num_toolbar_items()); // Sanity check: all gone?
458 ASSERT_TRUE(AddExtension(browser_action_c()));
459 ASSERT_TRUE(AddExtension(browser_action_a()));
460 ASSERT_TRUE(AddExtension(browser_action_b()));
461 EXPECT_EQ(3u, num_toolbar_items()); // Sanity check: all back?
462 EXPECT_EQ(0u, observer()->moved_count());
464 // Even though we unloaded and reloaded in a different order, the original
465 // order (A, B, C) should be preserved.
466 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
467 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
468 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
470 // Disabling extensions should also preserve order.
471 service()->DisableExtension(browser_action_b()->id(),
472 extensions::Extension::DISABLE_USER_ACTION
);
473 service()->DisableExtension(browser_action_c()->id(),
474 extensions::Extension::DISABLE_USER_ACTION
);
475 service()->DisableExtension(browser_action_a()->id(),
476 extensions::Extension::DISABLE_USER_ACTION
);
477 service()->EnableExtension(browser_action_c()->id());
478 service()->EnableExtension(browser_action_a()->id());
479 service()->EnableExtension(browser_action_b()->id());
481 // Make sure we still get the original A, B, C order.
482 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
483 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
484 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
486 // Move browser_action_b() to be first.
487 toolbar_model()->MoveActionIcon(browser_action_b()->id(), 0);
488 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
490 // Uninstall Extension B.
491 service()->UninstallExtension(browser_action_b()->id(),
492 extensions::UNINSTALL_REASON_FOR_TESTING
,
493 base::Bind(&base::DoNothing
),
494 NULL
); // Ignore error.
495 // List contains only A and C now. Validate that.
496 EXPECT_EQ(2u, num_toolbar_items());
497 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
498 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
500 ASSERT_TRUE(AddExtension(browser_action_b()));
502 // Make sure Extension B is _not_ first (its old position should have been
503 // forgotten at uninstall time). Order should be A, C, B.
504 EXPECT_EQ(3u, num_toolbar_items());
505 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
506 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
507 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
510 TEST_F(ToolbarActionsModelUnitTest
, ReorderOnPrefChange
) {
513 // Add the three browser action extensions.
514 ASSERT_TRUE(AddBrowserActionExtensions());
515 EXPECT_EQ(3u, num_toolbar_items());
517 // Change the value of the toolbar preference.
518 std::vector
<std::string
> new_order
;
519 new_order
.push_back(browser_action_c()->id());
520 new_order
.push_back(browser_action_b()->id());
521 extensions::ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order
);
523 // Verify order is changed.
524 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
525 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
526 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
529 // Test that new extension actions are always visible on installation and
530 // inserted at the "end" of the visible section.
531 TEST_F(ToolbarActionsModelUnitTest
, NewToolbarExtensionsAreVisible
) {
534 // Three extensions with actions.
535 scoped_refptr
<const extensions::Extension
> extension_a
=
536 extensions::extension_action_test_util::CreateActionExtension(
537 "a", extensions::extension_action_test_util::BROWSER_ACTION
);
538 scoped_refptr
<const extensions::Extension
> extension_b
=
539 extensions::extension_action_test_util::CreateActionExtension(
540 "b", extensions::extension_action_test_util::BROWSER_ACTION
);
541 scoped_refptr
<const extensions::Extension
> extension_c
=
542 extensions::extension_action_test_util::CreateActionExtension(
543 "c", extensions::extension_action_test_util::BROWSER_ACTION
);
544 scoped_refptr
<const extensions::Extension
> extension_d
=
545 extensions::extension_action_test_util::CreateActionExtension(
546 "d", extensions::extension_action_test_util::BROWSER_ACTION
);
548 // We should start off without any actions.
549 EXPECT_EQ(0u, num_toolbar_items());
550 EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
552 // Add one action. It should be visible.
553 service()->AddExtension(extension_a
.get());
554 EXPECT_EQ(1u, num_toolbar_items());
555 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
556 EXPECT_EQ(extension_a
.get()->id(), GetActionIdAtIndex(0u));
559 toolbar_model()->SetVisibleIconCount(0);
560 EXPECT_EQ(0u, toolbar_model()->visible_icon_count());
562 // Add a new action - it should be visible, so it should be in the first
563 // index. The other action should remain hidden.
564 service()->AddExtension(extension_b
.get());
565 EXPECT_EQ(2u, num_toolbar_items());
566 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
567 EXPECT_EQ(extension_b
.get()->id(), GetActionIdAtIndex(0u));
568 EXPECT_EQ(extension_a
.get()->id(), GetActionIdAtIndex(1u));
571 toolbar_model()->SetVisibleIconCount(2);
572 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
573 EXPECT_TRUE(toolbar_model()->all_icons_visible());
575 // Add the third action. Since all action are visible, it should go in the
577 service()->AddExtension(extension_c
.get());
578 EXPECT_EQ(3u, num_toolbar_items());
579 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
580 EXPECT_TRUE(toolbar_model()->all_icons_visible());
581 EXPECT_EQ(extension_b
.get()->id(), GetActionIdAtIndex(0u));
582 EXPECT_EQ(extension_a
.get()->id(), GetActionIdAtIndex(1u));
583 EXPECT_EQ(extension_c
.get()->id(), GetActionIdAtIndex(2u));
585 // Hide one action (two remaining visible).
586 toolbar_model()->SetVisibleIconCount(2);
587 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
589 // Add a fourth action. It should go at the end of the visible section and
590 // be visible, so it increases visible count by 1, and goes into the fourth
591 // index. The hidden action should remain hidden.
592 service()->AddExtension(extension_d
.get());
593 EXPECT_EQ(4u, num_toolbar_items());
594 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
595 EXPECT_EQ(extension_b
.get()->id(), GetActionIdAtIndex(0u));
596 EXPECT_EQ(extension_a
.get()->id(), GetActionIdAtIndex(1u));
597 EXPECT_EQ(extension_d
.get()->id(), GetActionIdAtIndex(2u));
598 EXPECT_EQ(extension_c
.get()->id(), GetActionIdAtIndex(3u));
601 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarHighlightMode
) {
604 EXPECT_FALSE(toolbar_model()->HighlightActions(
605 std::vector
<std::string
>(), ToolbarActionsModel::HIGHLIGHT_WARNING
));
606 EXPECT_EQ(0, observer()->highlight_mode_count());
608 // Add the three browser action extensions.
609 ASSERT_TRUE(AddBrowserActionExtensions());
610 EXPECT_EQ(3u, num_toolbar_items());
612 // Start with a visible count of 2 (non-zero, and not all).
613 toolbar_model()->SetVisibleIconCount(2u);
615 // Highlight one extension.
616 std::vector
<std::string
> action_ids
;
617 action_ids
.push_back(browser_action_b()->id());
618 toolbar_model()->HighlightActions(action_ids
,
619 ToolbarActionsModel::HIGHLIGHT_WARNING
);
620 EXPECT_EQ(1, observer()->highlight_mode_count());
621 EXPECT_TRUE(toolbar_model()->is_highlighting());
622 EXPECT_EQ(1u, num_toolbar_items());
623 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
624 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
626 // Stop highlighting.
627 toolbar_model()->StopHighlighting();
628 EXPECT_EQ(0, observer()->highlight_mode_count());
629 EXPECT_FALSE(toolbar_model()->is_highlighting());
631 // Verify that the extensions are back to normal.
632 EXPECT_EQ(3u, num_toolbar_items());
633 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
634 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
635 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
636 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
638 // Call stop highlighting a second time (shouldn't be notified).
639 toolbar_model()->StopHighlighting();
640 EXPECT_EQ(0, observer()->highlight_mode_count());
641 EXPECT_FALSE(toolbar_model()->is_highlighting());
643 // Highlight all extensions.
645 action_ids
.push_back(browser_action_a()->id());
646 action_ids
.push_back(browser_action_b()->id());
647 action_ids
.push_back(browser_action_c()->id());
648 toolbar_model()->HighlightActions(action_ids
,
649 ToolbarActionsModel::HIGHLIGHT_WARNING
);
650 EXPECT_EQ(1, observer()->highlight_mode_count());
651 EXPECT_EQ(3u, num_toolbar_items());
652 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
653 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
654 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
655 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
656 // Even though the visible count is 3, we shouldn't adjust the stored
658 EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(
659 extensions::pref_names::kToolbarSize
));
661 // Highlight only extension B (shrink the highlight list).
663 action_ids
.push_back(browser_action_b()->id());
664 toolbar_model()->HighlightActions(action_ids
,
665 ToolbarActionsModel::HIGHLIGHT_WARNING
);
666 EXPECT_EQ(2, observer()->highlight_mode_count());
667 EXPECT_EQ(1u, num_toolbar_items());
668 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
670 // Highlight extensions A and B (grow the highlight list).
672 action_ids
.push_back(browser_action_a()->id());
673 action_ids
.push_back(browser_action_b()->id());
674 toolbar_model()->HighlightActions(action_ids
,
675 ToolbarActionsModel::HIGHLIGHT_WARNING
);
676 EXPECT_EQ(3, observer()->highlight_mode_count());
677 EXPECT_EQ(2u, num_toolbar_items());
678 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
679 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
681 // Highlight no extensions (empty the highlight list).
683 toolbar_model()->HighlightActions(action_ids
,
684 ToolbarActionsModel::HIGHLIGHT_WARNING
);
685 EXPECT_EQ(2, observer()->highlight_mode_count());
686 EXPECT_FALSE(toolbar_model()->is_highlighting());
687 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
688 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
689 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
690 // Our toolbar size should be back to normal.
691 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
692 EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(
693 extensions::pref_names::kToolbarSize
));
696 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarHighlightModeRemove
) {
699 // Add the three browser action extensions.
700 ASSERT_TRUE(AddBrowserActionExtensions());
701 EXPECT_EQ(3u, num_toolbar_items());
703 // Highlight two of the extensions.
704 std::vector
<std::string
> action_ids
;
705 action_ids
.push_back(browser_action_a()->id());
706 action_ids
.push_back(browser_action_b()->id());
707 toolbar_model()->HighlightActions(action_ids
,
708 ToolbarActionsModel::HIGHLIGHT_WARNING
);
709 EXPECT_TRUE(toolbar_model()->is_highlighting());
710 EXPECT_EQ(1, observer()->highlight_mode_count());
711 EXPECT_EQ(2u, num_toolbar_items());
713 // Disable one of them - only one should remain highlighted.
714 service()->DisableExtension(browser_action_a()->id(),
715 extensions::Extension::DISABLE_USER_ACTION
);
716 EXPECT_TRUE(toolbar_model()->is_highlighting());
717 EXPECT_EQ(1u, num_toolbar_items());
718 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u));
720 // Uninstall the remaining highlighted extension. This should result in
721 // highlight mode exiting.
722 service()->UninstallExtension(browser_action_b()->id(),
723 extensions::UNINSTALL_REASON_FOR_TESTING
,
724 base::Bind(&base::DoNothing
),
725 NULL
); // Ignore error.
726 EXPECT_FALSE(toolbar_model()->is_highlighting());
727 EXPECT_EQ(0, observer()->highlight_mode_count());
728 EXPECT_EQ(1u, num_toolbar_items());
729 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
731 // Test that removing an unhighlighted extension still works.
732 // Reinstall extension B, and then highlight extension C.
733 ASSERT_TRUE(AddExtension(browser_action_b()));
734 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
736 action_ids
.push_back(browser_action_c()->id());
737 toolbar_model()->HighlightActions(action_ids
,
738 ToolbarActionsModel::HIGHLIGHT_WARNING
);
739 EXPECT_EQ(1, observer()->highlight_mode_count());
740 EXPECT_TRUE(toolbar_model()->is_highlighting());
741 EXPECT_EQ(1u, num_toolbar_items());
742 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
744 // Uninstalling B should not have visible impact.
745 service()->UninstallExtension(browser_action_b()->id(),
746 extensions::UNINSTALL_REASON_FOR_TESTING
,
747 base::Bind(&base::DoNothing
),
748 NULL
); // Ignore error.
749 EXPECT_TRUE(toolbar_model()->is_highlighting());
750 EXPECT_EQ(1, observer()->highlight_mode_count());
751 EXPECT_EQ(1u, num_toolbar_items());
752 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
754 // When we stop, only action C should remain.
755 toolbar_model()->StopHighlighting();
756 EXPECT_FALSE(toolbar_model()->is_highlighting());
757 EXPECT_EQ(0, observer()->highlight_mode_count());
758 EXPECT_EQ(1u, num_toolbar_items());
759 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
762 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarHighlightModeAdd
) {
765 // Add the three browser action extensions.
766 ASSERT_TRUE(AddBrowserActionExtensions());
767 EXPECT_EQ(3u, num_toolbar_items());
769 // Remove one (down to two).
770 ASSERT_TRUE(RemoveExtension(browser_action_c()));
772 // Highlight one of the two actions.
773 std::vector
<std::string
> action_ids
;
774 action_ids
.push_back(browser_action_a()->id());
775 toolbar_model()->HighlightActions(action_ids
,
776 ToolbarActionsModel::HIGHLIGHT_WARNING
);
777 EXPECT_TRUE(toolbar_model()->is_highlighting());
778 EXPECT_EQ(1u, num_toolbar_items());
779 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
781 // Adding a new extension should have no visible effect.
782 ASSERT_TRUE(AddExtension(browser_action_c()));
783 EXPECT_TRUE(toolbar_model()->is_highlighting());
784 EXPECT_EQ(1u, num_toolbar_items());
785 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
787 // When we stop highlighting, we should see the new extension show up.
788 toolbar_model()->StopHighlighting();
789 EXPECT_FALSE(toolbar_model()->is_highlighting());
790 EXPECT_EQ(3u, num_toolbar_items());
791 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
792 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
793 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
796 // Test that the action toolbar maintains the proper size, even after a pref
798 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarSizeAfterPrefChange
) {
801 // Add the three browser action extensions.
802 ASSERT_TRUE(AddBrowserActionExtensions());
803 EXPECT_EQ(3u, num_toolbar_items());
805 // Should be at max size.
806 EXPECT_TRUE(toolbar_model()->all_icons_visible());
807 EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
808 toolbar_model()->OnActionToolbarPrefChange();
809 // Should still be at max size.
810 EXPECT_TRUE(toolbar_model()->all_icons_visible());
811 EXPECT_EQ(num_toolbar_items(), toolbar_model()->visible_icon_count());
814 // Test that, in the absence of the extension-action-redesign switch, the
815 // model only contains extensions with browser actions and component actions.
816 TEST_F(ToolbarActionsModelUnitTest
, TestToolbarExtensionTypesNoSwitch
) {
818 ASSERT_TRUE(AddActionExtensions());
820 EXPECT_EQ(1u, num_toolbar_items());
821 EXPECT_EQ(browser_action()->id(), GetActionIdAtIndex(0u));
824 // Test that, with the extension-action-redesign switch, the model contains
825 // all types of extensions, except those which should not be displayed on the
826 // toolbar (like component extensions).
827 TEST_F(ToolbarActionsModelUnitTest
, TestToolbarExtensionTypesSwitch
) {
828 extensions::FeatureSwitch::ScopedOverride
enable_redesign(
829 extensions::FeatureSwitch::extension_action_redesign(), true);
832 ASSERT_TRUE(AddActionExtensions());
834 // With the switch on, extensions with page actions and no action should also
835 // be displayed in the toolbar.
836 EXPECT_EQ(3u, num_toolbar_items());
837 EXPECT_EQ(browser_action()->id(), GetActionIdAtIndex(0u));
838 EXPECT_EQ(page_action()->id(), GetActionIdAtIndex(1u));
839 EXPECT_EQ(no_action()->id(), GetActionIdAtIndex(2u));
842 // Test that hiding actions on the toolbar results in their removal from the
843 // model when the redesign switch is not enabled.
844 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarActionsVisibilityNoSwitch
) {
847 extensions::ExtensionActionAPI
* action_api
=
848 extensions::ExtensionActionAPI::Get(profile());
850 ASSERT_TRUE(AddBrowserActionExtensions());
851 // Sanity check: Order should start as A , B, C.
852 EXPECT_EQ(3u, num_toolbar_items());
853 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
854 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
855 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
857 // By default, all actions should be visible.
858 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(browser_action_a()->id()));
859 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(browser_action_b()->id()));
860 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(browser_action_c()->id()));
862 // Hiding an action should result in its removal from the toolbar.
863 action_api
->SetBrowserActionVisibility(browser_action_b()->id(), false);
865 action_api
->GetBrowserActionVisibility(browser_action_b()->id()));
866 // Thus, there should now only be two items on the toolbar - A and C.
867 EXPECT_EQ(2u, num_toolbar_items());
868 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
869 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
871 // Resetting the visibility to 'true' should result in the extension being
872 // added back at its original position.
873 action_api
->SetBrowserActionVisibility(browser_action_b()->id(), true);
874 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(browser_action_b()->id()));
875 // So the toolbar order should be A, B, C.
876 EXPECT_EQ(3u, num_toolbar_items());
877 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
878 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
879 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2u));
882 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarIncognitoModeTest
) {
884 ASSERT_TRUE(AddBrowserActionExtensions());
886 // Give two extensions incognito access.
887 // Note: We use ExtensionPrefs::SetIsIncognitoEnabled instead of
888 // util::SetIsIncognitoEnabled because the latter tries to reload the
889 // extension, which requries a filepath associated with the extension (and,
890 // for this test, reloading the extension is irrelevant to us).
891 extensions::ExtensionPrefs
* extension_prefs
=
892 extensions::ExtensionPrefs::Get(profile());
893 extension_prefs
->SetIsIncognitoEnabled(browser_action_b()->id(), true);
894 extension_prefs
->SetIsIncognitoEnabled(browser_action_c()->id(), true);
896 extensions::util::SetIsIncognitoEnabled(browser_action_b()->id(), profile(),
898 extensions::util::SetIsIncognitoEnabled(browser_action_c()->id(), profile(),
901 // Move C to the second index.
902 toolbar_model()->MoveActionIcon(browser_action_c()->id(), 1u);
903 // Set visible count to 3 so that C is overflowed. State is A, C, [B].
904 toolbar_model()->SetVisibleIconCount(2);
905 EXPECT_EQ(1u, observer()->moved_count());
907 // Get an incognito profile and toolbar.
908 ToolbarActionsModel
* incognito_model
=
909 extensions::extension_action_test_util::CreateToolbarModelForProfile(
910 profile()->GetOffTheRecordProfile());
912 ToolbarActionsModelTestObserver
incognito_observer(incognito_model
);
913 EXPECT_EQ(0u, incognito_observer
.moved_count());
915 // We should have two items: C, B, and the order should be preserved from the
917 EXPECT_EQ(2u, incognito_model
->toolbar_items().size());
918 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u, incognito_model
));
919 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u, incognito_model
));
921 // Actions in the overflow menu in the regular toolbar should remain in
922 // overflow in the incognito toolbar. So, we should have C, [B].
923 EXPECT_EQ(1u, incognito_model
->visible_icon_count());
924 // The regular model should still have two icons visible.
925 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
927 // Changing the incognito model size should not affect the regular model.
928 incognito_model
->SetVisibleIconCount(0);
929 EXPECT_EQ(0u, incognito_model
->visible_icon_count());
930 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
932 // Expanding the incognito model to 3 should register as "all icons"
933 // since it is all of the incognito-enabled extensions.
934 incognito_model
->SetVisibleIconCount(2u);
935 EXPECT_EQ(2u, incognito_model
->visible_icon_count());
936 EXPECT_TRUE(incognito_model
->all_icons_visible());
938 // Moving icons in the incognito toolbar should not affect the regular
939 // toolbar. Incognito currently has C, B...
940 incognito_model
->MoveActionIcon(browser_action_b()->id(), 0u);
941 // So now it should be B, C...
942 EXPECT_EQ(1u, incognito_observer
.moved_count());
943 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0u, incognito_model
));
944 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u, incognito_model
));
945 // ... and the regular toolbar should be unaffected.
946 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
947 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1u));
948 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
950 // Similarly, the observer for the regular model should not have received
952 EXPECT_EQ(1u, observer()->moved_count());
954 // And performing moves on the regular model should have no effect on the
955 // incognito model or its observers.
956 toolbar_model()->MoveActionIcon(browser_action_c()->id(), 2u);
957 EXPECT_EQ(2u, observer()->moved_count());
958 EXPECT_EQ(1u, incognito_observer
.moved_count());
961 // Test that enabling extensions incognito with an active incognito profile
963 TEST_F(ToolbarActionsModelUnitTest
, ActionsToolbarIncognitoEnableExtension
) {
966 const char* kManifest
=
969 " \"version\": \"1.0\","
970 " \"manifest_version\": 2,"
971 " \"browser_action\": {}"
974 // For this test, we need to have "real" extension files, because we need to
975 // be able to reload them during the incognito process. Since the toolbar
976 // needs to be notified of the reload, we need it this time (as opposed to
977 // above, where we simply set the prefs before the incognito bar was
979 extensions::TestExtensionDir dir1
;
980 dir1
.WriteManifest(base::StringPrintf(kManifest
, "incognito1"));
981 extensions::TestExtensionDir dir2
;
982 dir2
.WriteManifest(base::StringPrintf(kManifest
, "incognito2"));
984 extensions::TestExtensionDir
* dirs
[] = {&dir1
, &dir2
};
985 const extensions::Extension
* extensions
[] = {nullptr, nullptr};
986 for (size_t i
= 0; i
< arraysize(dirs
); ++i
) {
987 // The extension id will be calculated from the file path; we need this to
988 // wait for the extension to load.
989 base::FilePath path_for_id
=
990 base::MakeAbsoluteFilePath(dirs
[i
]->unpacked_path());
991 std::string id
= crx_file::id_util::GenerateIdForPath(path_for_id
);
992 extensions::TestExtensionRegistryObserver
observer(registry(), id
);
993 extensions::UnpackedInstaller::Create(service())
994 ->Load(dirs
[i
]->unpacked_path());
995 observer
.WaitForExtensionLoaded();
996 extensions
[i
] = registry()->enabled_extensions().GetByID(id
);
997 ASSERT_TRUE(extensions
[i
]);
1000 // For readability, alias to A and B. Since we'll be reloading these
1001 // extensions, we also can't rely on pointers.
1002 std::string extension_a
= extensions
[0]->id();
1003 std::string extension_b
= extensions
[1]->id();
1005 // The first model should have both extensions visible.
1006 EXPECT_EQ(2u, toolbar_model()->toolbar_items().size());
1007 EXPECT_EQ(extension_a
, GetActionIdAtIndex(0u));
1008 EXPECT_EQ(extension_b
, GetActionIdAtIndex(1u));
1010 // Set the model to only show one extension, so the order is A, [B].
1011 toolbar_model()->SetVisibleIconCount(1u);
1013 // Get an incognito profile and toolbar.
1014 ToolbarActionsModel
* incognito_model
=
1015 extensions::extension_action_test_util::CreateToolbarModelForProfile(
1016 profile()->GetOffTheRecordProfile());
1017 ToolbarActionsModelTestObserver
incognito_observer(incognito_model
);
1019 // Right now, no actions are enabled in incognito mode.
1020 EXPECT_EQ(0u, incognito_model
->toolbar_items().size());
1022 // Set extension B (which is overflowed) to be enabled in incognito. This
1023 // results in b reloading, so wait for it.
1025 extensions::TestExtensionRegistryObserver
observer(registry(), extension_b
);
1026 extensions::util::SetIsIncognitoEnabled(extension_b
, profile(), true);
1027 observer
.WaitForExtensionLoaded();
1030 // Now, we should have one icon in the incognito bar. But, since B is
1031 // overflowed in the main bar, it shouldn't be visible.
1032 EXPECT_EQ(1u, incognito_model
->toolbar_items().size());
1033 EXPECT_EQ(extension_b
, GetActionIdAtIndex(0u, incognito_model
));
1034 EXPECT_EQ(0u, incognito_model
->visible_icon_count());
1036 // Also enable extension a for incognito (again, wait for the reload).
1038 extensions::TestExtensionRegistryObserver
observer(registry(), extension_a
);
1039 extensions::util::SetIsIncognitoEnabled(extension_a
, profile(), true);
1040 observer
.WaitForExtensionLoaded();
1043 // Now, both extensions should be enabled in incognito mode. In addition, the
1044 // incognito toolbar should have expanded to show extension A (since it isn't
1045 // overflowed in the main bar).
1046 EXPECT_EQ(2u, incognito_model
->toolbar_items().size());
1047 EXPECT_EQ(extension_a
, GetActionIdAtIndex(0u, incognito_model
));
1048 EXPECT_EQ(extension_b
, GetActionIdAtIndex(1u, incognito_model
));
1049 EXPECT_EQ(1u, incognito_model
->visible_icon_count());
1052 // Test that hiding actions on the toolbar results in sending them to the
1053 // overflow menu when the redesign switch is enabled.
1054 TEST_F(ToolbarActionsModelUnitTest
,
1055 ActionsToolbarActionsVisibilityWithSwitchAndComponentActions
) {
1056 extensions::FeatureSwitch::ScopedOverride
enable_redesign(
1057 extensions::FeatureSwitch::extension_action_redesign(), true);
1060 // We choose to use all types of extensions here, since the misnamed
1061 // BrowserActionVisibility is now for toolbar visibility.
1062 ASSERT_TRUE(AddActionExtensions());
1064 // For readability, alias extensions A B C.
1065 const extensions::Extension
* extension_a
= browser_action();
1066 const extensions::Extension
* extension_b
= page_action();
1067 const extensions::Extension
* extension_c
= no_action();
1069 // Sanity check: Order should start as A, B, C, with all three visible.
1070 EXPECT_EQ(3u, num_toolbar_items());
1071 EXPECT_TRUE(toolbar_model()->all_icons_visible());
1072 EXPECT_EQ(extension_a
->id(), GetActionIdAtIndex(0u));
1073 EXPECT_EQ(extension_b
->id(), GetActionIdAtIndex(1u));
1074 EXPECT_EQ(extension_c
->id(), GetActionIdAtIndex(2u));
1076 extensions::ExtensionActionAPI
* action_api
=
1077 extensions::ExtensionActionAPI::Get(profile());
1079 // By default, all actions should be visible.
1080 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(extension_a
->id()));
1081 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(extension_c
->id()));
1082 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(extension_b
->id()));
1084 // Hiding an action should result in it being sent to the overflow menu.
1085 action_api
->SetBrowserActionVisibility(extension_b
->id(), false);
1087 // Thus, the order should be A, C, B, with B in the overflow.
1088 EXPECT_EQ(3u, num_toolbar_items());
1089 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
1090 EXPECT_EQ(extension_a
->id(), GetActionIdAtIndex(0u));
1091 EXPECT_EQ(extension_c
->id(), GetActionIdAtIndex(1u));
1092 EXPECT_EQ(extension_b
->id(), GetActionIdAtIndex(2u));
1094 // Hiding an extension's action should result in it being sent to the overflow
1095 // as well, but as the _first_ extension in the overflow.
1096 action_api
->SetBrowserActionVisibility(extension_a
->id(), false);
1097 // Thus, the order should be C, A, B, with A and B in the overflow.
1098 EXPECT_EQ(3u, num_toolbar_items());
1099 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
1100 EXPECT_EQ(extension_c
->id(), GetActionIdAtIndex(0u));
1101 EXPECT_EQ(extension_a
->id(), GetActionIdAtIndex(1u));
1102 EXPECT_EQ(extension_b
->id(), GetActionIdAtIndex(2u));
1104 // Resetting A's visibility to true should send it back to the visible icons
1105 // (and should grow visible icons by 1), but it should be added to the end of
1106 // the visible icon list (not to its original position).
1107 action_api
->SetBrowserActionVisibility(extension_a
->id(), true);
1108 // So order is C, A, B, with only B in the overflow.
1109 EXPECT_EQ(3u, num_toolbar_items());
1110 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
1111 EXPECT_EQ(extension_c
->id(), GetActionIdAtIndex(0u));
1112 EXPECT_EQ(extension_a
->id(), GetActionIdAtIndex(1u));
1113 EXPECT_EQ(extension_b
->id(), GetActionIdAtIndex(2u));
1115 // Resetting B to be visible should make the order C, A, B, with no
1117 action_api
->SetBrowserActionVisibility(extension_b
->id(), true);
1118 EXPECT_EQ(3u, num_toolbar_items());
1119 EXPECT_TRUE(toolbar_model()->all_icons_visible());
1120 EXPECT_EQ(extension_c
->id(), GetActionIdAtIndex(0u));
1121 EXPECT_EQ(extension_a
->id(), GetActionIdAtIndex(1u));
1122 EXPECT_EQ(extension_b
->id(), GetActionIdAtIndex(2u));
1124 // Regression test for crbug.com/515963. Check that an extension's visibility
1125 // is updated when it is moved out because another extension was removed.
1126 toolbar_model()->SetVisibleIconCount(1);
1127 base::RunLoop().RunUntilIdle();
1128 EXPECT_FALSE(action_api
->GetBrowserActionVisibility(extension_a
->id()));
1129 service()->DisableExtension(extension_c
->id(),
1130 extensions::Extension::DISABLE_USER_ACTION
);
1131 EXPECT_EQ(1u, toolbar_model()->visible_icon_count());
1132 EXPECT_TRUE(action_api
->GetBrowserActionVisibility(extension_a
->id()));
1135 // Test that observers receive no Added notifications until after the
1136 // ExtensionSystem has initialized.
1137 TEST_F(ToolbarActionsModelUnitTest
, ModelWaitsForExtensionSystemReady
) {
1138 InitializeEmptyExtensionService();
1139 ToolbarActionsModel
* toolbar_model
= extensions::extension_action_test_util::
1140 CreateToolbarModelForProfileWithoutWaitingForReady(profile());
1141 ToolbarActionsModelTestObserver
model_observer(toolbar_model
);
1143 EXPECT_TRUE(AddBrowserActionExtensions());
1145 // Since the model hasn't been initialized (the ExtensionSystem::ready task
1146 // hasn't been run), there should be no insertion notifications.
1147 EXPECT_EQ(0u, model_observer
.inserted_count());
1148 EXPECT_EQ(0u, model_observer
.initialized_count());
1149 EXPECT_FALSE(toolbar_model
->actions_initialized());
1151 // Run the ready task.
1152 static_cast<extensions::TestExtensionSystem
*>(
1153 extensions::ExtensionSystem::Get(profile()))
1155 // Run tasks posted to TestExtensionSystem.
1156 base::RunLoop().RunUntilIdle();
1158 // We should still have no insertions, but should have an initialized count.
1159 EXPECT_TRUE(toolbar_model
->actions_initialized());
1160 EXPECT_EQ(0u, model_observer
.inserted_count());
1161 EXPECT_EQ(1u, model_observer
.initialized_count());
1164 // Check that the toolbar model correctly clears and reorders when it detects
1165 // a preference change.
1166 TEST_F(ToolbarActionsModelUnitTest
, ToolbarModelPrefChange
) {
1169 ASSERT_TRUE(AddBrowserActionExtensions());
1171 // We should start in the basic A, B, C order.
1172 ASSERT_TRUE(browser_action_a());
1173 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0));
1174 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1));
1175 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2));
1176 // Record the difference between the inserted and removed counts. The actual
1177 // value of the counts is not important, but we need to be sure that if we
1178 // call to remove any, we also add them back.
1179 size_t inserted_and_removed_difference
=
1180 observer()->inserted_count() - observer()->removed_count();
1182 // Assign a new order, B, C, A, and write it in the prefs.
1183 std::vector
<std::string
> new_order
;
1184 new_order
.push_back(browser_action_b()->id());
1185 new_order
.push_back(browser_action_c()->id());
1186 new_order
.push_back(browser_action_a()->id());
1187 extensions::ExtensionPrefs::Get(profile())->SetToolbarOrder(new_order
);
1189 // Ensure everything has time to run.
1190 base::RunLoop().RunUntilIdle();
1192 // The new order should be reflected in the model.
1193 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(0));
1194 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(1));
1195 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2));
1196 EXPECT_EQ(inserted_and_removed_difference
,
1197 observer()->inserted_count() - observer()->removed_count());
1200 TEST_F(ToolbarActionsModelUnitTest
, ComponentExtensionsAddedToEnd
) {
1203 ASSERT_TRUE(AddBrowserActionExtensions());
1205 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0));
1206 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1));
1207 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(2));
1209 const char kName
[] = "component";
1210 extensions::DictionaryBuilder manifest
;
1211 manifest
.Set("name", kName
)
1212 .Set("description", "An extension")
1213 .Set("manifest_version", 2)
1214 .Set("version", "1.0.0")
1215 .Set("browser_action", extensions::DictionaryBuilder().Pass());
1216 scoped_refptr
<const extensions::Extension
> component_extension
=
1217 extensions::ExtensionBuilder()
1218 .SetManifest(manifest
.Pass())
1219 .SetID(crx_file::id_util::GenerateId(kName
))
1220 .SetLocation(extensions::Manifest::COMPONENT
)
1222 service()->AddExtension(component_extension
.get());
1224 EXPECT_EQ(component_extension
.get()->id(), GetActionIdAtIndex(0));
1225 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1));
1226 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2));
1227 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(3));
1230 TEST_F(ToolbarActionsModelUnitTest
, ToolbarModelHighlightsForToolbarRedesign
) {
1231 extensions::FeatureSwitch::ScopedOverride
enable_redesign(
1232 extensions::FeatureSwitch::extension_action_redesign(), true);
1233 InitializeEmptyExtensionService();
1234 EXPECT_TRUE(AddActionExtensions());
1235 ToolbarActionsModel
* toolbar_model
=
1236 extensions::extension_action_test_util::CreateToolbarModelForProfile(
1238 EXPECT_TRUE(toolbar_model
);
1239 base::RunLoop().RunUntilIdle();
1241 EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
1243 EXPECT_TRUE(toolbar_model
->is_highlighting());
1244 EXPECT_EQ(ToolbarActionsModel::HIGHLIGHT_INFO
,
1245 toolbar_model
->highlight_type());
1246 EXPECT_EQ(3u, toolbar_model
->visible_icon_count());
1247 EXPECT_EQ(3u, toolbar_model
->toolbar_items().size());
1249 scoped_ptr
<ToolbarActionsBarBubbleDelegate
> bubble(
1250 new ExtensionToolbarIconSurfacingBubbleDelegate(profile()));
1251 bubble
->OnBubbleClosed(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS
);
1253 EXPECT_FALSE(toolbar_model
->is_highlighting());
1254 EXPECT_EQ(ToolbarActionsModel::HIGHLIGHT_NONE
,
1255 toolbar_model
->highlight_type());
1258 // Test various different reorderings, removals, and reinsertions of the
1259 // toolbar with component actions.
1260 TEST_F(ToolbarActionsModelUnitTest
,
1261 ActionsToolbarReorderAndReinsertWithSwitchAndCOmponentActions
) {
1262 extensions::FeatureSwitch::ScopedOverride
enable_redesign(
1263 extensions::FeatureSwitch::extension_action_redesign(), true);
1264 SetMockActionsFactory(new MockComponentToolbarActionsFactory(nullptr));
1267 // One component action was added when the model was initialized.
1268 EXPECT_EQ(1u, num_toolbar_items());
1269 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
1271 // Add the three browser action extensions.
1272 ASSERT_TRUE(AddBrowserActionExtensions());
1274 // Verify the four actions are in the model in the proper order.
1275 EXPECT_EQ(4u, num_toolbar_items());
1276 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
1277 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
1278 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
1279 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(3u));
1281 // Order is now MCA, A, B, C. Let's put C first.
1282 toolbar_model()->MoveActionIcon(browser_action_c()->id(), 0);
1283 EXPECT_EQ(1u, observer()->moved_count());
1284 EXPECT_EQ(4u, num_toolbar_items());
1285 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
1286 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
1287 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(2u));
1288 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(3u));
1290 // Order is now C, MCA, A, B. Let's put MCA last.
1291 toolbar_model()->MoveActionIcon(component_action_id(), 3);
1292 EXPECT_EQ(2u, observer()->moved_count());
1293 EXPECT_EQ(4u, num_toolbar_items());
1294 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
1295 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
1296 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
1297 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(3u));
1299 // Order is now C, A, B, MCA. Move MCA to the location it already occupies.
1300 toolbar_model()->MoveActionIcon(component_action_id(), 3);
1301 EXPECT_EQ(3u, observer()->moved_count());
1302 EXPECT_EQ(4u, num_toolbar_items());
1303 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
1304 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
1305 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
1306 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(3u));
1308 // Order is still C, A, B, MCA. Move MCA to second to last, in preparation
1309 // for visibility checks.
1310 toolbar_model()->MoveActionIcon(component_action_id(), 2);
1311 EXPECT_EQ(4u, observer()->moved_count());
1312 EXPECT_EQ(4u, num_toolbar_items());
1313 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
1314 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(1u));
1315 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(2u));
1316 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(3u));
1318 // Order is now C, A, MCA, B. Show only three icons: C, A, MCA, [B].
1319 toolbar_model()->SetVisibleIconCount(3);
1320 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
1321 EXPECT_FALSE(toolbar_model()->all_icons_visible());
1323 // Show only two icons so we test MCA in the overflow. The icons should
1324 // be: C, A, [MCA], [B].
1325 toolbar_model()->SetVisibleIconCount(2);
1326 EXPECT_EQ(2u, toolbar_model()->visible_icon_count());
1327 EXPECT_FALSE(toolbar_model()->all_icons_visible());
1329 // Show all the icons again. Order should be C, A, MCA, B.
1330 toolbar_model()->SetVisibleIconCount(4);
1331 EXPECT_EQ(4u, toolbar_model()->visible_icon_count());
1332 EXPECT_TRUE(toolbar_model()->all_icons_visible());
1334 // Order is C, A, MCA, B. Remove C.
1335 ASSERT_TRUE(RemoveExtension(browser_action_c()));
1336 EXPECT_EQ(1u, observer()->removed_count());
1337 EXPECT_EQ(3u, num_toolbar_items());
1338 EXPECT_EQ(browser_action_a()->id(), GetActionIdAtIndex(0u));
1339 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));
1340 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(2u));
1342 // Order is now A, MCA, B. Remove A.
1343 ASSERT_TRUE(RemoveExtension(browser_action_a()));
1344 EXPECT_EQ(2u, observer()->removed_count());
1345 EXPECT_EQ(2u, num_toolbar_items());
1346 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
1347 EXPECT_EQ(browser_action_b()->id(), GetActionIdAtIndex(1u));
1349 // Order is now MCA, B. Remove B.
1350 ASSERT_TRUE(RemoveExtension(browser_action_b()));
1351 EXPECT_EQ(3u, observer()->removed_count());
1352 EXPECT_EQ(1u, num_toolbar_items());
1353 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(0u));
1355 // Load extension C again.
1356 ASSERT_TRUE(AddExtension(browser_action_c()));
1357 EXPECT_EQ(4u, observer()->inserted_count());
1358 EXPECT_EQ(2u, num_toolbar_items());
1359 // Make sure it gets its old spot in the list (at the beginning).
1360 EXPECT_EQ(browser_action_c()->id(), GetActionIdAtIndex(0u));
1361 EXPECT_EQ(component_action_id(), GetActionIdAtIndex(1u));