910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_H_
#define CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_H_

#include <concepts>
#include <utility>

#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/test/interaction/interactive_browser_window_test.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/views/interaction/interactive_views_test.h"

// Provides interactive test functionality for desktop browsers.
//
// Interactive tests use InteractionSequence, ElementTracker, and
// InteractionTestUtil to provide a common library of concise test methods. This
// convenience API is nicknamed "Kombucha" (see README.md for more information).
//
// This class is not a test fixture; it is a mixin that can be added to an
// existing browser test class using `InteractiveBrowserTestMixin<T>` - or just
// use `InteractiveBrowserTest`, which *is* a test fixture (preferred; see
// below).
class InteractiveBrowserTestApi
    : virtual public views::test::InteractiveViewsTestApi,
      virtual public InteractiveBrowserWindowTestApi {
 public:
  // These methods have multiple implementations in base classes; include them
  // all in the class namespace.
  using InteractiveBrowserWindowTestApi::EnsureNotPresent;
  using InteractiveBrowserWindowTestApi::EnsurePresent;
  using InteractiveBrowserWindowTestApi::ScrollIntoView;
  using InteractiveViewsTestApi::EnsureNotPresent;
  using InteractiveViewsTestApi::EnsurePresent;
  using InteractiveViewsTestApi::ScrollIntoView;

  // Instruments the WebContents held by `web_view` as `id`. Will wait for the
  // WebView to become visible if it is not.
  //
  // If `wait_for_ready` is true (default), the step will not complete until the
  // current page in the WebContents is fully loaded. (Note that this may not
  // cover dynamic loading of data; you may need to do a WaitForStateChange() to
  // be sure dynamic content is loaded).
  [[nodiscard]] MultiStep InstrumentNonTabWebView(ui::ElementIdentifier id,
                                                  ElementSpecifier web_view,
                                                  bool wait_for_ready = true);
  [[nodiscard]] MultiStep InstrumentNonTabWebView(
      ui::ElementIdentifier id,
      AbsoluteViewSpecifier web_view,
      bool wait_for_ready = true);

  // These are required so the following overloads don't hide the base class
  // variations.
  using InteractiveViewsTestApi::DragMouseTo;
  using InteractiveViewsTestApi::MoveMouseTo;

  // Find the DOM element at the given path in the reference element, which
  // should be an instrumented WebContents; see Instrument*(). Move the mouse to
  // the element's center point in screen coordinates.
  //
  // If the DOM element may be scrolled outside of the current viewport,
  // consider using ScrollIntoView(web_contents, where) before this verb.
  [[nodiscard]] MultiStep MoveMouseTo(ui::ElementIdentifier web_contents,
                                      const DeepQuery& where);

  // Find the DOM element at the given path in the reference element, which
  // should be an instrumented WebContents; see Instrument*(). Perform a drag
  // from the mouse's current location to the element's center point in screen
  // coordinates, and then if `release` is true, releases the mouse button.
  //
  // If the DOM element may be scrolled outside of the current viewport,
  // consider using ScrollIntoView(web_contents, where) before this verb.
  [[nodiscard]] MultiStep DragMouseTo(ui::ElementIdentifier web_contents,
                                      const DeepQuery& where,
                                      bool release = true);
};

// Template for adding InteractiveBrowserTestApi to any test fixture which is
// derived from InProcessBrowserTest.
//
// If you don't need to derive from some existing test class, prefer to use
// InteractiveBrowserTest.
//
// Note that this test fixture attempts to set the context widget from the
// created `browser()` during `SetUpOnMainThread()`. If your derived test
// fixture does not create a browser during set up, you will need to manually
// `SetContextWidget()` before calling `RunTestSequence()`, or use
// `RunTestTestSequenceInContext()` instead.
//
// See README.md for usage.
template <typename T>
  requires std::derived_from<T, InProcessBrowserTest>
class InteractiveBrowserTestMixin : public T, public InteractiveBrowserTestApi {
 public:
  template <typename... Args>
  explicit InteractiveBrowserTestMixin(Args&&... args)
      : T(std::forward<Args>(args)...) {}

  ~InteractiveBrowserTestMixin() override = default;

 protected:
  void SetUpOnMainThread() override {
    T::SetUpOnMainThread();
    private_test_impl().DoTestSetUp();
    if (Browser* browser = T::browser()) {
      SetContextWidget(
          BrowserView::GetBrowserViewForBrowser(browser)->GetWidget());
    }
  }

  void TearDownOnMainThread() override {
    private_test_impl().DoTestTearDown();
    T::TearDownOnMainThread();
  }
};

// Convenience test fixture for interactive browser tests. This is the preferred
// base class for Kombucha tests unless you specifically need something else.
//
// Note that this test fixture attempts to set the context widget from the
// created `browser()` during `SetUpOnMainThread()`. If your derived test
// fixture does not create a browser during set up, you will need to manually
// `SetContextWidget()` before calling `RunTestSequence()`, or use
// `RunTestTestSequenceInContext()` instead.
//
// See README.md for usage.
using InteractiveBrowserTest =
    InteractiveBrowserTestMixin<InProcessBrowserTest>;

#endif  // CHROME_TEST_INTERACTION_INTERACTIVE_BROWSER_TEST_H_