1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280

content / public / test / content_browser_test_utils.h [blame]

// 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 CONTENT_PUBLIC_TEST_CONTENT_BROWSER_TEST_UTILS_H_
#define CONTENT_PUBLIC_TEST_CONTENT_BROWSER_TEST_UTILS_H_

#include <map>
#include <string>

#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "content/public/common/page_type.h"
#include "ui/gfx/native_widget_types.h"
#include "url/gurl.h"
#include "url/origin.h"

namespace base {
class FilePath;

namespace apple {
class ScopedObjCClassSwizzler;
}  // namespace apple
}  // namespace base

namespace gfx {
class Point;
#if BUILDFLAG(IS_MAC)
class Range;
#endif
class Rect;
}  // namespace gfx

namespace net {
namespace test_server {
class EmbeddedTestServer;
}  // namespace test_server
}  // namespace net

// A collections of functions designed for use with content_shell based browser
// tests.
// Note: if a function here also works with browser_tests, it should be in
// content\public\test\browser_test_utils.h

namespace content {
class RenderFrameHost;
class RenderWidgetHost;
class Shell;
class ToRenderFrameHost;
class WebContents;

// Generate the file path for testing a particular test.
// The file for the tests is all located in
// content/test/data/dir/<file>
// The returned path is FilePath format.
//
// A null |dir| indicates the root directory - i.e.
// content/test/data/<file>
base::FilePath GetTestFilePath(const char* dir, const char* file);

// Generate the URL for testing a particular test.
// HTML for the tests is all located in
// test_root_directory/dir/<file>
// The returned path is GURL format.
//
// A null |dir| indicates the root directory - i.e.
// content/test/data/<file>
GURL GetTestUrl(const char* dir, const char* file);

// Navigates |window| to |url|, blocking until the navigation finishes. Returns
// true if the page was loaded successfully and the last committed URL matches
// |url|.  This is a browser-initiated navigation that simulates a user typing
// |url| into the address bar.
//
// Tests should ensure that NavigateToURL succeeds.  If the URL that will
// eventually commit is different from |url|, such as with redirects, use the
// version below which also takes the expected commit URL.  If the navigation
// will not result in a commit, such as a download or a 204 response, use
// NavigateToURLAndExpectNoCommit() instead.
[[nodiscard]] bool NavigateToURL(Shell* window, const GURL& url);

// Same as above, but takes in an additional URL, |expected_commit_url|, to
// which the navigation should eventually commit.  This is useful for cases
// like redirects, where navigation starts on one URL but ends up committing a
// different URL.  This function will return true if navigating to |url|
// results in a successful commit to |expected_commit_url|.
[[nodiscard]] bool NavigateToURL(Shell* window,
                                 const GURL& url,
                                 const GURL& expected_commit_url);

// Navigates |window| to |url|, blocking until the given number of navigations
// finishes. If |ignore_uncommitted_navigations| is true, then an aborted
// navigation also counts toward |number_of_navigations| being complete.
void NavigateToURLBlockUntilNavigationsComplete(
    Shell* window,
    const GURL& url,
    int number_of_navigations,
    bool ignore_uncommitted_navigations = true);

// Navigates |window| to |url|, blocks until the navigation finishes, and
// checks that the navigation did not commit (e.g., due to a crash or
// download).
[[nodiscard]] bool NavigateToURLAndExpectNoCommit(Shell* window,
                                                  const GURL& url);

// Reloads |window|, blocking until the given number of navigations finishes.
void ReloadBlockUntilNavigationsComplete(Shell* window,
                                         int number_of_navigations);

// Reloads |window| with bypassing cache flag, and blocks until the given number
// of navigations finishes.
void ReloadBypassingCacheBlockUntilNavigationsComplete(
    Shell* window,
    int number_of_navigations);

// A class to help with waiting for at least one javascript dialog to be
// requested.
//
// On creation or Restart, it uses set_dialog_request_callback to
// capture any future dialog request. Calling Wait() will
// either return immediately because a dialog has already been called or it will
// wait, processing events until one is requested.
//
// That means, object should be constructed, or Restart() called, before section
// that could request a modal dialog.
class AppModalDialogWaiter {
 public:
  explicit AppModalDialogWaiter(Shell* shell);
  void Restart();
  void Wait();

  bool WasDialogRequestedCallbackCalled() {
    return was_dialog_request_callback_called_;
  }

 private:
  void EarlyCallback();
  bool was_dialog_request_callback_called_ = false;
  raw_ptr<Shell> shell_;
};

// Extends the ToRenderFrameHost mechanism to content::Shells.
RenderFrameHost* ConvertToRenderFrameHost(Shell* shell);

// Writes an entry with the name and id of the first camera to the logs or
// an entry indicating that no camera is available. This must be invoked from
// the test method body, because at the time of invocation of
// testing::Test::SetUp() the BrowserMainLoop does not yet exist.
void LookupAndLogNameAndIdOfFirstCamera();

// Used to wait for a new Shell window to be created. Instantiate this object
// before the operation that will create the window.
class ShellAddedObserver {
 public:
  ShellAddedObserver();

