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"
8 #include "base/command_line.h"
9 #include "base/json/json_reader.h"
10 #include "base/process/kill.h"
11 #include "base/rand_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "base/test/test_timeouts.h"
17 #include "base/values.h"
18 #include "content/browser/renderer_host/render_widget_host_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/browser/web_contents/web_contents_view.h"
21 #include "content/common/input/synthetic_web_input_event_builders.h"
22 #include "content/public/browser/browser_context.h"
23 #include "content/public/browser/dom_operation_notification_details.h"
24 #include "content/public/browser/histogram_fetcher.h"
25 #include "content/public/browser/navigation_entry.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/web_contents.h"
32 #include "content/public/browser/web_contents_observer.h"
33 #include "content/public/test/test_utils.h"
34 #include "net/base/filename_util.h"
35 #include "net/cookies/cookie_store.h"
36 #include "net/test/embedded_test_server/embedded_test_server.h"
37 #include "net/test/embedded_test_server/http_request.h"
38 #include "net/test/embedded_test_server/http_response.h"
39 #include "net/test/python_utils.h"
40 #include "net/url_request/url_request_context.h"
41 #include "net/url_request/url_request_context_getter.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "ui/base/resource/resource_bundle.h"
44 #include "ui/compositor/test/draw_waiter_for_test.h"
45 #include "ui/events/gesture_detection/gesture_configuration.h"
46 #include "ui/events/keycodes/dom4/keycode_converter.h"
47 #include "ui/resources/grit/webui_resources.h"
50 #include "ui/aura/test/window_event_dispatcher_test_api.h"
51 #include "ui/aura/window.h"
52 #include "ui/aura/window_event_dispatcher.h"
53 #include "ui/aura/window_tree_host.h"
59 class DOMOperationObserver
: public NotificationObserver
,
60 public WebContentsObserver
{
62 explicit DOMOperationObserver(RenderViewHost
* rvh
)
63 : WebContentsObserver(WebContents::FromRenderViewHost(rvh
)),
65 registrar_
.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE
,
66 Source
<WebContents
>(web_contents()));
67 message_loop_runner_
= new MessageLoopRunner
;
70 void Observe(int type
,
71 const NotificationSource
& source
,
72 const NotificationDetails
& details
) override
{
73 DCHECK(type
== NOTIFICATION_DOM_OPERATION_RESPONSE
);
74 Details
<DomOperationNotificationDetails
> dom_op_details(details
);
75 response_
= dom_op_details
->json
;
77 message_loop_runner_
->Quit();
80 // Overridden from WebContentsObserver:
81 void RenderProcessGone(base::TerminationStatus status
) override
{
82 message_loop_runner_
->Quit();
85 bool WaitAndGetResponse(std::string
* response
) WARN_UNUSED_RESULT
{
86 message_loop_runner_
->Run();
87 *response
= response_
;
92 NotificationRegistrar registrar_
;
93 std::string response_
;
95 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
97 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver
);
100 class InterstitialObserver
: public content::WebContentsObserver
{
102 InterstitialObserver(content::WebContents
* web_contents
,
103 const base::Closure
& attach_callback
,
104 const base::Closure
& detach_callback
)
105 : WebContentsObserver(web_contents
),
106 attach_callback_(attach_callback
),
107 detach_callback_(detach_callback
) {
109 ~InterstitialObserver() override
{}
111 // WebContentsObserver methods:
112 void DidAttachInterstitialPage() override
{ attach_callback_
.Run(); }
113 void DidDetachInterstitialPage() override
{ detach_callback_
.Run(); }
116 base::Closure attach_callback_
;
117 base::Closure detach_callback_
;
119 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver
);
122 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
123 bool ExecuteScriptHelper(
124 RenderFrameHost
* render_frame_host
,
125 const std::string
& original_script
,
126 scoped_ptr
<base::Value
>* result
) WARN_UNUSED_RESULT
;
128 // Executes the passed |original_script| in the frame specified by
129 // |render_frame_host|. If |result| is not NULL, stores the value that the
130 // evaluation of the script in |result|. Returns true on success.
131 bool ExecuteScriptHelper(RenderFrameHost
* render_frame_host
,
132 const std::string
& original_script
,
133 scoped_ptr
<base::Value
>* result
) {
134 // TODO(jcampan): we should make the domAutomationController not require an
137 "window.domAutomationController.setAutomationId(0);" + original_script
;
138 DOMOperationObserver
dom_op_observer(render_frame_host
->GetRenderViewHost());
139 render_frame_host
->ExecuteJavaScriptForTests(base::UTF8ToUTF16(script
));
141 if (!dom_op_observer
.WaitAndGetResponse(&json
)) {
142 DLOG(ERROR
) << "Cannot communicate with DOMOperationObserver.";
146 // Nothing more to do for callers that ignore the returned JS value.
150 base::JSONReader
reader(base::JSON_ALLOW_TRAILING_COMMAS
);
151 result
->reset(reader
.ReadToValue(json
));
152 if (!result
->get()) {
153 DLOG(ERROR
) << reader
.GetErrorMessage();
160 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type
,
161 ui::KeyboardCode key_code
,
164 NativeWebKeyboardEvent
* event
) {
165 event
->nativeKeyCode
= native_key_code
;
166 event
->windowsKeyCode
= key_code
;
167 event
->setKeyIdentifierFromWindowsKeyCode();
169 event
->modifiers
= modifiers
;
170 event
->isSystemKey
= false;
171 event
->timeStampSeconds
= base::Time::Now().ToDoubleT();
172 event
->skip_in_browser
= true;
174 if (type
== blink::WebInputEvent::Char
||
175 type
== blink::WebInputEvent::RawKeyDown
) {
176 event
->text
[0] = key_code
;
177 event
->unmodifiedText
[0] = key_code
;
181 void InjectRawKeyEvent(WebContents
* web_contents
,
182 blink::WebInputEvent::Type type
,
183 ui::KeyboardCode key_code
,
186 NativeWebKeyboardEvent event
;
187 BuildSimpleWebKeyEvent(type
, key_code
, native_key_code
, modifiers
, &event
);
188 web_contents
->GetRenderViewHost()->ForwardKeyboardEvent(event
);
191 void GetCookiesCallback(std::string
* cookies_out
,
192 base::WaitableEvent
* event
,
193 const std::string
& cookies
) {
194 *cookies_out
= cookies
;
198 void GetCookiesOnIOThread(const GURL
& url
,
199 net::URLRequestContextGetter
* context_getter
,
200 base::WaitableEvent
* event
,
201 std::string
* cookies
) {
202 net::CookieStore
* cookie_store
=
203 context_getter
->GetURLRequestContext()->cookie_store();
204 cookie_store
->GetCookiesWithOptionsAsync(
205 url
, net::CookieOptions(),
206 base::Bind(&GetCookiesCallback
, cookies
, event
));
209 void SetCookieCallback(bool* result
,
210 base::WaitableEvent
* event
,
216 void SetCookieOnIOThread(const GURL
& url
,
217 const std::string
& value
,
218 net::URLRequestContextGetter
* context_getter
,
219 base::WaitableEvent
* event
,
221 net::CookieStore
* cookie_store
=
222 context_getter
->GetURLRequestContext()->cookie_store();
223 cookie_store
->SetCookieWithOptionsAsync(
224 url
, value
, net::CookieOptions(),
225 base::Bind(&SetCookieCallback
, result
, event
));
228 scoped_ptr
<net::test_server::HttpResponse
> CrossSiteRedirectResponseHandler(
229 const GURL
& server_base_url
,
230 const net::test_server::HttpRequest
& request
) {
231 std::string
prefix("/cross-site/");
232 if (!StartsWithASCII(request
.relative_url
, prefix
, true))
233 return scoped_ptr
<net::test_server::HttpResponse
>();
235 std::string params
= request
.relative_url
.substr(prefix
.length());
237 // A hostname to redirect to must be included in the URL, therefore at least
238 // one '/' character is expected.
239 size_t slash
= params
.find('/');
240 if (slash
== std::string::npos
)
241 return scoped_ptr
<net::test_server::HttpResponse
>();
243 // Replace the host of the URL with the one passed in the URL.
244 GURL::Replacements replace_host
;
245 replace_host
.SetHostStr(base::StringPiece(params
).substr(0, slash
));
246 GURL redirect_server
= server_base_url
.ReplaceComponents(replace_host
);
248 // Append the real part of the path to the new URL.
249 std::string path
= params
.substr(slash
+ 1);
250 GURL
redirect_target(redirect_server
.Resolve(path
));
251 DCHECK(redirect_target
.is_valid());
253 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
254 new net::test_server::BasicHttpResponse
);
255 http_response
->set_code(net::HTTP_MOVED_PERMANENTLY
);
256 http_response
->AddCustomHeader("Location", redirect_target
.spec());
257 return http_response
.Pass();
262 bool NavigateIframeToURL(WebContents
* web_contents
,
263 std::string iframe_id
,
265 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
266 // navigations generate extra DidStartLoading and DidStopLoading messages.
267 // Until we replace swappedout:// with frame proxies, we need to listen for
268 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
269 // for commit. See https://crbug.com/436250.
270 std::string script
= base::StringPrintf(
272 "var iframes = document.getElementById('%s');iframes.src='%s';"
274 iframe_id
.c_str(), url
.spec().c_str());
275 WindowedNotificationObserver
load_observer(
276 NOTIFICATION_NAV_ENTRY_COMMITTED
,
277 Source
<NavigationController
>(&web_contents
->GetController()));
278 bool result
= ExecuteScript(web_contents
, script
);
279 load_observer
.Wait();
283 GURL
GetFileUrlWithQuery(const base::FilePath
& path
,
284 const std::string
& query_string
) {
285 GURL url
= net::FilePathToFileURL(path
);
286 if (!query_string
.empty()) {
287 GURL::Replacements replacements
;
288 replacements
.SetQueryStr(query_string
);
289 return url
.ReplaceComponents(replacements
);
294 void WaitForLoadStopWithoutSuccessCheck(WebContents
* web_contents
) {
295 // In many cases, the load may have finished before we get here. Only wait if
296 // the tab still has a pending navigation.
297 if (web_contents
->IsLoading()) {
298 WindowedNotificationObserver
load_stop_observer(
299 NOTIFICATION_LOAD_STOP
,
300 Source
<NavigationController
>(&web_contents
->GetController()));
301 load_stop_observer
.Wait();
305 bool WaitForLoadStop(WebContents
* web_contents
) {
306 WaitForLoadStopWithoutSuccessCheck(web_contents
);
307 return IsLastCommittedEntryOfPageType(web_contents
, PAGE_TYPE_NORMAL
);
310 bool IsLastCommittedEntryOfPageType(WebContents
* web_contents
,
311 content::PageType page_type
) {
312 NavigationEntry
* last_entry
=
313 web_contents
->GetController().GetLastCommittedEntry();
316 return last_entry
->GetPageType() == page_type
;
319 void CrashTab(WebContents
* web_contents
) {
320 RenderProcessHost
* rph
= web_contents
->GetRenderProcessHost();
321 RenderProcessHostWatcher
watcher(
322 rph
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
323 rph
->Shutdown(0, false);
327 #if defined(USE_AURA)
328 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi
* dispatcher_test
,
329 RenderWidgetHostImpl
* widget_host
) {
330 return !dispatcher_test
->HoldingPointerMoves() &&
331 !widget_host
->resize_ack_pending_for_testing();
334 void WaitForResizeComplete(WebContents
* web_contents
) {
335 aura::Window
* content
= web_contents
->GetContentNativeView();
339 aura::WindowTreeHost
* window_host
= content
->GetHost();
340 aura::WindowEventDispatcher
* dispatcher
= window_host
->dispatcher();
341 aura::test::WindowEventDispatcherTestApi
dispatcher_test(dispatcher
);
342 RenderWidgetHostImpl
* widget_host
=
343 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
344 if (!IsResizeComplete(&dispatcher_test
, widget_host
)) {
345 WindowedNotificationObserver
resize_observer(
346 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
347 base::Bind(IsResizeComplete
, &dispatcher_test
, widget_host
));
348 resize_observer
.Wait();
351 #elif defined(OS_ANDROID)
352 bool IsResizeComplete(RenderWidgetHostImpl
* widget_host
) {
353 return !widget_host
->resize_ack_pending_for_testing();
356 void WaitForResizeComplete(WebContents
* web_contents
) {
357 RenderWidgetHostImpl
* widget_host
=
358 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
359 if (!IsResizeComplete(widget_host
)) {
360 WindowedNotificationObserver
resize_observer(
361 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE
,
362 base::Bind(IsResizeComplete
, widget_host
));
363 resize_observer
.Wait();
368 void SimulateMouseClick(WebContents
* web_contents
,
370 blink::WebMouseEvent::Button button
) {
371 int x
= web_contents
->GetContainerBounds().width() / 2;
372 int y
= web_contents
->GetContainerBounds().height() / 2;
373 SimulateMouseClickAt(web_contents
, modifiers
, button
, gfx::Point(x
, y
));
376 void SimulateMouseClickAt(WebContents
* web_contents
,
378 blink::WebMouseEvent::Button button
,
379 const gfx::Point
& point
) {
380 blink::WebMouseEvent mouse_event
;
381 mouse_event
.type
= blink::WebInputEvent::MouseDown
;
382 mouse_event
.button
= button
;
383 mouse_event
.x
= point
.x();
384 mouse_event
.y
= point
.y();
385 mouse_event
.modifiers
= modifiers
;
386 // Mac needs globalX/globalY for events to plugins.
387 gfx::Rect offset
= web_contents
->GetContainerBounds();
388 mouse_event
.globalX
= point
.x() + offset
.x();
389 mouse_event
.globalY
= point
.y() + offset
.y();
390 mouse_event
.clickCount
= 1;
391 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
392 mouse_event
.type
= blink::WebInputEvent::MouseUp
;
393 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
396 void SimulateMouseEvent(WebContents
* web_contents
,
397 blink::WebInputEvent::Type type
,
398 const gfx::Point
& point
) {
399 blink::WebMouseEvent mouse_event
;
400 mouse_event
.type
= type
;
401 mouse_event
.x
= point
.x();
402 mouse_event
.y
= point
.y();
403 web_contents
->GetRenderViewHost()->ForwardMouseEvent(mouse_event
);
406 void SimulateTapAt(WebContents
* web_contents
, const gfx::Point
& point
) {
407 blink::WebGestureEvent tap
;
408 tap
.type
= blink::WebGestureEvent::GestureTap
;
411 tap
.modifiers
= blink::WebInputEvent::ControlKey
;
412 RenderWidgetHostImpl
* widget_host
=
413 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
414 widget_host
->ForwardGestureEvent(tap
);
417 void SimulateTapWithModifiersAt(WebContents
* web_contents
,
419 const gfx::Point
& point
) {
420 blink::WebGestureEvent tap
;
421 tap
.type
= blink::WebGestureEvent::GestureTap
;
424 tap
.modifiers
= modifiers
;
425 RenderWidgetHostImpl
* widget_host
=
426 RenderWidgetHostImpl::From(web_contents
->GetRenderViewHost());
427 widget_host
->ForwardGestureEvent(tap
);
430 void SimulateKeyPress(WebContents
* web_contents
,
431 ui::KeyboardCode key_code
,
436 SimulateKeyPressWithCode(
437 web_contents
, key_code
, NULL
, control
, shift
, alt
, command
);
440 void SimulateKeyPressWithCode(WebContents
* web_contents
,
441 ui::KeyboardCode key_code
,
447 int native_key_code
= ui::KeycodeConverter::CodeToNativeKeycode(code
);
451 // The order of these key down events shouldn't matter for our simulation.
452 // For our simulation we can use either the left keys or the right keys.
454 modifiers
|= blink::WebInputEvent::ControlKey
;
455 InjectRawKeyEvent(web_contents
,
456 blink::WebInputEvent::RawKeyDown
,
458 ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
463 modifiers
|= blink::WebInputEvent::ShiftKey
;
464 InjectRawKeyEvent(web_contents
,
465 blink::WebInputEvent::RawKeyDown
,
467 ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
472 modifiers
|= blink::WebInputEvent::AltKey
;
473 InjectRawKeyEvent(web_contents
,
474 blink::WebInputEvent::RawKeyDown
,
476 ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
481 modifiers
|= blink::WebInputEvent::MetaKey
;
482 InjectRawKeyEvent(web_contents
,
483 blink::WebInputEvent::RawKeyDown
,
485 ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
491 blink::WebInputEvent::RawKeyDown
,
498 blink::WebInputEvent::Char
,
505 blink::WebInputEvent::KeyUp
,
510 // The order of these key releases shouldn't matter for our simulation.
512 modifiers
&= ~blink::WebInputEvent::ControlKey
;
513 InjectRawKeyEvent(web_contents
,
514 blink::WebInputEvent::KeyUp
,
516 ui::KeycodeConverter::CodeToNativeKeycode("ControlLeft"),
521 modifiers
&= ~blink::WebInputEvent::ShiftKey
;
522 InjectRawKeyEvent(web_contents
,
523 blink::WebInputEvent::KeyUp
,
525 ui::KeycodeConverter::CodeToNativeKeycode("ShiftLeft"),
530 modifiers
&= ~blink::WebInputEvent::AltKey
;
531 InjectRawKeyEvent(web_contents
,
532 blink::WebInputEvent::KeyUp
,
534 ui::KeycodeConverter::CodeToNativeKeycode("AltLeft"),
539 modifiers
&= ~blink::WebInputEvent::MetaKey
;
540 InjectRawKeyEvent(web_contents
,
541 blink::WebInputEvent::KeyUp
,
543 ui::KeycodeConverter::CodeToNativeKeycode("OSLeft"),
547 ASSERT_EQ(modifiers
, 0);
552 ToRenderFrameHost::ToRenderFrameHost(WebContents
* web_contents
)
553 : render_frame_host_(web_contents
->GetMainFrame()) {
556 ToRenderFrameHost::ToRenderFrameHost(RenderViewHost
* render_view_host
)
557 : render_frame_host_(render_view_host
->GetMainFrame()) {
560 ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost
* render_frame_host
)
561 : render_frame_host_(render_frame_host
) {
564 } // namespace internal
566 bool ExecuteScript(const internal::ToRenderFrameHost
& adapter
,
567 const std::string
& script
) {
568 std::string new_script
=
569 script
+ ";window.domAutomationController.send(0);";
570 return ExecuteScriptHelper(adapter
.render_frame_host(), new_script
, NULL
);
573 bool ExecuteScriptAndExtractInt(const internal::ToRenderFrameHost
& adapter
,
574 const std::string
& script
, int* result
) {
576 scoped_ptr
<base::Value
> value
;
577 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
582 return value
->GetAsInteger(result
);
585 bool ExecuteScriptAndExtractBool(const internal::ToRenderFrameHost
& adapter
,
586 const std::string
& script
, bool* result
) {
588 scoped_ptr
<base::Value
> value
;
589 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
594 return value
->GetAsBoolean(result
);
597 bool ExecuteScriptAndExtractString(const internal::ToRenderFrameHost
& adapter
,
598 const std::string
& script
,
599 std::string
* result
) {
601 scoped_ptr
<base::Value
> value
;
602 if (!ExecuteScriptHelper(adapter
.render_frame_host(), script
, &value
) ||
607 return value
->GetAsString(result
);
611 void AddToSetIfFrameMatchesPredicate(
612 std::set
<RenderFrameHost
*>* frame_set
,
613 const base::Callback
<bool(RenderFrameHost
*)>& predicate
,
614 RenderFrameHost
* host
) {
615 if (predicate
.Run(host
))
616 frame_set
->insert(host
);
620 RenderFrameHost
* FrameMatchingPredicate(
621 WebContents
* web_contents
,
622 const base::Callback
<bool(RenderFrameHost
*)>& predicate
) {
623 std::set
<RenderFrameHost
*> frame_set
;
624 web_contents
->ForEachFrame(
625 base::Bind(&AddToSetIfFrameMatchesPredicate
, &frame_set
, predicate
));
626 DCHECK_EQ(1U, frame_set
.size());
627 return *frame_set
.begin();
630 bool FrameMatchesName(const std::string
& name
, RenderFrameHost
* frame
) {
631 return frame
->GetFrameName() == name
;
634 bool FrameIsChildOfMainFrame(RenderFrameHost
* frame
) {
635 return frame
->GetParent() && !frame
->GetParent()->GetParent();
638 bool FrameHasSourceUrl(const GURL
& url
, RenderFrameHost
* frame
) {
639 return frame
->GetLastCommittedURL() == url
;
642 bool ExecuteWebUIResourceTest(WebContents
* web_contents
,
643 const std::vector
<int>& js_resource_ids
) {
644 // Inject WebUI test runner script first prior to other scripts required to
645 // run the test as scripts may depend on it being declared.
646 std::vector
<int> ids
;
647 ids
.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST
);
648 ids
.insert(ids
.end(), js_resource_ids
.begin(), js_resource_ids
.end());
651 for (std::vector
<int>::iterator iter
= ids
.begin();
654 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter
)
655 .AppendToString(&script
);
658 if (!ExecuteScript(web_contents
, script
))
661 DOMMessageQueue message_queue
;
662 if (!ExecuteScript(web_contents
, "runTests()"))
667 if (!message_queue
.WaitForMessage(&message
))
669 } while (message
.compare("\"PENDING\"") == 0);
671 return message
.compare("\"SUCCESS\"") == 0;
674 std::string
GetCookies(BrowserContext
* browser_context
, const GURL
& url
) {
676 base::WaitableEvent
event(true, false);
677 net::URLRequestContextGetter
* context_getter
=
678 browser_context
->GetRequestContext();
680 BrowserThread::PostTask(
681 BrowserThread::IO
, FROM_HERE
,
682 base::Bind(&GetCookiesOnIOThread
, url
,
683 make_scoped_refptr(context_getter
), &event
, &cookies
));
688 bool SetCookie(BrowserContext
* browser_context
,
690 const std::string
& value
) {
692 base::WaitableEvent
event(true, false);
693 net::URLRequestContextGetter
* context_getter
=
694 browser_context
->GetRequestContext();
696 BrowserThread::PostTask(
697 BrowserThread::IO
, FROM_HERE
,
698 base::Bind(&SetCookieOnIOThread
, url
, value
,
699 make_scoped_refptr(context_getter
), &event
, &result
));
704 void FetchHistogramsFromChildProcesses() {
705 scoped_refptr
<content::MessageLoopRunner
> runner
= new MessageLoopRunner
;
707 FetchHistogramsAsynchronously(
708 base::MessageLoop::current(),
709 runner
->QuitClosure(),
710 // If this call times out, it means that a child process is not
711 // responding, which is something we should not ignore. The timeout is
712 // set to be longer than the normal browser test timeout so that it will
713 // be prempted by the normal timeout.
714 TestTimeouts::action_max_timeout());
718 void SetupCrossSiteRedirector(
719 net::test_server::EmbeddedTestServer
* embedded_test_server
) {
720 embedded_test_server
->RegisterRequestHandler(
721 base::Bind(&CrossSiteRedirectResponseHandler
,
722 embedded_test_server
->base_url()));
725 void WaitForInterstitialAttach(content::WebContents
* web_contents
) {
726 if (web_contents
->ShowingInterstitialPage())
728 scoped_refptr
<content::MessageLoopRunner
> loop_runner(
729 new content::MessageLoopRunner
);
730 InterstitialObserver
observer(web_contents
,
731 loop_runner
->QuitClosure(),
736 void WaitForInterstitialDetach(content::WebContents
* web_contents
) {
737 RunTaskAndWaitForInterstitialDetach(web_contents
, base::Closure());
740 void RunTaskAndWaitForInterstitialDetach(content::WebContents
* web_contents
,
741 const base::Closure
& task
) {
742 if (!web_contents
|| !web_contents
->ShowingInterstitialPage())
744 scoped_refptr
<content::MessageLoopRunner
> loop_runner(
745 new content::MessageLoopRunner
);
746 InterstitialObserver
observer(web_contents
,
748 loop_runner
->QuitClosure());
751 // At this point, web_contents may have been deleted.
755 bool WaitForRenderFrameReady(RenderFrameHost
* rfh
) {
760 content::ExecuteScriptAndExtractString(
764 " function checkState() {"
765 " if (!done && document.readyState == 'complete') {"
767 " window.domAutomationController.send('pageLoadComplete');"
771 " document.addEventListener('readystatechange', checkState);"
774 return result
== "pageLoadComplete";
777 TitleWatcher::TitleWatcher(WebContents
* web_contents
,
778 const base::string16
& expected_title
)
779 : WebContentsObserver(web_contents
),
780 message_loop_runner_(new MessageLoopRunner
) {
781 EXPECT_TRUE(web_contents
!= NULL
);
782 expected_titles_
.push_back(expected_title
);
785 void TitleWatcher::AlsoWaitForTitle(const base::string16
& expected_title
) {
786 expected_titles_
.push_back(expected_title
);
789 TitleWatcher::~TitleWatcher() {
792 const base::string16
& TitleWatcher::WaitAndGetTitle() {
794 message_loop_runner_
->Run();
795 return observed_title_
;
798 void TitleWatcher::DidStopLoading() {
799 // When navigating through the history, the restored NavigationEntry's title
800 // will be used. If the entry ends up having the same title after we return
801 // to it, as will usually be the case, then WebContentsObserver::TitleSet
802 // will then be suppressed, since the NavigationEntry's title hasn't changed.
806 void TitleWatcher::TitleWasSet(NavigationEntry
* entry
, bool explicit_set
) {
810 void TitleWatcher::TestTitle() {
811 std::vector
<base::string16
>::const_iterator it
=
812 std::find(expected_titles_
.begin(),
813 expected_titles_
.end(),
814 web_contents()->GetTitle());
815 if (it
== expected_titles_
.end())
818 observed_title_
= *it
;
819 message_loop_runner_
->Quit();
822 WebContentsDestroyedWatcher::WebContentsDestroyedWatcher(
823 WebContents
* web_contents
)
824 : WebContentsObserver(web_contents
),
825 message_loop_runner_(new MessageLoopRunner
) {
826 EXPECT_TRUE(web_contents
!= NULL
);
829 WebContentsDestroyedWatcher::~WebContentsDestroyedWatcher() {
832 void WebContentsDestroyedWatcher::Wait() {
833 message_loop_runner_
->Run();
836 void WebContentsDestroyedWatcher::WebContentsDestroyed() {
837 message_loop_runner_
->Quit();
840 RenderProcessHostWatcher::RenderProcessHostWatcher(
841 RenderProcessHost
* render_process_host
, WatchType type
)
842 : render_process_host_(render_process_host
),
844 message_loop_runner_(new MessageLoopRunner
) {
845 render_process_host_
->AddObserver(this);
848 RenderProcessHostWatcher::RenderProcessHostWatcher(
849 WebContents
* web_contents
, WatchType type
)
850 : render_process_host_(web_contents
->GetRenderProcessHost()),
852 message_loop_runner_(new MessageLoopRunner
) {
853 render_process_host_
->AddObserver(this);
856 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
857 if (render_process_host_
)
858 render_process_host_
->RemoveObserver(this);
861 void RenderProcessHostWatcher::Wait() {
862 message_loop_runner_
->Run();
865 void RenderProcessHostWatcher::RenderProcessExited(
866 RenderProcessHost
* host
,
867 base::TerminationStatus status
,
869 if (type_
== WATCH_FOR_PROCESS_EXIT
)
870 message_loop_runner_
->Quit();
873 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
874 RenderProcessHost
* host
) {
875 render_process_host_
= NULL
;
876 if (type_
== WATCH_FOR_HOST_DESTRUCTION
)
877 message_loop_runner_
->Quit();
880 DOMMessageQueue::DOMMessageQueue() {
881 registrar_
.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE
,
882 NotificationService::AllSources());
885 DOMMessageQueue::~DOMMessageQueue() {}
887 void DOMMessageQueue::Observe(int type
,
888 const NotificationSource
& source
,
889 const NotificationDetails
& details
) {
890 Details
<DomOperationNotificationDetails
> dom_op_details(details
);
891 message_queue_
.push(dom_op_details
->json
);
892 if (message_loop_runner_
.get())
893 message_loop_runner_
->Quit();
896 void DOMMessageQueue::ClearQueue() {
897 message_queue_
= std::queue
<std::string
>();
900 bool DOMMessageQueue::WaitForMessage(std::string
* message
) {
902 if (message_queue_
.empty()) {
903 // This will be quit when a new message comes in.
904 message_loop_runner_
= new MessageLoopRunner
;
905 message_loop_runner_
->Run();
907 // The queue should not be empty, unless we were quit because of a timeout.
908 if (message_queue_
.empty())
910 *message
= message_queue_
.front();
911 message_queue_
.pop();
915 class WebContentsAddedObserver::RenderViewCreatedObserver
916 : public WebContentsObserver
{
918 explicit RenderViewCreatedObserver(WebContents
* web_contents
)
919 : WebContentsObserver(web_contents
),
920 render_view_created_called_(false),
921 main_frame_created_called_(false) {}
923 // WebContentsObserver:
924 void RenderViewCreated(RenderViewHost
* rvh
) override
{
925 render_view_created_called_
= true;
928 void RenderFrameCreated(RenderFrameHost
* rfh
) override
{
929 if (rfh
== web_contents()->GetMainFrame())
930 main_frame_created_called_
= true;
933 bool render_view_created_called_
;
934 bool main_frame_created_called_
;
937 WebContentsAddedObserver::WebContentsAddedObserver()
938 : web_contents_created_callback_(
939 base::Bind(&WebContentsAddedObserver::WebContentsCreated
,
940 base::Unretained(this))),
941 web_contents_(NULL
) {
942 WebContentsImpl::FriendZone::AddCreatedCallbackForTesting(
943 web_contents_created_callback_
);
946 WebContentsAddedObserver::~WebContentsAddedObserver() {
947 WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting(
948 web_contents_created_callback_
);
951 void WebContentsAddedObserver::WebContentsCreated(WebContents
* web_contents
) {
952 DCHECK(!web_contents_
);
953 web_contents_
= web_contents
;
954 child_observer_
.reset(new RenderViewCreatedObserver(web_contents
));
957 runner_
->QuitClosure().Run();
960 WebContents
* WebContentsAddedObserver::GetWebContents() {
962 return web_contents_
;
964 runner_
= new MessageLoopRunner();
966 return web_contents_
;
969 bool WebContentsAddedObserver::RenderViewCreatedCalled() {
970 if (child_observer_
) {
971 return child_observer_
->render_view_created_called_
&&
972 child_observer_
->main_frame_created_called_
;
977 } // namespace content