1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/public/test/browser_test_utils.h"
7 #include "base/auto_reset.h"
9 #include "base/command_line.h"
10 #include "base/json/json_reader.h"
11 #include "base/process/kill.h"
12 #include "base/rand_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/test/test_timeouts.h"
18 #include "base/values.h"
19 #include "content/browser/renderer_host/render_widget_host_impl.h"
20 #include "content/browser/web_contents/web_contents_impl.h"
21 #include "content/browser/web_contents/web_contents_view.h"
22 #include "content/common/input/synthetic_web_input_event_builders.h"
23 #include "content/common/view_messages.h"
24 #include "content/public/browser/browser_context.h"
25 #include "content/public/browser/dom_operation_notification_details.h"
26 #include "content/public/browser/histogram_fetcher.h"
27 #include "content/public/browser/navigation_entry.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_types.h"
30 #include "content/public/browser/render_frame_host.h"
31 #include "content/public/browser/render_process_host.h"
32 #include "content/public/browser/render_view_host.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/test/test_utils.h"
35 #include "net/base/filename_util.h"
36 #include "net/cookies/cookie_store.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "net/test/embedded_test_server/http_request.h"
39 #include "net/test/embedded_test_server/http_response.h"
40 #include "net/test/python_utils.h"
41 #include "net/url_request/url_request_context.h"
42 #include "net/url_request/url_request_context_getter.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/compositor/test/draw_waiter_for_test.h"
46 #include "ui/events/gesture_detection/gesture_configuration.h"
47 #include "ui/events/keycodes/dom/dom_code.h"
48 #include "ui/events/keycodes/dom/keycode_converter.h"
49 #include "ui/events/latency_info.h"
50 #include "ui/resources/grit/webui_resources.h"
53 #include "ui/aura/test/window_event_dispatcher_test_api.h"
54 #include "ui/aura/window.h"
55 #include "ui/aura/window_event_dispatcher.h"
56 #include "ui/aura/window_tree_host.h"
62 class DOMOperationObserver
: public NotificationObserver
,
63 public WebContentsObserver
{
65 explicit DOMOperationObserver(RenderViewHost
* rvh
)
66 : WebContentsObserver(WebContents::FromRenderViewHost(rvh
)),
68 registrar_
.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE
,
69 Source
<WebContents
>(web_contents()));
70 message_loop_runner_
= new MessageLoopRunner
;
73 void Observe(int type
,
74 const NotificationSource
& source
,
75 const NotificationDetails
& details
) override
{
76 DCHECK(type
== NOTIFICATION_DOM_OPERATION_RESPONSE
);
77 Details
<DomOperationNotificationDetails
> dom_op_details(details
);
79 response_
= dom_op_details
->json
;
81 message_loop_runner_
->Quit();
85 // Overridden from WebContentsObserver:
86 void RenderProcessGone(base::TerminationStatus status
) override
{
87 message_loop_runner_
->Quit();
90 bool WaitAndGetResponse(std::string
* response
) WARN_UNUSED_RESULT
{
91 message_loop_runner_
->Run();
92 *response
= response_
;
97 NotificationRegistrar registrar_
;
98 std::string response_
;
100 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
102 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver
);
105 class InterstitialObserver
: public content::WebContentsObserver
{
107 InterstitialObserver(content::WebContents
* web_contents
,
108 const base::Closure
& attach_callback
,
109 const base::Closure
& detach_callback
)
110 : WebContentsObserver(web_contents
),
111 attach_callback_(attach_callback
),
112 detach_callback_(detach_callback
) {
114 ~InterstitialObserver() override
{}
116 // WebContentsObserver methods:
117 void DidAttachInterstitialPage() override
{ attach_callback_
.Run(); }
118 void DidDetachInterstitialPage() override
{ detach_callback_
.Run(); }
121 base::Closure attach_callback_
;
122 base::Closure detach_callback_
;
124 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver
);
127 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
128 bool ExecuteScriptHelper(
129 RenderFrameHost
* render_frame_host
,
130 const std::string
& original_script
,
131 scoped_ptr
<base::Value
>* result
) WARN_UNUSED_RESULT
;
133 // Executes the passed |original_script| in the frame specified by
134 // |render_frame_host|. If |result| is not NULL, stores the value that the
135 // evaluation of the script in |result|. Returns true on success.
136 bool ExecuteScriptHelper(RenderFrameHost
* render_frame_host
,
137 const std::string
& original_script
,
138 scoped_ptr
<base::Value
>* result
) {
139 // TODO(jcampan): we should make the domAutomationController not require an
142 "window.domAutomationController.setAutomationId(0);" + original_script
;
143 DOMOperationObserver
dom_op_observer(render_frame_host
->GetRenderViewHost());
144 render_frame_host
->ExecuteJavaScriptWithUserGestureForTests(
145 base::UTF8ToUTF16(script
));
147 if (!dom_op_observer
.WaitAndGetResponse(&json
)) {
148 DLOG(ERROR
) << "Cannot communicate with DOMOperationObserver.";
152 // Nothing more to do for callers that ignore the returned JS value.
156 base::JSONReader
reader(base::JSON_ALLOW_TRAILING_COMMAS
);
157 *result
= reader
.ReadToValue(json
);
159 DLOG(ERROR
) << reader
.GetErrorMessage();
166 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type
,
167 ui::KeyboardCode key_code
,
170 NativeWebKeyboardEvent
* event
) {
171 event
->nativeKeyCode
= native_key_code
;
172 event
->windowsKeyCode
= key_code
;
173 event
->setKeyIdentifierFromWindowsKeyCode();
175 event
->modifiers
= modifiers
;
176 event
->isSystemKey
= false;
177 event
->timeStampSeconds
= base::Time::Now().ToDoubleT();
178 event
->skip_in_browser
= true;
180 if (type
== blink::WebInputEvent::Char
||
181 type
== blink::WebInputEvent::RawKeyDown
) {
182 event
->text
[0] = key_code
;
183 event
->unmodifiedText
[0] = key_code
;
187 void InjectRawKeyEvent(WebContents
* web_contents
,
188 blink::WebInputEvent::Type type
,
189 ui::KeyboardCode key_code
,
192 NativeWebKeyboardEvent event
;
193 BuildSimpleWebKeyEvent(type
, key_code
, native_key_code
, modifiers
, &event
);
194 web_contents
->GetRenderViewHost()->ForwardKeyboardEvent(event
);
197 void GetCookiesCallback(std::string
* cookies_out
,
198 base::WaitableEvent
* event
,
199 const std::string
& cookies
) {
200 *cookies_out
= cookies
;
204 void GetCookiesOnIOThread(const GURL
& url
,
205 net::URLRequestContextGetter
* context_getter
,
206 base::WaitableEvent
* event
,
207 std::string
* cookies
) {
208 net::CookieStore
* cookie_store
=
209 context_getter
->GetURLRequestContext()->cookie_store();
210 cookie_store
->GetCookiesWithOptionsAsync(
211 url
, net::CookieOptions(),
212 base::Bind(&GetCookiesCallback
, cookies
, event
));
215 void SetCookieCallback(bool* result
,
216 base::WaitableEvent
* event
,
222 void SetCookieOnIOThread(const GURL
& url
,
223 const std::string
& value
,
224 net::URLRequestContextGetter
* context_getter
,
225 base::WaitableEvent
* event
,
227 net::CookieStore
* cookie_store
=
228 context_getter
->GetURLRequestContext()->cookie_store();
229 cookie_store
->SetCookieWithOptionsAsync(
230 url
, value
, net::CookieOptions(),
231 base::Bind(&SetCookieCallback
, result
, event
));
234 scoped_ptr
<net::test_server::HttpResponse
> CrossSiteRedirectResponseHandler(
235 const GURL
& server_base_url
,
236 const net::test_server::HttpRequest
& request
) {
237 std::string
prefix("/cross-site/");
238 if (!base::StartsWith(request
.relative_url
, prefix
,
239 base::CompareCase::SENSITIVE
))
240 return scoped_ptr
<net::test_server::HttpResponse
>();
242 std::string params
= request
.relative_url
.substr(prefix
.length());
244 // A hostname to redirect to must be included in the URL, therefore at least
245 // one '/' character is expected.
246 size_t slash
= params
.find('/');
247 if (slash
== std::string::npos
)
248 return scoped_ptr
<net::test_server::HttpResponse
>();
250 // Replace the host of the URL with the one passed in the URL.
251 GURL::Replacements replace_host
;
252 replace_host
.SetHostStr(base::StringPiece(params
).substr(0, slash
));
253 GURL redirect_server
= server_base_url
.ReplaceComponents(replace_host
);
255 // Append the real part of the path to the new URL.
256 std::string path
= params
.substr(slash
+ 1);
257 GURL
redirect_target(redirect_server
.Resolve(path
));
258 DCHECK(redirect_target
.is_valid());
260 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
261 new net::test_server::BasicHttpResponse
);
262 http_response
->set_code(net::HTTP_MOVED_PERMANENTLY
);
263 http_response
->AddCustomHeader("Location", redirect_target
.spec());
264 return http_response
.Pass();
269 bool NavigateIframeToURL(WebContents
* web_contents
,
270 std::string iframe_id
,
272 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
273 // navigations generate extra DidStartLoading and DidStopLoading messages.
274 // Until we replace swappedout:// with frame proxies, we need to listen for
275 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
276 // for commit. See https://crbug.com/436250.
277 std::string script
= base::StringPrintf(
279 "var iframes = document.getElementById('%s');iframes.src='%s';"
281 iframe_id
.c_str(), url
.spec().c_str());
282 WindowedNotificationObserver
load_observer(
283 NOTIFICATION_NAV_ENTRY_COMMITTED
,
284 Source
<NavigationController
>(&web_contents
->GetController()));
285 bool result
= ExecuteScript(web_contents
, script
);
286 load_observer
.Wait();
290 GURL
GetFileUrlWithQuery(const base::FilePath
& path
,
291 const std::string
& query_string
) {
292 GURL url
= net::FilePathToFileURL(path
);
293 if (!query_string
.empty()) {
294 GURL::Replacements replacements
;
295 replacements
.SetQueryStr(query_string
);
296 return url
.ReplaceComponents(replacements
);
301 void WaitForLoadStopWithoutSuccessCheck(WebContents
* web_contents
) {
302 // In many cases, the load may have finished before we get here. Only wait if
303 // the tab still has a pending navigation.
304 if (web_contents
->IsLoading()) {
305 WindowedNotificationObserver
load_stop_observer(
306 NOTIFICATION_LOAD_STOP
,
307 Source
<NavigationController
>(&web_contents
->GetController()));
308 load_stop_observer
.Wait();
312 bool WaitForLoadStop(WebContents
* web_contents
) {
313 WaitForLoadStopWithoutSuccessCheck(web_contents
);
314 return IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
);
317 bool IsLastCommittedEntryOfPageType(WebContents
* web_contents
,
318 content::PageType page_type
) {
319 NavigationEntry
* last_entry
=
320 web_contents
->GetController().GetLastCommittedEntry();
323 return last_entry
->GetPageType() == page_type
;
326 void CrashTab(WebContents
* web_contents
) {
327 RenderProcessHost
* rph
= web_contents
->GetRenderProcessHost();
328 RenderProcessHostWatcher
watcher(
329 rph
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
330 rph
->Shutdown(0, false);
334 #if defined(USE_AURA)
335 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi
* dispatcher_test
,
336 RenderWidgetHostImpl
* widget_host
) {
337 return !dispatcher_test
->HoldingPointerMoves() &&
338 !widget_host
->resize_ack_pending_for_testing();
341 void WaitForResizeComplete(WebContents
* web_contents
) {
342 aura::Window
* content
= web_contents
->GetContentNativeView();
346 aura::WindowTreeHost
* window_host
= content
->GetHost();
347 aura::WindowEventDispatcher
* dispatcher
= window_host
->dispatcher();
348 aura::test::WindowEventDispatcherTestApi
dispatcher_test(dispatcher
);
349 RenderWidgetHostImpl
* widget_host
=
350 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
351 if (!IsResizeComplete(&dispatcher_test
, widget_host
)) {
352 WindowedNotificationObserver
resize_observer(
353 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
354 base::Bind(IsResizeComplete
, &dispatcher_test
, widget_host
));
355 resize_observer
.Wait();
358 #elif defined(OS_ANDROID)
359 bool IsResizeComplete(RenderWidgetHostImpl
* widget_host
) {
360 return !widget_host
->resize_ack_pending_for_testing();
363 void WaitForResizeComplete(WebContents
* web_contents
) {
364 RenderWidgetHostImpl
* widget_host
=
365 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
366 if (!IsResizeComplete(widget_host
)) {
367 WindowedNotificationObserver
resize_observer(
368 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
369 base::Bind(IsResizeComplete
, widget_host
));
370 resize_observer
.Wait();
375 void SimulateMouseClick(WebContents
* web_contents
,
377 blink::WebMouseEvent::Button button
) {
378 int x
= web_contents
->GetContainerBounds().width() / 2;
379 int y
= web_contents
->GetContainerBounds().height() / 2;
380 SimulateMouseClickAt(web_contents
, modifiers
, button
, gfx::Point(x
, y
));
383 void SimulateMouseClickAt(WebContents
* web_contents
,
385 blink::WebMouseEvent::Button button
,
386 const gfx::Point
& point
) {
387 blink::WebMouseEvent mouse_event
;
388 mouse_event
.type
= blink::WebInputEvent::MouseDown
;
389 mouse_event
.button
= button
;
390 mouse_event
.x
= point
.x();
391 mouse_event
.y
= point
.y();
392 mouse_event
.modifiers
= modifiers
;
393 // Mac needs globalX/globalY for events to plugins.
394 gfx::Rect offset
= web_contents
->GetContainerBounds();
395 mouse_event
.globalX
= point
.x() + offset
.x();
396 mouse_event
.globalY
= point
.y() + offset
.y();
397 mouse_event
.clickCount
= 1;
398 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
399 mouse_event
.type
= blink::WebInputEvent::MouseUp
;
400 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
403 void SimulateMouseEvent(WebContents
* web_contents
,
404 blink::WebInputEvent::Type type
,
405 const gfx::Point
& point
) {
406 blink::WebMouseEvent mouse_event
;
407 mouse_event
.type
= type
;
408 mouse_event
.x
= point
.x();
409 mouse_event
.y
= point
.y();
410 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
413 void SimulateTapAt(WebContents
* web_contents
, const gfx::Point
& point
) {
414 blink::WebGestureEvent tap
;
415 tap
.type
= blink::WebGestureEvent::GestureTap
;
418 tap
.modifiers
= blink::WebInputEvent::ControlKey
;
419 RenderWidgetHostImpl
* widget_host
=
420 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
421 widget_host
->ForwardGestureEvent(tap
);
424 void SimulateTapWithModifiersAt(WebContents
* web_contents
,
426 const gfx::Point
& point
) {
427 blink::WebGestureEvent tap
;
428 tap
.type
= blink::WebGestureEvent::GestureTap
;
431 tap
.modifiers
= modifiers
;
432 RenderWidgetHostImpl
* widget_host
=
433 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
434 widget_host
->ForwardGestureEvent(tap
);
437 void SimulateTouchPressAt(WebContents
* web_contents
, const gfx::Point
& point
) {
438 SyntheticWebTouchEvent touch
;
439 touch
.PressPoint(point
.x(), point
.y());
440 RenderWidgetHostImpl
* widget_host
=
441 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
442 widget_host
->ForwardTouchEventWithLatencyInfo(touch
, ui::LatencyInfo());
445 void SimulateKeyPress(WebContents
* web_contents
,
446 ui::KeyboardCode key_code
,
451 SimulateKeyPressWithCode(
452 web_contents
, key_code
, NULL
, control
, shift
, alt
, command
);
455 void SimulateKeyPressWithCode(WebContents
* web_contents
,
456 ui::KeyboardCode key_code
,
462 int native_key_code
= ui::KeycodeConverter::DomCodeToNativeKeycode(
463 ui::KeycodeConverter::CodeStringToDomCode(code
));
467 // The order of these key down events shouldn't matter for our simulation.
468 // For our simulation we can use either the left keys or the right keys.
470 modifiers
|= blink::WebInputEvent::ControlKey
;
472 web_contents
, blink::WebInputEvent::RawKeyDown
, ui::VKEY_CONTROL
,
473 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT
),
478 modifiers
|= blink::WebInputEvent::ShiftKey
;
480 web_contents
, blink::WebInputEvent::RawKeyDown
, ui::VKEY_SHIFT
,
481 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT
),
486 modifiers
|= blink::WebInputEvent::AltKey
;
488 web_contents
, blink::WebInputEvent::RawKeyDown
, ui::VKEY_MENU
,
489 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT
),
494 modifiers
|= blink::WebInputEvent::MetaKey
;
496 web_contents
, blink::WebInputEvent::RawKeyDown
, ui::VKEY_COMMAND
,
497 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT
),
500 InjectRawKeyEvent(web_contents
, blink::WebInputEvent::RawKeyDown
, key_code
,
501 native_key_code
, modifiers
);
503 InjectRawKeyEvent(web_contents
, blink::WebInputEvent::Char
, key_code
,
504 native_key_code
, modifiers
);
506 InjectRawKeyEvent(web_contents
, blink::WebInputEvent::KeyUp
, key_code
,
507 native_key_code
, modifiers
);
509 // The order of these key releases shouldn't matter for our simulation.
511 modifiers
&= ~blink::WebInputEvent::ControlKey
;
513 web_contents
, blink::WebInputEvent::KeyUp
, ui::VKEY_CONTROL
,
514 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT
),
519 modifiers
&= ~blink::WebInputEvent::ShiftKey
;
521 web_contents
, blink::WebInputEvent::KeyUp
, ui::VKEY_SHIFT
,
522 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT
),
527 modifiers
&= ~blink::WebInputEvent::AltKey
;
529 web_contents
, blink::WebInputEvent::KeyUp
, ui::VKEY_MENU
,
530 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT
),
535 modifiers
&= ~blink::WebInputEvent::MetaKey
;
537 web_contents
, blink::WebInputEvent::KeyUp
, ui::VKEY_COMMAND
,
538 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT
),
542 ASSERT_EQ(modifiers
, 0);
545 ToRenderFrameHost::ToRenderFrameHost(WebContents
* web_contents
)
546 : render_frame_host_(web_contents
->GetMainFrame()) {
549 ToRenderFrameHost::ToRenderFrameHost(RenderViewHost
* render_view_host
)
550 : render_frame_host_(render_view_host
->GetMainFrame()) {
553 ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost
* render_frame_host
)
554 : render_frame_host_(render_frame_host
) {
557 bool ExecuteScript(const ToRenderFrameHost
& adapter
,
558 const std::string
& script
) {
559 std::string new_script
=
560 script
+ ";window.domAutomationController.send(0);";
561 return ExecuteScriptHelper(adapter
.render_frame_host(), new_script
, NULL
);
564 bool ExecuteScriptAndExtractInt(const ToRenderFrameHost
& adapter
,
565 const std::string
& script
, int* result
) {
567 scoped_ptr
<base::Value
> value
;
568 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
573 return value
->GetAsInteger(result
);
576 bool ExecuteScriptAndExtractBool(const ToRenderFrameHost
& adapter
,
577 const std::string
& script
, bool* result
) {
579 scoped_ptr
<base::Value
> value
;
580 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
585 return value
->GetAsBoolean(result
);
588 bool ExecuteScriptAndExtractString(const ToRenderFrameHost
& adapter
,
589 const std::string
& script
,
590 std::string
* result
) {
592 scoped_ptr
<base::Value
> value
;
593 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
598 return value
->GetAsString(result
);
602 void AddToSetIfFrameMatchesPredicate(
603 std::set
<RenderFrameHost
*>* frame_set
,
604 const base::Callback
<bool(RenderFrameHost
*)>& predicate
,
605 RenderFrameHost
* host
) {
606 if (predicate
.Run(host
))
607 frame_set
->insert(host
);
611 RenderFrameHost
* FrameMatchingPredicate(
612 WebContents
* web_contents
,
613 const base::Callback
<bool(RenderFrameHost
*)>& predicate
) {
614 std::set
<RenderFrameHost
*> frame_set
;
615 web_contents
->ForEachFrame(
616 base::Bind(&AddToSetIfFrameMatchesPredicate
, &frame_set
, predicate
));
617 DCHECK_EQ(1U, frame_set
.size());
618 return *frame_set
.begin();
621 bool FrameMatchesName(const std::string
& name
, RenderFrameHost
* frame
) {
622 return frame
->GetFrameName() == name
;
625 bool FrameIsChildOfMainFrame(RenderFrameHost
* frame
) {
626 return frame
->GetParent() && !frame
->GetParent()->GetParent();
629 bool FrameHasSourceUrl(const GURL
& url
, RenderFrameHost
* frame
) {
630 return frame
->GetLastCommittedURL() == url
;
633 bool ExecuteWebUIResourceTest(WebContents
* web_contents
,
634 const std::vector
<int>& js_resource_ids
) {
635 // Inject WebUI test runner script first prior to other scripts required to
636 // run the test as scripts may depend on it being declared.
637 std::vector
<int> ids
;
638 ids
.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST
);
639 ids
.insert(ids
.end(), js_resource_ids
.begin(), js_resource_ids
.end());
642 for (std::vector
<int>::iterator iter
= ids
.begin();
645 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter
)
646 .AppendToString(&script
);
649 if (!ExecuteScript(web_contents
, script
))
652 DOMMessageQueue message_queue
;
653 if (!ExecuteScript(web_contents
, "runTests()"))
658 if (!message_queue
.WaitForMessage(&message
))
660 } while (message
.compare("\"PENDING\"") == 0);
662 return message
.compare("\"SUCCESS\"") == 0;
665 std::string
GetCookies(BrowserContext
* browser_context
, const GURL
& url
) {
667 base::WaitableEvent
event(true, false);
668 net::URLRequestContextGetter
* context_getter
=
669 browser_context
->GetRequestContext();
671 BrowserThread::PostTask(
672 BrowserThread::IO
, FROM_HERE
,
673 base::Bind(&GetCookiesOnIOThread
, url
,
674 make_scoped_refptr(context_getter
), &event
, &cookies
));
679 bool SetCookie(BrowserContext
* browser_context
,
681 const std::string
& value
) {
683 base::WaitableEvent
event(true, false);
684 net::URLRequestContextGetter
* context_getter
=
685 browser_context
->GetRequestContext();
687 BrowserThread::PostTask(
688 BrowserThread::IO
, FROM_HERE
,
689 base::Bind(&SetCookieOnIOThread
, url
, value
,
690 make_scoped_refptr(context_getter
), &event
, &result
));
695 void FetchHistogramsFromChildProcesses() {
696 scoped_refptr
<content::MessageLoopRunner
> runner
= new MessageLoopRunner
;
698 FetchHistogramsAsynchronously(
699 base::MessageLoop::current(),
700 runner
->QuitClosure(),
701 // If this call times out, it means that a child process is not
702 // responding, which is something we should not ignore. The timeout is
703 // set to be longer than the normal browser test timeout so that it will
704 // be prempted by the normal timeout.
705 TestTimeouts::action_max_timeout());
709 void SetupCrossSiteRedirector(
710 net::test_server::EmbeddedTestServer
* embedded_test_server
) {
711 embedded_test_server
->RegisterRequestHandler(
712 base::Bind(&CrossSiteRedirectResponseHandler
,
713 embedded_test_server
->base_url()));
716 void WaitForInterstitialAttach(content::WebContents
* web_contents
) {
717 if (web_contents
->ShowingInterstitialPage())
719 scoped_refptr
<content::MessageLoopRunner
> loop_runner(
720 new content::MessageLoopRunner
);
721 InterstitialObserver
observer(web_contents
,
722 loop_runner
->QuitClosure(),
727 void WaitForInterstitialDetach(content::WebContents
* web_contents
) {
728 RunTaskAndWaitForInterstitialDetach(web_contents
, base::Closure());
731 void RunTaskAndWaitForInterstitialDetach(content::WebContents
* web_contents
,
732 const base::Closure
& task
) {
733 if (!web_contents
|| !web_contents
->ShowingInterstitialPage())
735 scoped_refptr
<content::MessageLoopRunner
> loop_runner(
736 new content::MessageLoopRunner
);
737 InterstitialObserver
observer(web_contents
,
739 loop_runner
->QuitClosure());
742 // At this point, web_contents may have been deleted.
746 bool WaitForRenderFrameReady(RenderFrameHost
* rfh
) {
751 content::ExecuteScriptAndExtractString(
755 " function checkState() {"
756 " if (!done && document.readyState == 'complete') {"
758 " window.domAutomationController.send('pageLoadComplete');"
762 " document.addEventListener('readystatechange', checkState);"
765 return result
== "pageLoadComplete";
768 TitleWatcher::TitleWatcher(WebContents
* web_contents
,
769 const base::string16
& expected_title
)
770 : WebContentsObserver(web_contents
),
771 message_loop_runner_(new MessageLoopRunner
) {
772 EXPECT_TRUE(web_contents
!= NULL
);
773 expected_titles_
.push_back(expected_title
);
776 void TitleWatcher::AlsoWaitForTitle(const base::string16
& expected_title
) {
777 expected_titles_
.push_back(expected_title
);
780 TitleWatcher::~TitleWatcher() {
783 const base::string16
& TitleWatcher::WaitAndGetTitle() {
785 message_loop_runner_
->Run();
786 return observed_title_
;
789 void TitleWatcher::DidStopLoading() {
790 // When navigating through the history, the restored NavigationEntry's title
791 // will be used. If the entry ends up having the same title after we return
792 // to it, as will usually be the case, then WebContentsObserver::TitleSet
793 // will then be suppressed, since the NavigationEntry's title hasn't changed.
797 void TitleWatcher::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
801 void TitleWatcher::TestTitle() {
802 std::vector
<base::string16
>::const_iterator it
=
803 std::find(expected_titles_
.begin(),
804 expected_titles_
.end(),
805 web_contents()->GetTitle());
806 if (it
== expected_titles_
.end())
809 observed_title_
= *it
;
810 message_loop_runner_
->Quit();
813 RenderProcessHostWatcher::RenderProcessHostWatcher(
814 RenderProcessHost
* render_process_host
, WatchType type
)
815 : render_process_host_(render_process_host
),
817 did_exit_normally_(true),
818 message_loop_runner_(new MessageLoopRunner
) {
819 render_process_host_
->AddObserver(this);
822 RenderProcessHostWatcher::RenderProcessHostWatcher(
823 WebContents
* web_contents
, WatchType type
)
824 : render_process_host_(web_contents
->GetRenderProcessHost()),
826 did_exit_normally_(true),
827 message_loop_runner_(new MessageLoopRunner
) {
828 render_process_host_
->AddObserver(this);
831 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
832 if (render_process_host_
)
833 render_process_host_
->RemoveObserver(this);
836 void RenderProcessHostWatcher::Wait() {
837 message_loop_runner_
->Run();
840 void RenderProcessHostWatcher::RenderProcessExited(
841 RenderProcessHost
* host
,
842 base::TerminationStatus status
,
844 did_exit_normally_
= status
== base::TERMINATION_STATUS_NORMAL_TERMINATION
;
845 if (type_
== WATCH_FOR_PROCESS_EXIT
)
846 message_loop_runner_
->Quit();
849 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
850 RenderProcessHost
* host
) {
851 render_process_host_
= NULL
;
852 if (type_
== WATCH_FOR_HOST_DESTRUCTION
)
853 message_loop_runner_
->Quit();
856 DOMMessageQueue::DOMMessageQueue() {
857 registrar_
.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE
,
858 NotificationService::AllSources());
861 DOMMessageQueue::~DOMMessageQueue() {}
863 void DOMMessageQueue::Observe(int type
,
864 const NotificationSource
& source
,
865 const NotificationDetails
& details
) {
866 Details
<DomOperationNotificationDetails
> dom_op_details(details
);
867 message_queue_
.push(dom_op_details
->json
);
868 if (message_loop_runner_
.get())
869 message_loop_runner_
->Quit();
872 void DOMMessageQueue::ClearQueue() {
873 message_queue_
= std::queue
<std::string
>();
876 bool DOMMessageQueue::WaitForMessage(std::string
* message
) {
878 if (message_queue_
.empty()) {
879 // This will be quit when a new message comes in.
880 message_loop_runner_
= new MessageLoopRunner
;
881 message_loop_runner_
->Run();
883 // The queue should not be empty, unless we were quit because of a timeout.
884 if (message_queue_
.empty())
886 *message
= message_queue_
.front();
887 message_queue_
.pop();
891 class WebContentsAddedObserver::RenderViewCreatedObserver
892 : public WebContentsObserver
{
894 explicit RenderViewCreatedObserver(WebContents
* web_contents
)
895 : WebContentsObserver(web_contents
),
896 render_view_created_called_(false),
897 main_frame_created_called_(false) {}
899 // WebContentsObserver:
900 void RenderViewCreated(RenderViewHost
* rvh
) override
{
901 render_view_created_called_
= true;
904 void RenderFrameCreated(RenderFrameHost
* rfh
) override
{
905 if (rfh
== web_contents()->GetMainFrame())
906 main_frame_created_called_
= true;
909 bool render_view_created_called_
;
910 bool main_frame_created_called_
;
913 WebContentsAddedObserver::WebContentsAddedObserver()
914 : web_contents_created_callback_(
915 base::Bind(&WebContentsAddedObserver::WebContentsCreated
,
916 base::Unretained(this))),
917 web_contents_(NULL
) {
918 WebContentsImpl::FriendZone::AddCreatedCallbackForTesting(
919 web_contents_created_callback_
);
922 WebContentsAddedObserver::~WebContentsAddedObserver() {
923 WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting(
924 web_contents_created_callback_
);
927 void WebContentsAddedObserver::WebContentsCreated(WebContents
* web_contents
) {
928 DCHECK(!web_contents_
);
929 web_contents_
= web_contents
;
930 child_observer_
.reset(new RenderViewCreatedObserver(web_contents
));
933 runner_
->QuitClosure().Run();
936 WebContents
* WebContentsAddedObserver::GetWebContents() {
938 return web_contents_
;
940 runner_
= new MessageLoopRunner();
942 return web_contents_
;
945 bool WebContentsAddedObserver::RenderViewCreatedCalled() {
946 if (child_observer_
) {
947 return child_observer_
->render_view_created_called_
&&
948 child_observer_
->main_frame_created_called_
;
953 bool RequestFrame(WebContents
* web_contents
) {
954 DCHECK(web_contents
);
955 return RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost())
956 ->ScheduleComposite();
959 FrameWatcher::FrameWatcher()
960 : BrowserMessageFilter(ViewMsgStart
), frames_to_wait_(0) {
963 FrameWatcher::~FrameWatcher() {
966 void FrameWatcher::ReceivedFrameSwap() {
968 if (frames_to_wait_
== 0)
972 bool FrameWatcher::OnMessageReceived(const IPC::Message
& message
) {
973 if (message
.type() == ViewHostMsg_SwapCompositorFrame::ID
) {
974 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
975 base::Bind(&FrameWatcher::ReceivedFrameSwap
, this));
980 void FrameWatcher::AttachTo(WebContents
* web_contents
) {
981 DCHECK(web_contents
);
982 RenderWidgetHostImpl
* widget_host
=
983 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
984 widget_host
->GetProcess()->AddFilter(this);
987 void FrameWatcher::WaitFrames(int frames_to_wait
) {
988 if (frames_to_wait
<= 0)
990 base::RunLoop run_loop
;
991 base::AutoReset
<base::Closure
> reset_quit(&quit_
, run_loop
.QuitClosure());
992 base::AutoReset
<int> reset_frames_to_wait(&frames_to_wait_
, frames_to_wait
);
996 } // namespace content