  ShellAddedObserver(const ShellAddedObserver&) = delete;
  ShellAddedObserver& operator=(const ShellAddedObserver&) = delete;

  ~ShellAddedObserver();

  // Will run a message loop to wait for the new window if it hasn't been
  // created since the constructor.
  Shell* GetShell();

 private:
  void ShellCreated(Shell* shell);

  raw_ptr<Shell, AcrossTasksDanglingUntriaged> shell_ = nullptr;
  std::unique_ptr<base::RunLoop> runner_;
};

#if BUILDFLAG(IS_MAC)
// An observer of the RenderWidgetHostViewCocoa which is the NSView
// corresponding to the page.
class RenderWidgetHostViewCocoaObserver {
 public:
  // The method name for 'didAddSubview'.
  static constexpr char kDidAddSubview[] = "didAddSubview:";
  static constexpr char kShowDefinitionForAttributedString[] =
      "showDefinitionForAttributedString:atPoint:";

  // Returns the method swizzler for the given |method_name|. This is useful
  // when the original implementation of the method is needed.
  static base::apple::ScopedObjCClassSwizzler* GetSwizzler(
      const std::string& method_name);

  // Returns the unique RenderWidgetHostViewCocoaObserver instance (if any) for
  // the given WebContents. There can be at most one observer per WebContents
  // and to create a new observer the older one has to be deleted first.
  static RenderWidgetHostViewCocoaObserver* GetObserver(
      WebContents* web_contents);

  explicit RenderWidgetHostViewCocoaObserver(WebContents* web_contents);

  RenderWidgetHostViewCocoaObserver(const RenderWidgetHostViewCocoaObserver&) =
      delete;
  RenderWidgetHostViewCocoaObserver& operator=(
      const RenderWidgetHostViewCocoaObserver&) = delete;

  virtual ~RenderWidgetHostViewCocoaObserver();

  // Called when a new NSView is added as a subview of RWHVCocoa.
  // |rect_in_root_view| represents the bounds of the NSView in RWHVCocoa
  // coordinates. The view will be dismissed shortly after this call.
  virtual void DidAddSubviewWillBeDismissed(
      const gfx::Rect& rect_in_root_view) {}
  // Called when RenderWidgeHostViewCocoa is asked to show definition of
  // |for_word| using Mac's dictionary popup.
  virtual void OnShowDefinitionForAttributedString(
      const std::string& for_word) {}

  WebContents* web_contents() const { return web_contents_; }

 private:
  static void SetUpSwizzlers();

  static std::map<std::string,
                  std::unique_ptr<base::apple::ScopedObjCClassSwizzler>>
      rwhvcocoa_swizzlers_;
  static std::map<WebContents*, RenderWidgetHostViewCocoaObserver*> observers_;

  const raw_ptr<WebContents> web_contents_;
};

void SetWindowBounds(gfx::NativeWindow window, const gfx::Rect& bounds);

// This method will request the string (word) at |point| inside the |rwh| where
// |point| is with respect to the |rwh| coordinates. |result_callback| is called
// with the word as well as |baselinePoint| when the result comes back from the
// renderer. The baseline point is the position of the pop-up in AppKit
// coordinate system (inverted y-axis).
void GetStringAtPointForRenderWidget(
    RenderWidgetHost* rwh,
    const gfx::Point& point,
    base::OnceCallback<void(const std::string&, const gfx::Point&)>
        result_callback);

// This method will request the string identified by |range| inside the |rwh|.
// When the result comes back, |result_callback| is invoked with the given text
// and its position in AppKit coordinates (inverted-y axis).
void GetStringFromRangeForRenderWidget(
    RenderWidgetHost* rwh,
    const gfx::Range& range,
    base::OnceCallback<void(const std::string&, const gfx::Point&)>
        result_callback);

#endif

// Adds http://<hostname_to_isolate>/ to the list of origins that require
// isolation (for each of the hostnames in the |hostnames_to_isolate| vector).
//
// To ensure that the isolation applies to subsequent navigations in
// |web_contents|, this function forces a BrowsingInstance swap by performing
// one or two browser-initiated navigations in |web_contents| to another,
// random, guid-based hostname.
void IsolateOriginsForTesting(
    net::test_server::EmbeddedTestServer* embedded_test_server,
    WebContents* web_contents,
    std::vector<std::string> hostnames_to_isolate);

// Same as above, but takes full origins as input.  In particular, this version
// doesn't assume HTTP, so it can be used for also isolating HTTPS origins.
void IsolateOriginsForTesting(
    net::test_server::EmbeddedTestServer* embedded_test_server,
    WebContents* web_contents,
    std::vector<url::Origin> origins_to_isolate);

#if BUILDFLAG(IS_WIN)

void SetMockCursorPositionForTesting(WebContents* web_contents,
                                     const gfx::Point& position);

#endif  // BUILDFLAG(IS_WIN)

}  // namespace content

#endif  // CONTENT_PUBLIC_TEST_CONTENT_BROWSER_TEST_UTILS_H_