Add ianwen to watch list for related projects
[chromium-blink-merge.git] / content / public / test / browser_test_utils.cc
blob05d09db6b3678bdf959132e2ffa93e6cf9d7e755
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"
8 #include "base/bind.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/browser/web_contents_observer.h"
35 #include "content/public/test/test_utils.h"
36 #include "net/base/filename_util.h"
37 #include "net/cookies/cookie_store.h"
38 #include "net/test/embedded_test_server/embedded_test_server.h"
39 #include "net/test/embedded_test_server/http_request.h"
40 #include "net/test/embedded_test_server/http_response.h"
41 #include "net/test/python_utils.h"
42 #include "net/url_request/url_request_context.h"
43 #include "net/url_request/url_request_context_getter.h"
44 #include "testing/gtest/include/gtest/gtest.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/compositor/test/draw_waiter_for_test.h"
47 #include "ui/events/gesture_detection/gesture_configuration.h"
48 #include "ui/events/keycodes/dom/dom_code.h"
49 #include "ui/events/keycodes/dom/keycode_converter.h"
50 #include "ui/resources/grit/webui_resources.h"
52 #if defined(USE_AURA)
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"
57 #endif // USE_AURA
59 namespace content {
60 namespace {
62 class DOMOperationObserver : public NotificationObserver,
63 public WebContentsObserver {
64 public:
65 explicit DOMOperationObserver(RenderViewHost* rvh)
66 : WebContentsObserver(WebContents::FromRenderViewHost(rvh)),
67 did_respond_(false) {
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);
78 response_ = dom_op_details->json;
79 did_respond_ = true;
80 message_loop_runner_->Quit();
83 // Overridden from WebContentsObserver:
84 void RenderProcessGone(base::TerminationStatus status) override {
85 message_loop_runner_->Quit();
88 bool WaitAndGetResponse(std::string* response) WARN_UNUSED_RESULT {
89 message_loop_runner_->Run();
90 *response = response_;
91 return did_respond_;
94 private:
95 NotificationRegistrar registrar_;
96 std::string response_;
97 bool did_respond_;
98 scoped_refptr<MessageLoopRunner> message_loop_runner_;
100 DISALLOW_COPY_AND_ASSIGN(DOMOperationObserver);
103 class InterstitialObserver : public content::WebContentsObserver {
104 public:
105 InterstitialObserver(content::WebContents* web_contents,
106 const base::Closure& attach_callback,
107 const base::Closure& detach_callback)
108 : WebContentsObserver(web_contents),
109 attach_callback_(attach_callback),
110 detach_callback_(detach_callback) {
112 ~InterstitialObserver() override {}
114 // WebContentsObserver methods:
115 void DidAttachInterstitialPage() override { attach_callback_.Run(); }
116 void DidDetachInterstitialPage() override { detach_callback_.Run(); }
118 private:
119 base::Closure attach_callback_;
120 base::Closure detach_callback_;
122 DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
125 // Specifying a prototype so that we can add the WARN_UNUSED_RESULT attribute.
126 bool ExecuteScriptHelper(
127 RenderFrameHost* render_frame_host,
128 const std::string& original_script,
129 scoped_ptr<base::Value>* result) WARN_UNUSED_RESULT;
131 // Executes the passed |original_script| in the frame specified by
132 // |render_frame_host|. If |result| is not NULL, stores the value that the
133 // evaluation of the script in |result|. Returns true on success.
134 bool ExecuteScriptHelper(RenderFrameHost* render_frame_host,
135 const std::string& original_script,
136 scoped_ptr<base::Value>* result) {
137 // TODO(jcampan): we should make the domAutomationController not require an
138 // automation id.
139 std::string script =
140 "window.domAutomationController.setAutomationId(0);" + original_script;
141 DOMOperationObserver dom_op_observer(render_frame_host->GetRenderViewHost());
142 render_frame_host->ExecuteJavaScriptWithUserGestureForTests(
143 base::UTF8ToUTF16(script));
144 std::string json;
145 if (!dom_op_observer.WaitAndGetResponse(&json)) {
146 DLOG(ERROR) << "Cannot communicate with DOMOperationObserver.";
147 return false;
150 // Nothing more to do for callers that ignore the returned JS value.
151 if (!result)
152 return true;
154 base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
155 *result = reader.ReadToValue(json);
156 if (!*result) {
157 DLOG(ERROR) << reader.GetErrorMessage();
158 return false;
161 return true;
164 void BuildSimpleWebKeyEvent(blink::WebInputEvent::Type type,
165 ui::KeyboardCode key_code,
166 int native_key_code,
167 int modifiers,
168 NativeWebKeyboardEvent* event) {
169 event->nativeKeyCode = native_key_code;
170 event->windowsKeyCode = key_code;
171 event->setKeyIdentifierFromWindowsKeyCode();
172 event->type = type;
173 event->modifiers = modifiers;
174 event->isSystemKey = false;
175 event->timeStampSeconds = base::Time::Now().ToDoubleT();
176 event->skip_in_browser = true;
178 if (type == blink::WebInputEvent::Char ||
179 type == blink::WebInputEvent::RawKeyDown) {
180 event->text[0] = key_code;
181 event->unmodifiedText[0] = key_code;
185 void InjectRawKeyEvent(WebContents* web_contents,
186 blink::WebInputEvent::Type type,
187 ui::KeyboardCode key_code,
188 int native_key_code,
189 int modifiers) {
190 NativeWebKeyboardEvent event;
191 BuildSimpleWebKeyEvent(type, key_code, native_key_code, modifiers, &event);
192 web_contents->GetRenderViewHost()->ForwardKeyboardEvent(event);
195 void GetCookiesCallback(std::string* cookies_out,
196 base::WaitableEvent* event,
197 const std::string& cookies) {
198 *cookies_out = cookies;
199 event->Signal();
202 void GetCookiesOnIOThread(const GURL& url,
203 net::URLRequestContextGetter* context_getter,
204 base::WaitableEvent* event,
205 std::string* cookies) {
206 net::CookieStore* cookie_store =
207 context_getter->GetURLRequestContext()->cookie_store();
208 cookie_store->GetCookiesWithOptionsAsync(
209 url, net::CookieOptions(),
210 base::Bind(&GetCookiesCallback, cookies, event));
213 void SetCookieCallback(bool* result,
214 base::WaitableEvent* event,
215 bool success) {
216 *result = success;
217 event->Signal();
220 void SetCookieOnIOThread(const GURL& url,
221 const std::string& value,
222 net::URLRequestContextGetter* context_getter,
223 base::WaitableEvent* event,
224 bool* result) {
225 net::CookieStore* cookie_store =
226 context_getter->GetURLRequestContext()->cookie_store();
227 cookie_store->SetCookieWithOptionsAsync(
228 url, value, net::CookieOptions(),
229 base::Bind(&SetCookieCallback, result, event));
232 scoped_ptr<net::test_server::HttpResponse> CrossSiteRedirectResponseHandler(
233 const GURL& server_base_url,
234 const net::test_server::HttpRequest& request) {
235 std::string prefix("/cross-site/");
236 if (!base::StartsWithASCII(request.relative_url, prefix, true))
237 return scoped_ptr<net::test_server::HttpResponse>();
239 std::string params = request.relative_url.substr(prefix.length());
241 // A hostname to redirect to must be included in the URL, therefore at least
242 // one '/' character is expected.
243 size_t slash = params.find('/');
244 if (slash == std::string::npos)
245 return scoped_ptr<net::test_server::HttpResponse>();
247 // Replace the host of the URL with the one passed in the URL.
248 GURL::Replacements replace_host;
249 replace_host.SetHostStr(base::StringPiece(params).substr(0, slash));
250 GURL redirect_server = server_base_url.ReplaceComponents(replace_host);
252 // Append the real part of the path to the new URL.
253 std::string path = params.substr(slash + 1);
254 GURL redirect_target(redirect_server.Resolve(path));
255 DCHECK(redirect_target.is_valid());
257 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
258 new net::test_server::BasicHttpResponse);
259 http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
260 http_response->AddCustomHeader("Location", redirect_target.spec());
261 return http_response.Pass();
264 } // namespace
266 bool NavigateIframeToURL(WebContents* web_contents,
267 std::string iframe_id,
268 const GURL& url) {
269 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
270 // navigations generate extra DidStartLoading and DidStopLoading messages.
271 // Until we replace swappedout:// with frame proxies, we need to listen for
272 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
273 // for commit. See https://crbug.com/436250.
274 std::string script = base::StringPrintf(
275 "setTimeout(\""
276 "var iframes = document.getElementById('%s');iframes.src='%s';"
277 "\",0)",
278 iframe_id.c_str(), url.spec().c_str());
279 WindowedNotificationObserver load_observer(
280 NOTIFICATION_NAV_ENTRY_COMMITTED,
281 Source<NavigationController>(&web_contents->GetController()));
282 bool result = ExecuteScript(web_contents, script);
283 load_observer.Wait();
284 return result;
287 GURL GetFileUrlWithQuery(const base::FilePath& path,
288 const std::string& query_string) {
289 GURL url = net::FilePathToFileURL(path);
290 if (!query_string.empty()) {
291 GURL::Replacements replacements;
292 replacements.SetQueryStr(query_string);
293 return url.ReplaceComponents(replacements);
295 return url;
298 void WaitForLoadStopWithoutSuccessCheck(WebContents* web_contents) {
299 // In many cases, the load may have finished before we get here. Only wait if
300 // the tab still has a pending navigation.
301 if (web_contents->IsLoading()) {
302 WindowedNotificationObserver load_stop_observer(
303 NOTIFICATION_LOAD_STOP,
304 Source<NavigationController>(&web_contents->GetController()));
305 load_stop_observer.Wait();
309 bool WaitForLoadStop(WebContents* web_contents) {
310 WaitForLoadStopWithoutSuccessCheck(web_contents);
311 return IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL);
314 bool IsLastCommittedEntryOfPageType(WebContents* web_contents,
315 content::PageType page_type) {
316 NavigationEntry* last_entry =
317 web_contents->GetController().GetLastCommittedEntry();
318 if (!last_entry)
319 return false;
320 return last_entry->GetPageType() == page_type;
323 void CrashTab(WebContents* web_contents) {
324 RenderProcessHost* rph = web_contents->GetRenderProcessHost();
325 RenderProcessHostWatcher watcher(
326 rph, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
327 rph->Shutdown(0, false);
328 watcher.Wait();
331 #if defined(USE_AURA)
332 bool IsResizeComplete(aura::test::WindowEventDispatcherTestApi* dispatcher_test,
333 RenderWidgetHostImpl* widget_host) {
334 return !dispatcher_test->HoldingPointerMoves() &&
335 !widget_host->resize_ack_pending_for_testing();
338 void WaitForResizeComplete(WebContents* web_contents) {
339 aura::Window* content = web_contents->GetContentNativeView();
340 if (!content)
341 return;
343 aura::WindowTreeHost* window_host = content->GetHost();
344 aura::WindowEventDispatcher* dispatcher = window_host->dispatcher();
345 aura::test::WindowEventDispatcherTestApi dispatcher_test(dispatcher);
346 RenderWidgetHostImpl* widget_host =
347 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
348 if (!IsResizeComplete(&dispatcher_test, widget_host)) {
349 WindowedNotificationObserver resize_observer(
350 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
351 base::Bind(IsResizeComplete, &dispatcher_test, widget_host));
352 resize_observer.Wait();
355 #elif defined(OS_ANDROID)
356 bool IsResizeComplete(RenderWidgetHostImpl* widget_host) {
357 return !widget_host->resize_ack_pending_for_testing();
360 void WaitForResizeComplete(WebContents* web_contents) {
361 RenderWidgetHostImpl* widget_host =
362 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
363 if (!IsResizeComplete(widget_host)) {
364 WindowedNotificationObserver resize_observer(
365 NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
366 base::Bind(IsResizeComplete, widget_host));
367 resize_observer.Wait();
370 #endif
372 void SimulateMouseClick(WebContents* web_contents,
373 int modifiers,
374 blink::WebMouseEvent::Button button) {
375 int x = web_contents->GetContainerBounds().width() / 2;
376 int y = web_contents->GetContainerBounds().height() / 2;
377 SimulateMouseClickAt(web_contents, modifiers, button, gfx::Point(x, y));
380 void SimulateMouseClickAt(WebContents* web_contents,
381 int modifiers,
382 blink::WebMouseEvent::Button button,
383 const gfx::Point& point) {
384 blink::WebMouseEvent mouse_event;
385 mouse_event.type = blink::WebInputEvent::MouseDown;
386 mouse_event.button = button;
387 mouse_event.x = point.x();
388 mouse_event.y = point.y();
389 mouse_event.modifiers = modifiers;
390 // Mac needs globalX/globalY for events to plugins.
391 gfx::Rect offset = web_contents->GetContainerBounds();
392 mouse_event.globalX = point.x() + offset.x();
393 mouse_event.globalY = point.y() + offset.y();
394 mouse_event.clickCount = 1;
395 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
396 mouse_event.type = blink::WebInputEvent::MouseUp;
397 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
400 void SimulateMouseEvent(WebContents* web_contents,
401 blink::WebInputEvent::Type type,
402 const gfx::Point& point) {
403 blink::WebMouseEvent mouse_event;
404 mouse_event.type = type;
405 mouse_event.x = point.x();
406 mouse_event.y = point.y();
407 web_contents->GetRenderViewHost()->ForwardMouseEvent(mouse_event);
410 void SimulateTapAt(WebContents* web_contents, const gfx::Point& point) {
411 blink::WebGestureEvent tap;
412 tap.type = blink::WebGestureEvent::GestureTap;
413 tap.x = point.x();
414 tap.y = point.y();
415 tap.modifiers = blink::WebInputEvent::ControlKey;
416 RenderWidgetHostImpl* widget_host =
417 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
418 widget_host->ForwardGestureEvent(tap);
421 void SimulateTapWithModifiersAt(WebContents* web_contents,
422 unsigned modifiers,
423 const gfx::Point& point) {
424 blink::WebGestureEvent tap;
425 tap.type = blink::WebGestureEvent::GestureTap;
426 tap.x = point.x();
427 tap.y = point.y();
428 tap.modifiers = modifiers;
429 RenderWidgetHostImpl* widget_host =
430 RenderWidgetHostImpl::From(web_contents->GetRenderViewHost());
431 widget_host->ForwardGestureEvent(tap);
434 void SimulateKeyPress(WebContents* web_contents,
435 ui::KeyboardCode key_code,
436 bool control,
437 bool shift,
438 bool alt,
439 bool command) {
440 SimulateKeyPressWithCode(
441 web_contents, key_code, NULL, control, shift, alt, command);
444 void SimulateKeyPressWithCode(WebContents* web_contents,
445 ui::KeyboardCode key_code,
446 const char* code,
447 bool control,
448 bool shift,
449 bool alt,
450 bool command) {
451 int native_key_code = ui::KeycodeConverter::DomCodeToNativeKeycode(
452 ui::KeycodeConverter::CodeStringToDomCode(code));
454 int modifiers = 0;
456 // The order of these key down events shouldn't matter for our simulation.
457 // For our simulation we can use either the left keys or the right keys.
458 if (control) {
459 modifiers |= blink::WebInputEvent::ControlKey;
460 InjectRawKeyEvent(
461 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_CONTROL,
462 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
463 modifiers);
466 if (shift) {
467 modifiers |= blink::WebInputEvent::ShiftKey;
468 InjectRawKeyEvent(
469 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_SHIFT,
470 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
471 modifiers);
474 if (alt) {
475 modifiers |= blink::WebInputEvent::AltKey;
476 InjectRawKeyEvent(
477 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_MENU,
478 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
479 modifiers);
482 if (command) {
483 modifiers |= blink::WebInputEvent::MetaKey;
484 InjectRawKeyEvent(
485 web_contents, blink::WebInputEvent::RawKeyDown, ui::VKEY_COMMAND,
486 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
487 modifiers);
489 InjectRawKeyEvent(web_contents, blink::WebInputEvent::RawKeyDown, key_code,
490 native_key_code, modifiers);
492 InjectRawKeyEvent(web_contents, blink::WebInputEvent::Char, key_code,
493 native_key_code, modifiers);
495 InjectRawKeyEvent(web_contents, blink::WebInputEvent::KeyUp, key_code,
496 native_key_code, modifiers);
498 // The order of these key releases shouldn't matter for our simulation.
499 if (control) {
500 modifiers &= ~blink::WebInputEvent::ControlKey;
501 InjectRawKeyEvent(
502 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_CONTROL,
503 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::CONTROL_LEFT),
504 modifiers);
507 if (shift) {
508 modifiers &= ~blink::WebInputEvent::ShiftKey;
509 InjectRawKeyEvent(
510 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_SHIFT,
511 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::SHIFT_LEFT),
512 modifiers);
515 if (alt) {
516 modifiers &= ~blink::WebInputEvent::AltKey;
517 InjectRawKeyEvent(
518 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_MENU,
519 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::ALT_LEFT),
520 modifiers);
523 if (command) {
524 modifiers &= ~blink::WebInputEvent::MetaKey;
525 InjectRawKeyEvent(
526 web_contents, blink::WebInputEvent::KeyUp, ui::VKEY_COMMAND,
527 ui::KeycodeConverter::DomCodeToNativeKeycode(ui::DomCode::OS_LEFT),
528 modifiers);
531 ASSERT_EQ(modifiers, 0);
534 namespace internal {
536 ToRenderFrameHost::ToRenderFrameHost(WebContents* web_contents)
537 : render_frame_host_(web_contents->GetMainFrame()) {
540 ToRenderFrameHost::ToRenderFrameHost(RenderViewHost* render_view_host)
541 : render_frame_host_(render_view_host->GetMainFrame()) {
544 ToRenderFrameHost::ToRenderFrameHost(RenderFrameHost* render_frame_host)
545 : render_frame_host_(render_frame_host) {
548 } // namespace internal
550 bool ExecuteScript(const internal::ToRenderFrameHost& adapter,
551 const std::string& script) {
552 std::string new_script =
553 script + ";window.domAutomationController.send(0);";
554 return ExecuteScriptHelper(adapter.render_frame_host(), new_script, NULL);
557 bool ExecuteScriptAndExtractInt(const internal::ToRenderFrameHost& adapter,
558 const std::string& script, int* result) {
559 DCHECK(result);
560 scoped_ptr<base::Value> value;
561 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
562 !value.get()) {
563 return false;
566 return value->GetAsInteger(result);
569 bool ExecuteScriptAndExtractBool(const internal::ToRenderFrameHost& adapter,
570 const std::string& script, bool* result) {
571 DCHECK(result);
572 scoped_ptr<base::Value> value;
573 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
574 !value.get()) {
575 return false;
578 return value->GetAsBoolean(result);
581 bool ExecuteScriptAndExtractString(const internal::ToRenderFrameHost& adapter,
582 const std::string& script,
583 std::string* result) {
584 DCHECK(result);
585 scoped_ptr<base::Value> value;
586 if (!ExecuteScriptHelper(adapter.render_frame_host(), script, &value) ||
587 !value.get()) {
588 return false;
591 return value->GetAsString(result);
594 namespace {
595 void AddToSetIfFrameMatchesPredicate(
596 std::set<RenderFrameHost*>* frame_set,
597 const base::Callback<bool(RenderFrameHost*)>& predicate,
598 RenderFrameHost* host) {
599 if (predicate.Run(host))
600 frame_set->insert(host);
604 RenderFrameHost* FrameMatchingPredicate(
605 WebContents* web_contents,
606 const base::Callback<bool(RenderFrameHost*)>& predicate) {
607 std::set<RenderFrameHost*> frame_set;
608 web_contents->ForEachFrame(
609 base::Bind(&AddToSetIfFrameMatchesPredicate, &frame_set, predicate));
610 DCHECK_EQ(1U, frame_set.size());
611 return *frame_set.begin();
614 bool FrameMatchesName(const std::string& name, RenderFrameHost* frame) {
615 return frame->GetFrameName() == name;
618 bool FrameIsChildOfMainFrame(RenderFrameHost* frame) {
619 return frame->GetParent() && !frame->GetParent()->GetParent();
622 bool FrameHasSourceUrl(const GURL& url, RenderFrameHost* frame) {
623 return frame->GetLastCommittedURL() == url;
626 bool ExecuteWebUIResourceTest(WebContents* web_contents,
627 const std::vector<int>& js_resource_ids) {
628 // Inject WebUI test runner script first prior to other scripts required to
629 // run the test as scripts may depend on it being declared.
630 std::vector<int> ids;
631 ids.push_back(IDR_WEBUI_JS_WEBUI_RESOURCE_TEST);
632 ids.insert(ids.end(), js_resource_ids.begin(), js_resource_ids.end());
634 std::string script;
635 for (std::vector<int>::iterator iter = ids.begin();
636 iter != ids.end();
637 ++iter) {
638 ResourceBundle::GetSharedInstance().GetRawDataResource(*iter)
639 .AppendToString(&script);
640 script.append("\n");
642 if (!ExecuteScript(web_contents, script))
643 return false;
645 DOMMessageQueue message_queue;
646 if (!ExecuteScript(web_contents, "runTests()"))
647 return false;
649 std::string message;
650 do {
651 if (!message_queue.WaitForMessage(&message))
652 return false;
653 } while (message.compare("\"PENDING\"") == 0);
655 return message.compare("\"SUCCESS\"") == 0;
658 std::string GetCookies(BrowserContext* browser_context, const GURL& url) {
659 std::string cookies;
660 base::WaitableEvent event(true, false);
661 net::URLRequestContextGetter* context_getter =
662 browser_context->GetRequestContext();
664 BrowserThread::PostTask(
665 BrowserThread::IO, FROM_HERE,
666 base::Bind(&GetCookiesOnIOThread, url,
667 make_scoped_refptr(context_getter), &event, &cookies));
668 event.Wait();
669 return cookies;
672 bool SetCookie(BrowserContext* browser_context,
673 const GURL& url,
674 const std::string& value) {
675 bool result = false;
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(&SetCookieOnIOThread, url, value,
683 make_scoped_refptr(context_getter), &event, &result));
684 event.Wait();
685 return result;
688 void FetchHistogramsFromChildProcesses() {
689 scoped_refptr<content::MessageLoopRunner> runner = new MessageLoopRunner;
691 FetchHistogramsAsynchronously(
692 base::MessageLoop::current(),
693 runner->QuitClosure(),
694 // If this call times out, it means that a child process is not
695 // responding, which is something we should not ignore. The timeout is
696 // set to be longer than the normal browser test timeout so that it will
697 // be prempted by the normal timeout.
698 TestTimeouts::action_max_timeout());
699 runner->Run();
702 void SetupCrossSiteRedirector(
703 net::test_server::EmbeddedTestServer* embedded_test_server) {
704 embedded_test_server->RegisterRequestHandler(
705 base::Bind(&CrossSiteRedirectResponseHandler,
706 embedded_test_server->base_url()));
709 void WaitForInterstitialAttach(content::WebContents* web_contents) {
710 if (web_contents->ShowingInterstitialPage())
711 return;
712 scoped_refptr<content::MessageLoopRunner> loop_runner(
713 new content::MessageLoopRunner);
714 InterstitialObserver observer(web_contents,
715 loop_runner->QuitClosure(),
716 base::Closure());
717 loop_runner->Run();
720 void WaitForInterstitialDetach(content::WebContents* web_contents) {
721 RunTaskAndWaitForInterstitialDetach(web_contents, base::Closure());
724 void RunTaskAndWaitForInterstitialDetach(content::WebContents* web_contents,
725 const base::Closure& task) {
726 if (!web_contents || !web_contents->ShowingInterstitialPage())
727 return;
728 scoped_refptr<content::MessageLoopRunner> loop_runner(
729 new content::MessageLoopRunner);
730 InterstitialObserver observer(web_contents,
731 base::Closure(),
732 loop_runner->QuitClosure());
733 if (!task.is_null())
734 task.Run();
735 // At this point, web_contents may have been deleted.
736 loop_runner->Run();
739 bool WaitForRenderFrameReady(RenderFrameHost* rfh) {
740 if (!rfh)
741 return false;
742 std::string result;
743 EXPECT_TRUE(
744 content::ExecuteScriptAndExtractString(
745 rfh,
746 "(function() {"
747 " var done = false;"
748 " function checkState() {"
749 " if (!done && document.readyState == 'complete') {"
750 " done = true;"
751 " window.domAutomationController.send('pageLoadComplete');"
752 " }"
753 " }"
754 " checkState();"
755 " document.addEventListener('readystatechange', checkState);"
756 "})();",
757 &result));
758 return result == "pageLoadComplete";
761 TitleWatcher::TitleWatcher(WebContents* web_contents,
762 const base::string16& expected_title)
763 : WebContentsObserver(web_contents),
764 message_loop_runner_(new MessageLoopRunner) {
765 EXPECT_TRUE(web_contents != NULL);
766 expected_titles_.push_back(expected_title);
769 void TitleWatcher::AlsoWaitForTitle(const base::string16& expected_title) {
770 expected_titles_.push_back(expected_title);
773 TitleWatcher::~TitleWatcher() {
776 const base::string16& TitleWatcher::WaitAndGetTitle() {
777 TestTitle();
778 message_loop_runner_->Run();
779 return observed_title_;
782 void TitleWatcher::DidStopLoading() {
783 // When navigating through the history, the restored NavigationEntry's title
784 // will be used. If the entry ends up having the same title after we return
785 // to it, as will usually be the case, then WebContentsObserver::TitleSet
786 // will then be suppressed, since the NavigationEntry's title hasn't changed.
787 TestTitle();
790 void TitleWatcher::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
791 TestTitle();
794 void TitleWatcher::TestTitle() {
795 std::vector<base::string16>::const_iterator it =
796 std::find(expected_titles_.begin(),
797 expected_titles_.end(),
798 web_contents()->GetTitle());
799 if (it == expected_titles_.end())
800 return;
802 observed_title_ = *it;
803 message_loop_runner_->Quit();
806 WebContentsDestroyedWatcher::WebContentsDestroyedWatcher(
807 WebContents* web_contents)
808 : WebContentsObserver(web_contents),
809 message_loop_runner_(new MessageLoopRunner) {
810 EXPECT_TRUE(web_contents != NULL);
813 WebContentsDestroyedWatcher::~WebContentsDestroyedWatcher() {
816 void WebContentsDestroyedWatcher::Wait() {
817 message_loop_runner_->Run();
820 void WebContentsDestroyedWatcher::WebContentsDestroyed() {
821 message_loop_runner_->Quit();
824 RenderProcessHostWatcher::RenderProcessHostWatcher(
825 RenderProcessHost* render_process_host, WatchType type)
826 : render_process_host_(render_process_host),
827 type_(type),
828 did_exit_normally_(true),
829 message_loop_runner_(new MessageLoopRunner) {
830 render_process_host_->AddObserver(this);
833 RenderProcessHostWatcher::RenderProcessHostWatcher(
834 WebContents* web_contents, WatchType type)
835 : render_process_host_(web_contents->GetRenderProcessHost()),
836 type_(type),
837 did_exit_normally_(true),
838 message_loop_runner_(new MessageLoopRunner) {
839 render_process_host_->AddObserver(this);
842 RenderProcessHostWatcher::~RenderProcessHostWatcher() {
843 if (render_process_host_)
844 render_process_host_->RemoveObserver(this);
847 void RenderProcessHostWatcher::Wait() {
848 message_loop_runner_->Run();
851 void RenderProcessHostWatcher::RenderProcessExited(
852 RenderProcessHost* host,
853 base::TerminationStatus status,
854 int exit_code) {
855 did_exit_normally_ = status == base::TERMINATION_STATUS_NORMAL_TERMINATION;
856 if (type_ == WATCH_FOR_PROCESS_EXIT)
857 message_loop_runner_->Quit();
860 void RenderProcessHostWatcher::RenderProcessHostDestroyed(
861 RenderProcessHost* host) {
862 render_process_host_ = NULL;
863 if (type_ == WATCH_FOR_HOST_DESTRUCTION)
864 message_loop_runner_->Quit();
867 DOMMessageQueue::DOMMessageQueue() {
868 registrar_.Add(this, NOTIFICATION_DOM_OPERATION_RESPONSE,
869 NotificationService::AllSources());
872 DOMMessageQueue::~DOMMessageQueue() {}
874 void DOMMessageQueue::Observe(int type,
875 const NotificationSource& source,
876 const NotificationDetails& details) {
877 Details<DomOperationNotificationDetails> dom_op_details(details);
878 message_queue_.push(dom_op_details->json);
879 if (message_loop_runner_.get())
880 message_loop_runner_->Quit();
883 void DOMMessageQueue::ClearQueue() {
884 message_queue_ = std::queue<std::string>();
887 bool DOMMessageQueue::WaitForMessage(std::string* message) {
888 DCHECK(message);
889 if (message_queue_.empty()) {
890 // This will be quit when a new message comes in.
891 message_loop_runner_ = new MessageLoopRunner;
892 message_loop_runner_->Run();
894 // The queue should not be empty, unless we were quit because of a timeout.
895 if (message_queue_.empty())
896 return false;
897 *message = message_queue_.front();
898 message_queue_.pop();
899 return true;
902 class WebContentsAddedObserver::RenderViewCreatedObserver
903 : public WebContentsObserver {
904 public:
905 explicit RenderViewCreatedObserver(WebContents* web_contents)
906 : WebContentsObserver(web_contents),
907 render_view_created_called_(false),
908 main_frame_created_called_(false) {}
910 // WebContentsObserver:
911 void RenderViewCreated(RenderViewHost* rvh) override {
912 render_view_created_called_ = true;
915 void RenderFrameCreated(RenderFrameHost* rfh) override {
916 if (rfh == web_contents()->GetMainFrame())
917 main_frame_created_called_ = true;
920 bool render_view_created_called_;
921 bool main_frame_created_called_;
924 WebContentsAddedObserver::WebContentsAddedObserver()
925 : web_contents_created_callback_(
926 base::Bind(&WebContentsAddedObserver::WebContentsCreated,
927 base::Unretained(this))),
928 web_contents_(NULL) {
929 WebContentsImpl::FriendZone::AddCreatedCallbackForTesting(
930 web_contents_created_callback_);
933 WebContentsAddedObserver::~WebContentsAddedObserver() {
934 WebContentsImpl::FriendZone::RemoveCreatedCallbackForTesting(
935 web_contents_created_callback_);
938 void WebContentsAddedObserver::WebContentsCreated(WebContents* web_contents) {
939 DCHECK(!web_contents_);
940 web_contents_ = web_contents;
941 child_observer_.reset(new RenderViewCreatedObserver(web_contents));
943 if (runner_.get())
944 runner_->QuitClosure().Run();
947 WebContents* WebContentsAddedObserver::GetWebContents() {
948 if (web_contents_)
949 return web_contents_;
951 runner_ = new MessageLoopRunner();
952 runner_->Run();
953 return web_contents_;
956 bool WebContentsAddedObserver::RenderViewCreatedCalled() {
957 if (child_observer_) {
958 return child_observer_->render_view_created_called_ &&
959 child_observer_->main_frame_created_called_;
961 return false;
964 FrameWatcher::FrameWatcher()
965 : BrowserMessageFilter(ViewMsgStart), frames_to_wait_(0) {
968 FrameWatcher::~FrameWatcher() {
971 void FrameWatcher::ReceivedFrameSwap() {
972 --frames_to_wait_;
973 if (frames_to_wait_ == 0)
974 quit_.Run();
977 bool FrameWatcher::OnMessageReceived(const IPC::Message& message) {
978 if (message.type() == ViewHostMsg_SwapCompositorFrame::ID) {
979 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
980 base::Bind(&FrameWatcher::ReceivedFrameSwap, this));
982 return false;
985 void FrameWatcher::WaitFrames(int frames_to_wait) {
986 if (frames_to_wait <= 0)
987 return;
988 base::RunLoop run_loop;
989 base::AutoReset<base::Closure> reset_quit(&quit_, run_loop.QuitClosure());
990 base::AutoReset<int> reset_frames_to_wait(&frames_to_wait_, frames_to_wait);
991 run_loop.Run();
994 } // namespace content