Chromium Code Reviews| Index: content/browser/frame_host/navigation_controller_impl_browsertest.cc |
| diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
| index 8fc6ec99bb8c6def3a697740ff1ec3739b2e5cd8..b67ba3cb5c0a8dfc285b90dbd2ae68abff39bb10 100644 |
| --- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
| +++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc |
| @@ -469,59 +469,6 @@ class NoNavigationsObserver : public WebContentsObserver { |
| } |
| }; |
| -} // namespace |
| - |
| -// Some pages create a popup, then write an iframe into it. This causes a |
| -// subframe navigation without having any committed entry. Such navigations |
| -// just get thrown on the ground, but we shouldn't crash. |
| -// |
| -// This test actually hits NAVIGATION_TYPE_NAV_IGNORE three times. Two of them, |
| -// the initial window.open() and the iframe creation, don't try to create |
| -// navigation entries, and the third, the new navigation, tries to. |
| -IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) { |
|
Charlie Reis
2016/05/02 22:35:34
Sorry, had to move this test below so it could use
|
| - NavigateToURL(shell(), GURL(url::kAboutBlankURL)); |
| - EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
| - |
| - FrameTreeNode* root = |
| - static_cast<WebContentsImpl*>(shell()->web_contents())-> |
| - GetFrameTree()->root(); |
| - |
| - // Pop open a new window. |
| - ShellAddedObserver new_shell_observer; |
| - std::string script = "window.open()"; |
| - EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| - Shell* new_shell = new_shell_observer.GetShell(); |
| - ASSERT_NE(new_shell->web_contents(), shell()->web_contents()); |
| - FrameTreeNode* new_root = |
| - static_cast<WebContentsImpl*>(new_shell->web_contents())-> |
| - GetFrameTree()->root(); |
| - |
| - // Make a new iframe in it. |
| - NoNavigationsObserver observer(new_shell->web_contents()); |
| - script = "var iframe = document.createElement('iframe');" |
| - "iframe.src = 'data:text/html,<p>some page</p>';" |
| - "document.body.appendChild(iframe);"; |
| - EXPECT_TRUE(ExecuteScript(new_root->current_frame_host(), script)); |
| - // The success check is of the last-committed entry, and there is none. |
| - WaitForLoadStopWithoutSuccessCheck(new_shell->web_contents()); |
| - |
| - ASSERT_EQ(1U, new_root->child_count()); |
| - ASSERT_NE(nullptr, new_root->child_at(0)); |
| - |
| - // Navigate it. |
| - GURL frame_url = embedded_test_server()->GetURL( |
| - "/navigation_controller/simple_page_2.html"); |
| - script = "location.assign('" + frame_url.spec() + "')"; |
| - EXPECT_TRUE( |
| - ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
| - |
| - // Success is not crashing, and not navigating. |
| - EXPECT_EQ(nullptr, |
| - new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
| -} |
| - |
| -namespace { |
| - |
| class FrameNavigateParamsCapturer : public WebContentsObserver { |
| public: |
| // Observes navigation for the specified |node|. |
| @@ -680,6 +627,80 @@ class LoadCommittedCapturer : public WebContentsObserver { |
| } // namespace |
| +// Some pages create a popup, then write an iframe into it. This causes a |
| +// subframe navigation without having any committed entry. Such navigations |
| +// just get thrown on the ground, but we shouldn't crash. |
| +// |
| +// This test actually hits NAVIGATION_TYPE_NAV_IGNORE four times. Two of them, |
| +// the initial window.open() and the iframe creation, don't try to create |
| +// navigation entries, and the third and fourth, the new navigations, try to. |
| +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, SubframeOnEmptyPage) { |
| + // Navigate to a page to force the renderer process to start. |
| + NavigateToURL(shell(), GURL(url::kAboutBlankURL)); |
| + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); |
|
alexmos
2016/05/03 22:07:51
While we're here - the wait doesn't seem necessary
Charlie Reis
2016/05/03 23:43:05
Done.
|
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // Pop open a new window with no last committed entry. |
| + ShellAddedObserver new_shell_observer; |
| + { |
| + std::string script = "window.open()"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + } |
| + Shell* new_shell = new_shell_observer.GetShell(); |
| + ASSERT_NE(new_shell->web_contents(), shell()->web_contents()); |
| + FrameTreeNode* new_root = |
| + static_cast<WebContentsImpl*>(new_shell->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + EXPECT_FALSE( |
| + new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
| + |
| + // Make a new iframe in it. |
| + NoNavigationsObserver observer(new_shell->web_contents()); |
| + { |
| + LoadCommittedCapturer capturer(new_shell->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = 'data:text/html,<p>some page</p>';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(new_root->current_frame_host(), script)); |
| + capturer.Wait(); |
| + } |
| + ASSERT_EQ(1U, new_root->child_count()); |
| + ASSERT_NE(nullptr, new_root->child_at(0)); |
| + |
| + // Navigate it cross-site. |
| + GURL frame_url = embedded_test_server()->GetURL( |
| + "foo.com", "/navigation_controller/simple_page_2.html"); |
| + { |
| + LoadCommittedCapturer capturer(new_shell->web_contents()); |
| + std::string script = "location.assign('" + frame_url.spec() + "')"; |
| + EXPECT_TRUE( |
| + ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
| + capturer.Wait(); |
| + } |
| + |
| + // Success is not crashing, and not navigating. |
| + EXPECT_EQ(nullptr, |
| + new_shell->web_contents()->GetController().GetLastCommittedEntry()); |
| + |
| + // A nested iframe with a cross-site URL should also be able to commit. |
| + GURL grandchild_url(embedded_test_server()->GetURL( |
| + "bar.com", "/navigation_controller/simple_page_1.html")); |
| + { |
| + LoadCommittedCapturer capturer(new_shell->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + grandchild_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE( |
| + ExecuteScript(new_root->child_at(0)->current_frame_host(), script)); |
| + capturer.Wait(); |
| + } |
| + ASSERT_EQ(1U, new_root->child_at(0)->child_count()); |
| + EXPECT_EQ(grandchild_url, new_root->child_at(0)->child_at(0)->current_url()); |
| +} |
| + |
| IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| ErrorPageReplacement) { |
| NavigationController& controller = shell()->web_contents()->GetController(); |
| @@ -1571,6 +1592,196 @@ IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| } |
| } |
| +// Verify the tree of FrameNavigationEntries when a nested iframe commits inside |
| +// the initial blank page of a loading iframe. |
| +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| + FrameNavigationEntry_SlowNestedAutoSubframe) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_1.html")); |
| + NavigateToURL(shell(), main_url); |
|
alexmos
2016/05/03 22:07:51
nit: EXPECT_TRUE (in all tests)
Charlie Reis
2016/05/03 23:43:05
Done.
|
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // 1. Create a iframe with a URL that doesn't commit. |
| + GURL slow_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_2.html")); |
| + TestNavigationManager subframe_delayer(shell()->web_contents(), slow_url); |
| + { |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + slow_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + } |
| + subframe_delayer.WaitForWillStartRequest(); |
| + |
| + // Stop the request so that we can wait for load stop below, without ending up |
| + // with a commit for this frame. |
| + shell()->web_contents()->Stop(); |
| + |
| + // 2. A nested iframe with a cross-site URL should be able to commit. |
| + GURL foo_url(embedded_test_server()->GetURL( |
| + "foo.com", "/navigation_controller/simple_page_1.html")); |
| + { |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + foo_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
| + WaitForLoadStopWithoutSuccessCheck(shell()->web_contents()); |
| + } |
| + |
| + // TODO(creis): Check subframe entries once we create them in this case. |
| + // See https://crbug.com/608402. |
| + EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url()); |
| +} |
| + |
| +// Verify the tree of FrameNavigationEntries when a nested iframe commits inside |
| +// the initial blank page of an iframe with no committed entry. |
| +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| + FrameNavigationEntry_NoCommitNestedAutoSubframe) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_1.html")); |
| + NavigateToURL(shell(), main_url); |
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // 1. Create a iframe with a URL that doesn't commit. |
| + GURL no_commit_url(embedded_test_server()->GetURL("/nocontent")); |
| + { |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + no_commit_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + } |
| + EXPECT_EQ(GURL(), root->child_at(0)->current_url()); |
| + |
| + // 2. A nested iframe with a cross-site URL should be able to commit. |
| + GURL foo_url(embedded_test_server()->GetURL( |
| + "foo.com", "/navigation_controller/simple_page_1.html")); |
| + { |
| + LoadCommittedCapturer capturer(shell()->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + foo_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
| + capturer.Wait(); |
| + EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
| + } |
| + |
| + // TODO(creis): Check subframe entries once we create them in this case. |
| + // See https://crbug.com/608402. |
| + EXPECT_EQ(foo_url, root->child_at(0)->child_at(0)->current_url()); |
| +} |
| + |
| +// Verify the tree of FrameNavigationEntries when a nested iframe commits after |
| +// going back in-page, in which case its parent might not have been in the |
| +// NavigationEntry. |
| +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| + FrameNavigationEntry_BackNestedAutoSubframe) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_1.html")); |
| + NavigateToURL(shell(), main_url); |
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // 1. Navigate in-page. |
| + { |
| + FrameNavigateParamsCapturer capturer(root); |
| + std::string script = "history.pushState({}, 'foo', 'foo')"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + capturer.Wait(); |
| + EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type); |
| + EXPECT_TRUE(capturer.details().is_in_page); |
| + } |
| + |
| + // 2. Create an iframe. |
| + GURL child_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_2.html")); |
| + { |
| + LoadCommittedCapturer capturer(shell()->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + child_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + capturer.Wait(); |
| + EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
| + } |
| + |
| + // 3. Go back in-page. |
| + { |
| + TestNavigationObserver back_load_observer(shell()->web_contents()); |
| + shell()->web_contents()->GetController().GoBack(); |
| + back_load_observer.Wait(); |
| + } |
| + |
| + // 4. A nested iframe with a cross-site URL should be able to commit. |
| + GURL grandchild_url(embedded_test_server()->GetURL( |
| + "foo.com", "/navigation_controller/simple_page_1.html")); |
| + { |
| + LoadCommittedCapturer capturer(shell()->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + grandchild_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
| + capturer.Wait(); |
| + EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
| + } |
| + |
| + // TODO(creis): Check subframe entries once we create them in this case. |
| + // See https://crbug.com/608402. |
| + EXPECT_EQ(grandchild_url, root->child_at(0)->child_at(0)->current_url()); |
| +} |
| + |
| +// Verify the tree of FrameNavigationEntries when a nested iframe commits after |
| +// its parent changes its name, in which case we might not find the parent |
| +// FrameNavigationEntry. |
|
alexmos
2016/05/03 22:07:51
Would it be useful to also reference the crash bug
Charlie Reis
2016/05/03 23:43:05
Yep. 603245 was due to the back/forward CL and is
|
| +IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, |
| + FrameNavigationEntry_RenameNestedAutoSubframe) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_1.html")); |
| + NavigateToURL(shell(), main_url); |
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // 1. Create an iframe. |
| + GURL child_url(embedded_test_server()->GetURL( |
| + "/navigation_controller/simple_page_2.html")); |
| + { |
| + LoadCommittedCapturer capturer(shell()->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + child_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->current_frame_host(), script)); |
| + capturer.Wait(); |
| + EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
| + } |
| + |
| + // 2. Change the iframe's name. |
| + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), |
| + "window.name = 'foo';")); |
| + |
| + // 3. A nested iframe with a cross-site URL should be able to commit. |
| + GURL bar_url(embedded_test_server()->GetURL( |
| + "bar.com", "/navigation_controller/simple_page_1.html")); |
| + { |
| + LoadCommittedCapturer capturer(shell()->web_contents()); |
| + std::string script = "var iframe = document.createElement('iframe');" |
| + "iframe.src = '" + bar_url.spec() + "';" |
| + "document.body.appendChild(iframe);"; |
| + EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(), script)); |
| + |
| + capturer.Wait(); |
|
alexmos
2016/05/03 22:07:51
There are a lot of these create-frame-and-wait blo
Charlie Reis
2016/05/03 23:43:05
Yeah, it's a bit of a tradeoff. I tried switching
alexmos
2016/05/03 23:52:40
Acknowledged.
|
| + EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type()); |
| + } |
| + |
| + // TODO(creis): Check subframe entries once we create them in this case. |
| + // See https://crbug.com/608402. |
| + EXPECT_EQ(bar_url, root->child_at(0)->child_at(0)->current_url()); |
| +} |
| + |
| // Verify the tree of FrameNavigationEntries after NAVIGATION_TYPE_AUTO_SUBFRAME |
| // commits. |
| // TODO(creis): Test updating entries for history auto subframe navigations. |