chromium/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc

// Copyright 2014 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/renderer_context_menu/render_view_context_menu.h"

#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>

#include "base/base64.h"
#include "base/command_line.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/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/repeating_test_future.h"
#include "base/test/with_feature_override.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/accessibility/accessibility_state_utils.h"
#include "chrome/browser/apps/app_service/app_launch_params.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/pdf/pdf_extension_test_base.h"
#include "chrome/browser/pdf/pdf_extension_test_util.h"
#include "chrome/browser/pdf/test_pdf_viewer_stream_manager.h"
#include "chrome/browser/profiles/profile_attributes_entry.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_window.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/search_engines/template_url_service_factory.h"
#include "chrome/browser/sessions/session_restore.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_user_data.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/tabs/public/tab_features.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/toasts/toast_controller.h"
#include "chrome/browser/ui/toasts/toast_features.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/test/os_integration_test_override_impl.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_install_info.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_render_frame.mojom.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chrome/test/base/search_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/supervised_user/embedded_test_server_setup_mixin.h"
#include "chrome/test/supervised_user/supervision_mixin.h"
#include "components/compose/buildflags.h"
#include "components/guest_view/browser/guest_view_manager_delegate.h"
#include "components/guest_view/browser/test_guest_view_manager.h"
#include "components/lens/buildflags.h"
#include "components/lens/lens_features.h"
#include "components/lens/lens_metadata.mojom.h"
#include "components/lens/lens_testing_utils.h"
#include "components/pdf/browser/pdf_frame_util.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/scoped_privacy_sandbox_attestations.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_service.h"
#include "components/supervised_user/core/browser/supervised_user_preferences.h"
#include "components/supervised_user/core/browser/supervised_user_service.h"
#include "components/supervised_user/core/browser/supervised_user_url_filter.h"
#include "components/supervised_user/core/common/pref_names.h"
#include "components/supervised_user/core/common/supervised_user_constants.h"
#include "components/supervised_user/test_support/kids_management_api_server_mock.h"
#include "components/webapps/browser/installable/installable_metrics.h"
#include "components/webapps/browser/uninstall_result_code.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fenced_frame_test_util.h"
#include "content/public/test/hit_test_region_observer.h"
#include "content/public/test/test_frame_navigation_observer.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/browser/guest_view/mime_handler_view/test_mime_handler_view_guest.h"
#include "media/base/media_switches.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "net/base/load_flags.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_util.h"
#include "net/test/embedded_test_server/controllable_http_response.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 "pdf/buildflags.h"
#include "pdf/pdf_features.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
#include "third_party/blink/public/common/context_menu_data/context_menu_data.h"
#include "third_party/blink/public/common/context_menu_data/edit_flags.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/blink/public/common/page_state/page_state_serialization.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#include "third_party/blink/public/mojom/frame/frame.mojom.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
#include "third_party/libwebp/src/src/webp/decode.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/models/menu_model.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/codec/png_codec.h"

#if BUILDFLAG(ENABLE_COMPOSE)
#include "chrome/browser/compose/mock_chrome_compose_client.h"
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ui/chromeos/window_pin_util.h"
#include "ui/aura/window.h"
#endif

#if defined(USE_AURA)
#include "ui/aura/window.h"
#endif

#if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
#include "base/test/run_until.h"
#include "chrome/browser/ui/lens/lens_overlay_controller.h"
#include "chrome/browser/ui/views/lens/lens_side_panel_helper.h"
#include "components/lens/lens_overlay_permission_utils.h"
#include "ui/events/test/event_generator.h"
#endif

WebContents;
MimeHandlerViewGuest;
TestMimeHandlerViewGuest;
WebAppProvider;
AppId;

_;
Return;
TestWithParam;

namespace {

const char kAppUrl1[] =;
const char kAppUrl2[] =;

class AllowPreCommitInputFlagMixin : public InProcessBrowserTestMixin {};

class ContextMenuBrowserTestBase : public MixinBasedInProcessBrowserTest {};

class ContextMenuBrowserTest
    : public ContextMenuBrowserTestBase,
      public ::testing::WithParamInterface</*is_preview_enabled*/ bool> {};

INSTANTIATE_TEST_SUITE_P();

class PdfPluginContextMenuBrowserTest : public PDFExtensionTestBase {};

class PdfPluginContextMenuBrowserTestWithOopifOverride
    : public base::test::WithFeatureOverride,
      public PdfPluginContextMenuBrowserTest {};

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       NonExtensionMenuItemsAlwaysVisible) {}

// Verifies "Save link as" is not enabled for links blocked via policy.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       SaveLinkAsEntryIsDisabledForBlockedUrls) {}

// Verifies "Save as" is not enabled for links blocked via policy.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       SaveAsEntryIsDisabledForBlockedUrls) {}

// Verifies "Save as" is enabled for links that are not blocked via policy.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       SaveAsEntryIsNotDisabledForNonBlockedUrls) {}

// Verifies "Save image as" is not enabled for links blocked via policy.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       SaveImageAsEntryIsDisabledForBlockedUrls) {}

