1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view.h"
6 #include "base/bind.h"
7 #include "base/callback.h"
8 #include "base/compiler_specific.h"
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/run_loop.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "build/build_config.h"
17 #include "chrome/app/chrome_command_ids.h"
18 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
19 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
20 #include "chrome/browser/chrome_content_browser_client.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/bookmarks/bookmark_utils.h"
23 #include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_tabstrip.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/browser/ui/views/bookmarks/bookmark_bar_view_observer.h"
29 #include "chrome/browser/ui/views/bookmarks/bookmark_context_menu.h"
30 #include "chrome/browser/ui/views/bookmarks/bookmark_menu_controller_views.h"
31 #include "chrome/browser/ui/views/chrome_constrained_window_views_client.h"
32 #include "chrome/browser/ui/views/chrome_layout_provider.h"
33 #include "chrome/browser/ui/views/test/view_event_test_base.h"
34 #include "chrome/common/chrome_content_client.h"
35 #include "chrome/test/base/interactive_test_utils.h"
36 #include "chrome/test/base/scoped_testing_local_state.h"
37 #include "chrome/test/base/test_browser_window.h"
38 #include "chrome/test/base/testing_browser_process.h"
39 #include "chrome/test/base/testing_profile.h"
40 #include "chrome/test/base/ui_test_utils.h"
41 #include "components/bookmarks/browser/bookmark_model.h"
42 #include "components/bookmarks/common/bookmark_pref_names.h"
43 #include "components/bookmarks/test/bookmark_test_helpers.h"
44 #include "components/constrained_window/constrained_window_views.h"
45 #include "components/prefs/pref_service.h"
46 #include "content/public/browser/page_navigator.h"
47 #include "ui/base/test/ui_controls.h"
48 #include "ui/events/keycodes/keyboard_codes.h"
49 #include "ui/views/background.h"
50 #include "ui/views/controls/button/menu_button.h"
51 #include "ui/views/controls/menu/menu_controller.h"
52 #include "ui/views/controls/menu/menu_item_view.h"
53 #include "ui/views/controls/menu/submenu_view.h"
54 #include "ui/views/layout/flex_layout.h"
55 #include "ui/views/layout/flex_layout_types.h"
56 #include "ui/views/layout/layout_provider.h"
57 #include "ui/views/view_class_properties.h"
58 #include "ui/views/widget/drop_helper.h"
59 #include "ui/views/widget/widget.h"
60 
61 #if !defined(OS_MAC)
62 #include "ui/aura/env.h"
63 #include "ui/aura/env_observer.h"
64 #include "ui/aura/window.h"
65 #endif
66 
67 #if defined(OS_WIN)
68 #include "base/win/windows_version.h"
69 #include "ui/aura/window_tree_host.h"
70 #endif
71 
72 using base::ASCIIToUTF16;
73 using bookmarks::BookmarkModel;
74 using bookmarks::BookmarkNode;
75 using content::BrowserThread;
76 using content::OpenURLParams;
77 using content::PageNavigator;
78 using content::WebContents;
79 
80 namespace {
81 
82 #if !defined(OS_MAC)
83 
84 // Waits for a views::Widget dialog to show up.
85 class DialogWaiter : public aura::EnvObserver,
86                      public views::WidgetObserver {
87  public:
DialogWaiter()88   DialogWaiter() { aura::Env::GetInstance()->AddObserver(this); }
89 
~DialogWaiter()90   ~DialogWaiter() override { aura::Env::GetInstance()->RemoveObserver(this); }
91 
WaitForDialog()92   views::Widget* WaitForDialog() {
93     if (dialog_created_)
94       return dialog_;
95     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
96     quit_closure_ = run_loop.QuitClosure();
97     run_loop.Run();
98     return dialog_;
99   }
100 
101  private:
102   // aura::EnvObserver:
OnWindowInitialized(aura::Window * window)103   void OnWindowInitialized(aura::Window* window) override {
104     if (dialog_)
105       return;
106     views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
107     if (!widget || !widget->IsDialogBox())
108       return;
109     dialog_ = widget;
110     dialog_->AddObserver(this);
111   }
112 
113   // views::WidgetObserver:
OnWidgetActivationChanged(views::Widget * widget,bool active)114   void OnWidgetActivationChanged(views::Widget* widget, bool active) override {
115     CHECK_EQ(dialog_, widget);
116     if (active) {
117       dialog_created_ = true;
118       dialog_->RemoveObserver(this);
119       if (!quit_closure_.is_null())
120         quit_closure_.Run();
121     }
122   }
123 
124   bool dialog_created_ = false;
125   views::Widget* dialog_ = nullptr;
126   base::Closure quit_closure_;
127 
128   DISALLOW_COPY_AND_ASSIGN(DialogWaiter);
129 };
130 
131 // Waits for a dialog to terminate.
132 class DialogCloseWaiter : public views::WidgetObserver {
133  public:
DialogCloseWaiter(views::Widget * dialog)134   explicit DialogCloseWaiter(views::Widget* dialog)
135       : dialog_closed_(false) {
136     dialog->AddObserver(this);
137   }
138 
~DialogCloseWaiter()139   ~DialogCloseWaiter() override {
140     // It is not necessary to remove |this| from the dialog's observer, since
141     // the dialog is destroyed before this waiter.
142   }
143 
WaitForDialogClose()144   void WaitForDialogClose() {
145     if (dialog_closed_)
146       return;
147     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
148     quit_closure_ = run_loop.QuitClosure();
149     run_loop.Run();
150   }
151 
152  private:
153   // views::WidgetObserver:
OnWidgetDestroyed(views::Widget * widget)154   void OnWidgetDestroyed(views::Widget* widget) override {
155     dialog_closed_ = true;
156     if (!quit_closure_.is_null())
157       quit_closure_.Run();
158   }
159 
160   bool dialog_closed_;
161   base::Closure quit_closure_;
162 
163   DISALLOW_COPY_AND_ASSIGN(DialogCloseWaiter);
164 };
165 
166 // Waits for a views::Widget to receive a Tab key.
167 class TabKeyWaiter : public ui::EventHandler {
168  public:
TabKeyWaiter(views::Widget * widget)169   explicit TabKeyWaiter(views::Widget* widget)
170       : widget_(widget),
171         received_tab_(false) {
172     widget_->GetNativeWindow()->AddPreTargetHandler(this);
173   }
174 
~TabKeyWaiter()175   ~TabKeyWaiter() override {
176     widget_->GetNativeWindow()->RemovePreTargetHandler(this);
177   }
178 
WaitForTab()179   void WaitForTab() {
180     if (received_tab_)
181       return;
182     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
183     quit_closure_ = run_loop.QuitClosure();
184     run_loop.Run();
185   }
186 
187  private:
188   // ui::EventHandler:
OnKeyEvent(ui::KeyEvent * event)189   void OnKeyEvent(ui::KeyEvent* event) override {
190     if (event->type() == ui::ET_KEY_RELEASED &&
191         event->key_code() == ui::VKEY_TAB) {
192       received_tab_ = true;
193       if (!quit_closure_.is_null())
194         quit_closure_.Run();
195     }
196   }
197 
198   views::Widget* widget_;
199   bool received_tab_;
200   base::Closure quit_closure_;
201 
202   DISALLOW_COPY_AND_ASSIGN(TabKeyWaiter);
203 };
204 
MoveMouseAndPress(const gfx::Point & screen_pos,ui_controls::MouseButton button,int button_state,base::OnceClosure closure)205 void MoveMouseAndPress(const gfx::Point& screen_pos,
206                        ui_controls::MouseButton button,
207                        int button_state,
208                        base::OnceClosure closure) {
209   ASSERT_TRUE(ui_controls::SendMouseMove(screen_pos.x(), screen_pos.y()));
210   ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone(button, button_state,
211                                                          std::move(closure)));
212 }
213 
214 #endif  // !defined(OS_MAC)
215 
216 // PageNavigator implementation that records the URL.
217 class TestingPageNavigator : public PageNavigator {
218  public:
TestingPageNavigator()219   TestingPageNavigator() {}
~TestingPageNavigator()220   ~TestingPageNavigator() override {}
221 
OpenURL(const OpenURLParams & params)222   WebContents* OpenURL(const OpenURLParams& params) override {
223     urls_.push_back(params.url);
224     transitions_.push_back(params.transition);
225     return NULL;
226   }
227 
urls() const228   const std::vector<GURL>& urls() const { return urls_; }
last_url() const229   GURL last_url() const { return urls_.empty() ? GURL() : urls_.back(); }
230 
last_transition() const231   ui::PageTransition last_transition() const {
232     return transitions_.empty() ? ui::PAGE_TRANSITION_LINK
233                                 : transitions_.back();
234   }
235 
236  private:
237   std::vector<GURL> urls_;
238   std::vector<ui::PageTransition> transitions_;
239 
240   DISALLOW_COPY_AND_ASSIGN(TestingPageNavigator);
241 };
242 
243 }  // namespace
244 
245 // Base class for event generating bookmark view tests. These test are intended
246 // to exercise View's menus, but that's easier done with BookmarkBarView rather
247 // than View's menu itself.
248 //
249 // SetUp creates a bookmark model with the following structure.
250 // All folders are in upper case, all URLs in lower case.
251 // F1
252 //   f1a
253 //   F11
254 //     f11a
255 //   f1b
256 //   *
257 // a
258 // b
259 // c
260 // d
261 // F2
262 // e
263 // OTHER
264 //   oa
265 //   OF
266 //     ofa
267 //     ofb
268 //   OF2
269 //     of2a
270 //     of2b
271 //
272 // * if CreateBigMenu returns return true, 100 menu items are created here with
273 //   the names f1-f100.
274 //
275 // Subclasses should be sure and invoke super's implementation of SetUp and
276 // TearDown.
277 class BookmarkBarViewEventTestBase : public ViewEventTestBase {
278  public:
279   BookmarkBarViewEventTestBase() = default;
280   ~BookmarkBarViewEventTestBase() override = default;
281 
SetUp()282   void SetUp() override {
283     content_client_ = std::make_unique<ChromeContentClient>();
284     content::SetContentClient(content_client_.get());
285     browser_content_client_ = std::make_unique<ChromeContentBrowserClient>();
286     content::SetBrowserClientForTesting(browser_content_client_.get());
287 
288     views::MenuController::TurnOffMenuSelectionHoldForTest();
289     BookmarkBarView::DisableAnimationsForTesting(true);
290     SetConstrainedWindowViewsClient(CreateChromeConstrainedWindowViewsClient());
291 
292     local_state_.reset(
293         new ScopedTestingLocalState(TestingBrowserProcess::GetGlobal()));
294     TestingProfile::Builder profile_builder;
295     profile_builder.AddTestingFactory(
296         BookmarkModelFactory::GetInstance(),
297         BookmarkModelFactory::GetDefaultFactory());
298     profile_builder.AddTestingFactory(
299         ManagedBookmarkServiceFactory::GetInstance(),
300         ManagedBookmarkServiceFactory::GetDefaultFactory());
301     profile_ = profile_builder.Build();
302     model_ = BookmarkModelFactory::GetForBrowserContext(profile_.get());
303     bookmarks::test::WaitForBookmarkModelToLoad(model_);
304     profile_->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
305 
306     Browser::CreateParams native_params(profile_.get(), true);
307     browser_ = CreateBrowserWithTestWindowForParams(native_params);
308 
309     model_->ClearStore();
310 
311     AddTestData(CreateBigMenu());
312 
313     // Create the Widget. Note the initial size is given by
314     // GetPreferredSizeForContents() during initialization. This occurs after
315     // the WidgetDelegate provides |bb_view_| as the contents view and adds it
316     // to the hierarchy.
317     ViewEventTestBase::SetUp();
318     ASSERT_TRUE(bb_view_);
319 
320     // Verify the layout triggered by the initial size preserves the overflow
321     // state calculated in GetPreferredSizeForContents().
322     EXPECT_TRUE(GetBookmarkButton(5)->GetVisible());
323     EXPECT_FALSE(GetBookmarkButton(6)->GetVisible());
324   }
325 
TearDown()326   void TearDown() override {
327     if (window()) {
328       // Closing the window ensures |bb_view_| is deleted, which must happen
329       // before |model_| is deleted (which happens when |profile_| is reset).
330       window()->CloseNow();
331     }
332 
333     browser_->tab_strip_model()->CloseAllTabs();
334     browser_.reset();
335     profile_.reset();
336 
337     // Run the message loop to ensure we delete all tasks and fully shut down.
338     base::RunLoop().RunUntilIdle();
339 
340     ViewEventTestBase::TearDown();
341 
342     BookmarkBarView::DisableAnimationsForTesting(false);
343     constrained_window::SetConstrainedWindowViewsClient(nullptr);
344 
345     browser_content_client_.reset();
346     content_client_.reset();
347     content::SetContentClient(NULL);
348   }
349 
350  protected:
CreateContentsView()351   std::unique_ptr<views::View> CreateContentsView() override {
352     auto bb_view = std::make_unique<BookmarkBarView>(browser_.get(), nullptr);
353     // Real bookmark bars get a BookmarkBarViewBackground. Set an opaque
354     // background here just to avoid triggering subpixel rendering issues.
355     bb_view->SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
356     bb_view->SetPageNavigator(&navigator_);
357     bb_view_ = bb_view.get();
358     return bb_view;
359   }
360 
GetPreferredSizeForContents() const361   gfx::Size GetPreferredSizeForContents() const override {
362     // Calculate the preferred size so that one button doesn't fit, which
363     // triggers the overflow button to appear. We have to do this incrementally
364     // as there isn't a good way to determine the point at which the overflow
365     // button is shown.
366     //
367     // This code looks a bit hacky, but it is written so that it shouldn't
368     // depend on any of the layout code in BookmarkBarView, or extra buttons
369     // added to the right of the bookmarks. Instead, brute force search for a
370     // size that triggers the overflow button.
371     gfx::Size size = bb_view_->GetPreferredSize();
372     size.set_width(1000);
373     do {
374       size.set_width(size.width() - 25);
375       bb_view_->SetBounds(0, 0, size.width(), size.height());
376       bb_view_->Layout();
377     } while (bb_view_->bookmark_buttons_[6]->GetVisible());
378     return size;
379   }
380 
GetBookmarkButton(size_t view_index)381   views::LabelButton* GetBookmarkButton(size_t view_index) {
382     return bb_view_->bookmark_buttons_[view_index];
383   }
384 
385   // See comment above class description for what this does.
CreateBigMenu()386   virtual bool CreateBigMenu() { return false; }
387 
388   BookmarkModel* model_ = nullptr;
389   BookmarkBarView* bb_view_ = nullptr;
390   TestingPageNavigator navigator_;
391 
392  private:
AddTestData(bool big_menu)393   void AddTestData(bool big_menu) {
394     const BookmarkNode* bb_node = model_->bookmark_bar_node();
395     std::string test_base = "file:///c:/tmp/";
396     const BookmarkNode* f1 = model_->AddFolder(bb_node, 0, ASCIIToUTF16("F1"));
397     model_->AddURL(f1, 0, ASCIIToUTF16("f1a"), GURL(test_base + "f1a"));
398     const BookmarkNode* f11 = model_->AddFolder(f1, 1, ASCIIToUTF16("F11"));
399     model_->AddURL(f11, 0, ASCIIToUTF16("f11a"), GURL(test_base + "f11a"));
400     model_->AddURL(f1, 2, ASCIIToUTF16("f1b"), GURL(test_base + "f1b"));
401     if (big_menu) {
402       for (size_t i = 1; i <= 100; ++i) {
403         model_->AddURL(f1, i + 1, ASCIIToUTF16("f") + base::NumberToString16(i),
404                        GURL(test_base + "f" + base::NumberToString(i)));
405       }
406     }
407     model_->AddURL(bb_node, 1, ASCIIToUTF16("a"), GURL(test_base + "a"));
408     model_->AddURL(bb_node, 2, ASCIIToUTF16("b"), GURL(test_base + "b"));
409     model_->AddURL(bb_node, 3, ASCIIToUTF16("c"), GURL(test_base + "c"));
410     model_->AddURL(bb_node, 4, ASCIIToUTF16("d"), GURL(test_base + "d"));
411     model_->AddFolder(bb_node, 5, ASCIIToUTF16("F2"));
412     model_->AddURL(bb_node, 6, ASCIIToUTF16("d"), GURL(test_base + "d"));
413 
414     model_->AddURL(model_->other_node(), 0, ASCIIToUTF16("oa"),
415                    GURL(test_base + "oa"));
416     const BookmarkNode* of = model_->AddFolder(model_->other_node(), 1,
417                                                ASCIIToUTF16("OF"));
418     model_->AddURL(of, 0, ASCIIToUTF16("ofa"), GURL(test_base + "ofa"));
419     model_->AddURL(of, 1, ASCIIToUTF16("ofb"), GURL(test_base + "ofb"));
420     const BookmarkNode* of2 = model_->AddFolder(model_->other_node(), 2,
421                                                 ASCIIToUTF16("OF2"));
422     model_->AddURL(of2, 0, ASCIIToUTF16("of2a"), GURL(test_base + "of2a"));
423     model_->AddURL(of2, 1, ASCIIToUTF16("of2b"), GURL(test_base + "of2b"));
424   }
425 
426   std::unique_ptr<ChromeContentClient> content_client_;
427   std::unique_ptr<ChromeContentBrowserClient> browser_content_client_;
428   std::unique_ptr<TestingProfile> profile_;
429   std::unique_ptr<Browser> browser_;
430   std::unique_ptr<ScopedTestingLocalState> local_state_;
431 };
432 
433 class BookmarkBarViewDragTestBase : public BookmarkBarViewEventTestBase,
434                                     public BookmarkBarViewObserver,
435                                     public views::WidgetObserver {
436  public:
437   BookmarkBarViewDragTestBase() = default;
438   ~BookmarkBarViewDragTestBase() override = default;
439 
440   // views::WidgetObserver:
OnWidgetDragWillStart(views::Widget * widget)441   void OnWidgetDragWillStart(views::Widget* widget) override {
442     const gfx::Point target = GetDragTargetInScreen();
443     GetDragTaskRunner()->PostTask(
444         FROM_HERE,
445         base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove),
446                        target.x(), target.y()));
447   }
448 
OnWidgetDragComplete(views::Widget * widget)449   void OnWidgetDragComplete(views::Widget* widget) override {
450     // All drag tests drag node f1a, so at the end of the test, if the node was
451     // dropped where it was expected, the dropped node should have f1a's URL.
452     EXPECT_EQ(f1a_url_, GetDroppedNode()->url());
453 
454     Done();
455   }
456 
OnWidgetDestroying(views::Widget * widget)457   void OnWidgetDestroying(views::Widget* widget) override {
458     if (widget == window())
459       bookmark_bar_observer_.RemoveAll();
460   }
461 
OnWidgetDestroyed(views::Widget * widget)462   void OnWidgetDestroyed(views::Widget* widget) override {
463     widget_observer_.Remove(widget);
464   }
465 
466  protected:
467   // BookmarkBarViewEventTestBase:
DoTestOnMessageLoop()468   void DoTestOnMessageLoop() override {
469     widget_observer_.Add(window());
470     bookmark_bar_observer_.Add(bb_view_);
471 
472     // Record the URL for node f1a.
473     const auto& f1 = model_->bookmark_bar_node()->children().front();
474     f1a_url_ = f1->children().front()->url();
475 
476     // Move the mouse to the first folder on the bookmark bar and press the
477     // mouse.
478     views::LabelButton* button = GetBookmarkButton(0);
479     ui_test_utils::MoveMouseToCenterAndPress(
480         button, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
481         CreateEventTask(this, &BookmarkBarViewDragTestBase::OnMenuOpened));
482   }
483 
OnMenuOpened()484   virtual void OnMenuOpened() {
485     // Menu should be showing.
486     views::MenuItemView* menu = bb_view_->GetMenu();
487     ASSERT_NE(nullptr, menu);
488     views::SubmenuView* submenu = menu->GetSubmenu();
489     ASSERT_TRUE(submenu->IsShowing());
490 
491     // The menu is showing, so it has a widget we can observe now.
492     widget_observer_.Add(submenu->GetWidget());
493 
494     // Move mouse to center of node f1a and press button.
495     views::View* f1a = submenu->GetMenuItemAt(0);
496     ASSERT_NE(nullptr, f1a);
497     ui_test_utils::MoveMouseToCenterAndPress(
498         f1a, ui_controls::LEFT, ui_controls::DOWN,
499         CreateEventTask(this, &BookmarkBarViewDragTestBase::StartDrag));
500   }
501 
OnDragEntered()502   virtual void OnDragEntered() {
503     // Drop the element, which should result in calling OnWidgetDragComplete().
504     GetDragTaskRunner()->PostTask(
505         FROM_HERE,
506         base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseEvents),
507                        ui_controls::LEFT, ui_controls::UP,
508                        ui_controls::kNoAccelerator));
509   }
510 
511   // Called after the drag ends; returns the node the test thinks should be the
512   // dropped node.  This is used to verify that the dragged node was dropped in
513   // the expected position.
514   virtual const BookmarkNode* GetDroppedNode() const = 0;
515 
516   // Returns the point the node should be dragged to, in screen coordinates.
517   virtual gfx::Point GetDragTargetInScreen() const = 0;
518 
SetStopDraggingView(const views::View * view)519   void SetStopDraggingView(const views::View* view) {
520     views::DropHelper::SetDragEnteredCallbackForTesting(
521         view, base::BindRepeating(&BookmarkBarViewDragTestBase::OnDragEntered,
522                                   base::Unretained(this)));
523   }
524 
525  private:
StartDrag()526   void StartDrag() {
527     const views::View* drag_view =
528         bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(0);
529     const gfx::Point current_position =
530         ui_test_utils::GetCenterInScreenCoordinates(drag_view);
531     EXPECT_TRUE(ui_controls::SendMouseMove(current_position.x() + 10,
532                                            current_position.y()));
533   }
534 
535   GURL f1a_url_;
536   ScopedObserver<BookmarkBarView, BookmarkBarViewObserver>
537       bookmark_bar_observer_{this};
538   ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this};
539 };
540 
541 #if !defined(OS_MAC)
542 // The following tests were not enabled on Mac before. Consider enabling those
543 // that are able to run on Mac (https://crbug.com/845342).
544 
545 // Clicks on first menu, makes sure button is depressed. Moves mouse to first
546 // child, clicks it and makes sure a navigation occurs.
547 class BookmarkBarViewTest1 : public BookmarkBarViewEventTestBase {
548  protected:
DoTestOnMessageLoop()549   void DoTestOnMessageLoop() override {
550     // Move the mouse to the first folder on the bookmark bar and press the
551     // mouse.
552     views::LabelButton* button = GetBookmarkButton(0);
553     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
554         ui_controls::DOWN | ui_controls::UP,
555         CreateEventTask(this, &BookmarkBarViewTest1::Step2));
556   }
557 
558  private:
Step2()559   void Step2() {
560     // Menu should be showing.
561     views::MenuItemView* menu = bb_view_->GetMenu();
562     ASSERT_TRUE(menu != NULL);
563     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
564 
565     // Button should be depressed.
566     views::LabelButton* button = GetBookmarkButton(0);
567     ASSERT_TRUE(button->GetState() == views::Button::STATE_PRESSED);
568 
569     // Click on the 2nd menu item (A URL).
570     ASSERT_TRUE(menu->GetSubmenu());
571 
572     views::MenuItemView* menu_to_select =
573         menu->GetSubmenu()->GetMenuItemAt(0);
574     ui_test_utils::MoveMouseToCenterAndPress(menu_to_select, ui_controls::LEFT,
575         ui_controls::DOWN | ui_controls::UP,
576         CreateEventTask(this, &BookmarkBarViewTest1::Step3));
577   }
578 
Step3()579   void Step3() {
580     // We should have navigated to URL f1a.
581     const auto& f1 = model_->bookmark_bar_node()->children().front();
582     ASSERT_EQ(navigator_.last_url(), f1->children().front()->url());
583     ASSERT_FALSE(PageTransitionIsWebTriggerable(navigator_.last_transition()));
584 
585     // Make sure button is no longer pushed.
586     views::LabelButton* button = GetBookmarkButton(0);
587     ASSERT_TRUE(button->GetState() == views::Button::STATE_NORMAL);
588 
589     views::MenuItemView* menu = bb_view_->GetMenu();
590     ASSERT_TRUE(menu == NULL || !menu->GetSubmenu()->IsShowing());
591 
592     Done();
593   }
594 };
595 
596 VIEW_TEST(BookmarkBarViewTest1, Basic)
597 
598 // Brings up menu, clicks on empty space and make sure menu hides.
599 class BookmarkBarViewTest2 : public BookmarkBarViewEventTestBase {
600  protected:
DoTestOnMessageLoop()601   void DoTestOnMessageLoop() override {
602     // Move the mouse to the first folder on the bookmark bar and press the
603     // mouse.
604     views::LabelButton* button = GetBookmarkButton(0);
605     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
606         ui_controls::DOWN | ui_controls::UP,
607         CreateEventTask(this, &BookmarkBarViewTest2::Step2));
608   }
609 
610  private:
Step2()611   void Step2() {
612     // Menu should be showing.
613     views::MenuItemView* menu = bb_view_->GetMenu();
614     ASSERT_TRUE(menu != NULL && menu->GetSubmenu()->IsShowing());
615 
616     // Click on 0x0, which should trigger closing menu.
617     // NOTE: this code assume there is a left margin, which is currently
618     // true. If that changes, this code will need to find another empty space
619     // to press the mouse on.
620     ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone(
621         0, 0, CreateEventTask(this, &BookmarkBarViewTest2::Step3)));
622   }
623 
Step3()624   void Step3() {
625     // As the click is on the desktop the hook never sees the up, so we only
626     // wait on the down. We still send the up though else the system thinks
627     // the mouse is still down.
628     ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone(
629         ui_controls::LEFT, ui_controls::DOWN,
630         CreateEventTask(this, &BookmarkBarViewTest2::Step4)));
631     ASSERT_TRUE(
632         ui_controls::SendMouseEvents(ui_controls::LEFT, ui_controls::UP));
633   }
634 
Step4()635   void Step4() {
636     // The menu shouldn't be showing.
637     views::MenuItemView* menu = bb_view_->GetMenu();
638     ASSERT_TRUE(menu == NULL || !menu->GetSubmenu()->IsShowing());
639 
640     // Make sure button is no longer pushed.
641     views::LabelButton* button = GetBookmarkButton(0);
642     ASSERT_TRUE(button->GetState() == views::Button::STATE_NORMAL);
643 
644     Done();
645   }
646 };
647 
648 VIEW_TEST(BookmarkBarViewTest2, HideOnDesktopClick)
649 
650 // Brings up menu. Moves over child to make sure submenu appears, moves over
651 // another child and make sure next menu appears.
652 class BookmarkBarViewTest3 : public BookmarkBarViewEventTestBase {
653  protected:
DoTestOnMessageLoop()654   void DoTestOnMessageLoop() override {
655     // Move the mouse to the first folder on the bookmark bar and press the
656     // mouse.
657     views::MenuButton* button = bb_view_->other_bookmarks_button();
658     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
659         ui_controls::DOWN | ui_controls::UP,
660         CreateEventTask(this, &BookmarkBarViewTest3::Step2));
661   }
662 
663  private:
Step2()664   void Step2() {
665     // Menu should be showing.
666     views::MenuItemView* menu = bb_view_->GetMenu();
667     ASSERT_TRUE(menu != NULL);
668     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
669 
670     views::MenuItemView* child_menu =
671         menu->GetSubmenu()->GetMenuItemAt(1);
672     ASSERT_TRUE(child_menu != NULL);
673 
674     // Click on second child, which has a submenu.
675     ui_test_utils::MoveMouseToCenterAndPress(child_menu, ui_controls::LEFT,
676         ui_controls::DOWN | ui_controls::UP,
677         CreateEventTask(this, &BookmarkBarViewTest3::Step3));
678   }
679 
Step3()680   void Step3() {
681     // Make sure sub menu is showing.
682     views::MenuItemView* menu = bb_view_->GetMenu();
683     ASSERT_TRUE(menu);
684     views::MenuItemView* child_menu =
685         menu->GetSubmenu()->GetMenuItemAt(1);
686     ASSERT_TRUE(child_menu->GetSubmenu() != NULL);
687     ASSERT_TRUE(child_menu->GetSubmenu()->IsShowing());
688 
689     // Click on third child, which has a submenu too.
690     child_menu = menu->GetSubmenu()->GetMenuItemAt(2);
691     ASSERT_TRUE(child_menu != NULL);
692     ui_test_utils::MoveMouseToCenterAndPress(child_menu, ui_controls::LEFT,
693         ui_controls::DOWN | ui_controls::UP,
694         CreateEventTask(this, &BookmarkBarViewTest3::Step4));
695   }
696 
Step4()697   void Step4() {
698     // Make sure sub menu we first clicked isn't showing.
699     views::MenuItemView* menu = bb_view_->GetMenu();
700     views::MenuItemView* child_menu =
701         menu->GetSubmenu()->GetMenuItemAt(1);
702     ASSERT_TRUE(child_menu->GetSubmenu() != NULL);
703     ASSERT_FALSE(child_menu->GetSubmenu()->IsShowing());
704 
705     // And submenu we last clicked is showing.
706     child_menu = menu->GetSubmenu()->GetMenuItemAt(2);
707     ASSERT_TRUE(child_menu != NULL);
708     ASSERT_TRUE(child_menu->GetSubmenu()->IsShowing());
709 
710     // Nothing should have been selected.
711     EXPECT_EQ(GURL(), navigator_.last_url());
712 
713     // Hide menu.
714     menu->GetMenuController()->Cancel(views::MenuController::ExitType::kAll);
715 
716     Done();
717   }
718 };
719 
720 VIEW_TEST(BookmarkBarViewTest3, Submenus)
721 
722 // Observer that posts a task upon the context menu creation.
723 // This is necessary for Linux as the context menu has to check the clipboard,
724 // which invokes the event loop.
725 // Because |task| is a OnceClosure, callers should use a separate observer
726 // instance for each successive context menu creation they wish to observe.
727 class BookmarkContextMenuNotificationObserver {
728  public:
BookmarkContextMenuNotificationObserver(base::OnceClosure task)729   explicit BookmarkContextMenuNotificationObserver(base::OnceClosure task)
730       : task_(std::move(task)) {
731     BookmarkContextMenu::InstallPreRunCallback(base::BindOnce(
732         &BookmarkContextMenuNotificationObserver::ScheduleCallback,
733         base::Unretained(this)));
734   }
735 
ScheduleCallback()736   void ScheduleCallback() {
737     DCHECK(!task_.is_null());
738     base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(task_));
739   }
740 
741  private:
742   base::OnceClosure task_;
743 
744   DISALLOW_COPY_AND_ASSIGN(BookmarkContextMenuNotificationObserver);
745 };
746 
747 // Tests context menus by way of opening a context menu for a bookmark,
748 // then right clicking to get context menu and selecting the first menu item
749 // (open).
750 class BookmarkBarViewTest4 : public BookmarkBarViewEventTestBase {
751  public:
BookmarkBarViewTest4()752   BookmarkBarViewTest4()
753       : observer_(CreateEventTask(this, &BookmarkBarViewTest4::Step3)) {
754   }
755 
756  protected:
DoTestOnMessageLoop()757   void DoTestOnMessageLoop() override {
758     // Move the mouse to the first folder on the bookmark bar and press the
759     // mouse.
760     views::LabelButton* button = bb_view_->other_bookmarks_button();
761     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
762         ui_controls::DOWN | ui_controls::UP,
763         CreateEventTask(this, &BookmarkBarViewTest4::Step2));
764   }
765 
766  private:
Step2()767   void Step2() {
768     // Menu should be showing.
769     views::MenuItemView* menu = bb_view_->GetMenu();
770     ASSERT_TRUE(menu != NULL);
771     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
772 
773     views::MenuItemView* child_menu =
774         menu->GetSubmenu()->GetMenuItemAt(0);
775     ASSERT_TRUE(child_menu != NULL);
776 
777     // Right click on the first child to get its context menu.
778     ui_test_utils::MoveMouseToCenterAndPress(
779         child_menu, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
780         base::OnceClosure());
781     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
782   }
783 
Step3()784   void Step3() {
785     // Make sure the context menu is showing.
786     views::MenuItemView* menu = bb_view_->GetContextMenu();
787     ASSERT_TRUE(menu != NULL);
788     ASSERT_TRUE(menu->GetSubmenu());
789     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
790 
791     // Select the first menu item (open).
792     ui_test_utils::MoveMouseToCenterAndPress(
793         menu->GetSubmenu()->GetMenuItemAt(0),
794         ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
795         CreateEventTask(this, &BookmarkBarViewTest4::Step4));
796   }
797 
Step4()798   void Step4() {
799     EXPECT_EQ(navigator_.last_url(),
800               model_->other_node()->children().front()->url());
801     ASSERT_FALSE(PageTransitionIsWebTriggerable(navigator_.last_transition()));
802     Done();
803   }
804 
805   BookmarkContextMenuNotificationObserver observer_;
806 };
807 
808 VIEW_TEST(BookmarkBarViewTest4, ContextMenus)
809 
810 // Tests drag and drop within the same menu.
811 class BookmarkBarViewTest5 : public BookmarkBarViewDragTestBase {
812  protected:
813   // BookmarkBarViewDragTestBase:
OnMenuOpened()814   void OnMenuOpened() override {
815     BookmarkBarViewDragTestBase::OnMenuOpened();
816 
817     // Cause the second menu item to trigger a mouse up when dragged over.
818     SetStopDraggingView(bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1));
819   }
820 
GetDroppedNode() const821   const BookmarkNode* GetDroppedNode() const override {
822     return model_->bookmark_bar_node()->children()[0]->children()[1].get();
823   }
824 
GetDragTargetInScreen() const825   gfx::Point GetDragTargetInScreen() const override {
826     const views::View* target_view =
827         bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1);
828     gfx::Point target(target_view->width() / 2, target_view->height() - 1);
829     views::View::ConvertPointToScreen(target_view, &target);
830     return target;
831   }
832 };
833 
834 VIEW_TEST(BookmarkBarViewTest5, DND)
835 
836 // Tests holding mouse down on overflow button, dragging such that menu pops up
837 // then selecting an item.
838 class BookmarkBarViewTest6 : public BookmarkBarViewEventTestBase {
839  protected:
DoTestOnMessageLoop()840   void DoTestOnMessageLoop() override {
841     // Press the mouse button on the overflow button. Don't release it though.
842     views::LabelButton* button = bb_view_->overflow_button();
843     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
844         ui_controls::DOWN, CreateEventTask(this, &BookmarkBarViewTest6::Step2));
845   }
846 
847  private:
Step2()848   void Step2() {
849     // Menu should be showing.
850     views::MenuItemView* menu = bb_view_->GetMenu();
851     ASSERT_TRUE(menu != NULL);
852     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
853 
854     views::MenuItemView* child_menu =
855         menu->GetSubmenu()->GetMenuItemAt(0);
856     ASSERT_TRUE(child_menu != NULL);
857 
858     // Move mouse to center of menu and release mouse.
859     ui_test_utils::MoveMouseToCenterAndPress(child_menu, ui_controls::LEFT,
860         ui_controls::UP, CreateEventTask(this, &BookmarkBarViewTest6::Step3));
861   }
862 
Step3()863   void Step3() {
864     ASSERT_EQ(navigator_.last_url(),
865               model_->bookmark_bar_node()->children()[6]->url());
866     ASSERT_FALSE(PageTransitionIsWebTriggerable(navigator_.last_transition()));
867     Done();
868   }
869 };
870 
871 // If this flakes, disable and log details in http://crbug.com/523255.
872 VIEW_TEST(BookmarkBarViewTest6, OpenMenuOnClickAndHold)
873 
874 // Tests drag and drop to different menu.
875 class BookmarkBarViewTest7 : public BookmarkBarViewDragTestBase {
876  public:
877   // BookmarkBarViewDragTestBase:
OnDropMenuShown()878   void OnDropMenuShown() override {
879     views::MenuItemView* drop_menu = bb_view_->GetDropMenu();
880     ASSERT_NE(nullptr, drop_menu);
881     views::SubmenuView* drop_submenu = drop_menu->GetSubmenu();
882     ASSERT_TRUE(drop_submenu->IsShowing());
883 
884     // The button should be highlighted now.
885     EXPECT_EQ(views::Button::STATE_PRESSED,
886               bb_view_->other_bookmarks_button()->GetState());
887 
888     // Cause the target view to trigger a mouse up when dragged over.
889     const views::View* target_view = drop_submenu->GetMenuItemAt(0);
890     SetStopDraggingView(target_view);
891 
892     // Drag to the top of the target view.
893     gfx::Point target(target_view->width() / 2, 0);
894     views::View::ConvertPointToScreen(target_view, &target);
895     GetDragTaskRunner()->PostTask(
896         FROM_HERE,
897         base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove),
898                        target.x(), target.y()));
899   }
900 
OnWidgetDragComplete(views::Widget * widget)901   void OnWidgetDragComplete(views::Widget* widget) override {
902     // The button should be in normal state now.
903     EXPECT_EQ(views::Button::STATE_NORMAL,
904               bb_view_->other_bookmarks_button()->GetState());
905 
906     BookmarkBarViewDragTestBase::OnWidgetDragComplete(widget);
907   }
908 
909  protected:
910   // BookmarkBarViewDragTestBase:
GetDroppedNode() const911   const BookmarkNode* GetDroppedNode() const override {
912     return model_->other_node()->children().front().get();
913   }
914 
GetDragTargetInScreen() const915   gfx::Point GetDragTargetInScreen() const override {
916     return ui_test_utils::GetCenterInScreenCoordinates(
917         bb_view_->other_bookmarks_button());
918   }
919 };
920 
921 VIEW_TEST(BookmarkBarViewTest7, DNDToDifferentMenu)
922 
923 // Drags from one menu to next so that original menu closes, then back to
924 // original menu.
925 class BookmarkBarViewTest8 : public BookmarkBarViewDragTestBase {
926  public:
927   // BookmarkBarViewDragTestBase:
OnDropMenuShown()928   void OnDropMenuShown() override {
929     views::MenuItemView* drop_menu = bb_view_->GetDropMenu();
930     ASSERT_NE(nullptr, drop_menu);
931     views::SubmenuView* drop_submenu = drop_menu->GetSubmenu();
932     ASSERT_TRUE(drop_submenu->IsShowing());
933 
934     const views::View* target_view;
935     const auto* controller =
936         static_cast<const BookmarkMenuController*>(drop_menu->GetDelegate());
937     if (controller->node() == model_->other_node()) {
938       // Now drag back over first menu.
939       target_view = GetBookmarkButton(0);
940     } else {
941       // Drag to folder F11.
942       target_view = drop_submenu->GetMenuItemAt(1);
943 
944       // Cause folder F11 to trigger a mouse up when dragged over.
945       SetStopDraggingView(target_view);
946     }
947     const gfx::Point target =
948         ui_test_utils::GetCenterInScreenCoordinates(target_view);
949     GetDragTaskRunner()->PostTask(
950         FROM_HERE,
951         base::BindOnce(base::IgnoreResult(&ui_controls::SendMouseMove),
952                        target.x(), target.y()));
953   }
954 
955  protected:
956   // BookmarkBarViewDragTestBase:
GetDroppedNode() const957   const BookmarkNode* GetDroppedNode() const override {
958     const auto& f1 = model_->bookmark_bar_node()->children()[0];
959     return f1->children()[0]->children()[1].get();
960   }
961 
GetDragTargetInScreen() const962   gfx::Point GetDragTargetInScreen() const override {
963     return ui_test_utils::GetCenterInScreenCoordinates(
964         bb_view_->other_bookmarks_button());
965   }
966 };
967 
968 VIEW_TEST(BookmarkBarViewTest8, DNDBackToOriginatingMenu)
969 
970 // Moves the mouse over the scroll button and makes sure we get scrolling.
971 class BookmarkBarViewTest9 : public BookmarkBarViewEventTestBase {
972  protected:
CreateBigMenu()973   bool CreateBigMenu() override { return true; }
974 
DoTestOnMessageLoop()975   void DoTestOnMessageLoop() override {
976     // Move the mouse to the first folder on the bookmark bar and press the
977     // mouse.
978     views::LabelButton* button = GetBookmarkButton(0);
979     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
980         ui_controls::DOWN | ui_controls::UP,
981         CreateEventTask(this, &BookmarkBarViewTest9::Step2));
982   }
983 
984  private:
Step2()985   void Step2() {
986     // Menu should be showing.
987     views::MenuItemView* menu = bb_view_->GetMenu();
988     ASSERT_TRUE(menu != NULL);
989     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
990 
991     first_menu_ = menu->GetSubmenu()->GetMenuItemAt(0);
992     gfx::Point menu_loc;
993     views::View::ConvertPointToScreen(first_menu_, &menu_loc);
994     start_y_ = menu_loc.y();
995 
996     // Move the mouse over the scroll button.
997     views::View* scroll_container = menu->GetSubmenu()->parent();
998     ASSERT_TRUE(scroll_container != NULL);
999     scroll_container = scroll_container->parent();
1000     ASSERT_TRUE(scroll_container != NULL);
1001     views::View* scroll_down_button = scroll_container->children()[2];
1002     ASSERT_TRUE(scroll_down_button);
1003     gfx::Point loc(scroll_down_button->width() / 2,
1004                    scroll_down_button->height() / 2);
1005     views::View::ConvertPointToScreen(scroll_down_button, &loc);
1006 
1007     // On linux, the sending one location isn't enough.
1008     ASSERT_TRUE(ui_controls::SendMouseMove(loc.x() - 1, loc.y() - 1));
1009     ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone(
1010         loc.x(), loc.y(), CreateEventTask(this, &BookmarkBarViewTest9::Step3)));
1011   }
1012 
Step3()1013   void Step3() {
1014     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1015         FROM_HERE,
1016         base::BindOnce(&BookmarkBarViewTest9::Step4, base::Unretained(this)),
1017         base::TimeDelta::FromMilliseconds(200));
1018   }
1019 
Step4()1020   void Step4() {
1021     gfx::Point menu_loc;
1022     views::View::ConvertPointToScreen(first_menu_, &menu_loc);
1023     ASSERT_NE(start_y_, menu_loc.y());
1024 
1025     // Hide menu.
1026     bb_view_->GetMenu()->GetMenuController()->Cancel(
1027         views::MenuController::ExitType::kAll);
1028 
1029     // On linux, Cancelling menu will call Quit on the message loop,
1030     // which can interfere with Done. We need to run Done in the
1031     // next execution loop.
1032     base::ThreadTaskRunnerHandle::Get()->PostTask(
1033         FROM_HERE,
1034         base::BindOnce(&ViewEventTestBase::Done, base::Unretained(this)));
1035   }
1036 
1037   int start_y_;
1038   views::MenuItemView* first_menu_;
1039 };
1040 
1041 VIEW_TEST(BookmarkBarViewTest9, ScrollButtonScrolls)
1042 
1043 // Tests up/down/left/enter key messages.
1044 class BookmarkBarViewTest10 : public BookmarkBarViewEventTestBase {
1045  protected:
DoTestOnMessageLoop()1046   void DoTestOnMessageLoop() override {
1047     // Move the mouse to the first folder on the bookmark bar and press the
1048     // mouse.
1049     views::LabelButton* button = GetBookmarkButton(0);
1050     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1051         ui_controls::DOWN | ui_controls::UP,
1052         CreateEventTask(this, &BookmarkBarViewTest10::Step2));
1053   }
1054 
1055  private:
Step2()1056   void Step2() {
1057     // Menu should be showing.
1058     views::MenuItemView* menu = bb_view_->GetMenu();
1059     ASSERT_TRUE(menu != NULL);
1060     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1061 
1062     // Send a down event, which should select the first item.
1063     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1064         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
1065         CreateEventTask(this, &BookmarkBarViewTest10::Step3)));
1066   }
1067 
Step3()1068   void Step3() {
1069     // Make sure menu is showing and item is selected.
1070     views::MenuItemView* menu = bb_view_->GetMenu();
1071     ASSERT_TRUE(menu != NULL);
1072     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1073     ASSERT_TRUE(menu->GetSubmenu()->GetMenuItemAt(0)->IsSelected());
1074 
1075     // Send a key down event, which should select the next item.
1076     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1077         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
1078         CreateEventTask(this, &BookmarkBarViewTest10::Step4)));
1079   }
1080 
Step4()1081   void Step4() {
1082     views::MenuItemView* menu = bb_view_->GetMenu();
1083     ASSERT_TRUE(menu != NULL);
1084     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1085     ASSERT_FALSE(menu->GetSubmenu()->GetMenuItemAt(0)->IsSelected());
1086     ASSERT_TRUE(menu->GetSubmenu()->GetMenuItemAt(1)->IsSelected());
1087 
1088     // Send a right arrow to force the menu to open.
1089     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1090         window()->GetNativeWindow(), ui::VKEY_RIGHT, false, false, false, false,
1091         CreateEventTask(this, &BookmarkBarViewTest10::Step5)));
1092   }
1093 
Step5()1094   void Step5() {
1095     // Make sure the submenu is showing.
1096     views::MenuItemView* menu = bb_view_->GetMenu();
1097     ASSERT_TRUE(menu != NULL);
1098     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1099     views::MenuItemView* submenu = menu->GetSubmenu()->GetMenuItemAt(1);
1100     ASSERT_TRUE(submenu->IsSelected());
1101     ASSERT_TRUE(submenu->GetSubmenu());
1102     ASSERT_TRUE(submenu->GetSubmenu()->IsShowing());
1103 
1104     // Send a left arrow to close the submenu.
1105     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1106         window()->GetNativeWindow(), ui::VKEY_LEFT, false, false, false, false,
1107         CreateEventTask(this, &BookmarkBarViewTest10::Step6)));
1108   }
1109 
Step6()1110   void Step6() {
1111     // Make sure the submenu is showing.
1112     views::MenuItemView* menu = bb_view_->GetMenu();
1113     ASSERT_TRUE(menu != NULL);
1114     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1115     views::MenuItemView* submenu = menu->GetSubmenu()->GetMenuItemAt(1);
1116     ASSERT_TRUE(submenu->IsSelected());
1117     ASSERT_TRUE(!submenu->GetSubmenu() || !submenu->GetSubmenu()->IsShowing());
1118 
1119     // Send a down arrow to go down to f1b.
1120     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1121         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
1122         CreateEventTask(this, &BookmarkBarViewTest10::Step7)));
1123   }
1124 
Step7()1125   void Step7() {
1126     // Make sure menu is showing and item is selected.
1127     views::MenuItemView* menu = bb_view_->GetMenu();
1128     ASSERT_TRUE(menu != NULL);
1129     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1130     ASSERT_TRUE(menu->GetSubmenu()->GetMenuItemAt(2)->IsSelected());
1131 
1132     // Send a down arrow to wrap back to f1a.
1133     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1134         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
1135         CreateEventTask(this, &BookmarkBarViewTest10::Step8)));
1136   }
1137 
Step8()1138   void Step8() {
1139     // Make sure menu is showing and item is selected.
1140     views::MenuItemView* menu = bb_view_->GetMenu();
1141     ASSERT_TRUE(menu != NULL);
1142     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1143     ASSERT_TRUE(menu->GetSubmenu()->GetMenuItemAt(0)->IsSelected());
1144 
1145     // Send enter, which should select the item.
1146     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1147         window()->GetNativeWindow(), ui::VKEY_RETURN, false, false, false,
1148         false, CreateEventTask(this, &BookmarkBarViewTest10::Step9)));
1149   }
1150 
Step9()1151   void Step9() {
1152     const auto& f1 = model_->bookmark_bar_node()->children().front();
1153     ASSERT_EQ(navigator_.last_url(), f1->children().front()->url());
1154     ASSERT_FALSE(PageTransitionIsWebTriggerable(navigator_.last_transition()));
1155     Done();
1156   }
1157 };
1158 
1159 #if defined(OS_WIN)  // Fails on latest versions of Windows.
1160                      // https://crbug.com/1108551.
1161 #define MAYBE_KeyEvents DISABLED_KeyEvents
1162 #else
1163 #define MAYBE_KeyEvents KeyEvents
1164 #endif
1165 VIEW_TEST(BookmarkBarViewTest10, MAYBE_KeyEvents)
1166 
1167 // Make sure the menu closes with the following sequence: show menu, show
1168 // context menu, close context menu (via escape), then click else where. This
1169 // effectively verifies we maintain mouse capture after the context menu is
1170 // hidden.
1171 class BookmarkBarViewTest11 : public BookmarkBarViewEventTestBase {
1172  public:
BookmarkBarViewTest11()1173   BookmarkBarViewTest11()
1174       : observer_(CreateEventTask(this, &BookmarkBarViewTest11::Step3)) {
1175   }
1176 
1177  protected:
DoTestOnMessageLoop()1178   void DoTestOnMessageLoop() override {
1179     // Move the mouse to the first folder on the bookmark bar and press the
1180     // mouse.
1181     views::LabelButton* button = bb_view_->other_bookmarks_button();
1182     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1183         ui_controls::DOWN | ui_controls::UP,
1184         CreateEventTask(this, &BookmarkBarViewTest11::Step2));
1185   }
1186 
1187  private:
Step2()1188   void Step2() {
1189     // Menu should be showing.
1190     views::MenuItemView* menu = bb_view_->GetMenu();
1191     ASSERT_TRUE(menu != NULL);
1192     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1193 
1194     views::MenuItemView* child_menu =
1195         menu->GetSubmenu()->GetMenuItemAt(0);
1196     ASSERT_TRUE(child_menu != NULL);
1197 
1198     // Right click on the first child to get its context menu.
1199     ui_test_utils::MoveMouseToCenterAndPress(
1200         child_menu, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1201         base::OnceClosure());
1202     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
1203   }
1204 
Step3()1205   void Step3() {
1206     // Send escape so that the context menu hides.
1207     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1208         window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false, false,
1209         false, CreateEventTask(this, &BookmarkBarViewTest11::Step4)));
1210   }
1211 
Step4()1212   void Step4() {
1213     // Make sure the context menu is no longer showing.
1214     views::MenuItemView* menu = bb_view_->GetContextMenu();
1215     ASSERT_TRUE(!menu || !menu->GetSubmenu() ||
1216                 !menu->GetSubmenu()->IsShowing());
1217 
1218     // But the menu should be showing.
1219     menu = bb_view_->GetMenu();
1220     ASSERT_TRUE(menu && menu->GetSubmenu() && menu->GetSubmenu()->IsShowing());
1221 
1222     // Now click on empty space.
1223     gfx::Point mouse_loc;
1224     views::View::ConvertPointToScreen(bb_view_, &mouse_loc);
1225     ASSERT_TRUE(ui_controls::SendMouseMove(mouse_loc.x(), mouse_loc.y()));
1226     ASSERT_TRUE(ui_controls::SendMouseEventsNotifyWhenDone(
1227         ui_controls::LEFT, ui_controls::UP | ui_controls::DOWN,
1228         CreateEventTask(this, &BookmarkBarViewTest11::Step5)));
1229   }
1230 
Step5()1231   void Step5() {
1232     // Make sure the menu is not showing.
1233     views::MenuItemView* menu = bb_view_->GetMenu();
1234     ASSERT_TRUE(!menu || !menu->GetSubmenu() ||
1235                 !menu->GetSubmenu()->IsShowing());
1236     Done();
1237   }
1238 
1239   BookmarkContextMenuNotificationObserver observer_;
1240 };
1241 
1242 VIEW_TEST(BookmarkBarViewTest11, CloseMenuAfterClosingContextMenu)
1243 
1244 // Tests showing a modal dialog from a context menu.
1245 class BookmarkBarViewTest12 : public BookmarkBarViewEventTestBase {
1246  protected:
DoTestOnMessageLoop()1247   void DoTestOnMessageLoop() override {
1248     // Open up the other folder.
1249     views::LabelButton* button = bb_view_->other_bookmarks_button();
1250     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1251         ui_controls::DOWN | ui_controls::UP,
1252         CreateEventTask(this, &BookmarkBarViewTest12::Step2));
1253     chrome::kNumBookmarkUrlsBeforePrompting = 1;
1254   }
1255 
~BookmarkBarViewTest12()1256   ~BookmarkBarViewTest12() override {
1257     chrome::kNumBookmarkUrlsBeforePrompting = 15;
1258   }
1259 
1260  private:
Step2()1261   void Step2() {
1262     // Menu should be showing.
1263     views::MenuItemView* menu = bb_view_->GetMenu();
1264     ASSERT_TRUE(menu != NULL);
1265     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1266 
1267     views::MenuItemView* child_menu =
1268         menu->GetSubmenu()->GetMenuItemAt(1);
1269     ASSERT_TRUE(child_menu != NULL);
1270 
1271     // Right click on the second child (a folder) to get its context menu.
1272     ui_test_utils::MoveMouseToCenterAndPress(child_menu, ui_controls::RIGHT,
1273         ui_controls::DOWN | ui_controls::UP,
1274         CreateEventTask(this, &BookmarkBarViewTest12::Step3));
1275   }
1276 
Step3()1277   void Step3() {
1278     // Make sure the context menu is showing.
1279     views::MenuItemView* menu = bb_view_->GetContextMenu();
1280     ASSERT_TRUE(menu);
1281     ASSERT_TRUE(menu->GetSubmenu());
1282     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1283 
1284     // Select the first item in the context menu (open all).
1285     views::MenuItemView* child_menu =
1286         menu->GetSubmenu()->GetMenuItemAt(0);
1287     ASSERT_TRUE(child_menu != NULL);
1288 
1289     // Click and wait until the dialog box appears.
1290     auto dialog_waiter = std::make_unique<DialogWaiter>();
1291     ui_test_utils::MoveMouseToCenterAndPress(
1292         child_menu, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1293         base::BindOnce(&BookmarkBarViewTest12::Step4, base::Unretained(this),
1294                        std::move(dialog_waiter)));
1295   }
1296 
Step4(std::unique_ptr<DialogWaiter> waiter)1297   void Step4(std::unique_ptr<DialogWaiter> waiter) {
1298     views::Widget* dialog = waiter->WaitForDialog();
1299     waiter.reset();
1300 
1301     // Press tab to give focus to the cancel button. Wait until the widget
1302     // receives the tab key.
1303     TabKeyWaiter tab_waiter(dialog);
1304     ASSERT_TRUE(ui_controls::SendKeyPress(
1305         dialog->GetNativeWindow(), ui::VKEY_TAB, false, false, false, false));
1306     tab_waiter.WaitForTab();
1307 
1308     // For some reason return isn't processed correctly unless we delay.
1309     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1310         FROM_HERE,
1311         base::BindOnce(&BookmarkBarViewTest12::Step5, base::Unretained(this),
1312                        base::Unretained(dialog)),
1313         base::TimeDelta::FromSeconds(1));
1314   }
1315 
Step5(views::Widget * dialog)1316   void Step5(views::Widget* dialog) {
1317     DialogCloseWaiter waiter(dialog);
1318     // And press enter so that the cancel button is selected.
1319     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1320         dialog->GetNativeWindow(), ui::VKEY_RETURN, false, false, false, false,
1321         base::OnceClosure()));
1322     waiter.WaitForDialogClose();
1323     Done();
1324   }
1325 };
1326 
1327 VIEW_TEST(BookmarkBarViewTest12, CloseWithModalDialog)
1328 
1329 // Tests clicking on the separator of a context menu (this is for coverage of
1330 // bug 17862).
1331 class BookmarkBarViewTest13 : public BookmarkBarViewEventTestBase {
1332  public:
BookmarkBarViewTest13()1333   BookmarkBarViewTest13()
1334       : observer_(CreateEventTask(this, &BookmarkBarViewTest13::Step3)) {
1335   }
1336 
1337  protected:
DoTestOnMessageLoop()1338   void DoTestOnMessageLoop() override {
1339     // Move the mouse to the first folder on the bookmark bar and press the
1340     // mouse.
1341     views::LabelButton* button = bb_view_->other_bookmarks_button();
1342     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1343         ui_controls::DOWN | ui_controls::UP,
1344         CreateEventTask(this, &BookmarkBarViewTest13::Step2));
1345   }
1346 
1347  private:
Step2()1348   void Step2() {
1349     // Menu should be showing.
1350     views::MenuItemView* menu = bb_view_->GetMenu();
1351     ASSERT_TRUE(menu != NULL);
1352     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1353 
1354     views::MenuItemView* child_menu =
1355         menu->GetSubmenu()->GetMenuItemAt(0);
1356     ASSERT_TRUE(child_menu != NULL);
1357 
1358     // Right click on the first child to get its context menu.
1359     ui_test_utils::MoveMouseToCenterAndPress(
1360         child_menu, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1361         base::OnceClosure());
1362     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
1363   }
1364 
Step3()1365   void Step3() {
1366     // Make sure the context menu is showing.
1367     views::MenuItemView* menu = bb_view_->GetContextMenu();
1368     ASSERT_TRUE(menu != NULL);
1369     ASSERT_TRUE(menu->GetSubmenu());
1370     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1371 
1372     // Find the first separator.
1373     views::SubmenuView* submenu = menu->GetSubmenu();
1374     const auto i = std::find_if(
1375         submenu->children().begin(), submenu->children().end(),
1376         [](const auto* child) {
1377           return child->GetID() != views::MenuItemView::kMenuItemViewID;
1378         });
1379     ASSERT_FALSE(i == submenu->children().end());
1380 
1381     // Click on the separator. Clicking on the separator shouldn't visually
1382     // change anything.
1383     ui_test_utils::MoveMouseToCenterAndPress(
1384         *i, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1385         CreateEventTask(this, &BookmarkBarViewTest13::Step4));
1386   }
1387 
Step4()1388   void Step4() {
1389     // The context menu should still be showing.
1390     views::MenuItemView* menu = bb_view_->GetContextMenu();
1391     ASSERT_TRUE(menu != NULL);
1392     ASSERT_TRUE(menu->GetSubmenu());
1393     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1394 
1395     // Select the first context menu item.
1396     ui_test_utils::MoveMouseToCenterAndPress(
1397         menu->GetSubmenu()->GetMenuItemAt(0),
1398         ui_controls::LEFT,
1399         ui_controls::DOWN | ui_controls::UP,
1400         CreateEventTask(this, &BookmarkBarViewTest13::Step5));
1401   }
1402 
Step5()1403   void Step5() {
1404     Done();
1405   }
1406 
1407   BookmarkContextMenuNotificationObserver observer_;
1408 };
1409 
1410 VIEW_TEST(BookmarkBarViewTest13, ClickOnContextMenuSeparator)
1411 
1412 // Makes sure right clicking on a folder on the bookmark bar doesn't result in
1413 // both a context menu and showing the menu.
1414 class BookmarkBarViewTest14 : public BookmarkBarViewEventTestBase {
1415  public:
BookmarkBarViewTest14()1416   BookmarkBarViewTest14()
1417       : observer_(CreateEventTask(this, &BookmarkBarViewTest14::Step2)) {
1418   }
1419 
1420  protected:
DoTestOnMessageLoop()1421   void DoTestOnMessageLoop() override {
1422     // Move the mouse to the first folder on the bookmark bar and press the
1423     // right mouse button.
1424     views::LabelButton* button = GetBookmarkButton(0);
1425     ui_test_utils::MoveMouseToCenterAndPress(
1426         button, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1427         base::OnceClosure());
1428     // Step2 will be invoked by BookmarkContextMenuNotificationObserver.
1429   }
1430 
1431  private:
1432 
Step2()1433   void Step2() {
1434     // Menu should NOT be showing.
1435     views::MenuItemView* menu = bb_view_->GetMenu();
1436     ASSERT_TRUE(menu == NULL);
1437 
1438     // Send escape so that the context menu hides.
1439     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
1440         window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false, false,
1441         false, CreateEventTask(this, &BookmarkBarViewTest14::Step3)));
1442   }
1443 
Step3()1444   void Step3() {
1445     Done();
1446   }
1447 
1448   BookmarkContextMenuNotificationObserver observer_;
1449 };
1450 
1451 VIEW_TEST(BookmarkBarViewTest14, ContextMenus2)
1452 
1453 // Makes sure deleting from the context menu keeps the bookmark menu showing.
1454 class BookmarkBarViewTest15 : public BookmarkBarViewEventTestBase {
1455  public:
BookmarkBarViewTest15()1456   BookmarkBarViewTest15()
1457       : deleted_menu_id_(0),
1458         observer_(CreateEventTask(this, &BookmarkBarViewTest15::Step3)) {
1459   }
1460 
1461  protected:
DoTestOnMessageLoop()1462   void DoTestOnMessageLoop() override {
1463     // Show the other bookmarks.
1464     views::LabelButton* button = bb_view_->other_bookmarks_button();
1465     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1466         ui_controls::DOWN | ui_controls::UP,
1467         CreateEventTask(this, &BookmarkBarViewTest15::Step2));
1468   }
1469 
1470  private:
Step2()1471   void Step2() {
1472     // Menu should be showing.
1473     views::MenuItemView* menu = bb_view_->GetMenu();
1474     ASSERT_TRUE(menu != NULL);
1475     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1476 
1477     views::MenuItemView* child_menu =
1478         menu->GetSubmenu()->GetMenuItemAt(1);
1479     ASSERT_TRUE(child_menu != NULL);
1480 
1481     deleted_menu_id_ = child_menu->GetCommand();
1482 
1483     // Right click on the second child to get its context menu.
1484     ui_test_utils::MoveMouseToCenterAndPress(
1485         child_menu, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1486         base::OnceClosure());
1487     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
1488   }
1489 
Step3()1490   void Step3() {
1491     // Make sure the context menu is showing.
1492     views::MenuItemView* menu = bb_view_->GetContextMenu();
1493     ASSERT_TRUE(menu != NULL);
1494     ASSERT_TRUE(menu->GetSubmenu());
1495     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1496 
1497     views::MenuItemView* delete_menu =
1498         menu->GetMenuItemByID(IDC_BOOKMARK_BAR_REMOVE);
1499     ASSERT_TRUE(delete_menu);
1500 
1501     // Click on the delete button.
1502     ui_test_utils::MoveMouseToCenterAndPress(delete_menu,
1503         ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1504         CreateEventTask(this, &BookmarkBarViewTest15::Step4));
1505   }
1506 
Step4()1507   void Step4() {
1508     // The context menu should not be showing.
1509     views::MenuItemView* context_menu = bb_view_->GetContextMenu();
1510     ASSERT_TRUE(context_menu == NULL);
1511 
1512     // But the menu should be showing.
1513     views::MenuItemView* menu = bb_view_->GetMenu();
1514     ASSERT_TRUE(menu != NULL);
1515     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1516 
1517     // And the deleted_menu_id_ should have been removed.
1518     ASSERT_TRUE(menu->GetMenuItemByID(deleted_menu_id_) == NULL);
1519 
1520     bb_view_->GetMenu()->GetMenuController()->Cancel(
1521         views::MenuController::ExitType::kAll);
1522 
1523     Done();
1524   }
1525 
1526   int deleted_menu_id_;
1527   BookmarkContextMenuNotificationObserver observer_;
1528 };
1529 
1530 VIEW_TEST(BookmarkBarViewTest15, MenuStaysVisibleAfterDelete)
1531 
1532 // Tests that we don't crash or get stuck if the parent of a menu is closed.
1533 class BookmarkBarViewTest16 : public BookmarkBarViewEventTestBase {
1534  protected:
DoTestOnMessageLoop()1535   void DoTestOnMessageLoop() override {
1536     // Move the mouse to the first folder on the bookmark bar and press the
1537     // mouse.
1538     views::LabelButton* button = GetBookmarkButton(0);
1539     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1540         ui_controls::DOWN | ui_controls::UP,
1541         CreateEventTask(this, &BookmarkBarViewTest16::Step2));
1542   }
1543 
1544  private:
Step2()1545   void Step2() {
1546     // Menu should be showing.
1547     views::MenuItemView* menu = bb_view_->GetMenu();
1548     ASSERT_TRUE(menu != NULL);
1549     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1550 
1551     // Button should be depressed.
1552     views::LabelButton* button = GetBookmarkButton(0);
1553     ASSERT_TRUE(button->GetState() == views::Button::STATE_PRESSED);
1554 
1555     // Close the window.
1556     window()->Close();
1557 
1558     base::ThreadTaskRunnerHandle::Get()->PostTask(
1559         FROM_HERE, CreateEventTask(this, &BookmarkBarViewTest16::Done));
1560   }
1561 };
1562 
1563 VIEW_TEST(BookmarkBarViewTest16, DeleteMenu)
1564 
1565 // Makes sure right clicking on an item while a context menu is already showing
1566 // doesn't crash and works.
1567 class BookmarkBarViewTest17 : public BookmarkBarViewEventTestBase {
1568  public:
BookmarkBarViewTest17()1569   BookmarkBarViewTest17()
1570       : observer_(std::make_unique<BookmarkContextMenuNotificationObserver>(
1571             CreateEventTask(this, &BookmarkBarViewTest17::Step3))) {}
1572 
1573  protected:
DoTestOnMessageLoop()1574   void DoTestOnMessageLoop() override {
1575 #if defined(OS_WIN)
1576     // TODO(crbug.com/453796): Flaky on Windows7.
1577     if (base::win::GetVersion() <= base::win::Version::WIN7) {
1578       Done();
1579       return;
1580     }
1581 #endif
1582 
1583     // Move the mouse to the other folder on the bookmark bar and press the
1584     // left mouse button.
1585     views::LabelButton* button = bb_view_->other_bookmarks_button();
1586     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1587         ui_controls::DOWN | ui_controls::UP,
1588         CreateEventTask(this, &BookmarkBarViewTest17::Step2));
1589   }
1590 
1591  private:
Step2()1592   void Step2() {
1593     // Menu should be showing.
1594     views::MenuItemView* menu = bb_view_->GetMenu();
1595     ASSERT_TRUE(menu != NULL);
1596     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1597 
1598     // Right click on the second item to show its context menu.
1599     views::MenuItemView* child_menu = menu->GetSubmenu()->GetMenuItemAt(2);
1600     ASSERT_TRUE(child_menu != NULL);
1601     ui_test_utils::MoveMouseToCenterAndPress(
1602         child_menu, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1603         base::OnceClosure());
1604     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
1605   }
1606 
Step3()1607   void Step3() {
1608     // Make sure the context menu is showing.
1609     views::MenuItemView* context_menu = bb_view_->GetContextMenu();
1610     ASSERT_TRUE(context_menu != NULL);
1611     ASSERT_TRUE(context_menu->GetSubmenu());
1612     ASSERT_TRUE(context_menu->GetSubmenu()->IsShowing());
1613 
1614     // Right click on the first menu item to trigger its context menu.
1615     views::MenuItemView* menu = bb_view_->GetMenu();
1616     ASSERT_TRUE(menu != NULL);
1617     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1618     views::MenuItemView* child_menu = menu->GetSubmenu()->GetMenuItemAt(1);
1619     ASSERT_TRUE(child_menu != NULL);
1620 
1621     // The context menu and child_menu can be overlapped, calculate the
1622     // non-intersected Rect of the child menu and click on its center to make
1623     // sure the click is always on the child menu.
1624     gfx::Rect context_rect = context_menu->GetSubmenu()->GetBoundsInScreen();
1625     gfx::Rect child_menu_rect = child_menu->GetBoundsInScreen();
1626     gfx::Rect clickable_rect =
1627         gfx::SubtractRects(child_menu_rect, context_rect);
1628     ASSERT_FALSE(clickable_rect.IsEmpty());
1629     observer_ = std::make_unique<BookmarkContextMenuNotificationObserver>(
1630         CreateEventTask(this, &BookmarkBarViewTest17::Step4));
1631     MoveMouseAndPress(clickable_rect.CenterPoint(), ui_controls::RIGHT,
1632         ui_controls::DOWN | ui_controls::UP, base::Closure());
1633     // Step4 will be invoked by BookmarkContextMenuNotificationObserver.
1634   }
1635 
Step4()1636   void Step4() {
1637     // The context menu should still be showing.
1638     views::MenuItemView* context_menu = bb_view_->GetContextMenu();
1639     ASSERT_TRUE(context_menu != NULL);
1640 
1641     // And the menu should be showing.
1642     views::MenuItemView* menu = bb_view_->GetMenu();
1643     ASSERT_TRUE(menu != NULL);
1644     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1645 
1646     bb_view_->GetMenu()->GetMenuController()->Cancel(
1647         views::MenuController::ExitType::kAll);
1648 
1649     Done();
1650   }
1651 
1652   std::unique_ptr<BookmarkContextMenuNotificationObserver> observer_;
1653 };
1654 
1655 VIEW_TEST(BookmarkBarViewTest17, ContextMenus3)
1656 
1657 // Verifies sibling menus works. Clicks on the 'other bookmarks' folder, then
1658 // moves the mouse over the first item on the bookmark bar and makes sure the
1659 // menu appears.
1660 class BookmarkBarViewTest18 : public BookmarkBarViewEventTestBase {
1661  protected:
DoTestOnMessageLoop()1662   void DoTestOnMessageLoop() override {
1663     // Move the mouse to the other folder on the bookmark bar and press the
1664     // left mouse button.
1665     views::LabelButton* button = bb_view_->other_bookmarks_button();
1666     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1667         ui_controls::DOWN | ui_controls::UP,
1668         CreateEventTask(this, &BookmarkBarViewTest18::Step2));
1669   }
1670 
1671  private:
Step2()1672   void Step2() {
1673     // Menu should be showing.
1674     views::MenuItemView* menu = bb_view_->GetMenu();
1675     ASSERT_TRUE(menu != NULL);
1676     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1677     // The button should be pressed.
1678     EXPECT_EQ(views::Button::STATE_PRESSED,
1679               bb_view_->other_bookmarks_button()->GetState());
1680 
1681     // Move the mouse to the first folder on the bookmark bar.
1682     views::LabelButton* button = GetBookmarkButton(0);
1683     gfx::Point button_center(button->width() / 2, button->height() / 2);
1684     views::View::ConvertPointToScreen(button, &button_center);
1685     ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone(
1686         button_center.x(), button_center.y(),
1687         CreateEventTask(this, &BookmarkBarViewTest18::Step3)));
1688   }
1689 
Step3()1690   void Step3() {
1691     // Make sure the menu is showing.
1692     views::MenuItemView* menu = bb_view_->GetMenu();
1693     ASSERT_TRUE(menu != NULL);
1694     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1695 
1696     // The menu for the first folder should be in the pressed state (since the
1697     // menu is showing for it)...
1698     EXPECT_EQ(views::Button::STATE_PRESSED, GetBookmarkButton(0)->GetState());
1699     // ... And the "other bookmarks" button should no longer be pressed.
1700     EXPECT_EQ(views::Button::STATE_NORMAL,
1701               bb_view_->other_bookmarks_button()->GetState());
1702 
1703     menu->GetMenuController()->Cancel(views::MenuController::ExitType::kAll);
1704 
1705     Done();
1706   }
1707 };
1708 
1709 VIEW_TEST(BookmarkBarViewTest18, BookmarkBarViewTest18_SiblingMenu)
1710 
1711 // Verifies mousing over an already open sibling menu doesn't prematurely cancel
1712 // the menu.
1713 class BookmarkBarViewTest19 : public BookmarkBarViewEventTestBase {
1714  protected:
DoTestOnMessageLoop()1715   void DoTestOnMessageLoop() override {
1716     // Move the mouse to the other folder on the bookmark bar and press the
1717     // left mouse button.
1718     views::LabelButton* button = bb_view_->other_bookmarks_button();
1719     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1720         ui_controls::DOWN | ui_controls::UP,
1721         CreateEventTask(this, &BookmarkBarViewTest19::Step2));
1722   }
1723 
1724  private:
Step2()1725   void Step2() {
1726     // Menu should be showing.
1727     views::MenuItemView* menu = bb_view_->GetMenu();
1728     ASSERT_TRUE(menu != NULL);
1729     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1730 
1731     // Click on the first folder.
1732     views::MenuItemView* child_menu = menu->GetSubmenu()->GetMenuItemAt(1);
1733     ASSERT_TRUE(child_menu != NULL);
1734     ui_test_utils::MoveMouseToCenterAndPress(
1735         child_menu, ui_controls::LEFT,
1736         ui_controls::DOWN | ui_controls::UP,
1737         CreateEventTask(this, &BookmarkBarViewTest19::Step3));
1738   }
1739 
Step3()1740   void Step3() {
1741     // Make sure the menu is showing.
1742     views::MenuItemView* menu = bb_view_->GetMenu();
1743     ASSERT_TRUE(menu != NULL);
1744     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1745 
1746     // Move the mouse back to the "Other Bookmarks" button.
1747     views::LabelButton* button = bb_view_->other_bookmarks_button();
1748     gfx::Point button_center(button->width() / 2, button->height() / 2);
1749     views::View::ConvertPointToScreen(button, &button_center);
1750     ASSERT_TRUE(ui_controls::SendMouseMoveNotifyWhenDone(
1751         button_center.x() + 1, button_center.y() + 1,
1752         CreateEventTask(this, &BookmarkBarViewTest19::Step4)));
1753   }
1754 
Step4()1755   void Step4() {
1756     // Menu should be showing.
1757     views::MenuItemView* menu = bb_view_->GetMenu();
1758     ASSERT_TRUE(menu != NULL);
1759     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1760 
1761     // Click on the first folder.
1762     views::MenuItemView* child_menu = menu->GetSubmenu()->GetMenuItemAt(1);
1763     ASSERT_TRUE(child_menu != NULL);
1764     ui_test_utils::MoveMouseToCenterAndPress(
1765         child_menu,
1766         ui_controls::LEFT,
1767         ui_controls::DOWN | ui_controls::UP,
1768         CreateEventTask(this, &BookmarkBarViewTest19::Step5));
1769   }
1770 
Step5()1771   void Step5() {
1772     // Make sure the menu is showing.
1773     views::MenuItemView* menu = bb_view_->GetMenu();
1774     ASSERT_TRUE(menu != NULL);
1775     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1776 
1777     menu->GetMenuController()->Cancel(views::MenuController::ExitType::kAll);
1778 
1779     Done();
1780   }
1781 };
1782 
1783 VIEW_TEST(BookmarkBarViewTest19, BookmarkBarViewTest19_SiblingMenu)
1784 
1785 // Verify that when clicking a mouse button outside a context menu,
1786 // the context menu is dismissed *and* the underlying view receives
1787 // the the mouse event (due to event reposting).
1788 class BookmarkBarViewTest20 : public BookmarkBarViewEventTestBase {
1789  public:
1790   BookmarkBarViewTest20() = default;
1791 
1792  protected:
DoTestOnMessageLoop()1793   void DoTestOnMessageLoop() override {
1794     // Add |test_view_| next to |bb_view_|.
1795     views::View* parent = bb_view_->parent();
1796     parent->RemoveChildView(bb_view_);
1797     auto* const container_view =
1798         parent->AddChildView(std::make_unique<views::View>());
1799     auto* const layout =
1800         container_view->SetLayoutManager(std::make_unique<views::FlexLayout>());
1801     layout->SetIgnoreDefaultMainAxisMargins(true)
1802         .SetCollapseMargins(true)
1803         .SetDefault(views::kMarginsKey, gfx::Insets(0, 2));
1804     container_view->AddChildView(bb_view_);
1805     bb_view_->SetProperty(
1806         views::kFlexBehaviorKey,
1807         views::FlexSpecification(views::MinimumFlexSizeRule::kScaleToZero,
1808                                  views::MaximumFlexSizeRule::kUnbounded));
1809     test_view_ =
1810         container_view->AddChildView(std::make_unique<TestViewForMenuExit>());
1811     test_view_->SetPreferredSize(gfx::Size(20, 0));
1812     parent->Layout();
1813 
1814     EXPECT_EQ(0, test_view_->press_count());
1815 
1816     // Move the mouse to the Test View and press the left mouse button.
1817     ui_test_utils::MoveMouseToCenterAndPress(
1818         test_view_, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1819         CreateEventTask(this, &BookmarkBarViewTest20::Step1));
1820   }
1821 
1822  private:
Step1()1823   void Step1() {
1824     EXPECT_EQ(1, test_view_->press_count());
1825     EXPECT_EQ(nullptr, bb_view_->GetMenu());
1826 
1827     // Move the mouse to the first folder on the bookmark bar and press the
1828     // left mouse button.
1829     ui_test_utils::MoveMouseToCenterAndPress(
1830         GetBookmarkButton(0), ui_controls::LEFT,
1831         ui_controls::DOWN | ui_controls::UP,
1832         CreateEventTask(this, &BookmarkBarViewTest20::Step2));
1833   }
1834 
Step2()1835   void Step2() {
1836     EXPECT_EQ(1, test_view_->press_count());
1837     views::MenuItemView* menu = bb_view_->GetMenu();
1838     ASSERT_NE(nullptr, menu);
1839     EXPECT_TRUE(menu->GetSubmenu()->IsShowing());
1840 
1841     // Move the mouse to the Test View and press the left mouse button.
1842     // The context menu will consume the event and exit. Thereafter,
1843     // the event is reposted and delivered to the Test View which
1844     // increases its press-count.
1845     ui_test_utils::MoveMouseToCenterAndPress(
1846         test_view_, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1847         CreateEventTask(this, &BookmarkBarViewTest20::Step3));
1848   }
1849 
Step3()1850   void Step3() {
1851 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD)
1852     EXPECT_EQ(1, test_view_->press_count());
1853 #else
1854     EXPECT_EQ(2, test_view_->press_count());
1855 #endif
1856     EXPECT_EQ(nullptr, bb_view_->GetMenu());
1857     Done();
1858   }
1859 
1860   class TestViewForMenuExit : public views::View {
1861    public:
1862     TestViewForMenuExit() = default;
1863 
OnMousePressed(const ui::MouseEvent & event)1864     bool OnMousePressed(const ui::MouseEvent& event) override {
1865       ++press_count_;
1866       return true;
1867     }
press_count() const1868     int press_count() const { return press_count_; }
1869 
1870    private:
1871     int press_count_ = 0;
1872   };
1873 
1874   TestViewForMenuExit* test_view_ = nullptr;
1875 };
1876 
1877 VIEW_TEST(BookmarkBarViewTest20, ContextMenuExitTest)
1878 
1879 // Tests context menu by way of opening a context menu for a empty folder menu.
1880 // The opened context menu should behave as it is from the folder button.
1881 class BookmarkBarViewTest21 : public BookmarkBarViewEventTestBase {
1882  public:
BookmarkBarViewTest21()1883   BookmarkBarViewTest21()
1884       : observer_(CreateEventTask(this, &BookmarkBarViewTest21::Step3)) {
1885   }
1886 
1887  protected:
1888   // Move the mouse to the empty folder on the bookmark bar and press the
1889   // left mouse button.
DoTestOnMessageLoop()1890   void DoTestOnMessageLoop() override {
1891     views::LabelButton* button = GetBookmarkButton(5);
1892     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
1893         ui_controls::DOWN | ui_controls::UP,
1894         CreateEventTask(this, &BookmarkBarViewTest21::Step2));
1895   }
1896 
1897  private:
1898   // Confirm that a menu for empty folder shows and right click the menu.
Step2()1899   void Step2() {
1900     // Menu should be showing.
1901     views::MenuItemView* menu = bb_view_->GetMenu();
1902     ASSERT_TRUE(menu != NULL);
1903 
1904     views::SubmenuView* submenu = menu->GetSubmenu();
1905     ASSERT_TRUE(submenu->IsShowing());
1906     ASSERT_EQ(1u, submenu->children().size());
1907 
1908     views::View* view = submenu->children().front();
1909     ASSERT_NE(nullptr, view);
1910     EXPECT_EQ(views::MenuItemView::kEmptyMenuItemViewID, view->GetID());
1911 
1912     // Right click on the first child to get its context menu.
1913     ui_test_utils::MoveMouseToCenterAndPress(
1914         view, ui_controls::RIGHT, ui_controls::DOWN | ui_controls::UP,
1915         base::OnceClosure());
1916     // Step3 will be invoked by BookmarkContextMenuNotificationObserver.
1917   }
1918 
1919   // Confirm that context menu shows and click REMOVE menu.
Step3()1920   void Step3() {
1921     // Make sure the context menu is showing.
1922     views::MenuItemView* menu = bb_view_->GetContextMenu();
1923     ASSERT_TRUE(menu != NULL);
1924     ASSERT_TRUE(menu->GetSubmenu());
1925     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
1926 
1927     views::MenuItemView* delete_menu =
1928         menu->GetMenuItemByID(IDC_BOOKMARK_BAR_REMOVE);
1929     ASSERT_TRUE(delete_menu);
1930 
1931     // Click on the delete menu item.
1932     ui_test_utils::MoveMouseToCenterAndPress(delete_menu,
1933         ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
1934         CreateEventTask(this, &BookmarkBarViewTest21::Step4));
1935   }
1936 
1937   // Confirm that the empty folder gets removed and menu doesn't show.
Step4()1938   void Step4() {
1939     views::LabelButton* button = GetBookmarkButton(5);
1940     ASSERT_TRUE(button);
1941     EXPECT_EQ(ASCIIToUTF16("d"), button->GetText());
1942     EXPECT_TRUE(bb_view_->GetContextMenu() == NULL);
1943     EXPECT_TRUE(bb_view_->GetMenu() == NULL);
1944 
1945     Done();
1946   }
1947 
1948   BookmarkContextMenuNotificationObserver observer_;
1949 };
1950 
1951 // If this flakes, disable and log details in http://crbug.com/523255.
1952 VIEW_TEST(BookmarkBarViewTest21, ContextMenusForEmptyFolder)
1953 
1954 // Test that closing the source browser window while dragging a bookmark does
1955 // not cause a crash.
1956 class BookmarkBarViewTest22 : public BookmarkBarViewDragTestBase {
1957  public:
1958   // BookmarkBarViewDragTestBase:
OnWidgetDragComplete(views::Widget * widget)1959   void OnWidgetDragComplete(views::Widget* widget) override {}
1960 
OnWidgetDestroyed(views::Widget * widget)1961   void OnWidgetDestroyed(views::Widget* widget) override {
1962     BookmarkBarViewDragTestBase::OnWidgetDestroyed(widget);
1963     Done();
1964   }
1965 
1966  protected:
1967   // BookmarkBarViewDragTestBase:
OnMenuOpened()1968   void OnMenuOpened() override {
1969     BookmarkBarViewDragTestBase::OnMenuOpened();
1970 
1971     // Cause the second menu item to close the window when dragged over.
1972     SetStopDraggingView(bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1));
1973   }
1974 
OnDragEntered()1975   void OnDragEntered() override {
1976     // Stop the drag, so any nested message loop will terminate; closing the
1977     // window alone may not exit this message loop.
1978     BookmarkBarViewDragTestBase::OnDragEntered();
1979 
1980     window()->Close();
1981   }
1982 
GetDroppedNode() const1983   const BookmarkNode* GetDroppedNode() const override {
1984     // This test doesn't check what happens on drop.
1985     return nullptr;
1986   }
1987 
GetDragTargetInScreen() const1988   gfx::Point GetDragTargetInScreen() const override {
1989     return ui_test_utils::GetCenterInScreenCoordinates(
1990         bb_view_->GetMenu()->GetSubmenu()->GetMenuItemAt(1));
1991   }
1992 };
1993 
1994 VIEW_TEST(BookmarkBarViewTest22, CloseSourceBrowserDuringDrag)
1995 
1996 // Tests opening a context menu for a bookmark node from the keyboard.
1997 class BookmarkBarViewTest23 : public BookmarkBarViewEventTestBase {
1998  public:
BookmarkBarViewTest23()1999   BookmarkBarViewTest23()
2000       : observer_(CreateEventTask(this, &BookmarkBarViewTest23::Step4)) {
2001   }
2002 
2003  protected:
DoTestOnMessageLoop()2004   void DoTestOnMessageLoop() override {
2005     // Move the mouse to the first folder on the bookmark bar and press the
2006     // mouse.
2007     views::LabelButton* button = bb_view_->other_bookmarks_button();
2008     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
2009         ui_controls::DOWN | ui_controls::UP,
2010         CreateEventTask(this, &BookmarkBarViewTest23::Step2));
2011   }
2012 
2013  private:
Step2()2014   void Step2() {
2015     // Menu should be showing.
2016     views::MenuItemView* menu = bb_view_->GetMenu();
2017     ASSERT_TRUE(menu);
2018     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2019 
2020     // Navigate down to highlight the first menu item.
2021     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
2022         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
2023         CreateEventTask(this, &BookmarkBarViewTest23::Step3)));
2024   }
2025 
Step3()2026   void Step3() {
2027     // Menu should be showing.
2028     views::MenuItemView* menu = bb_view_->GetMenu();
2029     ASSERT_TRUE(menu);
2030     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2031 
2032     // Open the context menu via the keyboard.
2033     ASSERT_TRUE(ui_controls::SendKeyPress(window()->GetNativeWindow(),
2034                                           ui::VKEY_APPS, false, false, false,
2035                                           false));
2036     // The BookmarkContextMenuNotificationObserver triggers Step4.
2037   }
2038 
Step4()2039   void Step4() {
2040     // Make sure the context menu is showing.
2041     views::MenuItemView* menu = bb_view_->GetContextMenu();
2042     ASSERT_TRUE(menu);
2043     ASSERT_TRUE(menu->GetSubmenu());
2044     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2045 
2046     // Select the first menu item (open).
2047     ui_test_utils::MoveMouseToCenterAndPress(
2048         menu->GetSubmenu()->GetMenuItemAt(0),
2049         ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
2050         CreateEventTask(this, &BookmarkBarViewTest23::Step5));
2051   }
2052 
Step5()2053   void Step5() {
2054     EXPECT_EQ(navigator_.last_url(),
2055               model_->other_node()->children().front()->url());
2056     ASSERT_FALSE(PageTransitionIsWebTriggerable(navigator_.last_transition()));
2057     Done();
2058   }
2059 
2060   BookmarkContextMenuNotificationObserver observer_;
2061 };
2062 
2063 #if defined(OS_WIN)  // Fails on latest versions of Windows.
2064                      // https://crbug.com/1108551.
2065 #define MAYBE_ContextMenusKeyboard DISABLED_ContextMenusKeyboard
2066 #else
2067 #define MAYBE_ContextMenusKeyboard ContextMenusKeyboard
2068 #endif
2069 VIEW_TEST(BookmarkBarViewTest23, MAYBE_ContextMenusKeyboard)
2070 
2071 // Test that pressing escape on a menu opened via the keyboard dismisses the
2072 // context menu but not the parent menu.
2073 class BookmarkBarViewTest24 : public BookmarkBarViewEventTestBase {
2074  public:
BookmarkBarViewTest24()2075   BookmarkBarViewTest24()
2076       : observer_(CreateEventTask(this, &BookmarkBarViewTest24::Step4)) {}
2077 
2078  protected:
DoTestOnMessageLoop()2079   void DoTestOnMessageLoop() override {
2080     // Move the mouse to the first folder on the bookmark bar and press the
2081     // mouse.
2082     views::LabelButton* button = bb_view_->other_bookmarks_button();
2083     ui_test_utils::MoveMouseToCenterAndPress(button, ui_controls::LEFT,
2084         ui_controls::DOWN | ui_controls::UP,
2085         CreateEventTask(this, &BookmarkBarViewTest24::Step2));
2086   }
2087 
2088  private:
Step2()2089   void Step2() {
2090     // Menu should be showing.
2091     views::MenuItemView* menu = bb_view_->GetMenu();
2092     ASSERT_TRUE(menu);
2093     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2094 
2095     // Navigate down to highlight the first menu item.
2096     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
2097         window()->GetNativeWindow(), ui::VKEY_DOWN, false, false, false, false,
2098         CreateEventTask(this, &BookmarkBarViewTest24::Step3)));
2099   }
2100 
Step3()2101   void Step3() {
2102     // Menu should be showing.
2103     views::MenuItemView* menu = bb_view_->GetMenu();
2104     ASSERT_TRUE(menu);
2105     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2106 
2107     // Open the context menu via the keyboard.
2108     ASSERT_TRUE(ui_controls::SendKeyPress(window()->GetNativeWindow(),
2109                                           ui::VKEY_APPS, false, false, false,
2110                                           false));
2111     // The BookmarkContextMenuNotificationObserver triggers Step4.
2112   }
2113 
Step4()2114   void Step4() {
2115     // Make sure the context menu is showing.
2116     views::MenuItemView* menu = bb_view_->GetContextMenu();
2117     ASSERT_TRUE(menu);
2118     ASSERT_TRUE(menu->GetSubmenu());
2119     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2120 
2121     // Send escape to close the context menu.
2122     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
2123         window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false, false,
2124         false, CreateEventTask(this, &BookmarkBarViewTest24::Step5)));
2125   }
2126 
Step5()2127   void Step5() {
2128     // The context menu should be closed but the parent menu should still be
2129     // showing.
2130     ASSERT_FALSE(bb_view_->GetContextMenu());
2131 
2132     views::MenuItemView* menu = bb_view_->GetMenu();
2133     ASSERT_TRUE(menu);
2134     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2135 
2136     // Send escape to close the main menu.
2137     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
2138         window()->GetNativeWindow(), ui::VKEY_ESCAPE, false, false, false,
2139         false, CreateEventTask(this, &BookmarkBarViewTest24::Done)));
2140   }
2141 
2142   BookmarkContextMenuNotificationObserver observer_;
2143 };
2144 
2145 #if defined(OS_WIN)  // Fails on latest versions of Windows.
2146                      // https://crbug.com/1108551.
2147 #define MAYBE_ContextMenusKeyboardEscape DISABLED_ContextMenusKeyboardEscape
2148 #else
2149 #define MAYBE_ContextMenusKeyboardEscape ContextMenusKeyboardEscape
2150 #endif
2151 VIEW_TEST(BookmarkBarViewTest24, MAYBE_ContextMenusKeyboardEscape)
2152 
2153 #if defined(OS_WIN)
2154 // Tests that pressing the key KEYCODE closes the menu.
2155 template <ui::KeyboardCode KEYCODE>
2156 class BookmarkBarViewTest25 : public BookmarkBarViewEventTestBase {
2157  protected:
DoTestOnMessageLoop()2158   void DoTestOnMessageLoop() override {
2159     // Move the mouse to the first folder on the bookmark bar and press the
2160     // mouse.
2161     views::LabelButton* button = GetBookmarkButton(0);
2162     ui_test_utils::MoveMouseToCenterAndPress(
2163         button, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
2164         CreateEventTask(this, &BookmarkBarViewTest25::Step2));
2165   }
2166 
2167  private:
Step2()2168   void Step2() {
2169     // Menu should be showing.
2170     views::MenuItemView* menu = bb_view_->GetMenu();
2171     ASSERT_TRUE(menu);
2172     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2173 
2174     // Send KEYCODE key event, which should close the menu.
2175     ASSERT_TRUE(ui_controls::SendKeyPressNotifyWhenDone(
2176         window()->GetNativeWindow(), KEYCODE, false, false, false, false,
2177         CreateEventTask(this, &BookmarkBarViewTest25::Step3)));
2178   }
2179 
Step3()2180   void Step3() {
2181     // Make sure menu is not showing.
2182     views::MenuItemView* menu = bb_view_->GetMenu();
2183     ASSERT_TRUE(menu == nullptr);
2184 
2185     Done();
2186   }
2187 };
2188 
2189 // Tests that pressing F10 system key closes the menu.
2190 using BookmarkBarViewTest25F10 = BookmarkBarViewTest25<ui::VKEY_F10>;
2191 VIEW_TEST(BookmarkBarViewTest25F10, F10ClosesMenu)
2192 
2193 // Tests that pressing Alt system key closes the menu.
2194 using BookmarkBarViewTest25Alt = BookmarkBarViewTest25<ui::VKEY_MENU>;
2195 VIEW_TEST(BookmarkBarViewTest25Alt, AltClosesMenu)
2196 
2197 // Tests that WM_CANCELMODE closes the menu.
2198 class BookmarkBarViewTest26 : public BookmarkBarViewEventTestBase {
2199  protected:
DoTestOnMessageLoop()2200   void DoTestOnMessageLoop() override {
2201     // Move the mouse to the first folder on the bookmark bar and press the
2202     // mouse.
2203     views::LabelButton* button = GetBookmarkButton(0);
2204     ui_test_utils::MoveMouseToCenterAndPress(
2205         button, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
2206         CreateEventTask(this, &BookmarkBarViewTest26::Step2));
2207   }
2208 
2209  private:
Step2()2210   void Step2() {
2211     // Menu should be showing.
2212     views::MenuItemView* menu = bb_view_->GetMenu();
2213     ASSERT_TRUE(menu);
2214     ASSERT_TRUE(menu->GetSubmenu()->IsShowing());
2215 
2216     // Send WM_CANCELMODE, which should close the menu. The message is sent
2217     // synchronously, however, we post a task to make sure that the message is
2218     // processed completely before finishing the test.
2219     ::SendMessage(window()->GetNativeView()->GetHost()->GetAcceleratedWidget(),
2220                   WM_CANCELMODE, 0, 0);
2221 
2222     base::ThreadTaskRunnerHandle::Get()->PostTask(
2223         FROM_HERE,
2224         base::BindOnce(&BookmarkBarViewTest26::Step3, base::Unretained(this)));
2225   }
2226 
Step3()2227   void Step3() {
2228     // Menu should not be showing anymore.
2229     views::MenuItemView* menu = bb_view_->GetMenu();
2230     ASSERT_TRUE(menu == nullptr);
2231 
2232     Done();
2233   }
2234 };
2235 
2236 VIEW_TEST(BookmarkBarViewTest26, CancelModeClosesMenu)
2237 #endif
2238 
2239 class BookmarkBarViewTest27 : public BookmarkBarViewEventTestBase {
2240  protected:
DoTestOnMessageLoop()2241   void DoTestOnMessageLoop() override {
2242     views::LabelButton* button = GetBookmarkButton(0);
2243     ui_test_utils::MoveMouseToCenterAndPress(
2244         button, ui_controls::MIDDLE, ui_controls::DOWN | ui_controls::UP,
2245         CreateEventTask(this, &BookmarkBarViewTest27::Step2));
2246   }
2247 
2248  private:
Step2()2249   void Step2() {
2250     ASSERT_EQ(2u, navigator_.urls().size());
2251     EXPECT_EQ(navigator_.urls()[0],
2252               model_->bookmark_bar_node()->children()[0]->children()[0]->url());
2253     EXPECT_EQ(navigator_.urls()[1],
2254               model_->bookmark_bar_node()->children()[0]->children()[2]->url());
2255     Done();
2256   }
2257 };
2258 
2259 VIEW_TEST(BookmarkBarViewTest27, MiddleClickOnFolderOpensAllBookmarks)
2260 
2261 #endif  // defined(OS_MAC)
2262 
2263 class BookmarkBarViewTest28 : public BookmarkBarViewEventTestBase {
2264  protected:
2265 #if defined(OS_MAC)
2266   const ui_controls::AcceleratorState kAccelatorState = ui_controls::kCommand;
2267 #else
2268   const ui_controls::AcceleratorState kAccelatorState = ui_controls::kControl;
2269 #endif  // defined(OS_MAC)
2270 
DoTestOnMessageLoop()2271   void DoTestOnMessageLoop() override {
2272     views::LabelButton* button = GetBookmarkButton(0);
2273     ui_test_utils::MoveMouseToCenterAndPress(
2274         button, ui_controls::LEFT, ui_controls::UP | ui_controls::DOWN,
2275         CreateEventTask(this, &BookmarkBarViewTest28::Step2), kAccelatorState);
2276   }
2277 
2278  private:
Step2()2279   void Step2() {
2280     ASSERT_EQ(2u, navigator_.urls().size());
2281     EXPECT_EQ(navigator_.urls()[0],
2282               model_->bookmark_bar_node()->children()[0]->children()[0]->url());
2283     EXPECT_EQ(navigator_.urls()[1],
2284               model_->bookmark_bar_node()->children()[0]->children()[2]->url());
2285     Done();
2286   }
2287 };
2288 
2289 VIEW_TEST(BookmarkBarViewTest28, ClickWithModifierOnFolderOpensAllBookmarks)
2290