Add remoting and PPAPI tests to GN build
[chromium-blink-merge.git] / content / browser / frame_host / navigation_controller_impl_browsertest.cc
blob9024ff66517a200edaf5ae982bfd46fd18342fac
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/strings/stringprintf.h"
7 #include "content/browser/frame_host/frame_tree.h"
8 #include "content/browser/frame_host/navigation_controller_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/browser/web_contents_observer.h"
14 #include "content/public/common/bindings_policy.h"
15 #include "content/public/common/url_constants.h"
16 #include "content/public/test/browser_test_utils.h"
17 #include "content/public/test/content_browser_test.h"
18 #include "content/public/test/content_browser_test_utils.h"
19 #include "content/public/test/test_navigation_observer.h"
20 #include "content/public/test/test_utils.h"
21 #include "content/shell/browser/shell.h"
22 #include "content/test/content_browser_test_utils_internal.h"
23 #include "net/dns/mock_host_resolver.h"
24 #include "net/test/embedded_test_server/embedded_test_server.h"
26 namespace content {
28 class NavigationControllerBrowserTest : public ContentBrowserTest {
29 protected:
30 void SetUpOnMainThread() override {
31 host_resolver()->AddRule("*", "127.0.0.1");
32 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
36 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, LoadDataWithBaseURL) {
37 const GURL base_url("http://baseurl");
38 const GURL history_url("http://historyurl");
39 const std::string data = "<html><body>foo</body></html>";
41 const NavigationController& controller =
42 shell()->web_contents()->GetController();
43 // Load data. Blocks until it is done.
44 content::LoadDataWithBaseURL(shell(), history_url, data, base_url);
46 // We should use history_url instead of the base_url as the original url of
47 // this navigation entry, because base_url is only used for resolving relative
48 // paths in the data, or enforcing same origin policy.
49 EXPECT_EQ(controller.GetVisibleEntry()->GetOriginalRequestURL(), history_url);
52 // The renderer uses the position in the history list as a clue to whether a
53 // navigation is stale. In the case where the entry limit is reached and the
54 // history list is pruned, make sure that there is no mismatch that would cause
55 // it to start incorrectly rejecting navigations as stale. See
56 // http://crbug.com/89798.
57 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
58 DontIgnoreBackAfterNavEntryLimit) {
59 NavigationController& controller =
60 shell()->web_contents()->GetController();
62 const int kMaxEntryCount =
63 static_cast<int>(NavigationControllerImpl::max_entry_count());
65 // Load up to the max count, all entries should be there.
66 for (int url_index = 0; url_index < kMaxEntryCount; ++url_index) {
67 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
68 EXPECT_TRUE(NavigateToURL(shell(), url));
71 EXPECT_EQ(controller.GetEntryCount(), kMaxEntryCount);
73 // Navigate twice more more.
74 for (int url_index = kMaxEntryCount;
75 url_index < kMaxEntryCount + 2; ++url_index) {
76 GURL url(base::StringPrintf("data:text/html,page%d", url_index));
77 EXPECT_TRUE(NavigateToURL(shell(), url));
80 // We expect page0 and page1 to be gone.
81 EXPECT_EQ(kMaxEntryCount, controller.GetEntryCount());
82 EXPECT_EQ(GURL("data:text/html,page2"),
83 controller.GetEntryAtIndex(0)->GetURL());
85 // Now try to go back. This should not hang.
86 ASSERT_TRUE(controller.CanGoBack());
87 controller.GoBack();
88 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
90 // This should have successfully gone back.
91 EXPECT_EQ(GURL(base::StringPrintf("data:text/html,page%d", kMaxEntryCount)),
92 controller.GetLastCommittedEntry()->GetURL());
95 namespace {
97 int RendererHistoryLength(Shell* shell) {
98 int value = 0;
99 EXPECT_TRUE(ExecuteScriptAndExtractInt(
100 shell->web_contents(),
101 "domAutomationController.send(history.length)",
102 &value));
103 return value;
106 // Similar to the ones from content_browser_test_utils.
107 bool NavigateToURLAndReplace(Shell* shell, const GURL& url) {
108 WebContents* web_contents = shell->web_contents();
109 WaitForLoadStop(web_contents);
110 TestNavigationObserver same_tab_observer(web_contents, 1);
111 NavigationController::LoadURLParams params(url);
112 params.should_replace_current_entry = true;
113 web_contents->GetController().LoadURLWithParams(params);
114 web_contents->Focus();
115 same_tab_observer.Wait();
116 if (!IsLastCommittedEntryOfPageType(web_contents, PAGE_TYPE_NORMAL))
117 return false;
118 return web_contents->GetLastCommittedURL() == url;
121 } // namespace
123 // When loading a new page to replace an old page in the history list, make sure
124 // that the browser and renderer agree, and that both get it right.
125 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
126 CorrectLengthWithCurrentItemReplacement) {
127 NavigationController& controller =
128 shell()->web_contents()->GetController();
130 EXPECT_TRUE(NavigateToURL(shell(), GURL("data:text/html,page1")));
131 EXPECT_EQ(1, controller.GetEntryCount());
132 EXPECT_EQ(1, RendererHistoryLength(shell()));
134 EXPECT_TRUE(NavigateToURLAndReplace(shell(), GURL("data:text/html,page2")));
135 EXPECT_EQ(1, controller.GetEntryCount());
136 EXPECT_EQ(1, RendererHistoryLength(shell()));
138 // Note that there's no way to access the renderer's notion of the history
139 // offset via JavaScript. Checking just the history length, though, is enough;
140 // if the replacement failed, there would be a new history entry and thus an
141 // incorrect length.
144 // When spawning a new page from a WebUI page, make sure that the browser and
145 // renderer agree about the length of the history list, and that both get it
146 // right.
147 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
148 CorrectLengthWithNewTabNavigatingFromWebUI) {
149 GURL web_ui_page(std::string(kChromeUIScheme) + "://" +
150 std::string(kChromeUIGpuHost));
151 EXPECT_TRUE(NavigateToURL(shell(), web_ui_page));
152 EXPECT_EQ(BINDINGS_POLICY_WEB_UI,
153 shell()->web_contents()->GetRenderViewHost()->GetEnabledBindings());
155 ShellAddedObserver observer;
156 std::string page_url = embedded_test_server()->GetURL(
157 "/navigation_controller/simple_page_1.html").spec();
158 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
159 "window.open('" + page_url + "', '_blank')"));
160 Shell* shell2 = observer.GetShell();
161 WaitForLoadStop(shell2->web_contents());
163 EXPECT_EQ(1, shell2->web_contents()->GetController().GetEntryCount());
164 EXPECT_EQ(1, RendererHistoryLength(shell2));
166 // Again, as above, there's no way to access the renderer's notion of the
167 // history offset via JavaScript. Checking just the history length, again,
168 // will have to suffice.
171 namespace {
173 struct FrameNavigateParamsCapturer : public WebContentsObserver {
174 public:
175 // Observes navigation for the specified |node|.
176 explicit FrameNavigateParamsCapturer(FrameTreeNode* node)
177 : WebContentsObserver(
178 node->current_frame_host()->delegate()->GetAsWebContents()),
179 frame_tree_node_id_(node->frame_tree_node_id()),
180 message_loop_runner_(new MessageLoopRunner) {}
182 void Wait() {
183 message_loop_runner_->Run();
186 const FrameNavigateParams& params() const {
187 return params_;
190 const LoadCommittedDetails& details() const {
191 return details_;
194 private:
195 void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
196 const LoadCommittedDetails& details,
197 const FrameNavigateParams& params) override {
198 RenderFrameHostImpl* rfh =
199 static_cast<RenderFrameHostImpl*>(render_frame_host);
200 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
201 return;
203 params_ = params;
204 details_ = details;
205 message_loop_runner_->Quit();
208 // The id of the FrameTreeNode whose navigations to observe.
209 int frame_tree_node_id_;
211 // The params of the last navigation.
212 FrameNavigateParams params_;
214 // The details of the last navigation.
215 LoadCommittedDetails details_;
217 // The MessageLoopRunner used to spin the message loop.
218 scoped_refptr<MessageLoopRunner> message_loop_runner_;
221 struct LoadCommittedCapturer : public WebContentsObserver {
222 public:
223 // Observes the load commit for the specified |node|.
224 explicit LoadCommittedCapturer(FrameTreeNode* node)
225 : WebContentsObserver(
226 node->current_frame_host()->delegate()->GetAsWebContents()),
227 frame_tree_node_id_(node->frame_tree_node_id()),
228 message_loop_runner_(new MessageLoopRunner) {}
230 // Observes the load commit for the next created frame in the specified
231 // |web_contents|.
232 explicit LoadCommittedCapturer(WebContents* web_contents)
233 : WebContentsObserver(web_contents),
234 frame_tree_node_id_(0),
235 message_loop_runner_(new MessageLoopRunner) {}
237 void Wait() {
238 message_loop_runner_->Run();
241 ui::PageTransition transition_type() const {
242 return transition_type_;
245 private:
246 void RenderFrameCreated(RenderFrameHost* render_frame_host) override {
247 // If this object was created with a specified tree frame node, there
248 // shouldn't be any frames being created.
249 DCHECK_EQ(0, frame_tree_node_id_);
250 RenderFrameHostImpl* rfh =
251 static_cast<RenderFrameHostImpl*>(render_frame_host);
252 frame_tree_node_id_ = rfh->frame_tree_node()->frame_tree_node_id();
255 void DidCommitProvisionalLoadForFrame(
256 RenderFrameHost* render_frame_host,
257 const GURL& url,
258 ui::PageTransition transition_type) override {
259 DCHECK_NE(0, frame_tree_node_id_);
260 RenderFrameHostImpl* rfh =
261 static_cast<RenderFrameHostImpl*>(render_frame_host);
262 if (rfh->frame_tree_node()->frame_tree_node_id() != frame_tree_node_id_)
263 return;
265 transition_type_ = transition_type;
266 message_loop_runner_->Quit();
269 // The id of the FrameTreeNode whose navigations to observe.
270 int frame_tree_node_id_;
272 // The transition_type of the last navigation.
273 ui::PageTransition transition_type_;
275 // The MessageLoopRunner used to spin the message loop.
276 scoped_refptr<MessageLoopRunner> message_loop_runner_;
279 } // namespace
281 // Verify that the distinction between manual and auto subframes is properly set
282 // for subframe navigations. TODO(avi): It's rather bogus that the same info is
283 // in two different enums; http://crbug.com/453555.
284 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
285 ManualAndAutoSubframeNavigationClassification) {
286 GURL main_url(embedded_test_server()->GetURL(
287 "/navigation_controller/page_with_iframe.html"));
288 NavigateToURL(shell(), main_url);
290 // It is safe to obtain the root frame tree node here, as it doesn't change.
291 FrameTreeNode* root =
292 static_cast<WebContentsImpl*>(shell()->web_contents())->
293 GetFrameTree()->root();
295 ASSERT_EQ(1U, root->child_count());
296 ASSERT_NE(nullptr, root->child_at(0));
299 // Navigate the iframe to a new URL; expect a manual subframe transition.
300 FrameNavigateParamsCapturer capturer(root->child_at(0));
301 GURL frame_url(embedded_test_server()->GetURL(
302 "/navigation_controller/simple_page_1.html"));
303 NavigateFrameToURL(root->child_at(0), frame_url);
304 capturer.Wait();
305 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
306 capturer.params().transition);
307 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
311 // Do a history navigation; expect an auto subframe transition.
312 FrameNavigateParamsCapturer capturer(root->child_at(0));
313 shell()->web_contents()->GetController().GoBack();
314 capturer.Wait();
315 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
316 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
320 // Do a history navigation; expect an auto subframe transition.
321 FrameNavigateParamsCapturer capturer(root->child_at(0));
322 shell()->web_contents()->GetController().GoForward();
323 capturer.Wait();
324 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.params().transition);
325 EXPECT_EQ(NAVIGATION_TYPE_AUTO_SUBFRAME, capturer.details().type);
329 // Navigate the iframe to a new URL; expect a manual subframe transition.
330 FrameNavigateParamsCapturer capturer(root->child_at(0));
331 GURL frame_url(embedded_test_server()->GetURL(
332 "/navigation_controller/simple_page_2.html"));
333 NavigateFrameToURL(root->child_at(0), frame_url);
334 capturer.Wait();
335 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
336 capturer.params().transition);
337 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
341 // Use location.assign(); expect a manual subframe transition.
342 FrameNavigateParamsCapturer capturer(root->child_at(0));
343 GURL frame_url(embedded_test_server()->GetURL(
344 "/navigation_controller/simple_page_1.html"));
345 std::string script = "location.assign('" + frame_url.spec() + "')";
346 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
347 script));
348 capturer.Wait();
349 EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
350 capturer.params().transition);
351 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
355 // Use location.replace(); expect an auto subframe transition. (Replacements
356 // aren't "navigation" so we only see the frame load committing.)
357 LoadCommittedCapturer capturer(root->child_at(0));
358 GURL frame_url(embedded_test_server()->GetURL(
359 "/navigation_controller/simple_page_2.html"));
360 std::string script = "location.replace('" + frame_url.spec() + "')";
361 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
362 script));
363 capturer.Wait();
364 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
368 // Reload the subframe; expect an auto subframe transition. (Reloads aren't
369 // "navigation" so we only see the frame load committing.)
370 LoadCommittedCapturer capturer(root->child_at(0));
371 EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
372 "location.reload()"));
373 capturer.Wait();
374 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
378 // Create an iframe; expect an auto subframe transition. (Initial frame
379 // creation isn't "navigation" so we only see the frame load committing.)
380 LoadCommittedCapturer capturer(shell()->web_contents());
381 GURL frame_url(embedded_test_server()->GetURL(
382 "/navigation_controller/simple_page_1.html"));
383 std::string script = "var iframe = document.createElement('iframe');"
384 "iframe.src = '" + frame_url.spec() + "';"
385 "document.body.appendChild(iframe);";
386 EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
387 capturer.Wait();
388 EXPECT_EQ(ui::PAGE_TRANSITION_AUTO_SUBFRAME, capturer.transition_type());
392 } // namespace content