// Verifies "Save video as" is not enabled for links blocked via policy.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       SaveVideoAsEntryIsDisabledForBlockedUrls) {}

class ContextMenuForSupervisedUsersBrowserTest
    : public ContextMenuBrowserTestBase {};

IN_PROC_BROWSER_TEST_F(ContextMenuForSupervisedUsersBrowserTest,
                       SaveLinkAsEntryIsDisabledForUrlsNotAccessibleForChild) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuForSupervisedUsersBrowserTest,
    SaveLinkAsEntryIsDisabledForUrlsBlockedByAsyncCheckerForChild) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuForSupervisedUsersBrowserTest,
    SaveLinkAsEntryIsEnabledForUrlsAllowedByAsyncCheckerForChild) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuEntriesAreDisabledInLockedFullscreen) {
  int entries_to_test[] = {
      IDC_VIEW_SOURCE,
      IDC_CONTENT_CONTEXT_OPENLINKNEWTAB,
      IDC_CONTENT_CONTEXT_INSPECTELEMENT,
  };
  std::unique_ptr<TestRenderViewContextMenu> menu =
      CreateContextMenuMediaTypeNone(GURL("http://www.google.com/"),
                                     GURL("http://www.google.com/"));

  // Entries are enabled.
  for (auto entry : entries_to_test)
    EXPECT_TRUE(menu->IsCommandIdEnabled(entry));

  // Set locked fullscreen state.
  PinWindow(browser()->window()->GetNativeWindow(), /*trusted=*/true);

  // All entries are disabled in locked fullscreen (testing only a subset here).
  for (auto entry : entries_to_test)
    EXPECT_FALSE(menu->IsCommandIdEnabled(entry));
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenEntryPresentForNormalURLs) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenInAppPresentForURLsInScopeOfWebApp) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenInAppAbsentForURLsInScopeOfNonWindowedWebApp) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenEntryInAppAbsentForURLsOutOfScopeOfWebApp) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenInAppAbsentForURLsInNonLocallyInstalledApp) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       InAppOpenEntryPresentForRegularURLs) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenInAppAbsentForIncognito) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       InAppOpenEntryPresentForSameAppURLs) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       InAppOpenEntryPresentForOtherAppURLs) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenEntryAbsentForFilteredURLs) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ContextMenuForCanvas) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForEmojiPanel_Editable) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForEmojiPanel_NonEditable) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ShowsToastOnLinkCopied) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ShowsToastOnImageCopied) {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Executing the emoji panel item with no associated browser should not crash.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForEmojiPanel_NullBrowserCrash) {
  ui::SetShowEmojiKeyboardCallback(base::BindLambdaForTesting(
      [](ui::EmojiPickerCategory unused, ui::EmojiPickerFocusBehavior,
         const std::string&) { ui::ShowTabletModeEmojiPanel(); }));
  std::unique_ptr<content::WebContents> detached_web_contents =
      content::WebContents::Create(
          content::WebContents::CreateParams(browser()->profile()));
  TestRenderViewContextMenu menu(*detached_web_contents->GetPrimaryMainFrame(),
                                 {});
  menu.Init();
  menu.ExecuteCommand(IDC_CONTENT_CONTEXT_EMOJI, 0);
}
#else
// Executing the emoji panel item with no associated browser should not crash.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForEmojiPanel_NullBrowserCrash) {}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

// Only Chrome OS supports emoji panel callbacks.
#if BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForEmojiPanel_NoCallback) {
  // Reset the emoji callback.
  ui::SetShowEmojiKeyboardCallback(
      base::RepeatingCallback<void(ui::EmojiPickerCategory,
                                   ui::EmojiPickerFocusBehavior,
                                   const std::string&)>());

  content::ContextMenuParams params;
  params.is_editable = true;

  auto menu = CreateContextMenuFromParams(params);

  // If there's no callback, the emoji context menu should not be present.
  EXPECT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_EMOJI));
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(ENABLE_COMPOSE)
struct ContextMenuForComposeTestCase {};

class ContextMenuForComposeBrowserTest
    : public ContextMenuBrowserTestBase,
      public ::testing::WithParamInterface<ContextMenuForComposeTestCase> {};

IN_PROC_BROWSER_TEST_P(ContextMenuForComposeBrowserTest,
                       TestComposeItemPresent) {}

INSTANTIATE_TEST_SUITE_P();
#endif  // BUILDFLAG(ENABLE_COMPOSE)

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, CopyLinkTextMouse) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, CopyLinkTextTouchNoText) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, CopyLinkTextTouchTextOnly) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, CopyLinkTextTouchTextImage) {}

// Opens a link in a new tab via a "real" context menu.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, RealMenu) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenNewTabInChromeFromWebAppWithAnOpenBrowser) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       OpenNewTabInChromeFromWebAppWithoutAnOpenBrowser) {}

// Verify that "Open Link in New Tab" doesn't crash for about:blank.
// This is a regression test for https://crbug.com/1197027.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenAboutBlankInNewTab) {}

