chromium/chrome/browser/ui/lens/lens_overlay_controller_browsertest.cc

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

// This class runs functional tests for lens overlay. These tests spin up a full
// web browser, but allow for inspection and modification of internal state of
// LensOverlayController and other business-logic classes.

#include "chrome/browser/ui/lens/lens_overlay_controller.h"

#include <memory>

#include "base/strings/string_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/run_until.h"
#include "base/test/with_feature_override.h"
#include "build/build_config.h"
#include "chrome/browser/lens/core/mojom/geometry.mojom.h"
#include "chrome/browser/lens/core/mojom/lens.mojom.h"
#include "chrome/browser/lens/core/mojom/overlay_object.mojom.h"
#include "chrome/browser/lens/core/mojom/polygon.mojom.h"
#include "chrome/browser/lens/core/mojom/text.mojom-forward.h"
#include "chrome/browser/lens/core/mojom/text.mojom.h"
#include "chrome/browser/pdf/pdf_extension_test_base.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_browsertest_util.h"
#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/sync/sync_service_factory.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_actions.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_element_identifiers.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/lens/lens_overlay_colors.h"
#include "chrome/browser/ui/lens/lens_overlay_controller_glue.h"
#include "chrome/browser/ui/lens/lens_overlay_dismissal_source.h"
#include "chrome/browser/ui/lens/lens_overlay_entry_point_controller.h"
#include "chrome/browser/ui/lens/lens_overlay_invocation_source.h"
#include "chrome/browser/ui/lens/lens_overlay_side_panel_coordinator.h"
#include "chrome/browser/ui/lens/lens_overlay_url_builder.h"
#include "chrome/browser/ui/lens/lens_permission_bubble_controller.h"
#include "chrome/browser/ui/lens/lens_search_bubble_controller.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/browser/ui/tabs/public/tab_features.h"
#include "chrome/browser/ui/tabs/tab_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/side_panel/side_panel.h"
#include "chrome/browser/ui/views/side_panel/side_panel_coordinator.h"
#include "chrome/browser/ui/views/side_panel/side_panel_entry_id.h"
#include "chrome/browser/ui/views/side_panel/side_panel_util.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/lens/lens_features.h"
#include "components/lens/lens_overlay_permission_utils.h"
#include "components/lens/proto/server/lens_overlay_response.pb.h"
#include "components/permissions/test/permission_request_observer.h"
#include "components/prefs/pref_service.h"
#include "components/sessions/content/session_tab_helper.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/page_navigator.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h"
#include "content/public/common/result_codes.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/public/test/network_connection_change_simulator.h"
#include "content/public/test/no_renderer_crashes_assertion.h"
#include "content/public/test/test_navigation_observer.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/base/mock_network_change_notifier.h"
#include "net/base/network_change_notifier.h"
#include "net/base/url_util.h"
#include "pdf/pdf_features.h"
#include "services/metrics/public/cpp/ukm_builders.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#include "ui/base/page_transition_types.h"
#include "ui/base/window_open_disposition.h"
#include "ui/compositor/compositor_switches.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event_constants.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/any_widget_observer.h"
#include "url/origin.h"

namespace {

constexpr char kDocumentWithNamedElement[] =;
constexpr char kDocumentWithNamedElementWithFragment[] =;
constexpr char kDocumentWithImage[] =;
constexpr char kDocumentWithDynamicColor[] =;
constexpr char kPdfDocument[] =;

State;
LensOverlayInvocationSource;
LensOverlayDismissalSource;

constexpr char kNewTabLinkClickScript[] =;

constexpr char kSameTabLinkClickScript[] =;

constexpr char kCheckSearchboxInput[] =;

constexpr char kRequestNotificationsScript[] =;

constexpr char kCheckSidePanelResultsLoadedScript[] =;

constexpr char kCheckSidePanelTranslateResultsLoadedScript[] =;

constexpr char kCheckSidePanelThumbnailShownScript[] =;

constexpr char kHistoryStateScript[] =;

constexpr char kCloseSearchBubbleScript[] =;

// Returns true if the selection elements have bounds and are ready for input
// events.
constexpr char kOverlayReadyScript[] =;

constexpr char kTestSuggestSignals[] =;

constexpr char kStartTimeQueryParamKey[] =;
constexpr char kViewportWidthQueryParamKey[] =;
constexpr char kViewportHeightQueryParamKey[] =;
constexpr char kTextQueryParamKey[] =;

constexpr char kResultsSearchBaseUrl[] =;

void ClickBubbleDialogButton(
    views::BubbleDialogDelegate* bubble_widget_delegate,
    views::View* button) {}

const lens::mojom::GeometryPtr kTestGeometry =;
const lens::mojom::OverlayObjectPtr kTestOverlayObject =;
const lens::mojom::TextPtr kTestText =;
const lens::mojom::CenterRotatedBoxPtr kTestRegion =;

class LensOverlayPageFake : public lens::mojom::LensPage {};

// TODO(b/334147680): Since both our interactive UI tests and our browser tests
// both mock out network calls via this method, we should factor this out so it
// can be used across files.
class LensOverlayQueryControllerFake : public lens::LensOverlayQueryController {};

// Stubs out network requests and mojo calls.
class LensOverlayControllerFake : public LensOverlayController {};

class TabFeaturesFake : public tabs::TabFeatures {};

class LensOverlayControllerBrowserTest : public InProcessBrowserTest {};

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PermissionBubble_Accept) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PermissionBubble_Reject) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PermissionBubble_PrefChange) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DoesNotOpenOnCrashedWebContents) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, CaptureScreenshot) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, CreateAndLoadWebUI) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, ShowSidePanel) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       ShowSidePanelWithPendingRegion) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, CloseSidePanel) {}

