// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
#define CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
#include <queue>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
#include "base/process/process.h"
#include "base/strings/string16.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif
namespace base {
class RunLoop;
}
namespace gfx {
class Point;
}
// A collections of functions designed for use with content_browsertests and
// browser_tests.
// TO BE CLEAR: any function here must work against both binaries. If it only
// works with browser_tests, it should be in chrome\test\base\ui_test_utils.h.
// If it only works with content_browsertests, it should be in
// content\test\content_browser_test_utils.h.
namespace content {
class BrowserContext;
class MessageLoopRunner;
class RenderViewHost;
class WebContents;
// Generate a URL for a file path including a query string.
GURL GetFileUrlWithQuery(const base::FilePath& path,
const std::string& query_string);
// Waits for a load stop for the specified |web_contents|'s controller, if the
// tab is currently web_contents. Otherwise returns immediately.
void WaitForLoadStop(WebContents* web_contents);
// Causes the specified web_contents to crash. Blocks until it is crashed.
void CrashTab(WebContents* web_contents);
// Simulates clicking at the center of the given tab asynchronously; modifiers
// may contain bits from WebInputEvent::Modifiers.
void SimulateMouseClick(WebContents* web_contents,
int modifiers,
blink::WebMouseEvent::Button button);
// Simulates clicking at the point |point| of the given tab asynchronously;
// modifiers may contain bits from WebInputEvent::Modifiers.
void SimulateMouseClickAt(WebContents* web_contents,
int modifiers,
blink::WebMouseEvent::Button button,
const gfx::Point& point);
// Simulates asynchronously a mouse enter/move/leave event.
void SimulateMouseEvent(WebContents* web_contents,
blink::WebInputEvent::Type type,
const gfx::Point& point);
// Taps the screen at |point|.
void SimulateTapAt(WebContents* web_contents, const gfx::Point& point);
// Sends a key press asynchronously.
// The native code of the key event will be set to InvalidNativeKeycode().
// |key_code| alone is good enough for scenarios that only need the char
// value represented by a key event and not the physical key on the keyboard
// or the keyboard layout.
// For scenarios such as chromoting that need the native code,
// SimulateKeyPressWithCode should be used.
void SimulateKeyPress(WebContents* web_contents,
ui::KeyboardCode key_code,
bool control,
bool shift,
bool alt,
bool command);
// Sends a key press asynchronously.
// |code| specifies the UIEvents (aka: DOM4Events) value of the key:
// https://dvcs.w3.org/hg/d4e/raw-file/tip/source_respec.htm
// The native code of the key event will be set based on |code|.
// See ui/base/keycodes/vi usb_keycode_map.h for mappings between |code|
// and the native code.
// Examples of the various codes:
// key_code: VKEY_A
// code: "KeyA"
// native key code: 0x001e (for Windows).
// native key code: 0x0026 (for Linux).
void SimulateKeyPressWithCode(WebContents* web_contents,
ui::KeyboardCode key_code,
const char* code,
bool control,
bool shift,
bool alt,
bool command);
namespace internal {
// Allow ExecuteScript* methods to target either a WebContents or a
// RenderFrameHost. Targetting a WebContents means executing the script in the
// RenderFrameHost returned by WebContents::GetMainFrame(), which is the
// main frame. Pass a specific RenderFrameHost to target it.
class ToRenderFrameHost {
public:
ToRenderFrameHost(WebContents* web_contents);
ToRenderFrameHost(RenderViewHost* render_view_host);
ToRenderFrameHost(RenderFrameHost* render_frame_host);
RenderFrameHost* render_frame_host() const { return render_frame_host_; }
private:
RenderFrameHost* render_frame_host_;
};
} // namespace internal
// Executes the passed |script| in the specified frame. The |script| should not
// invoke domAutomationController.send(); otherwise, your test will hang or be
// flaky. If you want to extract a result, use one of the below functions.
// Returns true on success.
bool ExecuteScript(const internal::ToRenderFrameHost& adapter,
const std::string& script) WARN_UNUSED_RESULT;
// The following methods executes the passed |script| in the specified frame and
// sets |result| to the value passed to "window.domAutomationController.send" by
// the executed script. They return true on success, false if the script
// execution failed or did not evaluate to the expected type.
bool ExecuteScriptAndExtractInt(const internal::ToRenderFrameHost& adapter,
const std::string& script,
int* result) WARN_UNUSED_RESULT;
bool ExecuteScriptAndExtractBool(const internal::ToRenderFrameHost& adapter,
const std::string& script,
bool* result) WARN_UNUSED_RESULT;
bool ExecuteScriptAndExtractString(const internal::ToRenderFrameHost& adapter,
const std::string& script,
std::string* result) WARN_UNUSED_RESULT;
// Walks the frame tree of the specified WebContents and returns the sole frame
// that matches the specified predicate function. This function will DCHECK if
// no frames match the specified predicate, or if more than one frame matches.
RenderFrameHost* FrameMatchingPredicate(
WebContents* web_contents,
const base::Callback<bool(RenderFrameHost*)>& predicate);
// Predicates for use with FrameMatchingPredicate.
bool FrameMatchesName(const std::string& name, RenderFrameHost* frame);
bool FrameIsChildOfMainFrame(RenderFrameHost* frame);
bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame);
// Executes the WebUI resource test runner injecting each resource ID in
// |js_resource_ids| prior to executing the tests.
//
// Returns true if tests ran successfully, false otherwise.
bool ExecuteWebUIResourceTest(WebContents* web_contents,
const std::vector<int>& js_resource_ids);
// Returns the cookies for the given url.
std::string GetCookies(BrowserContext* browser_context, const GURL& url);
// Sets a cookie for the given url. Returns true on success.
bool SetCookie(BrowserContext* browser_context,
const GURL& url,
const std::string& value);
// Watches title changes on a WebContents, blocking until an expected title is
// set.
class TitleWatcher : public WebContentsObserver {
public:
// |web_contents| must be non-NULL and needs to stay alive for the
// entire lifetime of |this|. |expected_title| is the title that |this|
// will wait for.
TitleWatcher(WebContents* web_contents,
const base::string16& expected_title);
virtual ~TitleWatcher();
// Adds another title to watch for.
void AlsoWaitForTitle(const base::string16& expected_title);
// Waits until the title matches either expected_title or one of the titles
// added with AlsoWaitForTitle. Returns the value of the most recently
// observed matching title.
const base::string16& WaitAndGetTitle() WARN_UNUSED_RESULT;
private:
// Overridden WebContentsObserver methods.
virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE;
virtual void TitleWasSet(NavigationEntry* entry, bool explicit_set) OVERRIDE;
void TestTitle();
std::vector<base::string16> expected_titles_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
// The most recently observed expected title, if any.
base::string16 observed_title_;
DISALLOW_COPY_AND_ASSIGN(TitleWatcher);
};
// Watches a WebContents and blocks until it is destroyed.
class WebContentsDestroyedWatcher : public WebContentsObserver {
public:
explicit WebContentsDestroyedWatcher(WebContents* web_contents);
virtual ~WebContentsDestroyedWatcher();
// Waits until the WebContents is destroyed.
void Wait();
private:
// Overridden WebContentsObserver methods.
virtual void WebContentsDestroyed() OVERRIDE;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
DISALLOW_COPY_AND_ASSIGN(WebContentsDestroyedWatcher);
};
// Watches a RenderProcessHost and waits for specified destruction events.
class RenderProcessHostWatcher : public RenderProcessHostObserver {
public:
enum WatchType {
WATCH_FOR_PROCESS_EXIT,
WATCH_FOR_HOST_DESTRUCTION
};
RenderProcessHostWatcher(RenderProcessHost* render_process_host,
WatchType type);
// Waits for the render process that contains the specified web contents.
RenderProcessHostWatcher(WebContents* web_contents, WatchType type);
virtual ~RenderProcessHostWatcher();
// Waits until the renderer process exits.
void Wait();
private:
// Overridden RenderProcessHost::LifecycleObserver methods.
virtual void RenderProcessExited(RenderProcessHost* host,
base::ProcessHandle handle,
base::TerminationStatus status,
int exit_code) OVERRIDE;
virtual void RenderProcessHostDestroyed(RenderProcessHost* host) OVERRIDE;
RenderProcessHost* render_process_host_;
WatchType type_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
DISALLOW_COPY_AND_ASSIGN(RenderProcessHostWatcher);
};
// Watches for responses from the DOMAutomationController and keeps them in a
// queue. Useful for waiting for a message to be received.
class DOMMessageQueue : public NotificationObserver {
public:
// Constructs a DOMMessageQueue and begins listening for messages from the
// DOMAutomationController. Do not construct this until the browser has
// started.
DOMMessageQueue();
virtual ~DOMMessageQueue();
// Removes all messages in the message queue.
void ClearQueue();
// Wait for the next message to arrive. |message| will be set to the next
// message. Returns true on success.
bool WaitForMessage(std::string* message) WARN_UNUSED_RESULT;
// Overridden NotificationObserver methods.
virtual void Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) OVERRIDE;
private:
NotificationRegistrar registrar_;
std::queue<std::string> message_queue_;
scoped_refptr<MessageLoopRunner> message_loop_runner_;
DISALLOW_COPY_AND_ASSIGN(DOMMessageQueue);
};
} // namespace content
#endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_