// Verify that "Open Link in New Tab" doesn't crash for data: URLs.
// This is a regression test for https://crbug.com/1197027.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenDataURLInNewTab) {}

// Verify that "Open Link in New Tab" doesn't send URL fragment as referrer.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenInNewTabReferrer) {}

// Verify that "Open Link in Incognito Window " doesn't send referrer URL.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenIncognitoNoneReferrer) {}

// Check filename on clicking "Save Link As" via a "real" context menu.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, SuggestedFileName) {}

// Check which commands are present after opening the context menu for the main
// frame.  This is a regression test for https://crbug.com/1085040.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       MenuContentsVerification_MainFrame) {}

// Check which commands are present after opening the context menu for a
// subframe.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       MenuContentsVerification_Subframe) {}

#if !BUILDFLAG(IS_MAC)
// Check whether correct non-located context menu shows up for image element
// with height more than visual viewport bounds.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       NonLocatedContextMenuOnLargeImageElement) {}

// Check whether correct non-located context menu shows up for anchor element
// inside an editable element.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       NonLocatedContextMenuOnAnchorElement) {}
#endif

// Check filename on clicking "Save Link As" is ignored for cross origin.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, SuggestedFileNameCrossOrigin) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenImageInNewTab) {}

// Functionality is not present on ChromeOS.
#if !BUILDFLAG(IS_CHROMEOS_ASH)
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenLinkInProfileEntryPresent) {}

// Flaky on Lacros and Linux. https://crbug.com/1453315.
#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_LINUX)
#define MAYBE_OpenLinkInProfile
#else
#define MAYBE_OpenLinkInProfile
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_OpenLinkInProfile) {}

// Verify that "Open Link as <profile>" doesn't send referrer URL.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenProfileNoneReferrer) {}
#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)

class InterestGroupContentBrowserClient : public ChromeContentBrowserClient {};

class ContextMenuFencedFrameTest : public ContextMenuBrowserTestBase {};

// Check which commands are present after opening the context menu for a
// fencedframe.
// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_MenuContentsVerification_Fencedframe
#else
#define MAYBE_MenuContentsVerification_Fencedframe
#endif
IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTest,
                       MAYBE_MenuContentsVerification_Fencedframe) {}

IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTest,
                       SaveLinkAsEntryIsDisabledAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuFencedFrameTest,
    SaveLinkAsEntryIsDisabledInNestedIframeAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTest,
                       SaveAudioAsEntryIsDisabledAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuFencedFrameTest,
    SaveAudioAsEntryIsDisabledInNestedIframeAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTest,
                       SaveVideoAsEntryIsDisabledAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuFencedFrameTest,
    SaveVideoAsEntryIsDisabledInNestedIframeAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTest,
                       SaveImageAsEntryIsDisabledAfterNetworkCutoff) {}

IN_PROC_BROWSER_TEST_F(
    ContextMenuFencedFrameTest,
    SaveImageAsEntryIsDisabledInNestedIframeAfterNetworkCutoff) {}

// TODO(crbug.com/40285326): This fails with the field trial testing config.
class ContextMenuFencedFrameTestNoTestingConfig
    : public ContextMenuFencedFrameTest {};

// Test that automatic beacons are sent after clicking "Open Link in New Tab"
// from a contextual menu inside of a fenced frame.
IN_PROC_BROWSER_TEST_F(ContextMenuFencedFrameTestNoTestingConfig,
                       AutomaticBeaconSentAfterContextMenuNavigation) {}

