Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_browsertest.cc
blob8cdfedfaa3c6d52715b2164eed65138b1b6c88f1
1 // Copyright 2013 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 "base/strings/utf_string_conversions.h"
6 #include "base/values.h"
7 #include "content/browser/frame_host/navigation_entry_impl.h"
8 #include "content/browser/web_contents/web_contents_impl.h"
9 #include "content/browser/web_contents/web_contents_view.h"
10 #include "content/common/frame_messages.h"
11 #include "content/public/browser/load_notification_details.h"
12 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_observer.h"
15 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "content/public/common/content_paths.h"
20 #include "content/public/test/browser_test_utils.h"
21 #include "content/public/test/content_browser_test.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/public/test/test_utils.h"
25 #include "content/shell/browser/shell.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/test/embedded_test_server/embedded_test_server.h"
29 namespace content {
31 void ResizeWebContentsView(Shell* shell, const gfx::Size& size,
32 bool set_start_page) {
33 // Shell::SizeTo is not implemented on Aura; WebContentsView::SizeContents
34 // works on Win and ChromeOS but not Linux - we need to resize the shell
35 // window on Linux because if we don't, the next layout of the unchanged shell
36 // window will resize WebContentsView back to the previous size.
37 // SizeContents is a hack and should not be relied on.
38 #if defined(OS_MACOSX)
39 shell->SizeTo(size);
40 // If |set_start_page| is true, start with blank page to make sure resize
41 // takes effect.
42 if (set_start_page)
43 NavigateToURL(shell, GURL("about://blank"));
44 #else
45 static_cast<WebContentsImpl*>(shell->web_contents())->GetView()->
46 SizeContents(size);
47 #endif // defined(OS_MACOSX)
50 class WebContentsImplBrowserTest : public ContentBrowserTest {
51 public:
52 WebContentsImplBrowserTest() {}
54 private:
55 DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest);
58 // Keeps track of data from LoadNotificationDetails so we can later verify that
59 // they are correct, after the LoadNotificationDetails object is deleted.
60 class LoadStopNotificationObserver : public WindowedNotificationObserver {
61 public:
62 LoadStopNotificationObserver(NavigationController* controller)
63 : WindowedNotificationObserver(NOTIFICATION_LOAD_STOP,
64 Source<NavigationController>(controller)),
65 session_index_(-1),
66 controller_(NULL) {
68 void Observe(int type,
69 const NotificationSource& source,
70 const NotificationDetails& details) override {
71 if (type == NOTIFICATION_LOAD_STOP) {
72 const Details<LoadNotificationDetails> load_details(details);
73 url_ = load_details->url;
74 session_index_ = load_details->session_index;
75 controller_ = load_details->controller;
77 WindowedNotificationObserver::Observe(type, source, details);
80 GURL url_;
81 int session_index_;
82 NavigationController* controller_;
85 // Starts a new navigation as soon as the current one commits, but does not
86 // wait for it to complete. This allows us to observe DidStopLoading while
87 // a pending entry is present.
88 class NavigateOnCommitObserver : public WebContentsObserver {
89 public:
90 NavigateOnCommitObserver(Shell* shell, GURL url)
91 : WebContentsObserver(shell->web_contents()),
92 shell_(shell),
93 url_(url),
94 done_(false) {
97 // WebContentsObserver:
98 void NavigationEntryCommitted(
99 const LoadCommittedDetails& load_details) override {
100 if (!done_) {
101 done_ = true;
102 shell_->Stop();
103 shell_->LoadURL(url_);
107 Shell* shell_;
108 GURL url_;
109 bool done_;
112 class RenderViewSizeDelegate : public WebContentsDelegate {
113 public:
114 void set_size_insets(const gfx::Size& size_insets) {
115 size_insets_ = size_insets;
118 // WebContentsDelegate:
119 gfx::Size GetSizeForNewRenderView(WebContents* web_contents) const override {
120 gfx::Size size(web_contents->GetContainerBounds().size());
121 size.Enlarge(size_insets_.width(), size_insets_.height());
122 return size;
125 private:
126 gfx::Size size_insets_;
129 class RenderViewSizeObserver : public WebContentsObserver {
130 public:
131 RenderViewSizeObserver(Shell* shell, const gfx::Size& wcv_new_size)
132 : WebContentsObserver(shell->web_contents()),
133 shell_(shell),
134 wcv_new_size_(wcv_new_size) {
137 // WebContentsObserver:
138 void RenderViewCreated(RenderViewHost* rvh) override {
139 rwhv_create_size_ = rvh->GetView()->GetViewBounds().size();
142 void DidStartNavigationToPendingEntry(
143 const GURL& url,
144 NavigationController::ReloadType reload_type) override {
145 ResizeWebContentsView(shell_, wcv_new_size_, false);
148 gfx::Size rwhv_create_size() const { return rwhv_create_size_; }
150 private:
151 Shell* shell_; // Weak ptr.
152 gfx::Size wcv_new_size_;
153 gfx::Size rwhv_create_size_;
156 class LoadingStateChangedDelegate : public WebContentsDelegate {
157 public:
158 LoadingStateChangedDelegate()
159 : loadingStateChangedCount_(0)
160 , loadingStateToDifferentDocumentCount_(0) {
163 // WebContentsDelegate:
164 void LoadingStateChanged(WebContents* contents,
165 bool to_different_document) override {
166 loadingStateChangedCount_++;
167 if (to_different_document)
168 loadingStateToDifferentDocumentCount_++;
171 int loadingStateChangedCount() const { return loadingStateChangedCount_; }
172 int loadingStateToDifferentDocumentCount() const {
173 return loadingStateToDifferentDocumentCount_;
176 private:
177 int loadingStateChangedCount_;
178 int loadingStateToDifferentDocumentCount_;
181 // See: http://crbug.com/298193
182 #if defined(OS_WIN) || defined(OS_LINUX)
183 #define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
184 #else
185 #define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
186 #endif
188 // Test that DidStopLoading includes the correct URL in the details.
189 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
190 MAYBE_DidStopLoadingDetails) {
191 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
193 LoadStopNotificationObserver load_observer(
194 &shell()->web_contents()->GetController());
195 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
196 load_observer.Wait();
198 EXPECT_EQ("/title1.html", load_observer.url_.path());
199 EXPECT_EQ(0, load_observer.session_index_);
200 EXPECT_EQ(&shell()->web_contents()->GetController(),
201 load_observer.controller_);
204 // See: http://crbug.com/298193
205 #if defined(OS_WIN) || defined(OS_LINUX)
206 #define MAYBE_DidStopLoadingDetailsWithPending \
207 DISABLED_DidStopLoadingDetailsWithPending
208 #else
209 #define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending
210 #endif
212 // Test that DidStopLoading includes the correct URL in the details when a
213 // pending entry is present.
214 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
215 MAYBE_DidStopLoadingDetailsWithPending) {
216 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
217 GURL url("data:text/html,<div>test</div>");
219 // Listen for the first load to stop.
220 LoadStopNotificationObserver load_observer(
221 &shell()->web_contents()->GetController());
222 // Start a new pending navigation as soon as the first load commits.
223 // We will hear a DidStopLoading from the first load as the new load
224 // is started.
225 NavigateOnCommitObserver commit_observer(
226 shell(), embedded_test_server()->GetURL("/title2.html"));
227 NavigateToURL(shell(), url);
228 load_observer.Wait();
230 EXPECT_EQ(url, load_observer.url_);
231 EXPECT_EQ(0, load_observer.session_index_);
232 EXPECT_EQ(&shell()->web_contents()->GetController(),
233 load_observer.controller_);
235 // Test that a renderer-initiated navigation to an invalid URL does not leave
236 // around a pending entry that could be used in a URL spoof. We test this in
237 // a browser test because our unit test framework incorrectly calls
238 // DidStartProvisionalLoadForFrame for in-page navigations.
239 // See http://crbug.com/280512.
240 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
241 ClearNonVisiblePendingOnFail) {
242 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
244 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
246 // Navigate to an invalid URL and make sure it doesn't leave a pending entry.
247 LoadStopNotificationObserver load_observer1(
248 &shell()->web_contents()->GetController());
249 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
250 "window.location.href=\"nonexistent:12121\";"));
251 load_observer1.Wait();
252 EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
254 LoadStopNotificationObserver load_observer2(
255 &shell()->web_contents()->GetController());
256 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
257 "window.location.href=\"#foo\";"));
258 load_observer2.Wait();
259 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html#foo"),
260 shell()->web_contents()->GetVisibleURL());
263 // Crashes under ThreadSanitizer, http://crbug.com/356758.
264 #if defined(OS_WIN) || defined(OS_ANDROID) \
265 || defined(THREAD_SANITIZER)
266 #define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
267 #else
268 #define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView
269 #endif
270 // Test that RenderViewHost is created and updated at the size specified by
271 // WebContentsDelegate::GetSizeForNewRenderView().
272 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
273 MAYBE_GetSizeForNewRenderView) {
274 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
275 // Create a new server with a different site.
276 net::SpawnedTestServer https_server(
277 net::SpawnedTestServer::TYPE_HTTPS,
278 net::SpawnedTestServer::kLocalhost,
279 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
280 ASSERT_TRUE(https_server.Start());
282 scoped_ptr<RenderViewSizeDelegate> delegate(new RenderViewSizeDelegate());
283 shell()->web_contents()->SetDelegate(delegate.get());
284 ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get());
286 // When no size is set, RenderWidgetHostView adopts the size of
287 // WebContentsView.
288 NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"));
289 EXPECT_EQ(shell()->web_contents()->GetContainerBounds().size(),
290 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
291 size());
293 // When a size is set, RenderWidgetHostView and WebContentsView honor this
294 // size.
295 gfx::Size size(300, 300);
296 gfx::Size size_insets(10, 15);
297 ResizeWebContentsView(shell(), size, true);
298 delegate->set_size_insets(size_insets);
299 NavigateToURL(shell(), https_server.GetURL("/"));
300 size.Enlarge(size_insets.width(), size_insets.height());
301 EXPECT_EQ(size,
302 shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
303 size());
304 // The web_contents size is set by the embedder, and should not depend on the
305 // rwhv size. The behavior is correct on OSX, but incorrect on other
306 // platforms.
307 gfx::Size exp_wcv_size(300, 300);
308 #if !defined(OS_MACOSX)
309 exp_wcv_size.Enlarge(size_insets.width(), size_insets.height());
310 #endif
312 EXPECT_EQ(exp_wcv_size,
313 shell()->web_contents()->GetContainerBounds().size());
315 // If WebContentsView is resized after RenderWidgetHostView is created but
316 // before pending navigation entry is committed, both RenderWidgetHostView and
317 // WebContentsView use the new size of WebContentsView.
318 gfx::Size init_size(200, 200);
319 gfx::Size new_size(100, 100);
320 size_insets = gfx::Size(20, 30);
321 ResizeWebContentsView(shell(), init_size, true);
322 delegate->set_size_insets(size_insets);
323 RenderViewSizeObserver observer(shell(), new_size);
324 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
325 // RenderWidgetHostView is created at specified size.
326 init_size.Enlarge(size_insets.width(), size_insets.height());
327 EXPECT_EQ(init_size, observer.rwhv_create_size());
329 // Once again, the behavior is correct on OSX. The embedder explicitly sets
330 // the size to (100,100) during navigation. Both the wcv and the rwhv should
331 // take on that size.
332 #if !defined(OS_MACOSX)
333 new_size.Enlarge(size_insets.width(), size_insets.height());
334 #endif
335 gfx::Size actual_size = shell()->web_contents()->GetRenderWidgetHostView()->
336 GetViewBounds().size();
338 EXPECT_EQ(new_size, actual_size);
339 EXPECT_EQ(new_size, shell()->web_contents()->GetContainerBounds().size());
342 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
343 // Navigate to a page with frames and grab a subframe's FrameTreeNode ID.
344 ASSERT_TRUE(test_server()->Start());
345 NavigateToURL(shell(),
346 test_server()->GetURL("files/frame_tree/top.html"));
347 WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
348 FrameTreeNode* root = wc->GetFrameTree()->root();
349 ASSERT_EQ(3UL, root->child_count());
350 int64 frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
351 EXPECT_NE(-1, frame_tree_node_id);
353 // Navigate with the subframe's FrameTreeNode ID.
354 const GURL url(test_server()->GetURL("files/title1.html"));
355 OpenURLParams params(url, Referrer(), frame_tree_node_id, CURRENT_TAB,
356 ui::PAGE_TRANSITION_LINK, true);
357 shell()->web_contents()->OpenURL(params);
359 // Make sure the NavigationEntry ends up with the FrameTreeNode ID.
360 NavigationController* controller = &shell()->web_contents()->GetController();
361 EXPECT_TRUE(controller->GetPendingEntry());
362 EXPECT_EQ(frame_tree_node_id,
363 NavigationEntryImpl::FromNavigationEntry(
364 controller->GetPendingEntry())->frame_tree_node_id());
367 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
368 AppendingFrameInWebUIDoesNotCrash) {
369 const GURL kWebUIUrl("chrome://tracing");
370 const char kJSCodeForAppendingFrame[] =
371 "document.body.appendChild(document.createElement('iframe'));";
373 NavigateToURL(shell(), kWebUIUrl);
375 bool js_executed = content::ExecuteScript(shell()->web_contents(),
376 kJSCodeForAppendingFrame);
377 EXPECT_TRUE(js_executed);
380 // Observer class to track the creation of RenderFrameHost objects. It is used
381 // in subsequent tests.
382 class RenderFrameCreatedObserver : public WebContentsObserver {
383 public:
384 RenderFrameCreatedObserver(Shell* shell)
385 : WebContentsObserver(shell->web_contents()),
386 last_rfh_(NULL) {
389 void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
390 last_rfh_ = render_frame_host;
393 RenderFrameHost* last_rfh() const { return last_rfh_; }
395 private:
396 RenderFrameHost* last_rfh_;
398 DISALLOW_COPY_AND_ASSIGN(RenderFrameCreatedObserver);
401 // Test that creation of new RenderFrameHost objects sends the correct object
402 // to the WebContentObservers. See http://crbug.com/347339.
403 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
404 RenderFrameCreatedCorrectProcessForObservers) {
405 static const char kFooCom[] = "foo.com";
406 GURL::Replacements replace_host;
407 net::HostPortPair foo_host_port;
408 GURL cross_site_url;
410 // Setup the server to allow serving separate sites, so we can perform
411 // cross-process navigation.
412 host_resolver()->AddRule("*", "127.0.0.1");
413 ASSERT_TRUE(test_server()->Start());
415 foo_host_port = test_server()->host_port_pair();
416 foo_host_port.set_host(kFooCom);
418 GURL initial_url(test_server()->GetURL("/title1.html"));
420 cross_site_url = test_server()->GetURL("/title2.html");
421 replace_host.SetHostStr(kFooCom);
422 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
424 // Navigate to the initial URL and capture the RenderFrameHost for later
425 // comparison.
426 NavigateToURL(shell(), initial_url);
427 RenderFrameHost* orig_rfh = shell()->web_contents()->GetMainFrame();
429 // Install the observer and navigate cross-site.
430 RenderFrameCreatedObserver observer(shell());
431 NavigateToURL(shell(), cross_site_url);
433 // The observer should've seen a RenderFrameCreated call for the new frame
434 // and not the old one.
435 EXPECT_NE(observer.last_rfh(), orig_rfh);
436 EXPECT_EQ(observer.last_rfh(), shell()->web_contents()->GetMainFrame());
439 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
440 LoadingStateChangedForSameDocumentNavigation) {
441 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
442 scoped_ptr<LoadingStateChangedDelegate> delegate(
443 new LoadingStateChangedDelegate());
444 shell()->web_contents()->SetDelegate(delegate.get());
446 LoadStopNotificationObserver load_observer(
447 &shell()->web_contents()->GetController());
448 TitleWatcher title_watcher(shell()->web_contents(),
449 base::ASCIIToUTF16("pushState"));
450 NavigateToURL(shell(), embedded_test_server()->GetURL("/push_state.html"));
451 load_observer.Wait();
452 base::string16 title = title_watcher.WaitAndGetTitle();
453 ASSERT_EQ(title, base::ASCIIToUTF16("pushState"));
455 // LoadingStateChanged should be called 4 times: start and stop for the
456 // initial load of push_state.html, and start and stop for the "navigation"
457 // triggered by history.pushState(). However, the start notification for the
458 // history.pushState() navigation should set to_different_document to false.
459 EXPECT_EQ("pushState", shell()->web_contents()->GetLastCommittedURL().ref());
460 EXPECT_EQ(4, delegate->loadingStateChangedCount());
461 EXPECT_EQ(3, delegate->loadingStateToDifferentDocumentCount());
464 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
465 RenderViewCreatedForChildWindow) {
466 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
468 NavigateToURL(shell(),
469 embedded_test_server()->GetURL("/title1.html"));
471 WebContentsAddedObserver new_web_contents_observer;
472 ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
473 "var a = document.createElement('a');"
474 "a.href='./title2.html';"
475 "a.target = '_blank';"
476 "document.body.appendChild(a);"
477 "a.click();"));
478 WebContents* new_web_contents = new_web_contents_observer.GetWebContents();
479 WaitForLoadStop(new_web_contents);
480 EXPECT_TRUE(new_web_contents_observer.RenderViewCreatedCalled());
483 struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
484 public WebContentsObserver {
485 LoadProgressDelegateAndObserver(Shell* shell)
486 : WebContentsObserver(shell->web_contents()),
487 did_start_loading(false),
488 did_stop_loading(false) {
489 web_contents()->SetDelegate(this);
492 // WebContentsDelegate:
493 void LoadProgressChanged(WebContents* source, double progress) override {
494 EXPECT_TRUE(did_start_loading);
495 EXPECT_FALSE(did_stop_loading);
496 progresses.push_back(progress);
499 // WebContentsObserver:
500 void DidStartLoading() override {
501 EXPECT_FALSE(did_start_loading);
502 EXPECT_EQ(0U, progresses.size());
503 EXPECT_FALSE(did_stop_loading);
504 did_start_loading = true;
507 void DidStopLoading() override {
508 EXPECT_TRUE(did_start_loading);
509 EXPECT_GE(progresses.size(), 1U);
510 EXPECT_FALSE(did_stop_loading);
511 did_stop_loading = true;
514 bool did_start_loading;
515 std::vector<double> progresses;
516 bool did_stop_loading;
519 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgress) {
520 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
521 scoped_ptr<LoadProgressDelegateAndObserver> delegate(
522 new LoadProgressDelegateAndObserver(shell()));
524 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
526 const std::vector<double>& progresses = delegate->progresses;
527 // All updates should be in order ...
528 if (std::adjacent_find(progresses.begin(),
529 progresses.end(),
530 std::greater<double>()) != progresses.end()) {
531 ADD_FAILURE() << "Progress values should be in order: "
532 << ::testing::PrintToString(progresses);
535 // ... and the last one should be 1.0, meaning complete.
536 ASSERT_GE(progresses.size(), 1U)
537 << "There should be at least one progress update";
538 EXPECT_EQ(1.0, *progresses.rbegin());
541 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgressWithFrames) {
542 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
543 scoped_ptr<LoadProgressDelegateAndObserver> delegate(
544 new LoadProgressDelegateAndObserver(shell()));
546 NavigateToURL(shell(),
547 embedded_test_server()->GetURL("/frame_tree/top.html"));
549 const std::vector<double>& progresses = delegate->progresses;
550 // All updates should be in order ...
551 if (std::adjacent_find(progresses.begin(),
552 progresses.end(),
553 std::greater<double>()) != progresses.end()) {
554 ADD_FAILURE() << "Progress values should be in order: "
555 << ::testing::PrintToString(progresses);
558 // ... and the last one should be 1.0, meaning complete.
559 ASSERT_GE(progresses.size(), 1U)
560 << "There should be at least one progress update";
561 EXPECT_EQ(1.0, *progresses.rbegin());
564 // Ensure that a new navigation that interrupts a pending one will still fire
565 // a DidStopLoading. See http://crbug.com/429399.
566 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
567 LoadProgressAfterInterruptedNav) {
568 host_resolver()->AddRule("*", "127.0.0.1");
569 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
571 // Start at a real page.
572 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
574 // Simulate a navigation that has not completed.
575 scoped_ptr<LoadProgressDelegateAndObserver> delegate(
576 new LoadProgressDelegateAndObserver(shell()));
577 RenderFrameHost* main_frame = shell()->web_contents()->GetMainFrame();
578 FrameHostMsg_DidStartLoading start_msg(main_frame->GetRoutingID(), true);
579 static_cast<WebContentsImpl*>(shell()->web_contents())->OnMessageReceived(
580 main_frame, start_msg);
581 EXPECT_TRUE(delegate->did_start_loading);
582 EXPECT_FALSE(delegate->did_stop_loading);
584 // Also simulate a DidChangeLoadProgress, but not a DidStopLoading.
585 FrameHostMsg_DidChangeLoadProgress progress_msg(main_frame->GetRoutingID(),
586 1.0);
587 static_cast<WebContentsImpl*>(shell()->web_contents())->OnMessageReceived(
588 main_frame, progress_msg);
589 EXPECT_TRUE(delegate->did_start_loading);
590 EXPECT_FALSE(delegate->did_stop_loading);
592 // Now interrupt with a new cross-process navigation.
593 TestNavigationObserver tab_observer(shell()->web_contents(), 1);
594 GURL url(embedded_test_server()->GetURL("foo.com", "/title2.html"));
595 shell()->LoadURL(url);
596 tab_observer.Wait();
597 EXPECT_EQ(url, shell()->web_contents()->GetLastCommittedURL());
599 // We should have gotten to DidStopLoading.
600 EXPECT_TRUE(delegate->did_stop_loading);
603 struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
604 FirstVisuallyNonEmptyPaintObserver(Shell* shell)
605 : WebContentsObserver(shell->web_contents()),
606 did_fist_visually_non_empty_paint_(false) {}
608 void DidFirstVisuallyNonEmptyPaint() override {
609 did_fist_visually_non_empty_paint_ = true;
610 on_did_first_visually_non_empty_paint_.Run();
613 void WaitForDidFirstVisuallyNonEmptyPaint() {
614 if (did_fist_visually_non_empty_paint_)
615 return;
616 base::RunLoop run_loop;
617 on_did_first_visually_non_empty_paint_ = run_loop.QuitClosure();
618 run_loop.Run();
621 base::Closure on_did_first_visually_non_empty_paint_;
622 bool did_fist_visually_non_empty_paint_;
625 // See: http://crbug.com/395664
626 #if defined(OS_ANDROID)
627 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
628 #else
629 // http://crbug.com/398471
630 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
631 #endif
632 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
633 MAYBE_FirstVisuallyNonEmptyPaint) {
634 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
635 scoped_ptr<FirstVisuallyNonEmptyPaintObserver> observer(
636 new FirstVisuallyNonEmptyPaintObserver(shell()));
638 NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
640 observer->WaitForDidFirstVisuallyNonEmptyPaint();
641 ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
644 } // namespace content