// TODO(crbug.com/341383805): Enable once flakiness is fixed on all platforms.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DISABLED_DelayPermissionsPrompt) {}

// TODO(b/335801964): Test flaky on Mac.
#if BUILDFLAG(IS_MAC)
#define MAYBE_SidePanelInteractionsAfterRegionSelection
#else
#define MAYBE_SidePanelInteractionsAfterRegionSelection
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_SidePanelInteractionsAfterRegionSelection) {}

// TODO(b/350991033): Test flaky on Mac.
#if BUILDFLAG(IS_MAC)
#define MAYBE_ShowSidePanelAfterTextSelectionRequest
#else
#define MAYBE_ShowSidePanelAfterTextSelectionRequest
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_ShowSidePanelAfterTextSelectionRequest) {}

// TODO(b/335028577): Test flaky on Mac.
#if BUILDFLAG(IS_MAC)
#define MAYBE_ShowSidePanelAfterTranslateSelectionRequest
#else
#define MAYBE_ShowSidePanelAfterTranslateSelectionRequest
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_ShowSidePanelAfterTranslateSelectionRequest) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       IssueTranslateFullPageRequest) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       HandleStartQueryResponse) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       HandleStartQueryResponseError) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       HandleInteractionDataResponse) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       BackgroundAndForegroundUI) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       LoadURLInResultsFrame) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OfflineErrorPageInSidePanel) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       LoadURLInResultsFrameOverlayNotShowing) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SidePanel_SameTabSameOriginLinkClick) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SidePanel_SameTabCrossOriginLinkClick) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SidePanel_NewTabCrossOriginLinkClick) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SidePanel_NewTabCrossOriginLinkClickFromUntrustedSite) {}

// TODO(crbug.com/360161233): This test is flaky.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DISABLED_CloseSearchBubbleOnOverlayInteraction) {}

// TODO(crbug.com/360161233): This test is flaky.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DISABLED_SearchBubblePageClassification) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SearchBubbleLivePageAndResults) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       SearchBubbleCloseButtonClosesOverlay) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PopAndLoadQueryFromHistory) {}

// TODO(crbug.com/342390515): Test flaky on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_PopAndLoadQueryFromHistoryWithRegionAndTextSelection
#else
#define MAYBE_PopAndLoadQueryFromHistoryWithRegionAndTextSelection
#endif
IN_PROC_BROWSER_TEST_F(
    LensOverlayControllerBrowserTest,
    MAYBE_PopAndLoadQueryFromHistoryWithRegionAndTextSelection) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PopAndLoadQueryFromHistoryWithInitialImageBytes) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       PopAndLoadQueryFromHistoryWithMultimodalRequest) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       AddQueryToHistoryAfterResize) {}

// TODO(346840584): Disabled due to flakiness on Mac.
#if BUILDFLAG(IS_MAC)
#define MAYBE_RecordHistogramsShowAndClose
#else
#define MAYBE_RecordHistogramsShowAndClose
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_RecordHistogramsShowAndClose) {}

// TODO(346840584): Disabled due to flakiness on Mac.
#if BUILDFLAG(IS_MAC)
#define MAYBE_RecordHistogramsShowSearchAndClose
#else
#define MAYBE_RecordHistogramsShowSearchAndClose
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_RecordHistogramsShowSearchAndClose) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       RecordHistogramsDoubleOpenClose) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       RecordUkmAndTaskCompletionForLensOverlayInteraction) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesIfTabUrlPathChanges) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesIfTabUrlFragmentChanges) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesOnReload) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayStaysOpenWithHistoryState) {}

// TODO(b/340886492): Fix and reenable test on MSAN.
#if defined(MEMORY_SANITIZER)
#define MAYBE_OverlayClosesSidePanelBeforeOpening
#else
#define MAYBE_OverlayClosesSidePanelBeforeOpening
#endif
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       MAYBE_OverlayClosesSidePanelBeforeOpening) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesIfSidePanelIsOpened) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesIfNewSidePanelEntryAppears) {}

// TODO(b/340886492, b/349876638): Flaky on all platforms.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DISABLED_OverlaySidePanelEdgeCaseInteractions) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, FindBarClosesOverlay) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest, EnterprisePolicy) {}

// TODO(crbug.com/350292135): Flaky on all platforms. Re-enable once flakiness
// is fixed.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       DISABLED_OverlayCopyShortcut) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayClosesIfRendererExits) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayInBackgroundClosesIfRendererExits) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       OverlayInBackgroundClosesIfPageNavigates) {}

// Regression test for crbug.com/360710001. Asserts the untrusted lens page will
// load in an unsupported context (browser tab for e.g.) without crashing.
// TODO(crbug.com/360724768): This should be updated to assert the WebUI does
// not load in an unsupported context at all once improvements have landed.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       LoadsInUnsupportedContext) {}

class LensOverlayControllerBrowserFullscreenDisabled
    : public LensOverlayControllerBrowserTest {};

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserFullscreenDisabled,
                       FullscreenClosesOverlay) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserFullscreenDisabled,
                       ToolbarEntryPointState) {}

class LensOverlayControllerBrowserPDFTest
    : public base::test::WithFeatureOverride,
      public PDFExtensionTestBase {};

IN_PROC_BROWSER_TEST_P(LensOverlayControllerBrowserPDFTest,
                       ContextMenuOpensOverlay) {}

// This test is wrapped in this BUILDFLAG block because the fallback region
// search functionality will not be enabled if the flag is unset.
#if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
IN_PROC_BROWSER_TEST_P(LensOverlayControllerBrowserPDFTest,
                       ContextMenuViaKeyboardDoesNotOpenOverlay) {
  // Open the PDF document and wait for it to finish loading.
  const GURL url = embedded_test_server()->GetURL(kPdfDocument);
  content::RenderFrameHost* extension_host = LoadPdfGetExtensionHost(url);
  ASSERT_TRUE(extension_host);

  // State should start in off.
  auto* controller = browser()
                         ->tab_strip_model()
                         ->GetActiveTab()
                         ->tab_features()
                         ->lens_overlay_controller();
  ASSERT_EQ(controller->state(), State::kOff);

  bool run_observed = false;
  // Using EF_NONE event type represents a keyboard action.
  auto menu_observer = std::make_unique<ContextMenuNotificationObserver>(
      IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, ui::EF_NONE,
      base::BindLambdaForTesting([&](RenderViewContextMenu* menu) {
        // Verify the normal region search flow activates.
        lens::LensRegionSearchController* lens_region_search_controller =
            menu->GetLensRegionSearchControllerForTesting();
        ASSERT_NE(lens_region_search_controller, nullptr);
        run_observed = true;
      }));

  content::WebContents* tab =
      browser()->tab_strip_model()->GetActiveWebContents();
  content::SimulateMouseClick(tab, 0, blink::WebMouseEvent::Button::kRight);

  // Verify the region search flow eventually opens.
  ASSERT_TRUE(base::test::RunUntil([&]() { return run_observed; }));
  ASSERT_EQ(controller->state(), State::kOff);
}
#endif  // BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)

// TODO(crbug.com/40268279): Stop testing both modes after OOPIF PDF viewer
// launches.
INSTANTIATE_FEATURE_OVERRIDE_TEST_SUITE();

// Test with --enable-pixel-output-in-tests enabled, required to actually grab
// screenshots for color extraction.
class LensOverlayControllerBrowserWithPixelsTest
    : public LensOverlayControllerBrowserTest {};

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserWithPixelsTest,
                       DynamicTheme_Fallback) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserWithPixelsTest,
                       DynamicTheme_DynamicColorTangerine) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserWithPixelsTest,
                       ViewportImageBoundingBoxes) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       RecordTimeToFirstInteraction) {}

IN_PROC_BROWSER_TEST_F(LensOverlayControllerBrowserTest,
                       RecordTimeToFirstInteractionPendingRegion) {}

class LensOverlayControllerSearchBubbleDisabled
    : public LensOverlayControllerBrowserTest {};

IN_PROC_BROWSER_TEST_F(LensOverlayControllerSearchBubbleDisabled,
                       PreselectionToastShows) {}

// TODO(crbug.com/360161233): This test is flaky.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerSearchBubbleDisabled,
                       DISABLED_PreselectionToastDisappearsOnSelection) {}

// TODO(crbug.com/351958199): Flaky on all platforms.
IN_PROC_BROWSER_TEST_F(LensOverlayControllerSearchBubbleDisabled,
                       DISABLED_PreselectionToastOmniboxFocusState) {}

}  // namespace