#if BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)
// Maintains region search test state. In particular, note that |menu_observer_|
// must live until the right-click completes asynchronously. Used as a base
// class for common logic shared by the side panel and unified side panel tests
// for the region search feature.
class SearchByRegionBrowserBaseTest : public InProcessBrowserTest {
 protected:
  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();
    CreateAndSetEventGenerator();
  }

  // Sets the event generator to the current Browser window
  void CreateAndSetEventGenerator() {
    gfx::NativeWindow window = browser()->window()->GetNativeWindow();
#if defined(USE_AURA)
    // When using aura, we need to get the root window in order to send events
    // properly.
    window = window->GetRootWindow();
#endif
    event_generator_ = std::make_unique<ui::test::EventGenerator>(window);
    // This is needed to send the mouse event to the correct window on Mac. A
    // no-op on other platforms.
    event_generator_->set_target(ui::test::EventGenerator::Target::APPLICATION);
  }

  void SetUpCommandLine(base::CommandLine* command_line) override {
    // Tests in this suite make use of documents with no significant
    // rendered content, and such documents do not accept input for 500ms
    // unless we allow it.
    command_line->AppendSwitch(blink::switches::kAllowPreCommitInput);
  }

  void SetupAndLoadPage(const std::string& page_path) {
    // Load a simple initial page.
    ASSERT_TRUE(ui_test_utils::NavigateToURL(
        browser(), GURL(embedded_test_server()->GetURL(page_path))));
  }

  void AttemptFullscreenLensRegionSearch() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked. Omit event flags to simulate entering through the keyboard.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, /*event_flags=*/0,
        base::BindOnce(
            &SearchByRegionBrowserBaseTest::SimulateDragAndVerifyOverlayUI,
            base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  void AttemptLensRegionSearchNewTab() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked. Sets a callback to simulate dragging a region on the screen once
    // the region search UI has been set up.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, ui::EF_MOUSE_BUTTON,
        base::BindOnce(
            &SearchByRegionBrowserBaseTest::SimulateDragAndVerifyOverlayUI,
            base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  // This attempts region search on the menu item designated for non-Google
  // DSEs with mouse button event flags.
  void AttemptNonGoogleRegionSearch() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_WEB_REGION_SEARCH, ui::EF_MOUSE_BUTTON,
        base::BindOnce(
            &SearchByRegionBrowserBaseTest::SimulateDragAndVerifyOverlayUI,
            base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  GURL GetNonGoogleRegionSearchURL() {
    static const char kImageSearchURL[] = "/imagesearch";
    return embedded_test_server()->GetURL(kImageSearchURL);
  }

  GURL GetLensRegionSearchURL() {
    static const std::string kLensRegionSearchURL =
        lens::features::GetHomepageURLForLens() + "upload?ep=crs";
    return GURL(kLensRegionSearchURL);
  }

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

  // Simulates a valid drag for Lens region search. Must be called after the UI
  // is set up or else the event will not be properly received by the feature.
  void SimulateDrag() {
    content::WebContents* tab =
        browser()->tab_strip_model()->GetActiveWebContents();
    gfx::Point center = tab->GetContainerBounds().CenterPoint();
    event_generator_->MoveMouseTo(center);
    event_generator_->DragMouseBy(100, 100);
  }

  void SimulateDragAndVerifyOverlayUI(RenderViewContextMenu* menu) {
    // Verify Lens Region Search Controller was created after using the menu
    // item.
    lens::LensRegionSearchController* controller =
        menu->GetLensRegionSearchControllerForTesting();
    ASSERT_NE(controller, nullptr);
    ASSERT_TRUE(controller->IsOverlayUIVisibleForTesting());
    SimulateDrag();
    // The UI should be closed after the drag.
    ASSERT_FALSE(controller->IsOverlayUIVisibleForTesting());
  }

  // Asserts that the Lens region search controller overlay UI was not visible.
  void AssertOverlayUIHidden(RenderViewContextMenu* menu) {
    // Verify Lens Region Search Controller was created after using the menu
    // item.
    lens::LensRegionSearchController* controller =
        menu->GetLensRegionSearchControllerForTesting();
    ASSERT_NE(controller, nullptr);
    ASSERT_FALSE(controller->IsOverlayUIVisibleForTesting());
  }

  void VerifyLensUrl(std::string content, std::string expected_content) {
    // Match strings up to the query.
    std::size_t query_start_pos = content.find("?");
    // Match the query parameters, without the value of start_time.
    EXPECT_THAT(content,
                testing::MatchesRegex(
                    expected_content.substr(0, query_start_pos) +
                    ".*ep=crs&re=dcsp&s=4&st=\\d+&lm=.+&sideimagesearch=1"));
    if (quit_closure_)
      quit_closure_.Run();
  }

  // Ensures the last request seen by |web_contents| contained encoded image
  // data
  void ExpectThatRequestContainsImageData(content::WebContents* web_contents) {
    auto* last_entry = web_contents->GetController().GetLastCommittedEntry();
    EXPECT_TRUE(last_entry);
    EXPECT_TRUE(last_entry->GetHasPostData());

    std::string post_data = last_entry->GetPageState().ToEncodedData();
    std::string image_bytes = lens::GetImageBytesFromEncodedPostData(post_data);
    EXPECT_FALSE(image_bytes.empty());
  }

  // Sets up a custom test default search engine in order to test region search
  // for non-Google DSEs. Parameter to choose whether this test search engine
  // supports side image search.
  void SetupNonGoogleRegionSearchEngine(
      bool with_side_image_search_param = true) {
    static const char16_t kShortName[] = u"test";
    static const char kRegionSearchPostParams[] =
        "thumb={google:imageThumbnail}";

    TemplateURLService* model =
        TemplateURLServiceFactory::GetForProfile(browser()->profile());
    ASSERT_NE(model, nullptr);
    search_test_utils::WaitForTemplateURLServiceToLoad(model);
    ASSERT_TRUE(model->loaded());

    TemplateURLData data;
    data.SetShortName(kShortName);
    data.SetKeyword(data.short_name());
    data.SetURL(GetNonGoogleRegionSearchURL().spec());
    data.image_url = GetNonGoogleRegionSearchURL().spec();
    data.image_url_post_params = kRegionSearchPostParams;
    if (with_side_image_search_param)
      data.side_image_search_param = "sideimagesearch";

    TemplateURL* template_url = model->Add(std::make_unique<TemplateURL>(data));
    ASSERT_TRUE(template_url);
    model->SetUserSelectedDefaultSearchProvider(template_url);
  }

  void TearDownInProcessBrowserTestFixture() override {
    menu_observer_.reset();
    event_generator_.reset();
  }

  std::unique_ptr<ui::test::EventGenerator> event_generator_;
  std::unique_ptr<ContextMenuNotificationObserver> menu_observer_;
  base::RepeatingClosure quit_closure_;
};

class SearchByRegionWithUnifiedSidePanelBrowserTest
    : public SearchByRegionBrowserBaseTest {
 protected:
  void SetUp() override {
    // The test server must start first, so that we know the port that the test
    // server is using.
    ASSERT_TRUE(embedded_test_server()->Start());
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeaturesAndParameters(
        {
            {lens::features::kLensStandalone,
             {{lens::features::kHomepageURLForLens.name,
               GetLensRegionSearchURL().spec()}}},
        },
        {});

    // This does not use SearchByRegionBrowserBaseTest::SetUp because that
    // function does its own conflicting initialization of a FeatureList.
    InProcessBrowserTest::SetUp();
  }

  void SimulateFullscreenSearchAndVerifyLensUrl(RenderViewContextMenu* menu) {
    AssertOverlayUIHidden(menu);
    content::WebContents* contents =
        GetLensUnifiedSidePanelWebContentsAfterNavigation();

    std::string expected_content = GetLensRegionSearchURL().GetContent();
    std::string side_panel_content =
        contents->GetLastCommittedURL().GetContent();
    VerifyLensUrl(side_panel_content, expected_content);
  }

  void SimulateDragAndVerifyLensRequest(RenderViewContextMenu* menu) {
    SearchByRegionBrowserBaseTest::SimulateDragAndVerifyOverlayUI(menu);
    content::WebContents* contents =
        GetLensUnifiedSidePanelWebContentsAfterNavigation();

    std::string expected_content = GetLensRegionSearchURL().GetContent();
    std::string side_panel_content =
        contents->GetLastCommittedURL().GetContent();
    VerifyLensUrl(side_panel_content, expected_content);
    ExpectThatRequestContainsImageData(contents);
  }

  void SimulateDragAndVerifyNonGoogleUrlForSidePanel(
      RenderViewContextMenu* menu) {
    SearchByRegionBrowserBaseTest::SimulateDragAndVerifyOverlayUI(menu);
    content::WebContents* contents =
        GetLensUnifiedSidePanelWebContentsAfterNavigation();

    std::string side_panel_content =
        contents->GetLastCommittedURL().GetContent();
    std::string expected_content = GetNonGoogleRegionSearchURL().GetContent();
    // Match strings up to the query.
    std::size_t query_start_pos = side_panel_content.find("?");
    // Match the query parameters, without the value of start_time.
    EXPECT_THAT(
        side_panel_content,
        testing::MatchesRegex(expected_content.substr(0, query_start_pos) +
                              ".*sideimagesearch=1&vpw=\\d+&vph=\\d+"));
    ExpectThatRequestContainsImageData(contents);
    quit_closure_.Run();
  }

  void AttemptFullscreenLensRegionSearchWithUnifiedSidePanel() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked. Sets a callback to simulate dragging a region on the screen once
    // the region search UI has been set up. This function simulates entering
    // the menu item via keyboard.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, /*event_flags=*/0,
        base::BindOnce(&SearchByRegionWithUnifiedSidePanelBrowserTest::
                           SimulateFullscreenSearchAndVerifyLensUrl,
                       base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  void AttemptLensRegionSearchWithUnifiedSidePanel() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked. Sets a callback to simulate dragging a region on the screen once
    // the region search UI has been set up.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, ui::EF_MOUSE_BUTTON,
        base::BindOnce(&SearchByRegionWithUnifiedSidePanelBrowserTest::
                           SimulateDragAndVerifyLensRequest,
                       base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  void AttemptNonGoogleRegionSearchWithUnifiedSidePanel() {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked. Sets a callback to simulate dragging a region on the screen once
    // the region search UI has been set up.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_WEB_REGION_SEARCH, ui::EF_MOUSE_BUTTON,
        base::BindOnce(&SearchByRegionWithUnifiedSidePanelBrowserTest::
                           SimulateDragAndVerifyNonGoogleUrlForSidePanel,
                       base::Unretained(this)));
    RightClickToOpenContextMenu();
  }

  content::WebContents* GetLensUnifiedSidePanelWebContentsAfterNavigation() {
    // We need to verify the contents after the drag is finished.
    content::WebContents* contents =
        lens::GetLensUnifiedSidePanelWebContentsForTesting(browser());
    EXPECT_TRUE(contents);

    // Wait for the drag to commence a navigation upon the side panel web
    // contents. This takes two navigations because the unified side panel is
    // initially created with a dummy entry URL.
    content::TestNavigationObserver nav_observer(contents);
    nav_observer.WaitForNavigationFinished();
    return contents;
  }

  // Override Lens Region Search URL to use embedded test server as base domain.
  GURL GetLensRegionSearchURL() {
    static const char kLensRegionSearchURL[] = "/imagesearch";
    return embedded_test_server()->GetURL(kLensRegionSearchURL);
  }

  void SetupUnifiedSidePanel() {
    SetupAndLoadPage("/empty.html");
    lens::CreateLensUnifiedSidePanelEntryForTesting(browser());
    // We need to verify the contents before opening the side panel.
    content::WebContents* contents =
        lens::GetLensUnifiedSidePanelWebContentsForTesting(browser());
    // Wait for the side panel to open and finish loading web contents.
    content::TestNavigationObserver nav_observer(contents);
    nav_observer.WaitForNavigationFinished();
  }
};

// https://crbug.com/1444953
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#define MAYBE_ValidLensRegionSearchWithUnifiedSidePanel
#else
#define MAYBE_ValidLensRegionSearchWithUnifiedSidePanel
#endif
IN_PROC_BROWSER_TEST_F(SearchByRegionWithUnifiedSidePanelBrowserTest,
                       MAYBE_ValidLensRegionSearchWithUnifiedSidePanel) {
  SetupUnifiedSidePanel();
  // We need a base::RunLoop to ensure that our test does not finish until the
  // side panel has opened and we have verified the URL.
  base::RunLoop loop;
  quit_closure_ = base::BindRepeating(loop.QuitClosure());
  // The browser should open a draggable UI for a region search.
  AttemptLensRegionSearchWithUnifiedSidePanel();
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(SearchByRegionWithUnifiedSidePanelBrowserTest,
                       ProgressiveWebAppValidLensRegionSearch) {
  // Creates a Progressive Web App and set it to the default browser
  Browser* pwa_browser = InProcessBrowserTest::CreateBrowserForApp(
      "test_app", browser()->profile());
  CloseBrowserSynchronously(browser());
  SelectFirstBrowser();
  ASSERT_EQ(pwa_browser, browser());
  SearchByRegionBrowserBaseTest::CreateAndSetEventGenerator();

  SetupAndLoadPage("/empty.html");

  // The browser should open a draggable UI for a region search. The result
  // should open in a new tab.
  ui_test_utils::AllBrowserTabAddedWaiter add_tab;

  SearchByRegionBrowserBaseTest::AttemptLensRegionSearchNewTab();

  // Get the result URL in the new tab and verify.
  content::WebContents* new_tab = add_tab.Wait();
  content::WaitForLoadStop(new_tab);

  std::string new_tab_content = new_tab->GetLastCommittedURL().GetContent();
  std::string expected_content = GetLensRegionSearchURL().GetContent();

  // Match strings up to the query.
  std::size_t query_start_pos = new_tab_content.find("?");
  // Match the query parameters, without the value of start_time.
  EXPECT_THAT(new_tab_content, testing::MatchesRegex(
                                   expected_content.substr(0, query_start_pos) +
                                   ".*ep=crs&re=df&s=4&st=\\d+&lm=.+"));
}

// https://crbug.com/1444953
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#define MAYBE_ValidFullscreenLensRegionSearchWithUnifiedSidePanel
#else
#define MAYBE_ValidFullscreenLensRegionSearchWithUnifiedSidePanel
#endif
IN_PROC_BROWSER_TEST_F(
    SearchByRegionWithUnifiedSidePanelBrowserTest,
    MAYBE_ValidFullscreenLensRegionSearchWithUnifiedSidePanel) {
  SetupUnifiedSidePanel();
  // We need a base::RunLoop to ensure that our test does not finish until the
  // side panel has opened and we have verified the URL.
  base::RunLoop loop;
  quit_closure_ = base::BindRepeating(loop.QuitClosure());
  // The browser should open a draggable UI for a region search.
  AttemptFullscreenLensRegionSearchWithUnifiedSidePanel();
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(
    SearchByRegionWithUnifiedSidePanelBrowserTest,
    ValidNonGoogleRegionSearchWithUnifiedSidePanelAndSideImageSearch) {
  SetupNonGoogleRegionSearchEngine();
  SetupUnifiedSidePanel();
  // We need a base::RunLoop to ensure that our test does not finish until the
  // side panel has opened and we have verified the URL.
  base::RunLoop loop;
  quit_closure_ = base::BindRepeating(loop.QuitClosure());
  // The browser should open a draggable UI for a region search.
  AttemptNonGoogleRegionSearchWithUnifiedSidePanel();
  loop.Run();
}

IN_PROC_BROWSER_TEST_F(
    SearchByRegionWithUnifiedSidePanelBrowserTest,
    ValidNonGoogleRegionSearchWithUnifiedSidePanelAndNoSideImageSearch) {
  SetupAndLoadPage("/empty.html");
  SetupNonGoogleRegionSearchEngine(/*with_side_image_search_param=*/false);
  // The browser should open a draggable UI for a region search. The result
  // should open in a new tab.
  ui_test_utils::AllBrowserTabAddedWaiter add_tab;
  AttemptNonGoogleRegionSearch();

  // Get the result URL in the new tab and verify.
  content::WebContents* new_tab = add_tab.Wait();
  content::WaitForLoadStop(new_tab);
  std::string new_tab_content = new_tab->GetLastCommittedURL().GetContent();
  std::string expected_content = GetNonGoogleRegionSearchURL().GetContent();
  EXPECT_EQ(new_tab_content, expected_content);
}

class LensOverlayBrowserTest : public SearchByRegionBrowserBaseTest {
 protected:
  void SetUp() override {
    base::test::ScopedFeatureList feature_list;
    feature_list.InitWithFeatures({lens::features::kLensOverlay}, {});

    // This does not use SearchByRegionBrowserBaseTest::SetUp because that
    // function does its own conflicting initialization of a FeatureList.
    InProcessBrowserTest::SetUp();
  }

  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();

    // Permits sharing the page screenshot by default.
    PrefService* prefs = browser()->profile()->GetPrefs();
    prefs->SetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled, true);
  }

  void TearDownOnMainThread() override {
    InProcessBrowserTest::TearDownOnMainThread();

    // Disallow sharing the page screenshot by default.
    PrefService* prefs = browser()->profile()->GetPrefs();
    prefs->SetBoolean(lens::prefs::kLensSharingPageScreenshotEnabled, false);
  }

  void OpenContextMenuAndSelectRegionSearchEntrypoint(
      int event_flags,
      ContextMenuNotificationObserver::MenuShownCallback callback) {
    // |menu_observer_| will cause the search lens for image menu item to be
    // clicked.
    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_LENS_REGION_SEARCH, event_flags,
        std::move(callback));
    RightClickToOpenContextMenu();
  }

  void OpenImagePageAndContextMenuForLensImageSearch(
      std::string image_path,
      int event_flags,
      ContextMenuNotificationObserver::MenuShownCallback callback) {
    ASSERT_TRUE(embedded_test_server()->Start());
    GURL image_url(embedded_test_server()->GetURL(image_path));
    GURL page("data:text/html,<img src='" + image_url.spec() + "'>");
    ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), page));

    menu_observer_ = std::make_unique<ContextMenuNotificationObserver>(
        IDC_CONTENT_CONTEXT_SEARCHLENSFORIMAGE, event_flags,
        std::move(callback));
    content::WebContents* tab =
        browser()->tab_strip_model()->GetActiveWebContents();
    content::SimulateMouseClickAt(tab, 0, blink::WebMouseEvent::Button::kRight,
                                  gfx::Point(15, 15));
  }
};

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

  OpenContextMenuAndSelectRegionSearchEntrypoint(ui::EF_MOUSE_BUTTON,
                                                 base::NullCallback());

  // Clicking the region search entrypoint should eventually result in overlay
  // state.
  ASSERT_TRUE(base::test::RunUntil([&]() {
    return controller->state() == LensOverlayController::State::kOverlay;
  }));
}

