[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / content / browser / frame_host / navigation_controller_impl_browsertest.cc
blobaad2ac3c8a1806280a52513e2cb504e8a066b956
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/web_contents.h"
15 #include "content/public/browser/web_contents_observer.h"
16 #include "content/public/common/bindings_policy.h"
17 #include "content/public/common/content_switches.h"
18 #include "content/public/common/url_constants.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_navigation_observer.h"
23 #include "content/public/test/test_utils.h"
24 #include "content/shell/browser/shell.h"
25 #include "content/test/content_browser_test_utils_internal.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/test/embedded_test_server/embedded_test_server.h"
28 #include "net/test/url_request/url_request_failed_job.h"
30 namespace content {
32 class NavigationControllerBrowserTest : public ContentBrowserTest {
33 protected:
34 void SetUpOnMainThread() override {
35 host_resolver()->AddRule("*", "127.0.0.1");
36 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
40 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
41 const GURL base_url("http://baseurl");
42 const GURL history_url("http://historyurl");
43 const std::string data = "<html><body>foo</body></html>";
45 const NavigationController& controller =
46 shell()->web_contents()->GetController();
47 // Load data. Blocks until it is done.
48 content::LoadDataWithBaseURL(shell(), history_url, data, base_url);
50 // We should use history_url instead of the base_url as the original url of
51 // this navigation entry, because base_url is only used for resolving relative
52 // paths in the data, or enforcing same origin policy.
53 EXPECT_EQ(controller.GetVisibleEntry()->GetOriginalRequestURL(), history_url);
56 // The renderer uses the position in the history list as a clue to whether a
57 // navigation is stale. In the case where the entry limit is reached and the
58 // history list is pruned, make sure that there is no mismatch that would cause
59 // it to start incorrectly rejecting navigations as stale. See
60 // http://crbug.com/89798.
61 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
62 DontIgnoreBackAfterNavEntryLimit) {
63 NavigationController& controller =
64 shell()->web_contents()->GetController();
66 const int kMaxEntryCount =
67 static_cast<int>(NavigationControllerImpl::max_entry_count());
69 // Load up to the max count, all entries should be there.
70 for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
71 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
72 EXPECT_TRUE(NavigateToURL(shell(), url));
75 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
77 // Navigate twice more more.
78 for (int url_index = kMaxEntryCount;
79 url_index < kMaxEntryCount + 2; ++url_index) {
80 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
81 EXPECT_TRUE(NavigateToURL(shell(), url));
84 // We expect page0 and page1 to be gone.
85 EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
86 EXPECT_EQ(GURL("data:text/html,page2"),
87 controller.GetEntryAtIndex(0)->GetURL());
89 // Now try to go back. This should not hang.
90 ASSERT_TRUE(controller.CanGoBack());
91 controller.GoBack();
92 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
94 // This should have successfully gone back.
95 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
96 controller.GetLastCommittedEntry()->GetURL());
99 namespace {
101 int RendererHistoryLength(Shell* shell) {
102 int value = 0;
103 EXPECT_TRUE(ExecuteScriptAndExtractInt(
104 shell->web_contents(),
105 "domAutomationController.send(history.length)",
106 &value));
107 return value;
110 // Similar to the ones from content_browser_test_utils.
111 bool NavigateToURLAndReplace(Shell* shell, const GURL& url) {
112 WebContents* web_contents = shell->web_contents();
113 WaitForLoadStop(web_contents);
114 TestNavigationObserver same_tab_observer(web_contents, 1);
115 NavigationController::LoadURLParams params(url);
116 params.should_replace_current_entry = true;
117 web_contents->GetController().LoadURLWithParams(params);
118 web_contents->Focus();
119 same_tab_observer.Wait();
120 if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
121 return false;
122 return web_contents->GetLastCommittedURL() == url;
125 } // namespace
127 // When loading a new page to replace an old page in the history list, make sure
128 // that the browser and renderer agree, and that both get it right.
129 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
130 CorrectLengthWithCurrentItemReplacement) {
131 NavigationController& controller =
132 shell()->web_contents()->GetController();
134 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
135 EXPECT_EQ(1, controller.GetEntryCount());
136 EXPECT_EQ(1, RendererHistoryLength(shell()));
138 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page2")));
139 EXPECT_EQ(1, controller.GetEntryCount());
140 EXPECT_EQ(1, RendererHistoryLength(shell()));
142 // Note that there's no way to access the renderer's notion of the history
143 // offset via JavaScript. Checking just the history length, though, is enough;
144 // if the replacement failed, there would be a new history entry and thus an
145 // incorrect length.
148 // When spawning a new page from a WebUI page, make sure that the browser and
149 // renderer agree about the length of the history list, and that both get it
150 // right.
151 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
152 CorrectLengthWithNewTabNavigatingFromWebUI) {
153 GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
154 std::string(kChromeUIGpuHost));
155 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
156 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
157 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
159 ShellAddedObserver observer;
160 std::string page_url = embedded_test_server()->GetURL(
161 "/navigation_controller/simple_page_1.html").spec();
162 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
163 "window.open('" + page_url + "', '_blank')"));
164 Shell* shell2 = observer.GetShell();
165 EXPECT_TRUE(WaitForLoadStop(shell2->web_contents()));
167 EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
168 EXPECT_EQ(1, RendererHistoryLength(shell2));
170 // Again, as above, there's no way to access the renderer's notion of the
171 // history offset via JavaScript. Checking just the history length, again,
172 // will have to suffice.
175 namespace {
177 class NoNavigationsObserver : public WebContentsObserver {
178 public:
179 // Observes navigation for the specified |web_contents|.
180 explicit NoNavigationsObserver(WebContents* web_contents)
181 : WebContentsObserver(web_contents) {}
183 private:
184 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
185 const LoadCommittedDetails& details,
186 const FrameNavigateParams& params) override {
187 FAIL() << "No navigations should occur";
191 } // namespace
193 // Some pages create a popup, then write an iframe into it. This causes a
194 // subframe navigation without having any committed entry. Such navigations
195 // just get thrown on the ground, but we shouldn't crash.
197 // This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them,
198 // the initial window.open() and the iframe creation, don't try to create
199 // navigation entries, and the third, the new navigation, tries to.
200 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) {
201 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
202 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
204 FrameTreeNode* root =
205 static_cast<WebContentsImpl*>(shell()->web_contents())->
206 GetFrameTree()->root();
208 // Pop open a new window.
209 ShellAddedObserver new_shell_observer;
210 std::string script = "window.open()";
211 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
212 Shell* new_shell = new_shell_observer.GetShell();
213 ASSERT_NE(new_shell->web_contents(), shell()->web_contents());
214 FrameTreeNode* new_root =
215 static_cast<WebContentsImpl*>(new_shell->web_contents())->
216 GetFrameTree()->root();
218 // Make a new iframe in it.
219 NoNavigationsObserver observer(new_shell->web_contents());
220 script = "var iframe = document.createElement('iframe');"
221 "iframe.src = 'data:text/html,<p>some page</p>';"
222 "document.body.appendChild(iframe);";
223 EXPECT_TRUE(content::ExecuteScript(new_root->current_frame_host(), script));
224 // The success check is of the last-committed entry, and there is none.
225 WaitForLoadStopWithoutSuccessCheck(new_shell->web_contents());
227 ASSERT_EQ(1U, new_root->child_count());
228 ASSERT_NE(nullptr, new_root->child_at(0));
230 // Navigate it.
231 GURL frame_url = embedded_test_server()->GetURL(
232 "/navigation_controller/simple_page_2.html");
233 script = "location.assign('" + frame_url.spec() + "')";
234 EXPECT_TRUE(content::ExecuteScript(
235 new_root->child_at(0)->current_frame_host(), script));
237 // Success is not crashing, and not navigating.
238 EXPECT_EQ(nullptr,
239 new_shell->web_contents()->GetController().GetLastCommittedEntry());
242 namespace {
244 class FrameNavigateParamsCapturer : public WebContentsObserver {
245 public:
246 // Observes navigation for the specified |node|.
247 explicit FrameNavigateParamsCapturer(FrameTreeNode* node)
248 : WebContentsObserver(
249 node->current_frame_host()->delegate()->GetAsWebContents()),
250 frame_tree_node_id_(node->frame_tree_node_id()),
251 navigations_remaining_(1),
252 message_loop_runner_(new MessageLoopRunner) {}
254 void set_navigations_remaining(int count) {
255 navigations_remaining_ = count;
258 void Wait() {
259 message_loop_runner_->Run();
262 const FrameNavigateParams& params() const {
263 EXPECT_EQ(1U, params_.size());
264 return params_[0];
267 const std::vector<FrameNavigateParams>& all_params() const {
268 return params_;
271 const LoadCommittedDetails& details() const {
272 EXPECT_EQ(1U, details_.size());
273 return details_[0];
276 const std::vector<LoadCommittedDetails>& all_details() const {
277 return details_;
280 private:
281 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
282 const LoadCommittedDetails& details,
283 const FrameNavigateParams& params) override {
284 RenderFrameHostImpl* rfh =
285 static_cast<RenderFrameHostImpl*>(render_frame_host);
286 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
287 return;
289 --navigations_remaining_;
290 params_.push_back(params);
291 details_.push_back(details);
292 if (!web_contents()->IsLoading() && !navigations_remaining_)
293 message_loop_runner_->Quit();
296 void DidStopLoading() override {
297 if (!navigations_remaining_)
298 message_loop_runner_->Quit();
301 // The id of the FrameTreeNode whose navigations to observe.
302 int frame_tree_node_id_;
304 // How many navigations remain to capture.
305 int navigations_remaining_;
307 // The params of the navigations.
308 std::vector<FrameNavigateParams> params_;
310 // The details of the navigations.
311 std::vector<LoadCommittedDetails> details_;
313 // The MessageLoopRunner used to spin the message loop.
314 scoped_refptr<MessageLoopRunner> message_loop_runner_;
317 class LoadCommittedCapturer : public WebContentsObserver {
318 public:
319 // Observes the load commit for the specified |node|.
320 explicit LoadCommittedCapturer(FrameTreeNode* node)
321 : WebContentsObserver(
322 node->current_frame_host()->delegate()->GetAsWebContents()),
323 frame_tree_node_id_(node->frame_tree_node_id()),
324 message_loop_runner_(new MessageLoopRunner) {}
326 // Observes the load commit for the next created frame in the specified
327 // |web_contents|.
328 explicit LoadCommittedCapturer(WebContents* web_contents)
329 : WebContentsObserver(web_contents),
330 frame_tree_node_id_(0),
331 message_loop_runner_(new MessageLoopRunner) {}
333 void Wait() {
334 message_loop_runner_->Run();
337 ui::PageTransition transition_type() const {
338 return transition_type_;
341 private:
342 void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
343 // If this object was created with a specified tree frame node, there
344 // shouldn't be any frames being created.
345 DCHECK_EQ(0, frame_tree_node_id_);
346 RenderFrameHostImpl* rfh =
347 static_cast<RenderFrameHostImpl*>(render_frame_host);
348 frame_tree_node_id_ = rfh->frame_tree_node()->frame_tree_node_id();
351 void DidCommitProvisionalLoadForFrame(
352 RenderFrameHost* render_frame_host,
353 const GURL& url,
354 ui::PageTransition transition_type) override {
355 DCHECK_NE(0, frame_tree_node_id_);
356 RenderFrameHostImpl* rfh =
357 static_cast<RenderFrameHostImpl*>(render_frame_host);
358 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
359 return;
361 transition_type_ = transition_type;
362 if (!web_contents()->IsLoading())
363 message_loop_runner_->Quit();
366 void DidStopLoading() override { message_loop_runner_->Quit(); }
368 // The id of the FrameTreeNode whose navigations to observe.
369 int frame_tree_node_id_;
371 // The transition_type of the last navigation.
372 ui::PageTransition transition_type_;
374 // The MessageLoopRunner used to spin the message loop.
375 scoped_refptr<MessageLoopRunner> message_loop_runner_;
378 } // namespace
380 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
381 ErrorPageReplacement) {
382 NavigationController& controller = shell()->web_contents()->GetController();
383 GURL error_url(
384 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_RESET));
385 net::URLRequestFailedJob::AddUrlHandler();
387 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
388 EXPECT_EQ(1, controller.GetEntryCount());
390 FrameTreeNode* root =
391 static_cast<WebContentsImpl*>(shell()->web_contents())->
392 GetFrameTree()->root();
394 // Navigate to a page that fails to load. It must result in an error page, the
395 // NEW_PAGE navigation type, and an addition to the history list.
397 FrameNavigateParamsCapturer capturer(root);
398 NavigateFrameToURL(root, error_url);
399 capturer.Wait();
400 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
401 NavigationEntry* entry = controller.GetLastCommittedEntry();
402 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
403 EXPECT_EQ(2, controller.GetEntryCount());
406 // Navigate again to the page that fails to load. It must result in an error
407 // page, the EXISTING_PAGE navigation type, and no addition to the history
408 // list. We do not use SAME_PAGE here; that case only differs in that it
409 // clears the pending entry, and there is no pending entry after a load
410 // failure.
412 FrameNavigateParamsCapturer capturer(root);
413 NavigateFrameToURL(root, error_url);
414 capturer.Wait();
415 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
416 NavigationEntry* entry = controller.GetLastCommittedEntry();
417 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
418 EXPECT_EQ(2, controller.GetEntryCount());
421 // Make a new entry ...
422 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
423 EXPECT_EQ(3, controller.GetEntryCount());
425 // ... and replace it with a failed load. (Note that when you set the
426 // should_replace_current_entry flag, the navigation is classified as NEW_PAGE
427 // because that is a classification of the renderer's behavior, and the flag
428 // is a browser-side flag.)
430 FrameNavigateParamsCapturer capturer(root);
431 NavigateToURLAndReplace(shell(), error_url);
432 capturer.Wait();
433 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
434 NavigationEntry* entry = controller.GetLastCommittedEntry();
435 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
436 EXPECT_EQ(3, controller.GetEntryCount());
439 // Make a new web ui page to force a process swap ...
440 GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
441 std::string(kChromeUIGpuHost));
442 NavigateToURL(shell(), web_ui_page);
443 EXPECT_EQ(4, controller.GetEntryCount());
445 // ... and replace it with a failed load. (It is NEW_PAGE for the reason noted
446 // above.)
448 FrameNavigateParamsCapturer capturer(root);
449 NavigateToURLAndReplace(shell(), error_url);
450 capturer.Wait();
451 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
452 NavigationEntry* entry = controller.GetLastCommittedEntry();
453 EXPECT_EQ(PAGE_TYPE_ERROR, entry->GetPageType());
454 EXPECT_EQ(4, controller.GetEntryCount());
458 // Various tests for navigation type classifications. TODO(avi): It's rather
459 // bogus that the same info is in two different enums; http://crbug.com/453555.
461 // Verify that navigations for NAVIGATION_TYPE_NEW_PAGE are correctly
462 // classified.
463 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
464 NavigationTypeClassification_NewPage) {
465 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
467 FrameTreeNode* root =
468 static_cast<WebContentsImpl*>(shell()->web_contents())->
469 GetFrameTree()->root();
472 // Simple load.
473 FrameNavigateParamsCapturer capturer(root);
474 GURL frame_url(embedded_test_server()->GetURL(
475 "/navigation_controller/page_with_links.html"));
476 NavigateFrameToURL(root, frame_url);
477 capturer.Wait();
478 // TODO(avi,creis): Why is this (and quite a few others below) a "link"
479 // transition? Lots of these transitions should be cleaned up.
480 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
481 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
485 // Load via a fragment link click.
486 FrameNavigateParamsCapturer capturer(root);
487 std::string script = "document.getElementById('fraglink').click()";
488 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
489 capturer.Wait();
490 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
491 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
495 // Load via link click.
496 FrameNavigateParamsCapturer capturer(root);
497 std::string script = "document.getElementById('thelink').click()";
498 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
499 capturer.Wait();
500 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
501 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
505 // location.assign().
506 FrameNavigateParamsCapturer capturer(root);
507 GURL frame_url(embedded_test_server()->GetURL(
508 "/navigation_controller/simple_page_2.html"));
509 std::string script = "location.assign('" + frame_url.spec() + "')";
510 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
511 capturer.Wait();
512 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
513 capturer.params().transition);
514 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
518 // history.pushState().
519 FrameNavigateParamsCapturer capturer(root);
520 std::string script =
521 "history.pushState({}, 'page 1', 'simple_page_1.html')";
522 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
523 capturer.Wait();
524 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
525 capturer.params().transition);
526 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
530 // Verify that navigations for NAVIGATION_TYPE_EXISTING_PAGE are correctly
531 // classified.
532 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
533 NavigationTypeClassification_ExistingPage) {
534 GURL url1(embedded_test_server()->GetURL(
535 "/navigation_controller/simple_page_1.html"));
536 NavigateToURL(shell(), url1);
537 GURL url2(embedded_test_server()->GetURL(
538 "/navigation_controller/simple_page_2.html"));
539 NavigateToURL(shell(), url2);
541 FrameTreeNode* root =
542 static_cast<WebContentsImpl*>(shell()->web_contents())->
543 GetFrameTree()->root();
546 // Back from the browser side.
547 FrameNavigateParamsCapturer capturer(root);
548 shell()->web_contents()->GetController().GoBack();
549 capturer.Wait();
550 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
551 | ui::PAGE_TRANSITION_FORWARD_BACK
552 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
553 capturer.params().transition);
554 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
558 // Forward from the browser side.
559 FrameNavigateParamsCapturer capturer(root);
560 shell()->web_contents()->GetController().GoForward();
561 capturer.Wait();
562 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
563 | ui::PAGE_TRANSITION_FORWARD_BACK
564 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
565 capturer.params().transition);
566 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
570 // Back from the renderer side.
571 FrameNavigateParamsCapturer capturer(root);
572 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
573 "history.back()"));
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 // Forward from the renderer side.
584 FrameNavigateParamsCapturer capturer(root);
585 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
586 "history.forward()"));
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 // Back from the renderer side via history.go().
597 FrameNavigateParamsCapturer capturer(root);
598 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
599 "history.go(-1)"));
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 // Forward 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 // Reload from the browser side.
623 FrameNavigateParamsCapturer capturer(root);
624 shell()->web_contents()->GetController().Reload(false);
625 capturer.Wait();
626 EXPECT_EQ(ui::PAGE_TRANSITION_RELOAD, capturer.params().transition);
627 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
631 // Reload from the renderer side.
632 FrameNavigateParamsCapturer capturer(root);
633 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(),
634 "location.reload()"));
635 capturer.Wait();
636 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
637 capturer.params().transition);
638 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, capturer.details().type);
642 // location.replace().
643 FrameNavigateParamsCapturer capturer(root);
644 GURL frame_url(embedded_test_server()->GetURL(
645 "/navigation_controller/simple_page_1.html"));
646 std::string script = "location.replace('" + frame_url.spec() + "')";
647 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
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 // Verify that navigations for NAVIGATION_TYPE_SAME_PAGE are correctly
656 // classified.
657 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
658 NavigationTypeClassification_SamePage) {
659 GURL url1(embedded_test_server()->GetURL(
660 "/navigation_controller/simple_page_1.html"));
661 NavigateToURL(shell(), url1);
663 FrameTreeNode* root =
664 static_cast<WebContentsImpl*>(shell()->web_contents())->
665 GetFrameTree()->root();
668 // Simple load.
669 FrameNavigateParamsCapturer capturer(root);
670 GURL frame_url(embedded_test_server()->GetURL(
671 "/navigation_controller/simple_page_1.html"));
672 NavigateFrameToURL(root, frame_url);
673 capturer.Wait();
674 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
675 EXPECT_EQ(NAVIGATION_TYPE_SAME_PAGE, capturer.details().type);
679 // Verify that navigations for NAVIGATION_TYPE_IN_PAGE are correctly
680 // classified.
681 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
682 NavigationTypeClassification_InPage) {
683 GURL url1(embedded_test_server()->GetURL(
684 "/navigation_controller/simple_page_1.html"));
685 NavigateToURL(shell(), url1);
687 FrameTreeNode* root =
688 static_cast<WebContentsImpl*>(shell()->web_contents())->
689 GetFrameTree()->root();
692 // history.replaceState().
693 FrameNavigateParamsCapturer capturer(root);
694 std::string script =
695 "history.replaceState({}, 'page 1', 'simple_page_2.html')";
696 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
697 capturer.Wait();
698 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
699 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
702 // Back and forward across a fragment navigation.
704 GURL url2(embedded_test_server()->GetURL(
705 "/navigation_controller/page_with_links.html"));
706 NavigateToURL(shell(), url2);
707 std::string script = "document.getElementById('fraglink').click()";
708 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
709 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
712 // Back.
713 FrameNavigateParamsCapturer capturer(root);
714 shell()->web_contents()->GetController().GoBack();
715 capturer.Wait();
716 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
717 | ui::PAGE_TRANSITION_FORWARD_BACK
718 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
719 capturer.params().transition);
720 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
724 // Forward.
725 FrameNavigateParamsCapturer capturer(root);
726 shell()->web_contents()->GetController().GoForward();
727 capturer.Wait();
728 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
729 capturer.params().transition);
730 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
733 // Back and forward across a pushState-created navigation.
735 NavigateToURL(shell(), url1);
736 script = "history.pushState({}, 'page 2', 'simple_page_2.html')";
737 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
738 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
741 // Back.
742 FrameNavigateParamsCapturer capturer(root);
743 shell()->web_contents()->GetController().GoBack();
744 capturer.Wait();
745 EXPECT_EQ(ui::PAGE_TRANSITION_TYPED
746 | ui::PAGE_TRANSITION_FORWARD_BACK
747 | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
748 capturer.params().transition);
749 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
753 // Forward.
754 FrameNavigateParamsCapturer capturer(root);
755 shell()->web_contents()->GetController().GoForward();
756 capturer.Wait();
757 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
758 capturer.params().transition);
759 EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
763 // Verify that navigations for NAVIGATION_TYPE_NEW_SUBFRAME and
764 // NAVIGATION_TYPE_AUTO_SUBFRAME are properly classified.
765 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
766 NavigationTypeClassification_NewAndAutoSubframe) {
767 GURL main_url(embedded_test_server()->GetURL(
768 "/navigation_controller/page_with_iframe.html"));
769 NavigateToURL(shell(), main_url);
771 // It is safe to obtain the root frame tree node here, as it doesn't change.
772 FrameTreeNode* root =
773 static_cast<WebContentsImpl*>(shell()->web_contents())->
774 GetFrameTree()->root();
776 ASSERT_EQ(1U, root->child_count());
777 ASSERT_NE(nullptr, root->child_at(0));
780 // Simple load.
781 FrameNavigateParamsCapturer capturer(root->child_at(0));
782 GURL frame_url(embedded_test_server()->GetURL(
783 "/navigation_controller/simple_page_1.html"));
784 NavigateFrameToURL(root->child_at(0), frame_url);
785 capturer.Wait();
786 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
787 capturer.params().transition);
788 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
792 // Back.
793 FrameNavigateParamsCapturer capturer(root->child_at(0));
794 shell()->web_contents()->GetController().GoBack();
795 capturer.Wait();
796 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
797 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
801 // Forward.
802 FrameNavigateParamsCapturer capturer(root->child_at(0));
803 shell()->web_contents()->GetController().GoForward();
804 capturer.Wait();
805 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
806 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
810 // Simple load.
811 FrameNavigateParamsCapturer capturer(root->child_at(0));
812 GURL frame_url(embedded_test_server()->GetURL(
813 "/navigation_controller/page_with_links.html"));
814 NavigateFrameToURL(root->child_at(0), frame_url);
815 capturer.Wait();
816 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
817 capturer.params().transition);
818 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
822 // Load via a fragment link click.
823 FrameNavigateParamsCapturer capturer(root->child_at(0));
824 std::string script = "document.getElementById('fraglink').click()";
825 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
826 script));
827 capturer.Wait();
828 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
829 capturer.params().transition);
830 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
834 // location.assign().
835 FrameNavigateParamsCapturer capturer(root->child_at(0));
836 GURL frame_url(embedded_test_server()->GetURL(
837 "/navigation_controller/simple_page_1.html"));
838 std::string script = "location.assign('" + frame_url.spec() + "')";
839 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
840 script));
841 capturer.Wait();
842 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
843 capturer.params().transition);
844 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
848 // location.replace().
849 LoadCommittedCapturer capturer(root->child_at(0));
850 GURL frame_url(embedded_test_server()->GetURL(
851 "/navigation_controller/simple_page_2.html"));
852 std::string script = "location.replace('" + frame_url.spec() + "')";
853 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
854 script));
855 capturer.Wait();
856 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
860 // history.pushState().
861 FrameNavigateParamsCapturer capturer(root->child_at(0));
862 std::string script =
863 "history.pushState({}, 'page 1', 'simple_page_1.html')";
864 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
865 script));
866 capturer.Wait();
867 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
868 capturer.params().transition);
869 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
873 // history.replaceState().
874 LoadCommittedCapturer capturer(root->child_at(0));
875 std::string script =
876 "history.replaceState({}, 'page 2', 'simple_page_2.html')";
877 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
878 script));
879 capturer.Wait();
880 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
884 // Reload.
885 LoadCommittedCapturer capturer(root->child_at(0));
886 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
887 "location.reload()"));
888 capturer.Wait();
889 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
893 // Create an iframe.
894 LoadCommittedCapturer capturer(shell()->web_contents());
895 GURL frame_url(embedded_test_server()->GetURL(
896 "/navigation_controller/simple_page_1.html"));
897 std::string script = "var iframe = document.createElement('iframe');"
898 "iframe.src = '" + frame_url.spec() + "';"
899 "document.body.appendChild(iframe);";
900 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
901 capturer.Wait();
902 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
906 // Verify that navigations caused by client-side redirects are correctly
907 // classified.
908 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
909 NavigationTypeClassification_ClientSideRedirect) {
910 NavigateToURL(shell(), GURL(url::kAboutBlankURL));
911 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
913 FrameTreeNode* root =
914 static_cast<WebContentsImpl*>(shell()->web_contents())->
915 GetFrameTree()->root();
918 // Load the redirecting page.
919 FrameNavigateParamsCapturer capturer(root);
920 capturer.set_navigations_remaining(2);
921 GURL frame_url(embedded_test_server()->GetURL(
922 "/navigation_controller/client_redirect.html"));
923 NavigateFrameToURL(root, frame_url);
924 capturer.Wait();
926 std::vector<FrameNavigateParams> params = capturer.all_params();
927 std::vector<LoadCommittedDetails> details = capturer.all_details();
928 ASSERT_EQ(2U, params.size());
929 ASSERT_EQ(2U, details.size());
930 EXPECT_EQ(ui::PAGE_TRANSITION_LINK, params[0].transition);
931 EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, details[0].type);
932 EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT,
933 params[1].transition);
934 EXPECT_EQ(NAVIGATION_TYPE_EXISTING_PAGE, details[1].type);
939 // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME
940 // commits.
941 // TODO(creis): Test cross-site and nested iframes.
942 // TODO(creis): Test updating entries for history auto subframe navigations.
943 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
944 FrameNavigationEntry_AutoSubframe) {
945 GURL main_url(embedded_test_server()->GetURL(
946 "/navigation_controller/simple_page_1.html"));
947 NavigateToURL(shell(), main_url);
948 const NavigationControllerImpl& controller =
949 static_cast<const NavigationControllerImpl&>(
950 shell()->web_contents()->GetController());
951 FrameTreeNode* root =
952 static_cast<WebContentsImpl*>(shell()->web_contents())->
953 GetFrameTree()->root();
955 // Create an iframe.
956 GURL frame_url(embedded_test_server()->GetURL(
957 "/navigation_controller/simple_page_2.html"));
959 LoadCommittedCapturer capturer(shell()->web_contents());
960 std::string script = "var iframe = document.createElement('iframe');"
961 "iframe.src = '" + frame_url.spec() + "';"
962 "document.body.appendChild(iframe);";
963 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
964 capturer.Wait();
965 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
968 // Check last committed NavigationEntry.
969 EXPECT_EQ(1, controller.GetEntryCount());
970 NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
971 EXPECT_EQ(main_url, entry->GetURL());
972 FrameNavigationEntry* root_entry = entry->root_node()->frame_entry.get();
973 EXPECT_EQ(main_url, root_entry->url());
975 // Verify subframe entries if we're in --site-per-process mode.
976 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
977 switches::kSitePerProcess)) {
978 // The entry should now have a subframe FrameNavigationEntry.
979 ASSERT_EQ(1U, entry->root_node()->children.size());
980 FrameNavigationEntry* frame_entry =
981 entry->root_node()->children[0]->frame_entry.get();
982 EXPECT_EQ(frame_url, frame_entry->url());
983 } else {
984 // There are no subframe FrameNavigationEntries by default.
985 EXPECT_EQ(0U, entry->root_node()->children.size());
989 } // namespace content