chromium/chrome/browser/ui/ash/shelf/browser_shortcut_shelf_item_controller_browsertest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/ash/shelf/browser_shortcut_shelf_item_controller.h"

#include "ash/public/cpp/shelf_model.h"
#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test.h"
#include "ui/display/types/display_constants.h"

using BrowserShortcutShelfItemControllerTest = InProcessBrowserTest;

namespace {

ash::ShelfItemDelegate::AppMenuItems GetAppMenuItems(
    BrowserShortcutShelfItemController* controller,
    int event_flags) {
  return controller->GetAppMenuItems(event_flags, base::NullCallback());
}

}  // namespace

// Test the browser application menu for some browser window and tab states.
IN_PROC_BROWSER_TEST_F(BrowserShortcutShelfItemControllerTest, AppMenu) {
  BrowserShortcutShelfItemController* controller =
      ChromeShelfController::instance()
          ->GetBrowserShortcutShelfItemControllerForTesting();
  ASSERT_TRUE(controller);

  // InProcessBrowserTest's default browser window is shown with a blank tab.
  BrowserList* browser_list = BrowserList::GetInstance();
  EXPECT_EQ(1U, browser_list->size());
  auto items = GetAppMenuItems(controller, ui::EF_NONE);
  ASSERT_EQ(1U, items.size());
  EXPECT_EQ(u"about:blank", items[0].title);

  // Browsers are not listed in the menu if their windows have not been shown.
  Browser* browser1 =
      Browser::Create(Browser::CreateParams(browser()->profile(), true));
  EXPECT_FALSE(browser1->window()->IsVisible());
  EXPECT_EQ(2U, browser_list->size());
  EXPECT_EQ(1U, GetAppMenuItems(controller, ui::EF_NONE).size());

  // Browsers shown with no active tab appear as "New Tab" without crashing.
  browser1->window()->Show();
  EXPECT_TRUE(browser1->window()->IsVisible());
  EXPECT_FALSE(browser1->tab_strip_model()->GetActiveWebContents());
  EXPECT_EQ(2U, browser_list->size());
  items = GetAppMenuItems(controller, ui::EF_NONE);
  ASSERT_EQ(2U, items.size());
  EXPECT_EQ(u"about:blank", items[0].title);
  EXPECT_EQ(u"New Tab", items[1].title);

  // Browsers are listed with the title of their active contents.
  ASSERT_TRUE(ui_test_utils::NavigateToURL(
      browser(), GURL("data:text/html,<title>0</title>")));
  AddBlankTabAndShow(browser1);
  ASSERT_TRUE(ui_test_utils::NavigateToURL(
      browser1, GURL("data:text/html,<title>1</title>")));
  AddBlankTabAndShow(browser1);
  ASSERT_TRUE(ui_test_utils::NavigateToURL(
      browser1, GURL("data:text/html,<title>2</title>")));
  EXPECT_EQ(1, browser1->tab_strip_model()->active_index());
  items = GetAppMenuItems(controller, ui::EF_NONE);
  ASSERT_EQ(2U, items.size());
  EXPECT_EQ(u"0", items[0].title);
  EXPECT_EQ(u"2", items[1].title);

  // Setting the window title will update the app menu item.
  browser1->SetWindowUserTitle("foobar");
  items = GetAppMenuItems(controller, ui::EF_NONE);
  ASSERT_EQ(2U, items.size());
  EXPECT_EQ(u"0", items[0].title);
  EXPECT_EQ(u"foobar", items[1].title);

  // If the window title is cleared, the active content title will be set again
  // as the menu item title.
  browser1->SetWindowUserTitle("");
  items = GetAppMenuItems(controller, ui::EF_NONE);
  ASSERT_EQ(2U, items.size());
  EXPECT_EQ(u"0", items[0].title);
  EXPECT_EQ(u"2", items[1].title);

  // Shift-click will list all tabs in the applicable browsers.
  items = GetAppMenuItems(controller, ui::EF_SHIFT_DOWN);
  ASSERT_EQ(items.size(), 3U);
  EXPECT_EQ(u"0", items[0].title);
  EXPECT_EQ(u"1", items[1].title);
  EXPECT_EQ(u"2", items[2].title);

  // Close the window and wait for all asynchronous window teardown.
  CloseBrowserSynchronously(browser1);
  EXPECT_EQ(1U, browser_list->size());
  // Selecting an app menu item for the closed browser window should not crash.
  controller->ExecuteCommand(/*from_context_menu=*/false, /*command_id=*/1,
                             ui::EF_NONE, display::kInvalidDisplayId);

  // Create and close a window, but don't allow asynchronous teardown to occur.
  browser1 = CreateBrowser(browser()->profile());
  EXPECT_EQ(2U, browser_list->size());
  CloseBrowserAsynchronously(browser1);
  EXPECT_EQ(2U, browser_list->size());
  // The app menu should not list the browser window while it is closing.
  items = GetAppMenuItems(controller, ui::EF_NONE);
  EXPECT_EQ(1U, items.size());
  // Now, allow the asynchronous teardown to occur.
  EXPECT_EQ(2U, browser_list->size());
  ui_test_utils::WaitForBrowserToClose(browser1);
  EXPECT_EQ(1U, browser_list->size());
}