chromium/chrome/browser/ui/views/page_action/pwa_install_view_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 <stddef.h>

#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/extend.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/clamped_math.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/banners/test_app_banner_manager_desktop.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/color/chrome_color_id.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/page_action/page_action_icon_type.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
#include "chrome/browser/ui/views/location_bar/location_bar_view.h"
#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
#include "chrome/browser/ui/views/user_education/browser_feature_promo_controller.h"
#include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
#include "chrome/browser/web_applications/install_bounce_metric.h"
#include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/browser/web_applications/web_app_command_scheduler.h"
#include "chrome/browser/web_applications/web_app_constants.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_pref_guardrails.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/feature_engagement/public/feature_constants.h"
#include "components/feature_engagement/public/feature_list.h"
#include "components/omnibox/browser/omnibox_edit_model.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "components/site_engagement/content/site_engagement_service.h"
#include "components/webapps/browser/banners/app_banner_manager.h"
#include "components/webapps/browser/banners/installable_web_app_check_result.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "components/webapps/browser/uninstall_result_code.h"
#include "components/webapps/common/web_app_id.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/no_renderer_crashes_assertion.h"
#include "content/public/test/test_utils.h"
#include "extensions/common/extension.h"
#include "net/http/http_status_code.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "services/network/public/cpp/network_switches.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
#include "ui/color/color_provider.h"
#include "ui/gfx/color_utils.h"
#include "ui/views/accessibility/view_accessibility.h"
#include "ui/views/test/dialog_test.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
#include "ui/views/widget/any_widget_observer.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/components/arc/mojom/app.mojom.h"
#include "ash/components/arc/session/connection_holder.h"
#include "ash/components/arc/test/arc_util_test_support.h"
#include "ash/components/arc/test/connection_holder_util.h"
#include "ash/components/arc/test/fake_app_instance.h"
#include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/arc/session/arc_session_manager.h"
#include "chromeos/ash/components/standalone_browser/feature_refs.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

namespace webapps {
enum class InstallResultCode;
}

namespace {

class PwaInstallIconChangeWaiter : public views::ViewObserver {};

// static
void PwaInstallIconChangeWaiter::VerifyIconVisibility(views::View* iconView,
                                                      bool visible) {}

}  // namespace

// Tests various cases that effect the visibility of the install icon in the
// omnibox.
class PwaInstallViewBrowserTest : public extensions::ExtensionBrowserTest,
                                  public testing::WithParamInterface<bool> {};

// Tests that the plus icon is not shown when an existing app is installed and
// set to open in a window.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       PwaSetToOpenInWindowIsNotInstallable) {}

// Tests that the plus icon is not shown when an outer app is installed and we
// navigate to a nested app.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       NestedPwaIsNotInstallableWhenOuterPwaIsInstalled) {}

// Tests that the install icon is shown when an existing app is installed and
// set to open in a tab.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       PwaSetToOpenInTabIsInstallable) {}

// Tests that the plus icon updates its visibility when switching between
// installable/non-installable tabs.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       IconVisibilityAfterTabSwitching) {}

// Tests that the plus icon updates its visibility when PWAConfirmationBubbleView is showing in
// installable tab and switching to non-installable tab.
IN_PROC_BROWSER_TEST_P(
    PwaInstallViewBrowserTest,
    IconVisibilityAfterTabSwitchingWhenPWAConfirmationBubbleViewShowing) {}

// Tests that the install icon updates its visibility when tab crashes.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       IconVisibilityAfterTabCrashed) {}

// Tests that the plus icon updates its visibility once the installability check
// completes.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       IconVisibilityAfterInstallabilityCheck) {}

// Tests that the plus icon updates its visibility after installation.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       IconVisibilityAfterInstallation) {}

// Tests that the plus icon animates its label when the installability check
// passes but doesn't animate more than once for the same installability check.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, LabelAnimation) {}

// Tests that the plus icon becomes invisible when the user is typing in the
// omnibox.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, InputInOmnibox) {}

// Tests that the icon persists while loading the same scope and omits running
// the label animation again.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, NavigateToSameScope) {}

// Tests that the icon persists while loading the same scope but goes away when
// the installability check fails.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       NavigateToSameScopeNonInstallable) {}

// Tests that the icon updates its state after uninstallation.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       IconStateAfterUnInstallation) {}

// Tests that the icon and animation resets while loading a different scope.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, NavigateToDifferentScope) {}

// Tests that the icon and animation resets while loading a different empty
// scope.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       NavigateToDifferentEmptyScope) {}

// Tests that the animation is suppressed for navigations within the same scope
// for an exponentially increasing period of time.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, AnimationSuppression) {}

// Tests that the icon label is visible against the omnibox background after the
// native widget becomes active.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, TextContrast) {}

IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, BouncedInstallMeasured) {}

IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, BouncedInstallIgnored) {}

// Omnibox install promotion should show if there are no viable related apps
// even if prefer_related_applications is true.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, PreferRelatedAppUnknown) {}

// Omnibox install promotion should not show if prefer_related_applications is
// false but a related Chrome app is installed.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, PreferRelatedChromeApp) {}

// Omnibox install promotion should not show if prefer_related_applications is
// true and a Chrome app listed as related.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       ListedRelatedChromeAppInstalled) {}

// TODO(crbug.com/40796769): Flaky.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       DISABLED_PwaIntallIphSiteEngagement) {}

IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, PwaIntallIphIgnored) {}

IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest, IconViewAccessibleName) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Omnibox install promotion should not show if prefer_related_applications is
// true and an ARC app listed as related.
IN_PROC_BROWSER_TEST_P(PwaInstallViewBrowserTest,
                       ListedRelatedAndroidAppInstalled) {
  arc::SetArcPlayStoreEnabledForProfile(browser()->profile(), true);
  ArcAppListPrefs* arc_app_list_prefs =
      ArcAppListPrefs::Get(browser()->profile());
  auto app_instance =
      std::make_unique<arc::FakeAppInstance>(arc_app_list_prefs);
  arc_app_list_prefs->app_connection_holder()->SetInstance(app_instance.get());
  WaitForInstanceReady(arc_app_list_prefs->app_connection_holder());

  // Install test Android app.
  arc::mojom::ArcPackageInfo package;
  package.package_name = "com.example.app";
  app_instance->InstallPackage(package.Clone());

  StartNavigateToUrl(
      https_server_.GetURL("/banners/manifest_test_page.html?manifest="
                           "manifest_listing_related_android_app.json"));
  ASSERT_FALSE(app_banner_manager_->WaitForInstallableCheck());

  EXPECT_FALSE(pwa_install_view_->GetVisible());
  EXPECT_TRUE(base::EqualsASCII(
      webapps::AppBannerManager::GetInstallableWebAppName(web_contents_),
      "Manifest listing related android app"));
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

INSTANTIATE_TEST_SUITE_P();