Fix mis-classification of navigations when there is a pending page.
[chromium-blink-merge.git] / content / browser / frame_host / navigation_controller_impl_browsertest.cc
blob75b8e0912f53a6c5e14cc6c2b5eb865f4c7e22ed
1 // Copyright 2014 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/bind.h"
6 #include "base/command_line.h"
7 #include "base/strings/stringprintf.h"
8 #include "content/browser/frame_host/frame_navigation_entry.h"
9 #include "content/browser/frame_host/frame_tree.h"
10 #include "content/browser/frame_host/navigation_controller_impl.h"
11 #include "content/browser/frame_host/navigation_entry_impl.h"
12 #include "content/browser/web_contents/web_contents_impl.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/resource_controller.h"
15 #include "content/public/browser/resource_dispatcher_host.h"
16 #include "content/public/browser/resource_dispatcher_host_delegate.h"
17 #include "content/public/browser/resource_throttle.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/common/bindings_policy.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/common/url_constants.h"
23 #include "content/public/test/browser_test_utils.h"
24 #include "content/public/test/content_browser_test.h"
25 #include "content/public/test/content_browser_test_utils.h"
26 #include "content/public/test/test_navigation_observer.h"
27 #include "content/public/test/test_utils.h"
28 #include "content/shell/browser/shell.h"
29 #include "content/test/content_browser_test_utils_internal.h"
30 #include "net/dns/mock_host_resolver.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/test/url_request/url_request_failed_job.h"
34 namespace content {
36 class NavigationControllerBrowserTest : public ContentBrowserTest {
37 protected:
38 void SetUpOnMainThread() override {
39 host_resolver()->AddRule("*", "127.0.0.1");
40 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
44 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
45 const GURL base_url("http://baseurl");
46 const GURL history_url("http://historyurl");
47 const std::string data = "<html><body>foo</body></html>";
49 const NavigationController& controller =
50 shell()->web_contents()->GetController();
51 // Load data. Blocks until it is done.
52 content::LoadDataWithBaseURL(shell(), history_url, data, base_url);
54 // We should use history_url instead of the base_url as the original url of
55 // this navigation entry, because base_url is only used for resolving relative
56 // paths in the data, or enforcing same origin policy.
57 EXPECT_EQ(controller.GetVisibleEntry()->GetOriginalRequestURL(), history_url);
60 // The renderer uses the position in the history list as a clue to whether a
61 // navigation is stale. In the case where the entry limit is reached and the
62 // history list is pruned, make sure that there is no mismatch that would cause
63 // it to start incorrectly rejecting navigations as stale. See
64 // http://crbug.com/89798.
65 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
66 DontIgnoreBackAfterNavEntryLimit) {
67 NavigationController& controller =
68 shell()->web_contents()->GetController();
70 const int kMaxEntryCount =
71 static_cast<int>(NavigationControllerImpl::max_entry_count());
73 // Load up to the max count, all entries should be there.
74 for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
75 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
76 EXPECT_TRUE(NavigateToURL(shell(), url));
79 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
81 // Navigate twice more more.
82 for (int url_index = kMaxEntryCount;
83 url_index < kMaxEntryCount + 2; ++url_index) {
84 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
85 EXPECT_TRUE(NavigateToURL(shell(), url));
88 // We expect page0 and page1 to be gone.
89 EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
90 EXPECT_EQ(GURL("data:text/html,page2"),
91 controller.GetEntryAtIndex(0)->GetURL());
93 // Now try to go back. This should not hang.
94 ASSERT_TRUE(controller.CanGoBack());
95 controller.GoBack();
96 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
98 // This should have successfully gone back.
99 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
100 controller.GetLastCommittedEntry()->GetURL());
103 namespace {
105 int RendererHistoryLength(Shell* shell) {
106 int value = 0;
107 EXPECT_TRUE(ExecuteScriptAndExtractInt(
108 shell->web_contents(),
109 "domAutomationController.send(history.length)",
110 &value));
111 return value;
114 // Similar to the ones from content_browser_test_utils.
115 bool NavigateToURLAndReplace(Shell* shell, const GURL& url) {
116 WebContents* web_contents = shell->web_contents();
117 WaitForLoadStop(web_contents);
118 TestNavigationObserver same_tab_observer(web_contents, 1);
119 NavigationController::LoadURLParams params(url);
120 params.should_replace_current_entry = true;
121 web_contents->GetController().LoadURLWithParams(params);
122 web_contents->Focus();
123 same_tab_observer.Wait();
124 if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
125 return false;
126 return web_contents->GetLastCommittedURL() == url;
129 } // namespace
131 // When loading a new page to replace an old page in the history list, make sure
132 // that the browser and renderer agree, and that both get it right.
133 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
134 CorrectLengthWithCurrentItemReplacement) {
135 NavigationController& controller =
136 shell()->web_contents()->GetController();
138 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
139 EXPECT_EQ(1, controller.GetEntryCount());
140 EXPECT_EQ(1, RendererHistoryLength(shell()));
142 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page2")));
143 EXPECT_EQ(1, controller.GetEntryCount());
144 EXPECT_EQ(1, RendererHistoryLength(shell()));
146 // Note that there's no way to access the renderer's notion of the history
147 // offset via JavaScript. Checking just the history length, though, is enough;
148 // if the replacement failed, there would be a new history entry and thus an
149 // incorrect length.
152 // When spawning a new page from a WebUI page, make sure that the browser and
153 // renderer agree about the length of the history list, and that both get it
154 // right.
155 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
156 CorrectLengthWithNewTabNavigatingFromWebUI) {
157 GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
158 std::string(kChromeUIGpuHost));
159 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
160 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
161 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
163 ShellAddedObserver observer;
164 std::string page_url = embedded_test_server()->GetURL(
165 "/navigation_controller/simple_page_1.html").spec();
166 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
167 "window.open('" + page_url + "', '_blank')"));
168 Shell* shell2 = observer.GetShell();
169 EXPECT_TRUE(WaitForLoadStop(shell2->web_contents()));
171 EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
172 EXPECT_EQ(1, RendererHistoryLength(shell2));
174 // Again, as above, there's no way to access the renderer's notion of the
175 // history offset via JavaScript. Checking just the history length, again,
176 // will have to suffice.
179 namespace {
181 class NoNavigationsObserver : public WebContentsObserver {
182 public:
183 // Observes navigation for the specified |web_contents|.
184 explicit NoNavigationsObserver(WebContents* web_contents)
185 : WebContentsObserver(web_contents) {}
187 private:
188 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
189 const LoadCommittedDetails& details,
190 const FrameNavigateParams& params) override {
191 FAIL() << "No navigations should occur";
195 } // namespace
197 // Some pages create a popup, then write an iframe into it. This causes a
198 // subframe navigation without having any committed entry. Such navigations
199 // just get thrown on the ground, but we shouldn't crash.
201 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
202 // the initial window.open() and the iframe creation, don't try to create
203 // navigation entries, and the third, the new navigation, tries to.
204 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
205 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
206 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
208 FrameTreeNode* root =
209 static_cast<WebContentsImpl*>(shell()->web_contents())->
210 GetFrameTree()->root();
212 // Pop open a new window.
213 ShellAddedObserver new_shell_observer;
214 std::string script = "window.open()";
215 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
216 Shell* new_shell = new_shell_observer.GetShell();
217 ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
218 FrameTreeNode* new_root =
219 static_cast<WebContentsImpl*>(new_shell->web_contents())->
220 GetFrameTree()->root();
222 // Make a new iframe in it.
223 NoNavigationsObserver observer(new_shell->web_contents());
224 script = "var iframe = document.createElement('iframe');"
225 "iframe.src = 'data:text/html,<p>some page</p>';"
226 "document.body.appendChild(iframe);";
227 EXPECT_TRUE(content::ExecuteScript(new_root->current_frame_host(), script));
228 // The success check is of the last-committed entry, and there is none.
229 WaitForLoadStopWithoutSuccessCheck(new_shell->web_contents());
231 ASSERT_EQ(1U, new_root->child_count());
232 ASSERT_NE(nullptr, new_root->child_at(0));
234 // Navigate it.
235 GURL frame_url = embedded_test_server()->GetURL(
236 "/navigation_controller/simple_page_2.html");
237 script = "location.assign('" + frame_url.spec() + "')";
238 EXPECT_TRUE(content::ExecuteScript(
239 new_root->child_at(0)->current_frame_host(), script));
241 // Success is not crashing, and not navigating.
242 EXPECT_EQ(nullptr,
243 new_shell->web_contents()->GetController().GetLastCommittedEntry());
246 namespace {
248 class FrameNavigateParamsCapturer : public WebContentsObserver {
249 public:
250 // Observes navigation for the specified |node|.
251 explicit FrameNavigateParamsCapturer(FrameTreeNode* node)
252 : WebContentsObserver(
253 node->current_frame_host()->delegate()->GetAsWebContents()),
254 frame_tree_node_id_(node->frame_tree_node_id()),
255 navigations_remaining_(1),
256 wait_for_load_(true),
257 message_loop_runner_(new MessageLoopRunner) {}
259 void set_navigations_remaining(int count) {
260 navigations_remaining_ = count;
263 void set_wait_for_load(bool ignore) {
264 wait_for_load_ = ignore;
267 void Wait() {
268 message_loop_runner_->Run();
271 const FrameNavigateParams& params() const {
272 EXPECT_EQ(1U, params_.size());
273 return params_[0];
276 const std::vector<FrameNavigateParams>& all_params() const {
277 return params_;
280 const LoadCommittedDetails& details() const {
281 EXPECT_EQ(1U, details_.size());
282 return details_[0];
285 const std::vector<LoadCommittedDetails>& all_details() const {
286 return details_;
289 private:
290 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
291 const LoadCommittedDetails& details,
292 const FrameNavigateParams& params) override {
293 RenderFrameHostImpl* rfh =
294 static_cast<RenderFrameHostImpl*>(render_frame_host);
295 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
296 return;
298 --navigations_remaining_;
299 params_.push_back(params);
300 details_.push_back(details);
301 if (!navigations_remaining_ &&
302 (!web_contents()->IsLoading() || !wait_for_load_))
303 message_loop_runner_->Quit();
306 void DidStopLoading() override {
307 if (!navigations_remaining_)
308 message_loop_runner_->Quit();
311 // The id of the FrameTreeNode whose navigations to observe.
312 int frame_tree_node_id_;
314 // How many navigations remain to capture.
315 int navigations_remaining_;
317 // Whether to also wait for the load to complete.
318 bool wait_for_load_;
320 // The params of the navigations.
321 std::vector<FrameNavigateParams> params_;
323 // The details of the navigations.
324 std::vector<LoadCommittedDetails> details_;
326 // The MessageLoopRunner used to spin the message loop.
327 scoped_refptr<MessageLoopRunner> message_loop_runner_;
330 class LoadCommittedCapturer : public WebContentsObserver {
331 public:
332 // Observes the load commit for the specified |node|.
333 explicit LoadCommittedCapturer(FrameTreeNode* node)
334 : WebContentsObserver(
335 node->current_frame_host()->delegate()->GetAsWebContents()),
336 frame_tree_node_id_(node->frame_tree_node_id()),
337 message_loop_runner_(new MessageLoopRunner) {}
339 // Observes the load commit for the next created frame in the specified
340 // |web_contents|.
341 explicit LoadCommittedCapturer(WebContents* web_contents)
342 : WebContentsObserver(web_contents),
343 frame_tree_node_id_(0),
344 message_loop_runner_(new MessageLoopRunner) {}
346 void Wait() {
347 message_loop_runner_->Run();
350 ui::PageTransition transition_type() const {
351 return transition_type_;
354 private:
355 void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
356 // If this object was created with a specified tree frame node, there
357 // shouldn't be any frames being created.
358 DCHECK_EQ(0, frame_tree_node_id_);
359 RenderFrameHostImpl* rfh =
360 static_cast<RenderFrameHostImpl*>(render_frame_host);
361 frame_tree_node_id_ = rfh->frame_tree_node()->frame_tree_node_id();
364 void DidCommitProvisionalLoadForFrame(
365 RenderFrameHost* render_frame_host,
366 const GURL& url,
367 ui::PageTransition transition_type) override {
368 DCHECK_NE(0, frame_tree_node_id_);
369 RenderFrameHostImpl* rfh =
370 static_cast<RenderFrameHostImpl*>(render_frame_host);
371 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
372 return;
374 transition_type_ = transition_type;
375 if (!web_contents()->IsLoading())
376 message_loop_runner_->Quit();
379 void DidStopLoading() override { message_loop_runner_->Quit(); }
381 // The id of the FrameTreeNode whose navigations to observe.
382 int frame_tree_node_id_;
384 // The transition_type of the last navigation.
385 ui::PageTransition transition_type_;
387 // The MessageLoopRunner used to spin the message loop.
388 scoped_refptr<MessageLoopRunner> message_loop_runner_;
391 } // namespace
393 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
394 ErrorPageReplacement) {
395 NavigationController& controller = shell()->web_contents()->GetController();
396 GURL error_url(
397 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET));
398 net::URLRequestFailedJob::AddUrlHandler();
400 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
401 EXPECT_EQ(1, controller.GetEntryCount());
403 FrameTreeNode* root =
404 static_cast<WebContentsImpl*>(shell()->web_contents())->
405 GetFrameTree()->root();
407 // Navigate to a page that fails to load. It must result in an error page, the
408 // NEW_PAGE navigation type, and an addition to the history list.
410 FrameNavigateParamsCapturer capturer(root);
411 NavigateFrameToURL(root, error_url);
412 capturer.Wait();
413 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
414 NavigationEntry* entry = controller.GetLastCommittedEntry();
415 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
416 EXPECT_EQ(2, controller.GetEntryCount());
419 // Navigate again to the page that fails to load. It must result in an error
420 // page, the EXISTING_PAGE navigation type, and no addition to the history
421 // list. We do not use SAME_PAGE here; that case only differs in that it
422 // clears the pending entry, and there is no pending entry after a load
423 // failure.
425 FrameNavigateParamsCapturer capturer(root);
426 NavigateFrameToURL(root, error_url);
427 capturer.Wait();
428 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
429 NavigationEntry* entry = controller.GetLastCommittedEntry();
430 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
431 EXPECT_EQ(2, controller.GetEntryCount());
434 // Make a new entry ...
435 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
436 EXPECT_EQ(3, controller.GetEntryCount());
438 // ... and replace it with a failed load. (Note that when you set the
439 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
440 // because that is a classification of the renderer's behavior, and the flag
441 // is a browser-side flag.)
443 FrameNavigateParamsCapturer capturer(root);
444 NavigateToURLAndReplace(shell(), error_url);
445 capturer.Wait();
446 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
447 NavigationEntry* entry = controller.GetLastCommittedEntry();
448 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
449 EXPECT_EQ(3, controller.GetEntryCount());
452 // Make a new web ui page to force a process swap ...
453 GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
454 std::string(kChromeUIGpuHost));
455 NavigateToURL(shell(), web_ui_page);
456 EXPECT_EQ(4, controller.GetEntryCount());
458 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
459 // above.)
461 FrameNavigateParamsCapturer capturer(root);
462 NavigateToURLAndReplace(shell(), error_url);
463 capturer.Wait();
464 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
465 NavigationEntry* entry = controller.GetLastCommittedEntry();
466 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
467 EXPECT_EQ(4, controller.GetEntryCount());
471 // Various tests for navigation type classifications. TODO(avi): It's rather
472 // bogus that the same info is in two different enums; http://crbug.com/453555.
474 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
475 // classified.
476 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
477 NavigationTypeClassification_NewPage) {
478 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
480 FrameTreeNode* root =
481 static_cast<WebContentsImpl*>(shell()->web_contents())->
482 GetFrameTree()->root();
485 // Simple load.
486 FrameNavigateParamsCapturer capturer(root);
487 GURL frame_url(embedded_test_server()->GetURL(
488 "/navigation_controller/page_with_links.html"));
489 NavigateFrameToURL(root, frame_url);
490 capturer.Wait();
491 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
492 // transition? Lots of these transitions should be cleaned up.
493 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
494 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
498 // Load via a fragment link click.
499 FrameNavigateParamsCapturer capturer(root);
500 std::string script = "document.getElementById('fraglink').click()";
501 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
502 capturer.Wait();
503 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
504 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
508 // Load via link click.
509 FrameNavigateParamsCapturer capturer(root);
510 std::string script = "document.getElementById('thelink').click()";
511 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
512 capturer.Wait();
513 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
514 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
518 // location.assign().
519 FrameNavigateParamsCapturer capturer(root);
520 GURL frame_url(embedded_test_server()->GetURL(
521 "/navigation_controller/simple_page_2.html"));
522 std::string script = "location.assign('" + frame_url.spec() + "')";
523 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
524 capturer.Wait();
525 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
526 capturer.params().transition);
527 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
531 // history.pushState().
532 FrameNavigateParamsCapturer capturer(root);
533 std::string script =
534 "history.pushState({}, 'page 1', 'simple_page_1.html')";
535 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
536 capturer.Wait();
537 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
538 capturer.params().transition);
539 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
543 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
544 // classified.
545 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
546 NavigationTypeClassification_ExistingPage) {
547 GURL url1(embedded_test_server()->GetURL(
548 "/navigation_controller/simple_page_1.html"));
549 NavigateToURL(shell(), url1);
550 GURL url2(embedded_test_server()->GetURL(
551 "/navigation_controller/simple_page_2.html"));
552 NavigateToURL(shell(), url2);
554 FrameTreeNode* root =
555 static_cast<WebContentsImpl*>(shell()->web_contents())->
556 GetFrameTree()->root();
559 // Back from the browser side.
560 FrameNavigateParamsCapturer capturer(root);
561 shell()->web_contents()->GetController().GoBack();
562 capturer.Wait();
563 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
564 | ui::PAGE_TRANSITION_FORWARD_BACK
565 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
566 capturer.params().transition);
567 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
571 // Forward from the browser side.
572 FrameNavigateParamsCapturer capturer(root);
573 shell()->web_contents()->GetController().GoForward();
574 capturer.Wait();
575 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
576 | ui::PAGE_TRANSITION_FORWARD_BACK
577 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
578 capturer.params().transition);
579 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
583 // Back from the renderer side.
584 FrameNavigateParamsCapturer capturer(root);
585 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
586 "history.back()"));
587 capturer.Wait();
588 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
589 | ui::PAGE_TRANSITION_FORWARD_BACK
590 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
591 capturer.params().transition);
592 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
596 // Forward from the renderer side.
597 FrameNavigateParamsCapturer capturer(root);
598 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
599 "history.forward()"));
600 capturer.Wait();
601 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
602 | ui::PAGE_TRANSITION_FORWARD_BACK
603 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
604 capturer.params().transition);
605 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
609 // Back from the renderer side via history.go().
610 FrameNavigateParamsCapturer capturer(root);
611 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
612 "history.go(-1)"));
613 capturer.Wait();
614 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
615 | ui::PAGE_TRANSITION_FORWARD_BACK
616 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
617 capturer.params().transition);
618 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
622 // Forward from the renderer side via history.go().
623 FrameNavigateParamsCapturer capturer(root);
624 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
625 "history.go(1)"));
626 capturer.Wait();
627 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
628 | ui::PAGE_TRANSITION_FORWARD_BACK
629 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
630 capturer.params().transition);
631 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
635 // Reload from the browser side.
636 FrameNavigateParamsCapturer capturer(root);
637 shell()->web_contents()->GetController().Reload(false);
638 capturer.Wait();
639 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD, capturer.params().transition);
640 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
644 // Reload from the renderer side.
645 FrameNavigateParamsCapturer capturer(root);
646 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
647 "location.reload()"));
648 capturer.Wait();
649 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
650 capturer.params().transition);
651 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
655 // location.replace().
656 FrameNavigateParamsCapturer capturer(root);
657 GURL frame_url(embedded_test_server()->GetURL(
658 "/navigation_controller/simple_page_1.html"));
659 std::string script = "location.replace('" + frame_url.spec() + "')";
660 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
661 capturer.Wait();
662 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
663 capturer.params().transition);
664 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
668 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
669 // classified.
670 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
671 NavigationTypeClassification_SamePage) {
672 GURL url1(embedded_test_server()->GetURL(
673 "/navigation_controller/simple_page_1.html"));
674 NavigateToURL(shell(), url1);
676 FrameTreeNode* root =
677 static_cast<WebContentsImpl*>(shell()->web_contents())->
678 GetFrameTree()->root();
681 // Simple load.
682 FrameNavigateParamsCapturer capturer(root);
683 GURL frame_url(embedded_test_server()->GetURL(
684 "/navigation_controller/simple_page_1.html"));
685 NavigateFrameToURL(root, frame_url);
686 capturer.Wait();
687 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
688 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, capturer.details().type);
692 // Verify that navigations for NAVIGATION_TYPE_IN_PAGE are correctly
693 // classified.
694 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
695 NavigationTypeClassification_InPage) {
696 GURL url1(embedded_test_server()->GetURL(
697 "/navigation_controller/simple_page_1.html"));
698 NavigateToURL(shell(), url1);
700 FrameTreeNode* root =
701 static_cast<WebContentsImpl*>(shell()->web_contents())->
702 GetFrameTree()->root();
705 // history.replaceState().
706 FrameNavigateParamsCapturer capturer(root);
707 std::string script =
708 "history.replaceState({}, 'page 1', 'simple_page_2.html')";
709 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
710 capturer.Wait();
711 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
712 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
715 // Back and forward across a fragment navigation.
717 GURL url2(embedded_test_server()->GetURL(
718 "/navigation_controller/page_with_links.html"));
719 NavigateToURL(shell(), url2);
720 std::string script = "document.getElementById('fraglink').click()";
721 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
722 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
725 // Back.
726 FrameNavigateParamsCapturer capturer(root);
727 shell()->web_contents()->GetController().GoBack();
728 capturer.Wait();
729 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
730 | ui::PAGE_TRANSITION_FORWARD_BACK
731 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
732 capturer.params().transition);
733 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
737 // Forward.
738 FrameNavigateParamsCapturer capturer(root);
739 shell()->web_contents()->GetController().GoForward();
740 capturer.Wait();
741 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
742 capturer.params().transition);
743 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
746 // Back and forward across a pushState-created navigation.
748 NavigateToURL(shell(), url1);
749 script = "history.pushState({}, 'page 2', 'simple_page_2.html')";
750 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
751 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
754 // Back.
755 FrameNavigateParamsCapturer capturer(root);
756 shell()->web_contents()->GetController().GoBack();
757 capturer.Wait();
758 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
759 | ui::PAGE_TRANSITION_FORWARD_BACK
760 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
761 capturer.params().transition);
762 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
766 // Forward.
767 FrameNavigateParamsCapturer capturer(root);
768 shell()->web_contents()->GetController().GoForward();
769 capturer.Wait();
770 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
771 capturer.params().transition);
772 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
776 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
777 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
778 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
779 NavigationTypeClassification_NewAndAutoSubframe) {
780 GURL main_url(embedded_test_server()->GetURL(
781 "/navigation_controller/page_with_iframe.html"));
782 NavigateToURL(shell(), main_url);
784 // It is safe to obtain the root frame tree node here, as it doesn't change.
785 FrameTreeNode* root =
786 static_cast<WebContentsImpl*>(shell()->web_contents())->
787 GetFrameTree()->root();
789 ASSERT_EQ(1U, root->child_count());
790 ASSERT_NE(nullptr, root->child_at(0));
793 // Simple load.
794 FrameNavigateParamsCapturer capturer(root->child_at(0));
795 GURL frame_url(embedded_test_server()->GetURL(
796 "/navigation_controller/simple_page_1.html"));
797 NavigateFrameToURL(root->child_at(0), frame_url);
798 capturer.Wait();
799 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
800 capturer.params().transition);
801 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
805 // Back.
806 FrameNavigateParamsCapturer capturer(root->child_at(0));
807 shell()->web_contents()->GetController().GoBack();
808 capturer.Wait();
809 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
810 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
814 // Forward.
815 FrameNavigateParamsCapturer capturer(root->child_at(0));
816 shell()->web_contents()->GetController().GoForward();
817 capturer.Wait();
818 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
819 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
823 // Simple load.
824 FrameNavigateParamsCapturer capturer(root->child_at(0));
825 GURL frame_url(embedded_test_server()->GetURL(
826 "/navigation_controller/page_with_links.html"));
827 NavigateFrameToURL(root->child_at(0), frame_url);
828 capturer.Wait();
829 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
830 capturer.params().transition);
831 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
835 // Load via a fragment link click.
836 FrameNavigateParamsCapturer capturer(root->child_at(0));
837 std::string script = "document.getElementById('fraglink').click()";
838 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
839 script));
840 capturer.Wait();
841 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
842 capturer.params().transition);
843 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
847 // location.assign().
848 FrameNavigateParamsCapturer capturer(root->child_at(0));
849 GURL frame_url(embedded_test_server()->GetURL(
850 "/navigation_controller/simple_page_1.html"));
851 std::string script = "location.assign('" + frame_url.spec() + "')";
852 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
853 script));
854 capturer.Wait();
855 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
856 capturer.params().transition);
857 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
861 // location.replace().
862 LoadCommittedCapturer capturer(root->child_at(0));
863 GURL frame_url(embedded_test_server()->GetURL(
864 "/navigation_controller/simple_page_2.html"));
865 std::string script = "location.replace('" + frame_url.spec() + "')";
866 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
867 script));
868 capturer.Wait();
869 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
873 // history.pushState().
874 FrameNavigateParamsCapturer capturer(root->child_at(0));
875 std::string script =
876 "history.pushState({}, 'page 1', 'simple_page_1.html')";
877 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
878 script));
879 capturer.Wait();
880 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
881 capturer.params().transition);
882 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
886 // history.replaceState().
887 LoadCommittedCapturer capturer(root->child_at(0));
888 std::string script =
889 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
890 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
891 script));
892 capturer.Wait();
893 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
897 // Reload.
898 LoadCommittedCapturer capturer(root->child_at(0));
899 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
900 "location.reload()"));
901 capturer.Wait();
902 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
906 // Create an iframe.
907 LoadCommittedCapturer capturer(shell()->web_contents());
908 GURL frame_url(embedded_test_server()->GetURL(
909 "/navigation_controller/simple_page_1.html"));
910 std::string script = "var iframe = document.createElement('iframe');"
911 "iframe.src = '" + frame_url.spec() + "';"
912 "document.body.appendChild(iframe);";
913 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
914 capturer.Wait();
915 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
919 // Verify that navigations caused by client-side redirects are correctly
920 // classified.
921 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
922 NavigationTypeClassification_ClientSideRedirect) {
923 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
924 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
926 FrameTreeNode* root =
927 static_cast<WebContentsImpl*>(shell()->web_contents())->
928 GetFrameTree()->root();
931 // Load the redirecting page.
932 FrameNavigateParamsCapturer capturer(root);
933 capturer.set_navigations_remaining(2);
934 GURL frame_url(embedded_test_server()->GetURL(
935 "/navigation_controller/client_redirect.html"));
936 NavigateFrameToURL(root, frame_url);
937 capturer.Wait();
939 std::vector<FrameNavigateParams> params = capturer.all_params();
940 std::vector<LoadCommittedDetails> details = capturer.all_details();
941 ASSERT_EQ(2U, params.size());
942 ASSERT_EQ(2U, details.size());
943 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, params[0].transition);
944 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, details[0].type);
945 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
946 params[1].transition);
947 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details[1].type);
951 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
952 // commits.
953 // TODO(creis): Test cross-site and nested iframes.
954 // TODO(creis): Test updating entries for history auto subframe navigations.
955 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
956 FrameNavigationEntry_AutoSubframe) {
957 GURL main_url(embedded_test_server()->GetURL(
958 "/navigation_controller/simple_page_1.html"));
959 NavigateToURL(shell(), main_url);
960 const NavigationControllerImpl& controller =
961 static_cast<const NavigationControllerImpl&>(
962 shell()->web_contents()->GetController());
963 FrameTreeNode* root =
964 static_cast<WebContentsImpl*>(shell()->web_contents())->
965 GetFrameTree()->root();
967 // Create an iframe.
968 GURL frame_url(embedded_test_server()->GetURL(
969 "/navigation_controller/simple_page_2.html"));
971 LoadCommittedCapturer capturer(shell()->web_contents());
972 std::string script = "var iframe = document.createElement('iframe');"
973 "iframe.src = '" + frame_url.spec() + "';"
974 "document.body.appendChild(iframe);";
975 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
976 capturer.Wait();
977 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
980 // Check last committed NavigationEntry.
981 EXPECT_EQ(1, controller.GetEntryCount());
982 NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
983 EXPECT_EQ(main_url, entry->GetURL());
984 FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
985 EXPECT_EQ(main_url, root_entry->url());
987 // Verify subframe entries if we're in --site-per-process mode.
988 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
989 switches::kSitePerProcess)) {
990 // The entry should now have a subframe FrameNavigationEntry.
991 ASSERT_EQ(1U, entry->root_node()->children.size());
992 FrameNavigationEntry* frame_entry =
993 entry->root_node()->children[0]->frame_entry.get();
994 EXPECT_EQ(frame_url, frame_entry->url());
995 } else {
996 // There are no subframe FrameNavigationEntries by default.
997 EXPECT_EQ(0U, entry->root_node()->children.size());
1001 namespace {
1003 class HttpThrottle : public ResourceThrottle {
1004 public:
1005 // ResourceThrottle
1006 void WillStartRequest(bool* defer) override {
1007 *defer = true;
1010 const char* GetNameForLogging() const override {
1011 return "HttpThrottle";
1015 class StallDelegate : public ResourceDispatcherHostDelegate {
1016 // ResourceDispatcherHostDelegate
1017 void RequestBeginning(
1018 net::URLRequest* request,
1019 content::ResourceContext* resource_context,
1020 content::AppCacheService* appcache_service,
1021 ResourceType resource_type,
1022 ScopedVector<content::ResourceThrottle>* throttles) override {
1023 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
1024 throttles->push_back(new HttpThrottle);
1028 // Loads |start_url|, then loads |stalled_url| which stalls. While the page is
1029 // stalled, an in-page navigation happens. Make sure that all the navigations
1030 // are properly classified.
1031 void DoReplaceStateWhilePending(Shell* shell,
1032 const GURL& start_url,
1033 const GURL& stalled_url,
1034 const std::string& replace_state_filename) {
1035 NavigationControllerImpl& controller =
1036 static_cast<NavigationControllerImpl&>(
1037 shell->web_contents()->GetController());
1039 FrameTreeNode* root =
1040 static_cast<WebContentsImpl*>(shell->web_contents())->
1041 GetFrameTree()->root();
1043 // Start with one page.
1044 EXPECT_TRUE(NavigateToURL(shell, start_url));
1046 // Have the user decide to go to a different page which is very slow.
1047 StallDelegate stall_delegate;
1048 ResourceDispatcherHost::Get()->SetDelegate(&stall_delegate);
1049 controller.LoadURL(
1050 stalled_url, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
1052 // That should be the pending entry.
1053 NavigationEntryImpl* entry = controller.GetPendingEntry();
1054 ASSERT_NE(nullptr, entry);
1055 EXPECT_EQ(stalled_url, entry->GetURL());
1058 // Now the existing page uses history.replaceState().
1059 FrameNavigateParamsCapturer capturer(root);
1060 capturer.set_wait_for_load(false);
1061 std::string script =
1062 "history.replaceState({}, '', '" + replace_state_filename + "')";
1063 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1064 capturer.Wait();
1066 // The fact that there was a pending entry shouldn't interfere with the
1067 // classification.
1068 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
1071 ResourceDispatcherHost::Get()->SetDelegate(nullptr);
1074 } // namespace
1076 IN_PROC_BROWSER_TEST_F(
1077 NavigationControllerBrowserTest,
1078 NavigationTypeClassification_On1InPageToXWhile2Pending) {
1079 GURL url1(embedded_test_server()->GetURL(
1080 "/navigation_controller/simple_page_1.html"));
1081 GURL url2(embedded_test_server()->GetURL(
1082 "/navigation_controller/simple_page_2.html"));
1083 DoReplaceStateWhilePending(shell(), url1, url2, "x");
1086 IN_PROC_BROWSER_TEST_F(
1087 NavigationControllerBrowserTest,
1088 NavigationTypeClassification_On1InPageTo2While2Pending) {
1089 GURL url1(embedded_test_server()->GetURL(
1090 "/navigation_controller/simple_page_1.html"));
1091 GURL url2(embedded_test_server()->GetURL(
1092 "/navigation_controller/simple_page_2.html"));
1093 DoReplaceStateWhilePending(shell(), url1, url2, "simple_page_2.html");
1096 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1097 NavigationTypeClassification_On1InPageToXWhile1Pending) {
1098 GURL url(embedded_test_server()->GetURL(
1099 "/navigation_controller/simple_page_1.html"));
1100 DoReplaceStateWhilePending(shell(), url, url, "x");
1103 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1104 NavigationTypeClassification_On1InPageTo1While1Pending) {
1105 GURL url(embedded_test_server()->GetURL(
1106 "/navigation_controller/simple_page_1.html"));
1107 DoReplaceStateWhilePending(shell(), url, url, "simple_page_1.html");
1110 // Ensure the renderer process does not get confused about the current entry
1111 // due to subframes and replaced entries. See https://crbug.com/480201.
1112 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
1113 PreventSpoofFromSubframeAndReplace) {
1114 // Start at an initial URL.
1115 GURL url1(embedded_test_server()->GetURL(
1116 "/navigation_controller/simple_page_1.html"));
1117 NavigateToURL(shell(), url1);
1119 // Now go to a page with a real iframe.
1120 GURL url2(embedded_test_server()->GetURL(
1121 "/navigation_controller/page_with_data_iframe.html"));
1122 NavigateToURL(shell(), url2);
1124 // It is safe to obtain the root frame tree node here, as it doesn't change.
1125 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1126 ->GetFrameTree()
1127 ->root();
1128 ASSERT_EQ(1U, root->child_count());
1129 ASSERT_NE(nullptr, root->child_at(0));
1132 // Navigate in the iframe.
1133 FrameNavigateParamsCapturer capturer(root->child_at(0));
1134 GURL frame_url(embedded_test_server()->GetURL(
1135 "/navigation_controller/simple_page_2.html"));
1136 NavigateFrameToURL(root->child_at(0), frame_url);
1137 capturer.Wait();
1138 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
1142 // Go back in the iframe.
1143 TestNavigationObserver back_load_observer(shell()->web_contents());
1144 shell()->web_contents()->GetController().GoBack();
1145 back_load_observer.Wait();
1149 // Go forward in the iframe.
1150 TestNavigationObserver forward_load_observer(shell()->web_contents());
1151 shell()->web_contents()->GetController().GoForward();
1152 forward_load_observer.Wait();
1155 GURL url3(embedded_test_server()->GetURL(
1156 "/navigation_controller/page_with_iframe.html"));
1158 // location.replace() to cause an inert commit.
1159 TestNavigationObserver replace_load_observer(shell()->web_contents());
1160 std::string script = "location.replace('" + url3.spec() + "')";
1161 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
1162 replace_load_observer.Wait();
1166 // Go back to url2.
1167 TestNavigationObserver back_load_observer(shell()->web_contents());
1168 shell()->web_contents()->GetController().GoBack();
1169 back_load_observer.Wait();
1171 // Make sure the URL is correct for both the entry and the main frame, and
1172 // that the process hasn't been killed for showing a spoof.
1173 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1174 EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
1175 EXPECT_EQ(url2, root->current_url());
1179 // Go back to reset main frame entirely.
1180 TestNavigationObserver back_load_observer(shell()->web_contents());
1181 shell()->web_contents()->GetController().GoBack();
1182 back_load_observer.Wait();
1183 EXPECT_EQ(url1, shell()->web_contents()->GetLastCommittedURL());
1184 EXPECT_EQ(url1, root->current_url());
1188 // Go forward.
1189 TestNavigationObserver back_load_observer(shell()->web_contents());
1190 shell()->web_contents()->GetController().GoForward();
1191 back_load_observer.Wait();
1192 EXPECT_EQ(url2, shell()->web_contents()->GetLastCommittedURL());
1193 EXPECT_EQ(url2, root->current_url());
1197 // Go forward to the replaced URL.
1198 TestNavigationObserver forward_load_observer(shell()->web_contents());
1199 shell()->web_contents()->GetController().GoForward();
1200 forward_load_observer.Wait();
1202 // Make sure the URL is correct for both the entry and the main frame, and
1203 // that the process hasn't been killed for showing a spoof.
1204 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1205 EXPECT_EQ(url3, shell()->web_contents()->GetLastCommittedURL());
1206 EXPECT_EQ(url3, root->current_url());
1210 } // namespace content