IN_PROC_BROWSER_TEST_F(LensOverlayBrowserTest,
                       RegionSearchContextMenuDoesNotOpenRegionSearch) {
  bool run = false;
  OpenContextMenuAndSelectRegionSearchEntrypoint(
      ui::EF_MOUSE_BUTTON,
      // Callback that will be called after the context menu item is clicked.
      base::BindLambdaForTesting([&](RenderViewContextMenu* menu) {
        // Verify the normal region search flow does not activate
        lens::LensRegionSearchController* controller =
            menu->GetLensRegionSearchControllerForTesting();
        ASSERT_EQ(controller, nullptr);
        run = true;
      }));

  // Verify the callback above finished running before finishing the test.
  ASSERT_TRUE(base::test::RunUntil([&]() { return run == true; }));
}

IN_PROC_BROWSER_TEST_F(LensOverlayBrowserTest,
                       RegionSearchContextMenuOpensRegionSearchForKeyboard) {
  bool run = false;
  // EF_NONE event_type will be treated as a keyboard press.
  OpenContextMenuAndSelectRegionSearchEntrypoint(
      ui::EF_NONE,
      // Callback that will be called after the context menu item is clicked.
      base::BindLambdaForTesting([&](RenderViewContextMenu* menu) {
        // Verify the normal region search flow activates.
        lens::LensRegionSearchController* controller =
            menu->GetLensRegionSearchControllerForTesting();
        ASSERT_NE(controller, nullptr);
        run = true;
      }));

  // Verify the callback above finished running before finishing the test.
  ASSERT_TRUE(base::test::RunUntil([&]() { return run == true; }));
}

