Add ability to gather metrics to BubbleManager.
[chromium-blink-merge.git] / chrome / browser / ui / toolbar / toolbar_actions_model_unittest.cc
blob63d1a55817b4b2c9ec859a43d331f415235a1432
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"
40 namespace {
42 // A simple observer that tracks the number of times certain events occur.
43 class ToolbarActionsModelTestObserver : public ToolbarActionsModel::Observer {
44 public:
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_; }
54 private:
55 // ToolbarActionsModel::Observer:
56 void OnToolbarActionAdded(const std::string& id, int index) override {
57 ++inserted_count_;
60 void OnToolbarActionRemoved(const std::string& id) override {
61 ++removed_count_;
64 void OnToolbarActionMoved(const std::string& id, int index) override {
65 ++moved_count_;
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_;
83 size_t moved_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)
93 : model_(model),
94 inserted_count_(0),
95 removed_count_(0),
96 moved_count_(0),
97 highlight_mode_count_(0),
98 initialized_count_(0) {
99 model_->AddObserver(this);
102 ToolbarActionsModelTestObserver::~ToolbarActionsModelTestObserver() {
103 model_->RemoveObserver(this);
106 } // namespace
108 class ToolbarActionsModelUnitTest
109 : public extensions::ExtensionServiceTestBase {
110 public:
111 ToolbarActionsModelUnitTest() {}
112 ~ToolbarActionsModelUnitTest() override {}
114 protected:
115 // Initialize the ExtensionService, ToolbarActionsModel, and
116 // ExtensionSystem.
117 void Init();
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)
124 WARN_UNUSED_RESULT;
125 testing::AssertionResult RemoveExtension(
126 const scoped_refptr<const extensions::Extension>& extension)
127 WARN_UNUSED_RESULT;
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
139 // |toolbar_model_|.
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;
178 private:
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();
207 toolbar_model_ =
208 extensions::extension_action_test_util::CreateToolbarModelForProfile(
209 profile());
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(
250 "browser_action",
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() {
269 browser_action_a_ =
270 extensions::extension_action_test_util::CreateActionExtension(
271 "browser_actionA",
272 extensions::extension_action_test_util::BROWSER_ACTION);
273 browser_action_b_ =
274 extensions::extension_action_test_util::CreateActionExtension(
275 "browser_actionB",
276 extensions::extension_action_test_util::BROWSER_ACTION);
277 browser_action_c_ =
278 extensions::extension_action_test_util::CreateActionExtension(
279 "browser_actionC",
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(
291 size_t index,
292 const ToolbarActionsModel* model) const {
293 return index < model->toolbar_items().size()
294 ? model->toolbar_items()[index].id
295 : std::string();
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: "
309 << (*iter)->name();
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) {
323 Init();
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(
339 "browser_action",
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) {
363 Init();
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));
406 // Unload B again.
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
440 // uninstallation.
441 TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarUnloadDisableAndUninstall) {
442 Init();
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) {
511 Init();
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) {
532 Init();
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));
558 // Hide all actions.
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));
570 // Show all actions.
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
576 // last index.
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) {
602 Init();
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.
644 action_ids.clear();
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
657 // preference.
658 EXPECT_EQ(2, profile()->GetPrefs()->GetInteger(
659 extensions::pref_names::kToolbarSize));
661 // Highlight only extension B (shrink the highlight list).
662 action_ids.clear();
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).
671 action_ids.clear();
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).
682 action_ids.clear();
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) {
697 Init();
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));
735 action_ids.clear();
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) {
763 Init();
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
797 // change.
798 TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarSizeAfterPrefChange) {
799 Init();
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) {
817 Init();
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);
830 Init();
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) {
845 Init();
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);
864 EXPECT_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) {
883 Init();
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(),
897 true);
898 extensions::util::SetIsIncognitoEnabled(browser_action_c()->id(), profile(),
899 true);
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
916 // original model.
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
951 // any updates.
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
962 // works.
963 TEST_F(ToolbarActionsModelUnitTest, ActionsToolbarIncognitoEnableExtension) {
964 Init();
966 const char* kManifest =
968 " \"name\": \"%s\","
969 " \"version\": \"1.0\","
970 " \"manifest_version\": 2,"
971 " \"browser_action\": {}"
972 "}";
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
978 // created.
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);
1058 Init();
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
1116 // overflow.
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()))
1154 ->SetReady();
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) {
1167 Init();
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) {
1201 Init();
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)
1221 .Build();
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(
1237 profile());
1238 EXPECT_TRUE(toolbar_model);
1239 base::RunLoop().RunUntilIdle();
1241 EXPECT_TRUE(ExtensionToolbarIconSurfacingBubbleDelegate::ShouldShowForProfile(
1242 profile()));
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));
1265 Init();
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));