Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / browser / web_contents / web_contents_impl_browsertest.cc
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.
4
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/public/browser/load_notification_details.h"
11 #include "content/public/browser/navigation_controller.h"
12 #include "content/public/browser/notification_details.h"
13 #include "content/public/browser/notification_observer.h"
14 #include "content/public/browser/notification_types.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/render_widget_host_view.h"
17 #include "content/public/browser/web_contents_observer.h"
18 #include "content/public/common/content_paths.h"
19 #include "content/public/test/browser_test_utils.h"
20 #include "content/public/test/content_browser_test.h"
21 #include "content/public/test/content_browser_test_utils.h"
22 #include "content/public/test/test_utils.h"
23 #include "content/shell/browser/shell.h"
24 #include "net/dns/mock_host_resolver.h"
25 #include "net/test/embedded_test_server/embedded_test_server.h"
26
27 namespace content {
28
29 void ResizeWebContentsView(Shell* shell, const gfx::Size& size,
30                            bool set_start_page) {
31   // Shell::SizeTo is not implemented on Aura; WebContentsView::SizeContents
32   // works on Win and ChromeOS but not Linux - we need to resize the shell
33   // window on Linux because if we don't, the next layout of the unchanged shell
34   // window will resize WebContentsView back to the previous size.
35   // SizeContents is a hack and should not be relied on.
36 #if defined(OS_MACOSX)
37   shell->SizeTo(size);
38   // If |set_start_page| is true, start with blank page to make sure resize
39   // takes effect.
40   if (set_start_page)
41     NavigateToURL(shell, GURL("about://blank"));
42 #else
43   static_cast<WebContentsImpl*>(shell->web_contents())->GetView()->
44       SizeContents(size);
45 #endif  // defined(OS_MACOSX)
46 }
47
48 class WebContentsImplBrowserTest : public ContentBrowserTest {
49  public:
50   WebContentsImplBrowserTest() {}
51
52  private:
53   DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest);
54 };
55
56 // Keeps track of data from LoadNotificationDetails so we can later verify that
57 // they are correct, after the LoadNotificationDetails object is deleted.
58 class LoadStopNotificationObserver : public WindowedNotificationObserver {
59  public:
60   LoadStopNotificationObserver(NavigationController* controller)
61       : WindowedNotificationObserver(NOTIFICATION_LOAD_STOP,
62                                      Source<NavigationController>(controller)),
63         session_index_(-1),
64         controller_(NULL) {
65   }
66   virtual void Observe(int type,
67                        const NotificationSource& source,
68                        const NotificationDetails& details) OVERRIDE {
69     if (type == NOTIFICATION_LOAD_STOP) {
70       const Details<LoadNotificationDetails> load_details(details);
71       url_ = load_details->url;
72       session_index_ = load_details->session_index;
73       controller_ = load_details->controller;
74     }
75     WindowedNotificationObserver::Observe(type, source, details);
76   }
77
78   GURL url_;
79   int session_index_;
80   NavigationController* controller_;
81 };
82
83 // Starts a new navigation as soon as the current one commits, but does not
84 // wait for it to complete.  This allows us to observe DidStopLoading while
85 // a pending entry is present.
86 class NavigateOnCommitObserver : public WebContentsObserver {
87  public:
88   NavigateOnCommitObserver(Shell* shell, GURL url)
89       : WebContentsObserver(shell->web_contents()),
90         shell_(shell),
91         url_(url),
92         done_(false) {
93   }
94
95   // WebContentsObserver:
96   virtual void NavigationEntryCommitted(
97       const LoadCommittedDetails& load_details) OVERRIDE {
98     if (!done_) {
99       done_ = true;
100       shell_->Stop();
101       shell_->LoadURL(url_);
102     }
103   }
104
105   Shell* shell_;
106   GURL url_;
107   bool done_;
108 };
109
110 class RenderViewSizeDelegate : public WebContentsDelegate {
111  public:
112   void set_size_insets(const gfx::Size& size_insets) {
113     size_insets_ = size_insets;
114   }
115
116   // WebContentsDelegate:
117   virtual gfx::Size GetSizeForNewRenderView(
118       WebContents* web_contents) const OVERRIDE {
119     gfx::Size size(web_contents->GetContainerBounds().size());
120     size.Enlarge(size_insets_.width(), size_insets_.height());
121     return size;
122   }
123
124  private:
125   gfx::Size size_insets_;
126 };
127
128 class RenderViewSizeObserver : public WebContentsObserver {
129  public:
130   RenderViewSizeObserver(Shell* shell, const gfx::Size& wcv_new_size)
131       : WebContentsObserver(shell->web_contents()),
132         shell_(shell),
133         wcv_new_size_(wcv_new_size) {
134   }
135
136   // WebContentsObserver:
137   virtual void RenderViewCreated(RenderViewHost* rvh) OVERRIDE {
138     rwhv_create_size_ = rvh->GetView()->GetViewBounds().size();
139   }
140
141   virtual void DidStartNavigationToPendingEntry(
142       const GURL& url,
143       NavigationController::ReloadType reload_type) OVERRIDE {
144     ResizeWebContentsView(shell_, wcv_new_size_, false);
145   }
146
147   gfx::Size rwhv_create_size() const { return rwhv_create_size_; }
148
149  private:
150   Shell* shell_;  // Weak ptr.
151   gfx::Size wcv_new_size_;
152   gfx::Size rwhv_create_size_;
153 };
154
155 class LoadingStateChangedDelegate : public WebContentsDelegate {
156  public:
157   LoadingStateChangedDelegate()
158       : loadingStateChangedCount_(0)
159       , loadingStateToDifferentDocumentCount_(0) {
160   }
161
162   // WebContentsDelegate:
163   virtual void LoadingStateChanged(WebContents* contents,
164                                    bool to_different_document) OVERRIDE {
165       loadingStateChangedCount_++;
166       if (to_different_document)
167         loadingStateToDifferentDocumentCount_++;
168   }
169
170   int loadingStateChangedCount() const { return loadingStateChangedCount_; }
171   int loadingStateToDifferentDocumentCount() const {
172     return loadingStateToDifferentDocumentCount_;
173   }
174
175  private:
176   int loadingStateChangedCount_;
177   int loadingStateToDifferentDocumentCount_;
178 };
179
180 // See: http://crbug.com/298193
181 #if defined(OS_WIN)
182 #define MAYBE_DidStopLoadingDetails DISABLED_DidStopLoadingDetails
183 #else
184 #define MAYBE_DidStopLoadingDetails DidStopLoadingDetails
185 #endif
186
187 // Test that DidStopLoading includes the correct URL in the details.
188 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
189                        MAYBE_DidStopLoadingDetails) {
190   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
191
192   LoadStopNotificationObserver load_observer(
193       &shell()->web_contents()->GetController());
194   NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
195   load_observer.Wait();
196
197   EXPECT_EQ("/title1.html", load_observer.url_.path());
198   EXPECT_EQ(0, load_observer.session_index_);
199   EXPECT_EQ(&shell()->web_contents()->GetController(),
200             load_observer.controller_);
201 }
202
203 // See: http://crbug.com/298193
204 #if defined(OS_WIN)
205 #define MAYBE_DidStopLoadingDetailsWithPending \
206   DISABLED_DidStopLoadingDetailsWithPending
207 #else
208 #define MAYBE_DidStopLoadingDetailsWithPending DidStopLoadingDetailsWithPending
209 #endif
210
211 // Test that DidStopLoading includes the correct URL in the details when a
212 // pending entry is present.
213 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
214                        MAYBE_DidStopLoadingDetailsWithPending) {
215   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
216   GURL url("data:text/html,<div>test</div>");
217
218   // Listen for the first load to stop.
219   LoadStopNotificationObserver load_observer(
220       &shell()->web_contents()->GetController());
221   // Start a new pending navigation as soon as the first load commits.
222   // We will hear a DidStopLoading from the first load as the new load
223   // is started.
224   NavigateOnCommitObserver commit_observer(
225       shell(), embedded_test_server()->GetURL("/title2.html"));
226   NavigateToURL(shell(), url);
227   load_observer.Wait();
228
229   EXPECT_EQ(url, load_observer.url_);
230   EXPECT_EQ(0, load_observer.session_index_);
231   EXPECT_EQ(&shell()->web_contents()->GetController(),
232             load_observer.controller_);
233 }
234 // Test that a renderer-initiated navigation to an invalid URL does not leave
235 // around a pending entry that could be used in a URL spoof.  We test this in
236 // a browser test because our unit test framework incorrectly calls
237 // DidStartProvisionalLoadForFrame for in-page navigations.
238 // See http://crbug.com/280512.
239 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
240                        ClearNonVisiblePendingOnFail) {
241   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
242
243   NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
244
245   // Navigate to an invalid URL and make sure it doesn't leave a pending entry.
246   LoadStopNotificationObserver load_observer1(
247       &shell()->web_contents()->GetController());
248   ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
249                             "window.location.href=\"nonexistent:12121\";"));
250   load_observer1.Wait();
251   EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
252
253   LoadStopNotificationObserver load_observer2(
254       &shell()->web_contents()->GetController());
255   ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
256                             "window.location.href=\"#foo\";"));
257   load_observer2.Wait();
258   EXPECT_EQ(embedded_test_server()->GetURL("/title1.html#foo"),
259             shell()->web_contents()->GetVisibleURL());
260 }
261
262 // Crashes under ThreadSanitizer, http://crbug.com/356758.
263 #if defined(OS_WIN) || defined(OS_ANDROID) \
264     || defined(THREAD_SANITIZER)
265 #define MAYBE_GetSizeForNewRenderView DISABLED_GetSizeForNewRenderView
266 #else
267 #define MAYBE_GetSizeForNewRenderView GetSizeForNewRenderView
268 #endif
269 // Test that RenderViewHost is created and updated at the size specified by
270 // WebContentsDelegate::GetSizeForNewRenderView().
271 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
272                        MAYBE_GetSizeForNewRenderView) {
273   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
274   // Create a new server with a different site.
275   net::SpawnedTestServer https_server(
276       net::SpawnedTestServer::TYPE_HTTPS,
277       net::SpawnedTestServer::kLocalhost,
278       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
279   ASSERT_TRUE(https_server.Start());
280
281   scoped_ptr<RenderViewSizeDelegate> delegate(new RenderViewSizeDelegate());
282   shell()->web_contents()->SetDelegate(delegate.get());
283   ASSERT_TRUE(shell()->web_contents()->GetDelegate() == delegate.get());
284
285   // When no size is set, RenderWidgetHostView adopts the size of
286   // WebContentsView.
287   NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html"));
288   EXPECT_EQ(shell()->web_contents()->GetContainerBounds().size(),
289             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
290                 size());
291
292   // When a size is set, RenderWidgetHostView and WebContentsView honor this
293   // size.
294   gfx::Size size(300, 300);
295   gfx::Size size_insets(10, 15);
296   ResizeWebContentsView(shell(), size, true);
297   delegate->set_size_insets(size_insets);
298   NavigateToURL(shell(), https_server.GetURL("/"));
299   size.Enlarge(size_insets.width(), size_insets.height());
300   EXPECT_EQ(size,
301             shell()->web_contents()->GetRenderWidgetHostView()->GetViewBounds().
302                 size());
303   // The web_contents size is set by the embedder, and should not depend on the
304   // rwhv size. The behavior is correct on OSX, but incorrect on other
305   // platforms.
306   gfx::Size exp_wcv_size(300, 300);
307 #if !defined(OS_MACOSX)
308   exp_wcv_size.Enlarge(size_insets.width(), size_insets.height());
309 #endif
310
311   EXPECT_EQ(exp_wcv_size,
312             shell()->web_contents()->GetContainerBounds().size());
313
314   // If WebContentsView is resized after RenderWidgetHostView is created but
315   // before pending navigation entry is committed, both RenderWidgetHostView and
316   // WebContentsView use the new size of WebContentsView.
317   gfx::Size init_size(200, 200);
318   gfx::Size new_size(100, 100);
319   size_insets = gfx::Size(20, 30);
320   ResizeWebContentsView(shell(), init_size, true);
321   delegate->set_size_insets(size_insets);
322   RenderViewSizeObserver observer(shell(), new_size);
323   NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
324   // RenderWidgetHostView is created at specified size.
325   init_size.Enlarge(size_insets.width(), size_insets.height());
326   EXPECT_EQ(init_size, observer.rwhv_create_size());
327
328 // Once again, the behavior is correct on OSX. The embedder explicitly sets
329 // the size to (100,100) during navigation. Both the wcv and the rwhv should
330 // take on that size.
331 #if !defined(OS_MACOSX)
332   new_size.Enlarge(size_insets.width(), size_insets.height());
333 #endif
334   gfx::Size actual_size = shell()->web_contents()->GetRenderWidgetHostView()->
335       GetViewBounds().size();
336
337   EXPECT_EQ(new_size, actual_size);
338   EXPECT_EQ(new_size, shell()->web_contents()->GetContainerBounds().size());
339 }
340
341 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, OpenURLSubframe) {
342   // Navigate to a page with frames and grab a subframe's FrameTreeNode ID.
343   ASSERT_TRUE(test_server()->Start());
344   NavigateToURL(shell(),
345                 test_server()->GetURL("files/frame_tree/top.html"));
346   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
347   FrameTreeNode* root = wc->GetFrameTree()->root();
348   ASSERT_EQ(3UL, root->child_count());
349   int64 frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
350   EXPECT_NE(-1, frame_tree_node_id);
351
352   // Navigate with the subframe's FrameTreeNode ID.
353   const GURL url(test_server()->GetURL("files/title1.html"));
354   OpenURLParams params(url, Referrer(), frame_tree_node_id, CURRENT_TAB,
355                        ui::PAGE_TRANSITION_LINK, true);
356   shell()->web_contents()->OpenURL(params);
357
358   // Make sure the NavigationEntry ends up with the FrameTreeNode ID.
359   NavigationController* controller = &shell()->web_contents()->GetController();
360   EXPECT_TRUE(controller->GetPendingEntry());
361   EXPECT_EQ(frame_tree_node_id,
362             NavigationEntryImpl::FromNavigationEntry(
363                 controller->GetPendingEntry())->frame_tree_node_id());
364 }
365
366 // Observer class to track the creation of RenderFrameHost objects. It is used
367 // in subsequent tests.
368 class RenderFrameCreatedObserver : public WebContentsObserver {
369  public:
370   RenderFrameCreatedObserver(Shell* shell)
371       : WebContentsObserver(shell->web_contents()),
372         last_rfh_(NULL) {
373   }
374
375   virtual void RenderFrameCreated(RenderFrameHost* render_frame_host) OVERRIDE {
376     last_rfh_ = render_frame_host;
377   }
378
379   RenderFrameHost* last_rfh() const { return last_rfh_; }
380
381  private:
382   RenderFrameHost* last_rfh_;
383
384   DISALLOW_COPY_AND_ASSIGN(RenderFrameCreatedObserver);
385 };
386
387 // Test that creation of new RenderFrameHost objects sends the correct object
388 // to the WebContentObservers. See http://crbug.com/347339.
389 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
390                        RenderFrameCreatedCorrectProcessForObservers) {
391   std::string foo_com("foo.com");
392   GURL::Replacements replace_host;
393   net::HostPortPair foo_host_port;
394   GURL cross_site_url;
395
396   // Setup the server to allow serving separate sites, so we can perform
397   // cross-process navigation.
398   host_resolver()->AddRule("*", "127.0.0.1");
399   ASSERT_TRUE(test_server()->Start());
400
401   foo_host_port = test_server()->host_port_pair();
402   foo_host_port.set_host(foo_com);
403
404   GURL initial_url(test_server()->GetURL("/title1.html"));
405
406   cross_site_url = test_server()->GetURL("/title2.html");
407   replace_host.SetHostStr(foo_com);
408   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
409
410   // Navigate to the initial URL and capture the RenderFrameHost for later
411   // comparison.
412   NavigateToURL(shell(), initial_url);
413   RenderFrameHost* orig_rfh = shell()->web_contents()->GetMainFrame();
414
415   // Install the observer and navigate cross-site.
416   RenderFrameCreatedObserver observer(shell());
417   NavigateToURL(shell(), cross_site_url);
418
419   // The observer should've seen a RenderFrameCreated call for the new frame
420   // and not the old one.
421   EXPECT_NE(observer.last_rfh(), orig_rfh);
422   EXPECT_EQ(observer.last_rfh(), shell()->web_contents()->GetMainFrame());
423 }
424
425 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
426                        LoadingStateChangedForSameDocumentNavigation) {
427   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
428   scoped_ptr<LoadingStateChangedDelegate> delegate(
429       new LoadingStateChangedDelegate());
430   shell()->web_contents()->SetDelegate(delegate.get());
431
432   LoadStopNotificationObserver load_observer(
433       &shell()->web_contents()->GetController());
434   TitleWatcher title_watcher(shell()->web_contents(),
435                              base::ASCIIToUTF16("pushState"));
436   NavigateToURL(shell(), embedded_test_server()->GetURL("/push_state.html"));
437   load_observer.Wait();
438   base::string16 title = title_watcher.WaitAndGetTitle();
439   ASSERT_EQ(title, base::ASCIIToUTF16("pushState"));
440
441   // LoadingStateChanged should be called 4 times: start and stop for the
442   // initial load of push_state.html, and start and stop for the "navigation"
443   // triggered by history.pushState(). However, the start notification for the
444   // history.pushState() navigation should set to_different_document to false.
445   EXPECT_EQ("pushState", shell()->web_contents()->GetURL().ref());
446   EXPECT_EQ(4, delegate->loadingStateChangedCount());
447   EXPECT_EQ(3, delegate->loadingStateToDifferentDocumentCount());
448 }
449
450 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
451                        RenderViewCreatedForChildWindow) {
452   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
453
454   NavigateToURL(shell(),
455                 embedded_test_server()->GetURL("/title1.html"));
456
457   WebContentsAddedObserver new_web_contents_observer;
458   ASSERT_TRUE(ExecuteScript(shell()->web_contents(),
459                             "var a = document.createElement('a');"
460                             "a.href='./title2.html';"
461                             "a.target = '_blank';"
462                             "document.body.appendChild(a);"
463                             "a.click();"));
464   WebContents* new_web_contents = new_web_contents_observer.GetWebContents();
465   WaitForLoadStop(new_web_contents);
466   EXPECT_TRUE(new_web_contents_observer.RenderViewCreatedCalled());
467 }
468
469 struct LoadProgressDelegateAndObserver : public WebContentsDelegate,
470                                          public WebContentsObserver {
471   LoadProgressDelegateAndObserver(Shell* shell)
472       : WebContentsObserver(shell->web_contents()),
473         did_start_loading(false),
474         did_stop_loading(false) {
475     web_contents()->SetDelegate(this);
476   }
477
478   // WebContentsDelegate:
479   virtual void LoadProgressChanged(WebContents* source,
480                                    double progress) OVERRIDE {
481     EXPECT_TRUE(did_start_loading);
482     EXPECT_FALSE(did_stop_loading);
483     progresses.push_back(progress);
484   }
485
486   // WebContentsObserver:
487   virtual void DidStartLoading(RenderViewHost* render_view_host) OVERRIDE {
488     EXPECT_FALSE(did_start_loading);
489     EXPECT_EQ(0U, progresses.size());
490     EXPECT_FALSE(did_stop_loading);
491     did_start_loading = true;
492   }
493
494   virtual void DidStopLoading(RenderViewHost* render_view_host) OVERRIDE {
495     EXPECT_TRUE(did_start_loading);
496     EXPECT_GE(progresses.size(), 1U);
497     EXPECT_FALSE(did_stop_loading);
498     did_stop_loading = true;
499   }
500
501   bool did_start_loading;
502   std::vector<double> progresses;
503   bool did_stop_loading;
504 };
505
506 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, LoadProgress) {
507   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
508   scoped_ptr<LoadProgressDelegateAndObserver> delegate(
509       new LoadProgressDelegateAndObserver(shell()));
510
511   NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
512
513   const std::vector<double>& progresses = delegate->progresses;
514   // All updates should be in order ...
515   if (std::adjacent_find(progresses.begin(),
516                          progresses.end(),
517                          std::greater<double>()) != progresses.end()) {
518     ADD_FAILURE() << "Progress values should be in order: "
519                   << ::testing::PrintToString(progresses);
520   }
521
522   // ... and the last one should be 1.0, meaning complete.
523   ASSERT_GE(progresses.size(), 1U)
524       << "There should be at least one progress update";
525   EXPECT_EQ(1.0, *progresses.rbegin());
526 }
527
528 struct FirstVisuallyNonEmptyPaintObserver : public WebContentsObserver {
529   FirstVisuallyNonEmptyPaintObserver(Shell* shell)
530       : WebContentsObserver(shell->web_contents()),
531         did_fist_visually_non_empty_paint_(false) {}
532
533   virtual void DidFirstVisuallyNonEmptyPaint() OVERRIDE {
534     did_fist_visually_non_empty_paint_ = true;
535     on_did_first_visually_non_empty_paint_.Run();
536   }
537
538   void WaitForDidFirstVisuallyNonEmptyPaint() {
539     if (did_fist_visually_non_empty_paint_)
540       return;
541     base::RunLoop run_loop;
542     on_did_first_visually_non_empty_paint_ = run_loop.QuitClosure();
543     run_loop.Run();
544   }
545
546   base::Closure on_did_first_visually_non_empty_paint_;
547   bool did_fist_visually_non_empty_paint_;
548 };
549
550 // See: http://crbug.com/395664
551 #if defined(OS_ANDROID)
552 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
553 #else
554 // http://crbug.com/398471
555 #define MAYBE_FirstVisuallyNonEmptyPaint DISABLED_FirstVisuallyNonEmptyPaint
556 #endif
557 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
558                        MAYBE_FirstVisuallyNonEmptyPaint) {
559   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
560   scoped_ptr<FirstVisuallyNonEmptyPaintObserver> observer(
561       new FirstVisuallyNonEmptyPaintObserver(shell()));
562
563   NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html"));
564
565   observer->WaitForDidFirstVisuallyNonEmptyPaint();
566   ASSERT_TRUE(observer->did_fist_visually_non_empty_paint_);
567 }
568
569 }  // namespace content
570