IN_PROC_BROWSER_TEST_F(LensOverlayBrowserTest,
                       ImageSearchContextMenuDoesNotOpenImageSearch) {
  bool run = false;
  int starting_tab_index = browser()->tab_strip_model()->active_index();
  OpenImagePageAndContextMenuForLensImageSearch(
      "/google/logo.gif", ui::EF_MOUSE_BUTTON,
      // Callback that will be called after the context menu item is clicked.
      base::BindLambdaForTesting([&](RenderViewContextMenu* menu) {
        // Verify the normal image search flow does not activate.
        lens::LensRegionSearchController* controller =
            menu->GetLensRegionSearchControllerForTesting();
        ASSERT_EQ(controller, nullptr);
        run = true;
      }));

  // Verify the callback above finished running before finishing the test.
  ASSERT_TRUE(base::test::RunUntil([&]() { return run == true; }));
  // Verify that the tab has not been changed.
  ASSERT_EQ(browser()->tab_strip_model()->active_index(), starting_tab_index);
}

// https://crbug.com/1444953
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
#define MAYBE_ImageSearchContextMenuOpensImageSearchForKeyboard
#else
#define MAYBE_ImageSearchContextMenuOpensImageSearchForKeyboard
#endif
IN_PROC_BROWSER_TEST_F(
    LensOverlayBrowserTest,
    MAYBE_ImageSearchContextMenuOpensImageSearchForKeyboard) {
  bool run = false;
  int starting_tab_index = browser()->tab_strip_model()->active_index();
  // EF_NONE event_type will be treated as a keyboard press.
  OpenImagePageAndContextMenuForLensImageSearch(
      "/google/logo.gif", ui::EF_NONE,
      // Callback that will be called after the context menu item is clicked.
      base::BindLambdaForTesting(
          [&](RenderViewContextMenu* menu) { run = true; }));

  // Verify the callback above finished running before finishing the test.
  ASSERT_TRUE(base::test::RunUntil([&]() { return run == true; }));
  // Verify that a new tab opens with Lens results.
  ASSERT_NE(browser()->tab_strip_model()->active_index(), starting_tab_index);
}

