910e62b5创建于 1月15日历史提交
// Copyright 2012 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_BASE_INTERACTIVE_TEST_UTILS_H_
#define CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_H_

#include <utility>

#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/view_ids.h"
#include "ui/base/test/ui_controls.h"
#include "ui/display/display.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/native_ui_types.h"
#include "ui/views/widget/widget_observer.h"

class BrowserWindowInterface;

namespace display {
class Screen;
}  // namespace display

#if defined(TOOLKIT_VIEWS)
namespace views {
class View;
class Widget;
}
#endif

namespace ui_test_utils {

// Use in browser interactive uitests to wait until a browser is set to active.
// To use, create and call WaitForActivation(). Since on some platforms, the
// active browser list kept in |BrowserList| is updated before the actual
// activation (see |BrowserView::Show()| for details), observe the widget
// directly and wait for it to actually get activated.
class BrowserActivationWaiter : public views::WidgetObserver {
 public:
  explicit BrowserActivationWaiter(const BrowserWindowInterface* browser);
  BrowserActivationWaiter(const BrowserActivationWaiter&) = delete;
  BrowserActivationWaiter& operator=(const BrowserActivationWaiter&) = delete;
  ~BrowserActivationWaiter() override;

  // Runs a message loop until the widget associated to |browser| supplied to
  // the constructor is activated, or returns immediately if |browser| has
  // already active. Should only be called once.
  void WaitForActivation();

  // views::WidgetObserver
  void OnWidgetActivationChanged(views::Widget* widget, bool active) override;

 private:
  bool observed_ = false;
  base::RunLoop run_loop_;
};

// Use in browser interactive uitests to wait until a browser is deactivated.
// To use, create and call WaitForDeactivation().
class BrowserDeactivationWaiter : public BrowserListObserver {
 public:
  explicit BrowserDeactivationWaiter(const Browser* browser);
  BrowserDeactivationWaiter(const BrowserDeactivationWaiter&) = delete;
  BrowserDeactivationWaiter& operator=(const BrowserDeactivationWaiter&) =
      delete;
  ~BrowserDeactivationWaiter() override;

  // Runs a message loop until the |browser_| supplied to the constructor is
  // deactivated, or returns immediately if |browser_| has already become
  // inactive.
  // Should only be called once.
  void WaitForDeactivation();

 private:
  // BrowserListObserver:
  void OnBrowserNoLongerActive(Browser* browser) override;

  const base::WeakPtr<const Browser> browser_;
  bool observed_ = false;
  base::RunLoop run_loop_;
};

// Brings the native window for |browser| to the foreground and waits until the
// browser is active.
[[nodiscard]] bool BringBrowserWindowToFront(
    const BrowserWindowInterface* browser);

// Returns true if the View is focused.
bool IsViewFocused(const Browser* browser, ViewID vid);

// Simulates a mouse click on a View in the browser.
void ClickOnView(views::View* view);
void ClickOnView(const Browser* browser, ViewID vid);

// Makes focus shift to the given View without clicking it.
void FocusView(const Browser* browser, ViewID vid);

// A collection of utilities that are used from interactive_ui_tests. These are
// separated from ui_test_utils.h to ensure that browser_tests don't use them,
// since they depend on focus which isn't possible for sharded test.

// Hide a native window.
void HideNativeWindow(gfx::NativeWindow window);

// Show and focus a native window. Returns true on success.
[[nodiscard]] bool ShowAndFocusNativeWindow(gfx::NativeWindow window);

// Sends key press and release events to a `browser` or `window`. Waits until at
// least the key release (or key press, depending on `wait_for`) events have
// been dispatched, or the test times out. It's useful to wait for key press
// instead of key release when the target may be deleted in response to key
// press. This may wait for key release even if `wait_for` is `kKeyPress` on
// platforms where it's possible to confirm that key release has been dispatched
// on a deleted target. This uses `ui_controls::SendKeyPress`, see it for
// details. Returns true if the event was successfully dispatched.
[[nodiscard]] bool SendKeyPressSync(
    const BrowserWindowInterface* browser,
    ui::KeyboardCode key,
    bool control,
    bool shift,
    bool alt,
    bool command,
    ui_controls::KeyEventType wait_for = ui_controls::kKeyRelease);
[[nodiscard]] bool SendKeyPressToWindowSync(
    const gfx::NativeWindow window,
    ui::KeyboardCode key,
    bool control,
    bool shift,
    bool alt,
    bool command,
    ui_controls::KeyEventType wait_for = ui_controls::kKeyRelease);

// Sends a move event blocking until received. Returns true if the event was
// successfully received. This uses ui_controls::SendMouse***NotifyWhenDone,
// see it for details.
[[nodiscard]] bool SendMouseMoveSync(
    const gfx::Point& location,
    gfx::NativeWindow window_hint = gfx::NativeWindow());
[[nodiscard]] bool SendMouseEventsSync(
    ui_controls::MouseButton type,
    int button_state,
    gfx::NativeWindow window_hint = gfx::NativeWindow());

// A combination of SendMouseMove to the middle of the view followed by
// SendMouseEvents. Only exposed for toolkit-views.
// Alternatives: ClickOnView() and ui::test::EventGenerator.
#if defined(TOOLKIT_VIEWS)
void MoveMouseToCenterAndClick(
    views::View* view,
    ui_controls::MouseButton button,
    int button_state,
    base::OnceClosure task,
    int accelerator_state = ui_controls::kNoAccelerator);

void MoveMouseToCenterWithOffsetAndClick(
    views::View* view,
    const gfx::Vector2d& offset,
    ui_controls::MouseButton button,
    int button_state,
    base::OnceClosure task,
    int accelerator_state = ui_controls::kNoAccelerator);

// Returns the center of |view| in screen coordinates.
gfx::Point GetCenterInScreenCoordinates(const views::View* view);

// Blocks until the given view is focused (or not focused, depending on
// |focused|). Returns immediately if the state is already correct.
void WaitForViewFocus(Browser* browser, ViewID vid, bool focused);
void WaitForViewFocus(Browser* browser, views::View* view, bool focused);
#endif

#if BUILDFLAG(IS_MAC)
// Clear pressed modifier keys and report true if any key modifiers were down.
bool ClearKeyEventModifiers();

// Ensures that if no key window is set (can happen in apps that are not
// frontmost), we simulate the frontmost window becoming key, which triggers
// any logic that would normally run in this case.
void HandleMissingKeyWindow();
#endif

namespace internal {

// A utility function to send a mouse click event in a closure. It's shared by
// ui_controls_linux.cc and ui_controls_mac.cc
void ClickTask(ui_controls::MouseButton button,
               int button_state,
               base::OnceClosure followup,
               int accelerator_state = ui_controls::kNoAccelerator);

}  // namespace internal

// Returns the secondary display from the screen. DCHECKs if there is no such
// display.
display::Display GetSecondaryDisplay(display::Screen* screen);

// Returns the pair of displays -- the first one is the primary display and the
// second one is the other display.
std::pair<display::Display, display::Display> GetDisplays(
    display::Screen* screen);

}  // namespace ui_test_utils

#endif  // CHROME_TEST_BASE_INTERACTIVE_TEST_UTILS_H_