// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/values.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/load_notification_details.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/common/content_paths.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" #include "content/shell/shell.h" #include "content/test/content_browser_test.h" #include "content/test/content_browser_test_utils.h" #include "net/test/embedded_test_server/embedded_test_server.h" namespace content { class WebContentsImplBrowserTest : public ContentBrowserTest { public: WebContentsImplBrowserTest() {} private: DISALLOW_COPY_AND_ASSIGN(WebContentsImplBrowserTest); }; // Keeps track of data from LoadNotificationDetails so we can later verify that // they are correct, after the LoadNotificationDetails object is deleted. class LoadStopNotificationObserver : public WindowedNotificationObserver { public: LoadStopNotificationObserver(NavigationController* controller) : WindowedNotificationObserver(NOTIFICATION_LOAD_STOP, Source(controller)), session_index_(-1), controller_(NULL) { } virtual void Observe(int type, const NotificationSource& source, const NotificationDetails& details) OVERRIDE { if (type == NOTIFICATION_LOAD_STOP) { const Details load_details(details); url_ = load_details->url; session_index_ = load_details->session_index; controller_ = load_details->controller; } WindowedNotificationObserver::Observe(type, source, details); } GURL url_; int session_index_; NavigationController* controller_; }; // Starts a new navigation as soon as the current one commits, but does not // wait for it to complete. This allows us to observe DidStopLoading while // a pending entry is present. class NavigateOnCommitObserver : public WebContentsObserver { public: NavigateOnCommitObserver(Shell* shell, GURL url) : WebContentsObserver(shell->web_contents()), shell_(shell), url_(url), done_(false) { } // WebContentsObserver: virtual void NavigationEntryCommitted( const LoadCommittedDetails& load_details) OVERRIDE { if (!done_) { done_ = true; shell_->LoadURL(url_); } } Shell* shell_; GURL url_; bool done_; }; // Test that DidStopLoading includes the correct URL in the details. IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, DidStopLoadingDetails) { ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); LoadStopNotificationObserver load_observer( &shell()->web_contents()->GetController()); NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); load_observer.Wait(); EXPECT_EQ("/title1.html", load_observer.url_.path()); EXPECT_EQ(0, load_observer.session_index_); EXPECT_EQ(&shell()->web_contents()->GetController(), load_observer.controller_); } // Test that DidStopLoading includes the correct URL in the details when a // pending entry is present. IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, DidStopLoadingDetailsWithPending) { ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); // Listen for the first load to stop. LoadStopNotificationObserver load_observer( &shell()->web_contents()->GetController()); // Start a new pending navigation as soon as the first load commits. // We will hear a DidStopLoading from the first load as the new load // is started. NavigateOnCommitObserver commit_observer( shell(), embedded_test_server()->GetURL("/title2.html")); NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); load_observer.Wait(); EXPECT_EQ("/title1.html", load_observer.url_.path()); EXPECT_EQ(0, load_observer.session_index_); EXPECT_EQ(&shell()->web_contents()->GetController(), load_observer.controller_); } // Test that the browser receives the proper frame attach/detach messages from // the renderer and builds proper frame tree. IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FrameTree) { ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); NavigateToURL(shell(), embedded_test_server()->GetURL("/frame_tree/top.html")); WebContentsImpl* wc = static_cast(shell()->web_contents()); RenderViewHostImpl* rvh = static_cast( wc->GetRenderViewHost()); FrameTreeNode* root = wc->GetFrameTreeRootForTesting(); // Check that the root node is properly created with the frame id of the // initial navigation. EXPECT_EQ(3UL, root->child_count()); EXPECT_EQ(std::string(), root->frame_name()); EXPECT_EQ(rvh->main_frame_id(), root->frame_id()); EXPECT_EQ(2UL, root->child_at(0)->child_count()); EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str()); // Verify the deepest node exists and has the right name. EXPECT_EQ(2UL, root->child_at(2)->child_count()); EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count()); EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count()); EXPECT_STREQ("3-1-id", root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str()); // Navigate to about:blank, which should leave only the root node of the frame // tree in the browser process. NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")); root = wc->GetFrameTreeRootForTesting(); EXPECT_EQ(0UL, root->child_count()); EXPECT_EQ(std::string(), root->frame_name()); EXPECT_EQ(rvh->main_frame_id(), root->frame_id()); } } // namespace content