#endif  // BUILDFLAG(ENABLE_LENS_DESKTOP_GOOGLE_BRANDED_FEATURES)

#if BUILDFLAG(ENABLE_PDF)
IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       FullPagePdfHasPageItems) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       FullPagePdfFullscreenItems) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       CopyWithoutText) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       CopyText) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       CopyTextWithRestriction) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       IframedPdfHasNoPageItems) {}

IN_PROC_BROWSER_TEST_P(PdfPluginContextMenuBrowserTestWithOopifOverride,
                       RotateInFullPagePdf) {}

class OopifPdfPluginContextMenuBrowserTest
    : public PdfPluginContextMenuBrowserTest {};

IN_PROC_BROWSER_TEST_F(OopifPdfPluginContextMenuBrowserTest,
                       RotateInEmbeddedPdf) {}

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

#endif  // BUILDFLAG(ENABLE_PDF)

class LoadImageRequestObserver : public content::WebContentsObserver {};

class LoadImageBrowserTest : public InProcessBrowserTest {};

IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImage) {}

IN_PROC_BROWSER_TEST_F(LoadImageBrowserTest, LoadImageWithMap) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ContextMenuForVideo) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForVideoWithBlobLink) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForVideoWithReadableFrame) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForVideoWithoutReadableFrame) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, ContextMenuForEncryptedVideo) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForVideoNotInPictureInPicture) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       ContextMenuForVideoInPictureInPicture) {}

