chromium/chrome/browser/ui/ash/app_list/app_list_with_recent_apps_browsertest.cc

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

#include "ash/public/cpp/test/app_list_test_api.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "base/metrics/histogram_base.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/ash/app_list/app_list_client_impl.h"
#include "chrome/browser/ash/app_list/search/search_controller.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/ui/browser_window.h"
#include "content/public/test/browser_test.h"
#include "ui/aura/window.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/view.h"

// The helper class to verify the bubble app list with recent apps shown.
class AppListWithRecentAppBrowserTest
    : public extensions::ExtensionBrowserTest {
 public:
  AppListWithRecentAppBrowserTest() = default;
  AppListWithRecentAppBrowserTest(const AppListWithRecentAppBrowserTest&) =
      delete;
  AppListWithRecentAppBrowserTest& operator=(
      const AppListWithRecentAppBrowserTest&) = delete;
  ~AppListWithRecentAppBrowserTest() override = default;

  // extensions::ExtensionBrowserTest:
  void SetUpOnMainThread() override {
    ExtensionBrowserTest::SetUpOnMainThread();
    AppListClientImpl* client = AppListClientImpl::GetInstance();
    ASSERT_TRUE(client);
    client->UpdateProfile();

    // Ensure async callbacks are run.
    base::RunLoop().RunUntilIdle();

    // Install enough apps to show the recent apps view.
    LoadExtension(test_data_dir_.AppendASCII("app1"));
    LoadExtension(test_data_dir_.AppendASCII("app2"));

    event_generator_ = std::make_unique<ui::test::EventGenerator>(
        browser()->window()->GetNativeWindow()->GetRootWindow());
    app_list_test_api_.ShowBubbleAppListAndWait();
  }

  void EnsureZeroStateSearchDone() {
    base::RunLoop run_loop;
    AppListClientImpl::GetInstance()
        ->search_controller()
        ->WaitForZeroStateCompletionForTest(run_loop.QuitClosure());
    run_loop.Run();
  }

  ash::AppListTestApi app_list_test_api_;
  std::unique_ptr<ui::test::EventGenerator> event_generator_;
};

// TODO(crbug.com/335362001): Re-enable this test
IN_PROC_BROWSER_TEST_F(AppListWithRecentAppBrowserTest, MouseClickAtRecentApp) {
  views::View* recent_app = app_list_test_api_.GetRecentAppAt(0);
  ASSERT_TRUE(recent_app);
  event_generator_->MoveMouseTo(recent_app->GetBoundsInScreen().CenterPoint());
  base::HistogramTester histogram_tester;
  event_generator_->ClickLeftButton();

  // Verify that the recent app activation is recorded.
  histogram_tester.ExpectBucketCount(
      "Apps.NewUserFirstLauncherAction.ClamshellMode",
      static_cast<int>(ash::AppListLaunchedFrom::kLaunchedFromRecentApps),
      /*expected_bucket_count=*/1);
}

// Tests that recent apps are shown in tablet mode app list after transition
// from bubble launcher search to tablet mode.
IN_PROC_BROWSER_TEST_F(AppListWithRecentAppBrowserTest,
                       RecentAppsShownInTabletModeAfterClearingSearch) {
  // Minimize the browser window so tablet mode launcher becomes visible
  // immediately after transition to tablet mode.
  browser()->window()->Minimize();

  views::View* recent_app = app_list_test_api_.GetRecentAppAt(0);
  ASSERT_TRUE(recent_app);

  // Simulate launcher search.
  app_list_test_api_.SimulateSearch(u"foo");

  // Transition to tablet mode while bubble launcher is showing search UI, to
  // verify that recent apps are not empty if launcher is shown just after
  // clearing search.
  ash::ShellTestApi().SetTabletModeEnabledForTest(true);
  app_list_test_api_.WaitForAppListShowAnimation(/*is_bubble_window =*/false);
  EnsureZeroStateSearchDone();

  recent_app = app_list_test_api_.GetRecentAppAt(0);
  ASSERT_TRUE(recent_app);
}

// Tests that recent apps remaiin stable after exiting launcher search, even
// after uninstalling a shown recent apps (which forces recent apps view
// refresh).
IN_PROC_BROWSER_TEST_F(AppListWithRecentAppBrowserTest,
                       DISABLED_RecentAppsNotUpdatedAfterShowingSearch) {
  std::vector<std::string> initial_recent_apps =
      app_list_test_api_.GetRecentAppIds();
  ASSERT_EQ(4u, initial_recent_apps.size());

  // Install another app, and verify it shows up in recent apps once launcher is
  // reshown.
  const extensions::Extension* app_to_remove =
      LoadExtension(test_data_dir_.AppendASCII("app3"));
  ASSERT_TRUE(app_to_remove);

  std::vector<std::string> recent_apps_after_reshow = {
      app_to_remove->id(), initial_recent_apps[0], initial_recent_apps[1],
      initial_recent_apps[2], initial_recent_apps[3]};

  AppListClientImpl::GetInstance()->DismissView();
  app_list_test_api_.ShowBubbleAppListAndWait();
  EXPECT_EQ(recent_apps_after_reshow, app_list_test_api_.GetRecentAppIds());

  // Verify that newly installed apps do no pop in into recent apps while
  // launcher is shown.
  const extensions::Extension* most_recent_app =
      LoadExtension(test_data_dir_.AppendASCII("app4"));
  ASSERT_TRUE(most_recent_app);
  EXPECT_EQ(recent_apps_after_reshow, app_list_test_api_.GetRecentAppIds());

  // Go to search and back - verify there is still no pop-in in recent apps.
  app_list_test_api_.SimulateSearch(u"foo");
  event_generator_->PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE);
  // Toggling search should not trigger zero state search, but if it does, make
  // sure the results are flushed, which will fail the test later on.
  EnsureZeroStateSearchDone();

  EXPECT_EQ(recent_apps_after_reshow, app_list_test_api_.GetRecentAppIds());

  // Uninstall an app shown in recent apps. Verify that the app is removed from
  // recent apps, but new app does not pop-in.
  UninstallExtension(app_to_remove->id());
  EXPECT_EQ(initial_recent_apps, app_list_test_api_.GetRecentAppIds());

  // Most recent apps should show up in recent apps after launcher is reshown.
  AppListClientImpl::GetInstance()->DismissView();
  app_list_test_api_.ShowBubbleAppListAndWait();

  recent_apps_after_reshow[0] = most_recent_app->id();
  EXPECT_EQ(recent_apps_after_reshow, app_list_test_api_.GetRecentAppIds());
}