// This test checks that we don't crash when creating a context menu for a
// WebContents with no Browser.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, BrowserlessWebContentsCrash) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, GifImageShare) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, GifImageDownscaleToJpeg) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_RequestPngForGifImage
#else
#define MAYBE_RequestPngForGifImage
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_RequestPngForGifImage) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_PngImageDownscaleToPng
#else
#define MAYBE_PngImageDownscaleToPng
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_PngImageDownscaleToPng) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, PngImageOriginalDownscaleToPng) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_JpgImageDownscaleToJpg
#else
#define MAYBE_JpgImageDownscaleToJpg
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_JpgImageDownscaleToJpg) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, JpgImageDownscaleToWebp) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_PngImageDownscaleToWebp
#else
#define MAYBE_PngImageDownscaleToWebp
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_PngImageDownscaleToWebp) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_GifImageDownscaleToWebp
#else
#define MAYBE_GifImageDownscaleToWebp
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_GifImageDownscaleToWebp) {}

// TODO(crbug.com/40273673): Enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_WebpImageDownscaleToWebp
#else
#define MAYBE_WebpImageDownscaleToWebp
#endif
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, MAYBE_WebpImageDownscaleToWebp) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest,
                       CopyLinkToTextDisabledWithScrollToTextPolicyDisabled) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, OpenInReadingMode) {}

// Ensure that the context menu can tolerate changes to session history that
// happen between menu initialization and command execution.
IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, BackAfterBackEntryRemoved) {}

// Given a URL, produces an HTML document which contains a cross-origin child
// iframe which contains a link to that URL. Both the cross-origin child iframe
// and the link inside that iframe fill the entire size of the parent frame so
// they are easy to target with clicks.
static std::string BuildCrossOriginChildFrameHTML(const GURL& link) {}

IN_PROC_BROWSER_TEST_P(ContextMenuBrowserTest, SubframeNewTabInitiator) {}

}  // namespace