blob: 55f66f1f12208832c59c7bf0a914097b0b7bc255 [file] [log] [blame]
naskob2f82b82016-04-15 07:09:071// Copyright 2016 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.
4
naskoe4ebe0782016-10-27 16:52:175#include "base/command_line.h"
Gabriel Charette078e3662017-08-28 22:59:046#include "base/run_loop.h"
Alex Moshchukd252c192017-07-17 22:03:487#include "base/test/scoped_feature_list.h"
Alex Moshchuk71f485592017-08-16 16:20:008#include "base/test/test_timeouts.h"
Reza.Zakerinasab875245c2018-02-27 17:09:019#include "build/build_config.h"
naskoe4ebe0782016-10-27 16:52:1710#include "chrome/app/chrome_command_ids.h"
naskob2f82b82016-04-15 07:09:0711#include "chrome/browser/chrome_notification_types.h"
naskoe4ebe0782016-10-27 16:52:1712#include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
naskob2f82b82016-04-15 07:09:0713#include "chrome/browser/ui/browser.h"
afakhry4d116bd2016-11-29 17:25:2514#include "chrome/browser/ui/browser_commands.h"
naskob2f82b82016-04-15 07:09:0715#include "chrome/browser/ui/tabs/tab_strip_model.h"
clamyb4f02242017-09-19 12:58:2716#include "chrome/common/url_constants.h"
naskob2f82b82016-04-15 07:09:0717#include "chrome/test/base/in_process_browser_test.h"
18#include "chrome/test/base/ui_test_utils.h"
Alex Moshchukd252c192017-07-17 22:03:4819#include "components/network_session_configurator/common/network_switches.h"
afakhry4d116bd2016-11-29 17:25:2520#include "components/url_formatter/url_formatter.h"
21#include "content/public/browser/navigation_entry.h"
naskob2f82b82016-04-15 07:09:0722#include "content/public/browser/navigation_handle.h"
23#include "content/public/browser/notification_service.h"
afakhry4d116bd2016-11-29 17:25:2524#include "content/public/browser/render_frame_host.h"
clamyb4f02242017-09-19 12:58:2725#include "content/public/browser/render_process_host.h"
naskob2f82b82016-04-15 07:09:0726#include "content/public/browser/web_contents_observer.h"
Alex Moshchuk71f485592017-08-16 16:20:0027#include "content/public/common/browser_side_navigation_policy.h"
Alex Moshchukd252c192017-07-17 22:03:4828#include "content/public/common/content_features.h"
lgreycb827f612017-01-13 01:32:2429#include "content/public/common/content_switches.h"
naskoe4ebe0782016-10-27 16:52:1730#include "content/public/common/context_menu_params.h"
afakhry4d116bd2016-11-29 17:25:2531#include "content/public/common/url_constants.h"
naskob2f82b82016-04-15 07:09:0732#include "content/public/test/browser_test_utils.h"
Alex Moshchuk71f485592017-08-16 16:20:0033#include "content/public/test/navigation_handle_observer.h"
naskob2f82b82016-04-15 07:09:0734#include "content/public/test/test_navigation_observer.h"
Alex Moshchukd252c192017-07-17 22:03:4835#include "google_apis/gaia/gaia_switches.h"
naskoe4ebe0782016-10-27 16:52:1736#include "net/dns/mock_host_resolver.h"
naskob2f82b82016-04-15 07:09:0737
38class ChromeNavigationBrowserTest : public InProcessBrowserTest {
39 public:
40 ChromeNavigationBrowserTest() {}
41 ~ChromeNavigationBrowserTest() override {}
42
43 void SetUpCommandLine(base::CommandLine* command_line) override {
lgreycb827f612017-01-13 01:32:2444 // Backgrounded renderer processes run at a lower priority, causing the
45 // tests to take more time to complete. Disable backgrounding so that the
46 // tests don't time out.
47 command_line->AppendSwitch(switches::kDisableRendererBackgrounding);
48
naskob2f82b82016-04-15 07:09:0749 ASSERT_TRUE(embedded_test_server()->Start());
50 }
51
52 void StartServerWithExpiredCert() {
53 expired_https_server_.reset(
54 new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
55 expired_https_server_->SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
56 expired_https_server_->AddDefaultHandlers(
57 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
58 ASSERT_TRUE(expired_https_server_->Start());
59 }
60
61 net::EmbeddedTestServer* expired_https_server() {
62 return expired_https_server_.get();
63 }
64
65 private:
66 std::unique_ptr<net::EmbeddedTestServer> expired_https_server_;
67
68 DISALLOW_COPY_AND_ASSIGN(ChromeNavigationBrowserTest);
69};
70
71// Helper class to track and allow waiting for navigation start events.
72class DidStartNavigationObserver : public content::WebContentsObserver {
73 public:
74 explicit DidStartNavigationObserver(content::WebContents* web_contents)
75 : content::WebContentsObserver(web_contents),
76 message_loop_runner_(new content::MessageLoopRunner) {}
77 ~DidStartNavigationObserver() override {}
78
gab2998ee72017-05-05 16:23:5079 // Runs a nested run loop and blocks until the full load has
naskob2f82b82016-04-15 07:09:0780 // completed.
81 void Wait() { message_loop_runner_->Run(); }
82
83 private:
84 // WebContentsObserver
85 void DidStartNavigation(content::NavigationHandle* handle) override {
86 if (message_loop_runner_->loop_running())
87 message_loop_runner_->Quit();
88 }
89
90 // The MessageLoopRunner used to spin the message loop.
91 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
92
93 DISALLOW_COPY_AND_ASSIGN(DidStartNavigationObserver);
94};
95
96// Test to verify that navigations are not deleting the transient
97// NavigationEntry when showing an interstitial page and the old renderer
98// process is trying to navigate. See https://crbug.com/600046.
99IN_PROC_BROWSER_TEST_F(
100 ChromeNavigationBrowserTest,
101 TransientEntryPreservedOnMultipleNavigationsDuringInterstitial) {
102 StartServerWithExpiredCert();
103
104 GURL setup_url =
105 embedded_test_server()->GetURL("/window_open_and_navigate.html");
106 GURL initial_url = embedded_test_server()->GetURL("/title1.html");
107 GURL error_url(expired_https_server()->GetURL("/ssl/blank_page.html"));
108
109 ui_test_utils::NavigateToURL(browser(), setup_url);
110 content::WebContents* main_web_contents =
111 browser()->tab_strip_model()->GetActiveWebContents();
112
113 // Call the JavaScript method in the test page, which opens a new window
114 // and stores a handle to it.
115 content::WindowedNotificationObserver tab_added_observer(
116 chrome::NOTIFICATION_TAB_ADDED,
117 content::NotificationService::AllSources());
118 EXPECT_TRUE(content::ExecuteScript(main_web_contents, "openWin();"));
119 tab_added_observer.Wait();
120 content::WebContents* new_web_contents =
121 browser()->tab_strip_model()->GetActiveWebContents();
122
123 // Navigate the opened window to a page that will successfully commit and
124 // create a NavigationEntry.
125 {
126 content::TestNavigationObserver observer(new_web_contents);
127 EXPECT_TRUE(content::ExecuteScript(
128 main_web_contents, "navigate('" + initial_url.spec() + "');"));
129 observer.Wait();
130 EXPECT_EQ(initial_url, new_web_contents->GetLastCommittedURL());
131 }
132
133 // Navigate the opened window to a page which will trigger an
134 // interstitial.
135 {
136 content::TestNavigationObserver observer(new_web_contents);
137 EXPECT_TRUE(content::ExecuteScript(
138 main_web_contents, "navigate('" + error_url.spec() + "');"));
139 observer.Wait();
140 EXPECT_EQ(initial_url, new_web_contents->GetLastCommittedURL());
141 EXPECT_EQ(error_url, new_web_contents->GetVisibleURL());
142 }
143
144 // Navigate again the opened window to the same page. It should not cause
145 // WebContents::GetVisibleURL to return the last committed one.
146 {
147 DidStartNavigationObserver nav_observer(new_web_contents);
148 EXPECT_TRUE(content::ExecuteScript(
149 main_web_contents, "navigate('" + error_url.spec() + "');"));
150 nav_observer.Wait();
151 EXPECT_EQ(error_url, new_web_contents->GetVisibleURL());
152 EXPECT_TRUE(new_web_contents->GetController().GetTransientEntry());
153 EXPECT_FALSE(new_web_contents->IsLoading());
154 }
155}
naskoe4ebe0782016-10-27 16:52:17156
afakhry4d116bd2016-11-29 17:25:25157// Tests that viewing frame source on a local file:// page with an iframe
158// with a remote URL shows the correct tab title.
159IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, TestViewFrameSource) {
160 // The local page file:// URL.
161 GURL local_page_with_iframe_url = ui_test_utils::GetTestUrl(
162 base::FilePath(base::FilePath::kCurrentDirectory),
163 base::FilePath(FILE_PATH_LITERAL("iframe.html")));
164
165 // The non-file:// URL of the page to load in the iframe.
166 GURL iframe_target_url = embedded_test_server()->GetURL("/title1.html");
167 ui_test_utils::NavigateToURL(browser(), local_page_with_iframe_url);
168 content::WebContents* web_contents =
169 browser()->tab_strip_model()->GetActiveWebContents();
170
171 content::TestNavigationObserver observer(web_contents);
172 ASSERT_TRUE(content::ExecuteScript(
173 web_contents->GetMainFrame(),
174 base::StringPrintf("var iframe = document.getElementById('test');\n"
175 "iframe.setAttribute('src', '%s');\n",
176 iframe_target_url.spec().c_str())));
177 observer.Wait();
178
179 content::RenderFrameHost* frame =
180 content::ChildFrameAt(web_contents->GetMainFrame(), 0);
181 ASSERT_TRUE(frame);
182 ASSERT_NE(frame, web_contents->GetMainFrame());
183
184 content::ContextMenuParams params;
185 params.page_url = local_page_with_iframe_url;
186 params.frame_url = frame->GetLastCommittedURL();
afakhry4d116bd2016-11-29 17:25:25187 TestRenderViewContextMenu menu(frame, params);
188 menu.Init();
189 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE, 0);
190 ASSERT_EQ(browser()->tab_strip_model()->count(), 2);
191 content::WebContents* new_web_contents =
192 browser()->tab_strip_model()->GetWebContentsAt(1);
193 ASSERT_NE(new_web_contents, web_contents);
194 WaitForLoadStop(new_web_contents);
195
196 GURL view_frame_source_url(content::kViewSourceScheme + std::string(":") +
197 iframe_target_url.spec());
198 EXPECT_EQ(url_formatter::FormatUrl(view_frame_source_url),
199 new_web_contents->GetTitle());
200}
201
Nasko Oskovdeb6c7ea2017-11-30 18:18:11202// Base class for ctrl+click tests, which contains all the common functionality
203// independent from which process the navigation happens in. Each subclass
204// defines its own expectations depending on the conditions of the test.
205class CtrlClickProcessTest : public ChromeNavigationBrowserTest {
lukaszaf206da92017-04-20 23:26:51206 protected:
Nasko Oskovdeb6c7ea2017-11-30 18:18:11207 virtual void VerifyProcessExpectations(
208 content::WebContents* main_contents,
209 content::WebContents* new_contents) = 0;
Nasko Oskovdeb6c7ea2017-11-30 18:18:11210
lukaszaf206da92017-04-20 23:26:51211 // Simulates ctrl-clicking an anchor with the given id in |main_contents|.
Nasko Oskovdeb6c7ea2017-11-30 18:18:11212 // Verifies that the new contents are in the correct process and separate
213 // BrowsingInstance from |main_contents|. Returns contents of the newly
lukaszaf206da92017-04-20 23:26:51214 // opened tab.
215 content::WebContents* SimulateCtrlClick(content::WebContents* main_contents,
216 const char* id_of_anchor_to_click) {
217 // Ctrl-click the anchor/link in the page.
218 content::WebContents* new_contents = nullptr;
219 {
220 content::WebContentsAddedObserver new_tab_observer;
221#if defined(OS_MACOSX)
222 const char* new_tab_click_script_template =
223 "simulateClick(\"%s\", { metaKey: true });";
224#else
225 const char* new_tab_click_script_template =
226 "simulateClick(\"%s\", { ctrlKey: true });";
227#endif
228 std::string new_tab_click_script = base::StringPrintf(
229 new_tab_click_script_template, id_of_anchor_to_click);
230 EXPECT_TRUE(ExecuteScript(main_contents, new_tab_click_script));
231
232 // Wait for a new tab to appear (the whole point of this test).
233 new_contents = new_tab_observer.GetWebContents();
234 }
235
Nasko Oskovdeb6c7ea2017-11-30 18:18:11236 // Verify that the new tab has the right contents and is in the tab strip.
lukaszaf206da92017-04-20 23:26:51237 EXPECT_TRUE(WaitForLoadStop(new_contents));
lukaszaf206da92017-04-20 23:26:51238 EXPECT_LT(1, browser()->tab_strip_model()->count()); // More than 1 tab?
Nasko Oskovdeb6c7ea2017-11-30 18:18:11239 CHECK_NE(TabStripModel::kNoTab,
240 browser()->tab_strip_model()->GetIndexOfWebContents(new_contents));
lukaszaf206da92017-04-20 23:26:51241 GURL expected_url(embedded_test_server()->GetURL("/title1.html"));
242 EXPECT_EQ(expected_url, new_contents->GetLastCommittedURL());
243
Nasko Oskovdeb6c7ea2017-11-30 18:18:11244 VerifyProcessExpectations(main_contents, new_contents);
lukaszaf206da92017-04-20 23:26:51245
lukaszaf206da92017-04-20 23:26:51246 {
247 // Double-check that main_contents has expected window.name set.
248 // This is a sanity check of test setup; this is not a product test.
249 std::string name_of_main_contents_window;
250 EXPECT_TRUE(ExecuteScriptAndExtractString(
251 main_contents, "window.domAutomationController.send(window.name)",
252 &name_of_main_contents_window));
253 EXPECT_EQ("main_contents", name_of_main_contents_window);
254
255 // Verify that the new contents doesn't have a window.opener set.
lukaszabe2f0da2017-04-25 00:43:00256 bool window_opener_cast_to_bool = true;
lukaszaf206da92017-04-20 23:26:51257 EXPECT_TRUE(ExecuteScriptAndExtractBool(
258 new_contents, "window.domAutomationController.send(!!window.opener)",
259 &window_opener_cast_to_bool));
260 EXPECT_FALSE(window_opener_cast_to_bool);
261
Nasko Oskovdeb6c7ea2017-11-30 18:18:11262 VerifyBrowsingInstanceExpectations(main_contents, new_contents);
lukaszaf206da92017-04-20 23:26:51263 }
264
265 return new_contents;
266 }
lukaszabe2f0da2017-04-25 00:43:00267
268 void TestCtrlClick(const char* id_of_anchor_to_click) {
269 // Navigate to the test page.
270 GURL main_url(embedded_test_server()->GetURL(
271 "/frame_tree/anchor_to_same_site_location.html"));
272 ui_test_utils::NavigateToURL(browser(), main_url);
273
274 // Verify that there is only 1 active tab (with the right contents
275 // committed).
276 EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
277 content::WebContents* main_contents =
278 browser()->tab_strip_model()->GetWebContentsAt(0);
279 EXPECT_EQ(main_url, main_contents->GetLastCommittedURL());
280
281 // Test what happens after ctrl-click. SimulateCtrlClick will verify
Nasko Oskovdeb6c7ea2017-11-30 18:18:11282 // that |new_contents1| is in the correct process and separate
283 // BrowsingInstance from |main_contents|.
lukaszabe2f0da2017-04-25 00:43:00284 content::WebContents* new_contents1 =
285 SimulateCtrlClick(main_contents, id_of_anchor_to_click);
286
Nasko Oskovdeb6c7ea2017-11-30 18:18:11287 // Test that each subsequent ctrl-click also gets the correct process.
lukaszabe2f0da2017-04-25 00:43:00288 content::WebContents* new_contents2 =
289 SimulateCtrlClick(main_contents, id_of_anchor_to_click);
lukaszabe2f0da2017-04-25 00:43:00290 EXPECT_FALSE(new_contents1->GetSiteInstance()->IsRelatedSiteInstance(
291 new_contents2->GetSiteInstance()));
Nasko Oskovdeb6c7ea2017-11-30 18:18:11292 VerifyProcessExpectations(new_contents1, new_contents2);
293 }
Lukasz Anforowiczaf2f33572018-01-17 14:05:08294
295 private:
296 void VerifyBrowsingInstanceExpectations(content::WebContents* main_contents,
297 content::WebContents* new_contents) {
298 // Verify that the new contents cannot find the old contents via
299 // window.open. (i.e. window.open should open a new window, rather than
300 // returning a reference to main_contents / old window).
301 std::string location_of_opened_window;
302 EXPECT_TRUE(ExecuteScriptAndExtractString(
303 new_contents,
304 "w = window.open('', 'main_contents');"
305 "window.domAutomationController.send(w.location.href);",
306 &location_of_opened_window));
307 EXPECT_EQ(url::kAboutBlankURL, location_of_opened_window);
308 }
Nasko Oskovdeb6c7ea2017-11-30 18:18:11309};
310
311// Tests that verify that ctrl-click results 1) open up in a new renderer
312// process (https://crbug.com/23815) and 2) are in a new BrowsingInstance (e.g.
313// cannot find the opener's window by name - https://crbug.com/658386).
314class CtrlClickShouldEndUpInNewProcessTest : public CtrlClickProcessTest {
315 protected:
316 void VerifyProcessExpectations(content::WebContents* main_contents,
317 content::WebContents* new_contents) override {
318 // Verify that the two WebContents are in a different process, SiteInstance
319 // and BrowsingInstance from the old contents.
320 EXPECT_NE(main_contents->GetMainFrame()->GetProcess(),
321 new_contents->GetMainFrame()->GetProcess());
322 EXPECT_NE(main_contents->GetMainFrame()->GetSiteInstance(),
323 new_contents->GetMainFrame()->GetSiteInstance());
324 EXPECT_FALSE(main_contents->GetSiteInstance()->IsRelatedSiteInstance(
325 new_contents->GetSiteInstance()));
326 }
lukaszaf206da92017-04-20 23:26:51327};
328
329IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, NoTarget) {
lukaszabe2f0da2017-04-25 00:43:00330 TestCtrlClick("test-anchor-no-target");
331}
lukaszaf206da92017-04-20 23:26:51332
lukaszabe2f0da2017-04-25 00:43:00333IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, BlankTarget) {
334 TestCtrlClick("test-anchor-with-blank-target");
335}
lukaszaf206da92017-04-20 23:26:51336
lukaszabe2f0da2017-04-25 00:43:00337IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInNewProcessTest, SubframeTarget) {
338 TestCtrlClick("test-anchor-with-subframe-target");
lukaszaf206da92017-04-20 23:26:51339}
340
Nasko Oskovdeb6c7ea2017-11-30 18:18:11341// Similar to the tests above, but verifies that the new WebContents ends up in
342// the same process as the opener when it is exceeding the process limit.
343// See https://crbug.com/774723.
344class CtrlClickShouldEndUpInSameProcessTest : public CtrlClickProcessTest {
345 public:
346 void SetUpCommandLine(base::CommandLine* command_line) override {
347 CtrlClickProcessTest::SetUpCommandLine(command_line);
348 content::IsolateAllSitesForTesting(command_line);
349 content::RenderProcessHost::SetMaxRendererProcessCount(1);
350 }
351
352 void SetUpOnMainThread() override {
353 CtrlClickProcessTest::SetUpOnMainThread();
354 host_resolver()->AddRule("*", "127.0.0.1");
355 }
356
357 protected:
358 void VerifyProcessExpectations(content::WebContents* contents1,
359 content::WebContents* contents2) override {
360 // Verify that the two WebContents are in the same process, though different
361 // SiteInstance and BrowsingInstance from the old contents.
362 EXPECT_EQ(contents1->GetMainFrame()->GetProcess(),
363 contents2->GetMainFrame()->GetProcess());
364 EXPECT_EQ(contents1->GetMainFrame()->GetSiteInstance()->GetSiteURL(),
365 contents2->GetMainFrame()->GetSiteInstance()->GetSiteURL());
366 EXPECT_FALSE(contents1->GetSiteInstance()->IsRelatedSiteInstance(
367 contents2->GetSiteInstance()));
368 }
Nasko Oskovdeb6c7ea2017-11-30 18:18:11369};
370
371IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, NoTarget) {
372 TestCtrlClick("test-anchor-no-target");
373}
374
375IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, BlankTarget) {
376 TestCtrlClick("test-anchor-with-blank-target");
377}
378
379IN_PROC_BROWSER_TEST_F(CtrlClickShouldEndUpInSameProcessTest, SubframeTarget) {
380 TestCtrlClick("test-anchor-with-subframe-target");
381}
382
naskoe4ebe0782016-10-27 16:52:17383class ChromeNavigationPortMappedBrowserTest : public InProcessBrowserTest {
384 public:
385 ChromeNavigationPortMappedBrowserTest() {}
386 ~ChromeNavigationPortMappedBrowserTest() override {}
387
388 void SetUpCommandLine(base::CommandLine* command_line) override {
389 ASSERT_TRUE(embedded_test_server()->Start());
390
391 // Use the command line parameter for the host resolver, so URLs without
392 // explicit port numbers can be mapped under the hood to the port number
393 // the |embedded_test_server| uses. It is required to test with potentially
394 // malformed URLs.
395 std::string port =
396 base::IntToString(embedded_test_server()->host_port_pair().port());
397 command_line->AppendSwitchASCII(
398 "host-resolver-rules",
399 "MAP * 127.0.0.1:" + port + ", EXCLUDE 127.0.0.1*");
400 }
401
402 private:
403 DISALLOW_COPY_AND_ASSIGN(ChromeNavigationPortMappedBrowserTest);
404};
405
406// Test to verify that a malformed URL set as the virtual URL of a
407// NavigationEntry will result in the navigation being dropped.
408// See https://crbug.com/657720.
409IN_PROC_BROWSER_TEST_F(ChromeNavigationPortMappedBrowserTest,
410 ContextMenuNavigationToInvalidUrl) {
411 GURL initial_url = embedded_test_server()->GetURL("/title1.html");
412 GURL new_tab_url(
413 "www.foo.com::/server-redirect?https%3A%2F%2Fptop.only.wip.la%3A443%2Fhttp%2Fbar.com%2Ftitle2.html");
414
415 // Navigate to an initial page, to ensure we have a committed document
416 // from which to perform a context menu initiated navigation.
417 ui_test_utils::NavigateToURL(browser(), initial_url);
418 content::WebContents* web_contents =
419 browser()->tab_strip_model()->GetActiveWebContents();
420
421 // This corresponds to "Open link in new tab".
422 content::ContextMenuParams params;
423 params.is_editable = false;
Blink Reformat1c4d759e2017-04-09 16:34:54424 params.media_type = blink::WebContextMenuData::kMediaTypeNone;
naskoe4ebe0782016-10-27 16:52:17425 params.page_url = initial_url;
426 params.link_url = new_tab_url;
427
428 content::WindowedNotificationObserver tab_added_observer(
429 chrome::NOTIFICATION_TAB_ADDED,
430 content::NotificationService::AllSources());
431
432 TestRenderViewContextMenu menu(web_contents->GetMainFrame(), params);
433 menu.Init();
434 menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB, 0);
435
436 // Wait for the new tab to be created and for loading to stop. The
437 // navigation should not be allowed, therefore there should not be a last
438 // committed URL in the new tab.
439 tab_added_observer.Wait();
440 content::WebContents* new_web_contents =
441 browser()->tab_strip_model()->GetWebContentsAt(
442 browser()->tab_strip_model()->count() - 1);
443 WaitForLoadStop(new_web_contents);
444
445 // If the test is unsuccessful, the return value from GetLastCommittedURL
446 // will be the virtual URL for the created NavigationEntry.
447 // Note: Before the bug was fixed, the URL was the new_tab_url with a scheme
448 // prepended and one less ":" character after the host.
449 EXPECT_EQ(GURL(), new_web_contents->GetLastCommittedURL());
450}
nasko7058e5de2017-04-18 23:05:30451
452// A test performing two simultaneous navigations, to ensure code in chrome/,
453// such as tab helpers, can handle those cases.
454// This test starts a browser-initiated cross-process navigation, which is
455// delayed. At the same time, the renderer does a synchronous navigation
456// through pushState, which will create a separate navigation and associated
457// NavigationHandle. Afterwards, the original cross-process navigation is
458// resumed and confirmed to properly commit.
459IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
460 SlowCrossProcessNavigationWithPushState) {
461 const GURL kURL1 = embedded_test_server()->GetURL("/title1.html");
462 const GURL kPushStateURL =
463 embedded_test_server()->GetURL("/title1.html#fragment");
464 const GURL kURL2 = embedded_test_server()->GetURL("/title2.html");
465
466 content::WebContents* web_contents =
467 browser()->tab_strip_model()->GetActiveWebContents();
468
469 // Navigate to the initial page.
470 ui_test_utils::NavigateToURL(browser(), kURL1);
471
472 // Start navigating to the second page.
473 content::TestNavigationManager manager(web_contents, kURL2);
474 content::NavigationHandleCommitObserver navigation_observer(web_contents,
475 kURL2);
476 web_contents->GetController().LoadURL(
477 kURL2, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
478 EXPECT_TRUE(manager.WaitForRequestStart());
479
480 // The current page does a PushState.
481 content::NavigationHandleCommitObserver push_state_observer(web_contents,
482 kPushStateURL);
483 std::string push_state =
484 "history.pushState({}, \"title 1\", \"" + kPushStateURL.spec() + "\");";
485 EXPECT_TRUE(ExecuteScript(web_contents, push_state));
486 content::NavigationEntry* last_committed =
487 web_contents->GetController().GetLastCommittedEntry();
488 EXPECT_TRUE(last_committed);
489 EXPECT_EQ(kPushStateURL, last_committed->GetURL());
490
491 EXPECT_TRUE(push_state_observer.has_committed());
492 EXPECT_TRUE(push_state_observer.was_same_document());
493 EXPECT_TRUE(push_state_observer.was_renderer_initiated());
494
495 // Let the navigation finish. It should commit successfully.
496 manager.WaitForNavigationFinished();
497 last_committed = web_contents->GetController().GetLastCommittedEntry();
498 EXPECT_TRUE(last_committed);
499 EXPECT_EQ(kURL2, last_committed->GetURL());
500
501 EXPECT_TRUE(navigation_observer.has_committed());
502 EXPECT_FALSE(navigation_observer.was_same_document());
503 EXPECT_FALSE(navigation_observer.was_renderer_initiated());
504}
Alex Moshchukd252c192017-07-17 22:03:48505
Alex Moshchuk71f485592017-08-16 16:20:00506// Check that if a page has an iframe that loads an error page, that error page
507// does not inherit the Content Security Policy from the parent frame. See
508// https://crbug.com/703801. This test is in chrome/ because error page
509// behavior is only fully defined in chrome/.
510IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
511 ErrorPageDoesNotInheritCSP) {
512 GURL url(
513 embedded_test_server()->GetURL("/page_with_csp_and_error_iframe.html"));
514 content::WebContents* web_contents =
515 browser()->tab_strip_model()->GetActiveWebContents();
516
517 // Navigate to a page that disallows scripts via CSP and has an iframe that
518 // tries to load an invalid URL, which results in an error page.
519 GURL error_url("http://invalid.foo/");
520 content::NavigationHandleObserver observer(web_contents, error_url);
521 ui_test_utils::NavigateToURL(browser(), url);
522 EXPECT_TRUE(observer.has_committed());
523 EXPECT_TRUE(observer.is_error());
524
525 // The error page should not inherit the CSP directive that blocks all
526 // scripts from the parent frame, so this script should be allowed to
527 // execute. Since ExecuteScript will execute the passed-in script regardless
528 // of CSP, use a javascript: URL which does go through the CSP checks.
529 content::RenderFrameHost* error_host =
530 ChildFrameAt(web_contents->GetMainFrame(), 0);
531 std::string location;
532 EXPECT_TRUE(ExecuteScriptAndExtractString(
533 error_host,
534 "location='javascript:domAutomationController.send(location.href)';",
535 &location));
536 EXPECT_EQ(location, content::kUnreachableWebDataURL);
537
538 // The error page should have a unique origin.
539 std::string origin;
540 EXPECT_TRUE(ExecuteScriptAndExtractString(
Philip Jägenstedt67302a22018-09-14 09:58:05541 error_host, "domAutomationController.send(self.origin);", &origin));
Alex Moshchuk71f485592017-08-16 16:20:00542 EXPECT_EQ("null", origin);
543}
544
545// Test that web pages can't navigate to an error page URL, either directly or
546// via a redirect, and that web pages can't embed error pages in iframes.
547IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
548 NavigationToErrorURLIsDisallowed) {
549 content::WebContents* web_contents =
550 browser()->tab_strip_model()->GetActiveWebContents();
551 GURL url(embedded_test_server()->GetURL("/title1.html"));
552 ui_test_utils::NavigateToURL(browser(), url);
553 EXPECT_EQ(url, web_contents->GetLastCommittedURL());
554
555 // Try navigating to the error page URL and make sure it is canceled and the
556 // old URL remains the last committed one.
557 GURL error_url(content::kUnreachableWebDataURL);
558 EXPECT_TRUE(ExecuteScript(web_contents,
559 "location.href = '" + error_url.spec() + "';"));
560 content::WaitForLoadStop(web_contents);
561 EXPECT_EQ(url, web_contents->GetLastCommittedURL());
562
563 // Now try navigating to a URL that tries to redirect to the error page URL,
564 // and make sure the redirect is blocked. Note that DidStopLoading will
565 // still fire after the redirect is canceled, so TestNavigationObserver can
566 // be used to wait for it.
567 GURL redirect_to_error_url(
568 embedded_test_server()->GetURL("/server-redirect?" + error_url.spec()));
569 content::TestNavigationObserver observer(web_contents);
570 EXPECT_TRUE(ExecuteScript(
571 web_contents, "location.href = '" + redirect_to_error_url.spec() + "';"));
572 observer.Wait();
573 EXPECT_EQ(url, web_contents->GetLastCommittedURL());
574
575 // Also ensure that a page can't embed an iframe for an error page URL.
576 EXPECT_TRUE(ExecuteScript(web_contents,
577 "var frame = document.createElement('iframe');\n"
578 "frame.src = '" + error_url.spec() + "';\n"
579 "document.body.appendChild(frame);"));
580 content::WaitForLoadStop(web_contents);
581 content::RenderFrameHost* subframe_host =
582 ChildFrameAt(web_contents->GetMainFrame(), 0);
583 // The new subframe should remain blank without a committed URL.
584 EXPECT_TRUE(subframe_host->GetLastCommittedURL().is_empty());
585}
586
587// This test ensures that navigating to a page that returns an error code and
588// an empty document still shows Chrome's helpful error page instead of the
589// empty document.
590IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
591 EmptyDocumentWithErrorCode) {
592 GURL url(embedded_test_server()->GetURL("/empty_with_404.html"));
593 content::WebContents* web_contents =
594 browser()->tab_strip_model()->GetActiveWebContents();
595
596 // Wait for the navigation to complete. The empty document should trigger
597 // loading of the 404 error page, so check that the last committed entry was
598 // indeed for the error page.
599 content::TestNavigationObserver observer(web_contents);
600 EXPECT_TRUE(
601 ExecuteScript(web_contents, "location.href = '" + url.spec() + "';"));
602 observer.Wait();
603 EXPECT_FALSE(observer.last_navigation_succeeded());
604 EXPECT_EQ(url, web_contents->GetLastCommittedURL());
605 EXPECT_TRUE(
606 IsLastCommittedEntryOfPageType(web_contents, content::PAGE_TYPE_ERROR));
607
608 // Verify that the error page has correct content. This needs to wait for
609 // the error page content to be populated asynchronously by scripts after
610 // DidFinishLoad.
611 while (true) {
612 std::string content;
613 EXPECT_TRUE(ExecuteScriptAndExtractString(
614 web_contents,
615 "domAutomationController.send("
616 " document.body ? document.body.innerText : '');",
617 &content));
618 if (content.find("HTTP ERROR 404") != std::string::npos)
619 break;
620 base::RunLoop run_loop;
621 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
622 FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
623 run_loop.Run();
624 }
625}
626
Alex Moshchukd252c192017-07-17 22:03:48627class SignInIsolationBrowserTest : public ChromeNavigationBrowserTest {
628 public:
629 SignInIsolationBrowserTest()
630 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
631 ~SignInIsolationBrowserTest() override {}
632
Alex Moshchuk95e8906d2017-07-21 01:06:23633 void SetUp() override {
Alex Moshchukd252c192017-07-17 22:03:48634 https_server_.ServeFilesFromSourceDirectory("chrome/test/data");
635 ASSERT_TRUE(https_server_.InitializeAndListen());
636 ChromeNavigationBrowserTest::SetUp();
637 }
638
639 void SetUpCommandLine(base::CommandLine* command_line) override {
640 // Override the sign-in URL so that it includes correct port from the test
641 // server.
642 command_line->AppendSwitchASCII(
643 ::switches::kGaiaUrl,
644 https_server()->GetURL("accounts.google.com", "/").spec());
645
646 // Ignore cert errors so that the sign-in URL can be loaded from a site
647 // other than localhost (the EmbeddedTestServer serves a certificate that
648 // is valid for localhost).
649 command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
650
651 ChromeNavigationBrowserTest::SetUpCommandLine(command_line);
652 }
653
654 void SetUpOnMainThread() override {
655 host_resolver()->AddRule("*", "127.0.0.1");
656 https_server_.StartAcceptingConnections();
657 ChromeNavigationBrowserTest::SetUpOnMainThread();
658 }
659
660 net::EmbeddedTestServer* https_server() { return &https_server_; }
661
Alex Moshchuk95e8906d2017-07-21 01:06:23662 private:
Alex Moshchukd252c192017-07-17 22:03:48663 net::EmbeddedTestServer https_server_;
664
665 DISALLOW_COPY_AND_ASSIGN(SignInIsolationBrowserTest);
666};
667
668// This test ensures that the sign-in origin requires a dedicated process. It
Alex Moshchuk36417aa2018-06-13 18:01:12669// only ensures that the sign-in origin is added as an isolated origin at
670// chrome/ layer; IsolatedOriginTest provides the main test coverage of origins
671// whitelisted for process isolation. See https://crbug.com/739418.
Alex Moshchukd252c192017-07-17 22:03:48672IN_PROC_BROWSER_TEST_F(SignInIsolationBrowserTest, NavigateToSignInPage) {
673 const GURL first_url =
674 embedded_test_server()->GetURL("google.com", "/title1.html");
675 const GURL signin_url =
676 https_server()->GetURL("accounts.google.com", "/title1.html");
677 ui_test_utils::NavigateToURL(browser(), first_url);
678 content::WebContents* web_contents =
679 browser()->tab_strip_model()->GetActiveWebContents();
680 scoped_refptr<content::SiteInstance> first_instance(
681 web_contents->GetMainFrame()->GetSiteInstance());
682
683 // Make sure that a renderer-initiated navigation to the sign-in page swaps
684 // processes.
685 content::TestNavigationManager manager(web_contents, signin_url);
686 EXPECT_TRUE(
687 ExecuteScript(web_contents, "location = '" + signin_url.spec() + "';"));
688 manager.WaitForNavigationFinished();
689 EXPECT_NE(web_contents->GetMainFrame()->GetSiteInstance(), first_instance);
690}
Alex Moshchuk95e8906d2017-07-21 01:06:23691
arthursonzognib43863ad2017-08-30 15:53:20692// Helper class. Track one navigation and tell whether a response from the
693// server has been received or not. It is useful for discerning navigations
694// blocked after or before the request has been sent.
695class WillProcessResponseObserver : public content::WebContentsObserver {
696 public:
697 explicit WillProcessResponseObserver(content::WebContents* web_contents,
698 const GURL& url)
699 : content::WebContentsObserver(web_contents), url_(url) {}
700 ~WillProcessResponseObserver() override {}
701
702 bool WillProcessResponseCalled() { return will_process_response_called_; }
703
704 private:
705 GURL url_;
706 bool will_process_response_called_ = false;
707
708 // Is used to set |will_process_response_called_| to true when
709 // NavigationThrottle::WillProcessResponse() is called.
710 class WillProcessResponseObserverThrottle
711 : public content::NavigationThrottle {
712 public:
713 WillProcessResponseObserverThrottle(content::NavigationHandle* handle,
714 bool* will_process_response_called)
715 : NavigationThrottle(handle),
716 will_process_response_called_(will_process_response_called) {}
717
718 const char* GetNameForLogging() override {
719 return "WillProcessResponseObserverThrottle";
720 }
721
722 private:
723 bool* will_process_response_called_;
724 NavigationThrottle::ThrottleCheckResult WillProcessResponse() override {
725 *will_process_response_called_ = true;
726 return NavigationThrottle::PROCEED;
727 }
728 };
729
730 // WebContentsObserver
731 void DidStartNavigation(content::NavigationHandle* handle) override {
732 if (handle->GetURL() == url_) {
733 handle->RegisterThrottleForTesting(
734 std::make_unique<WillProcessResponseObserverThrottle>(
735 handle, &will_process_response_called_));
736 }
737 }
738};
739
740// In HTTP/HTTPS documents, check that no request with the "ftp:" scheme are
741// submitted to load an iframe.
742// See https://crbug.com/757809.
743// Note: This test couldn't be a content_browsertests, since there would be
744// not handler defined for the "ftp" protocol in
745// URLRequestJobFactoryImpl::protocol_handler_map_.
Reza.Zakerinasab875245c2018-02-27 17:09:01746// Flaky on Mac only. http://crbug.com/816646
Arthur Sonzognid61d2be2018-06-06 09:04:27747IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, BlockLegacySubresources) {
arthursonzognib43863ad2017-08-30 15:53:20748 net::SpawnedTestServer ftp_server(
749 net::SpawnedTestServer::TYPE_FTP,
750 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
751 ASSERT_TRUE(ftp_server.Start());
752
753 GURL main_url_http(embedded_test_server()->GetURL("/iframe.html"));
754 GURL main_url_ftp(ftp_server.GetURL("iframe.html"));
755 GURL iframe_url_http(embedded_test_server()->GetURL("/simple.html"));
756 GURL iframe_url_ftp(ftp_server.GetURL("simple.html"));
757 GURL redirect_url(embedded_test_server()->GetURL("/server-redirect?"));
758
759 struct {
760 GURL main_url;
761 GURL iframe_url;
762 bool allowed;
763 } kTestCases[] = {
764 {main_url_http, iframe_url_http, true},
765 {main_url_http, iframe_url_ftp, false},
766 {main_url_ftp, iframe_url_http, true},
767 {main_url_ftp, iframe_url_ftp, true},
768 };
769 for (const auto test_case : kTestCases) {
770 // Blocking the request should work, even after a redirect.
771 for (bool redirect : {false, true}) {
772 GURL iframe_url =
773 redirect ? GURL(redirect_url.spec() + test_case.iframe_url.spec())
774 : test_case.iframe_url;
775 SCOPED_TRACE(::testing::Message()
776 << std::endl
777 << "- main_url = " << test_case.main_url << std::endl
778 << "- iframe_url = " << iframe_url << std::endl);
779
780 ui_test_utils::NavigateToURL(browser(), test_case.main_url);
781 content::WebContents* web_contents =
782 browser()->tab_strip_model()->GetActiveWebContents();
783 content::NavigationHandleObserver navigation_handle_observer(web_contents,
784 iframe_url);
785 WillProcessResponseObserver will_process_response_observer(web_contents,
786 iframe_url);
787 EXPECT_TRUE(NavigateIframeToURL(web_contents, "test", iframe_url));
788
789 if (test_case.allowed) {
790 EXPECT_TRUE(will_process_response_observer.WillProcessResponseCalled());
791 EXPECT_FALSE(navigation_handle_observer.is_error());
792 EXPECT_EQ(test_case.iframe_url,
793 navigation_handle_observer.last_committed_url());
794 } else {
795 EXPECT_FALSE(
796 will_process_response_observer.WillProcessResponseCalled());
797 EXPECT_TRUE(navigation_handle_observer.is_error());
798 EXPECT_EQ(net::ERR_ABORTED,
799 navigation_handle_observer.net_error_code());
800 }
801 }
802 }
803}
clamyb4f02242017-09-19 12:58:27804
805// Check that it's possible to navigate to a chrome scheme URL from a crashed
806// tab. See https://crbug.com/764641.
807IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, ChromeSchemeNavFromSadTab) {
808 // Kill the renderer process.
809 content::RenderProcessHost* process = browser()
810 ->tab_strip_model()
811 ->GetActiveWebContents()
812 ->GetMainFrame()
813 ->GetProcess();
814 content::RenderProcessHostWatcher crash_observer(
815 process, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
Wez0abfbf512018-03-03 01:54:45816 process->Shutdown(-1);
clamyb4f02242017-09-19 12:58:27817 crash_observer.Wait();
818
819 // Attempt to navigate to a chrome://... URL. This used to hang and never
820 // commit in PlzNavigate mode.
821 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIVersionURL));
822}
clamy8d8fe8332017-09-21 16:24:10823
824// Check that a browser-initiated navigation to a cross-site URL that then
825// redirects to a pdf hosted on another site works.
826IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest, CrossSiteRedirectionToPDF) {
827 net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
828 https_server.AddDefaultHandlers(
829 base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
830 ASSERT_TRUE(https_server.Start());
831
832 GURL initial_url = embedded_test_server()->GetURL("/title1.html");
833 GURL pdf_url = embedded_test_server()->GetURL("/pdf/test.pdf");
834 GURL cross_site_redirecting_url =
835 https_server.GetURL("/server-redirect?" + pdf_url.spec());
836 ui_test_utils::NavigateToURL(browser(), initial_url);
837 ui_test_utils::NavigateToURL(browser(), cross_site_redirecting_url);
838 EXPECT_EQ(pdf_url, browser()
839 ->tab_strip_model()
840 ->GetActiveWebContents()
841 ->GetLastCommittedURL());
842}
Charles Harrison26b6c12e2017-11-04 06:30:46843
Makoto Shimazue9c808f2018-04-10 01:23:59844// TODO(csharrison): These tests should become tentative WPT, once the feature
845// is enabled by default.
Charlie Harrison25d683972018-06-28 22:27:34846using NavigationConsumingTest = ChromeNavigationBrowserTest;
Charles Harrison26b6c12e2017-11-04 06:30:46847
Makoto Shimazue9c808f2018-04-10 01:23:59848// The fullscreen API is spec'd to require a user activation (aka user gesture),
849// so use that API to test if navigation consumes the activation.
850// https://fullscreen.spec.whatwg.org/#allowed-to-request-fullscreen
851IN_PROC_BROWSER_TEST_F(NavigationConsumingTest,
852 NavigationConsumesUserGesture_Fullscreen) {
853 ui_test_utils::NavigateToURL(
854 browser(),
855 embedded_test_server()->GetURL("/navigation_consumes_gesture.html"));
856 content::WebContents* contents =
857 browser()->tab_strip_model()->GetActiveWebContents();
858
859 // Normally, fullscreen should work, as long as there is a user gesture.
860 bool is_fullscreen = false;
861 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
862 contents, "document.body.webkitRequestFullscreen();", &is_fullscreen));
863 EXPECT_TRUE(is_fullscreen);
864
865 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
866 contents, "document.webkitExitFullscreen();", &is_fullscreen));
867 EXPECT_FALSE(is_fullscreen);
868
Makoto Shimazue9c808f2018-04-10 01:23:59869 // However, starting a navigation should consume the gesture. Fullscreen
870 // should not work afterwards. Make sure the navigation is synchronously
871 // started via click().
872 std::string script = R"(
873 document.getElementsByTagName('a')[0].click();
874 document.body.webkitRequestFullscreen();
875 )";
876
877 // Use the TestNavigationManager to ensure the navigation is not finished
878 // before fullscreen can occur.
879 content::TestNavigationManager nav_manager(
880 contents, embedded_test_server()->GetURL("/title1.html"));
881 EXPECT_TRUE(
882 content::ExecuteScriptAndExtractBool(contents, script, &is_fullscreen));
883 EXPECT_FALSE(is_fullscreen);
884}
885
886// Similar to the fullscreen test above, but checks that popups are successfully
887// blocked if spawned after a navigation.
Charles Harrison26b6c12e2017-11-04 06:30:46888IN_PROC_BROWSER_TEST_F(NavigationConsumingTest,
889 NavigationConsumesUserGesture_Popups) {
890 ui_test_utils::NavigateToURL(browser(),
891 embedded_test_server()->GetURL("/links.html"));
892 content::WebContents* contents =
893 browser()->tab_strip_model()->GetActiveWebContents();
894
895 // Normally, a popup should open fine if it is associated with a user gesture.
896 bool did_open = false;
897 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
898 contents, "window.domAutomationController.send(!!window.open());",
899 &did_open));
900 EXPECT_TRUE(did_open);
901
902 // Starting a navigation should consume a gesture, but make sure that starting
903 // a same-document navigation doesn't do the consuming.
904 std::string same_document_script = R"(
905 document.getElementById("ref").click();
906 window.domAutomationController.send(!!window.open());
907 )";
908 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
909 contents, same_document_script, &did_open));
910 EXPECT_TRUE(did_open);
911
912 // If the navigation is to a different document, the gesture should be
913 // successfully consumed.
914 std::string different_document_script = R"(
915 document.getElementById("title1").click();
916 window.domAutomationController.send(!!window.open());
917 )";
918 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
919 contents, different_document_script, &did_open));
920 EXPECT_FALSE(did_open);
921}
Charlie Harrison25d683972018-06-28 22:27:34922
923// Regression test for https://crbug.com/856779, where a navigation to a
924// top-level, same process frame in another tab fails to focus that tab.
925IN_PROC_BROWSER_TEST_F(NavigationConsumingTest, TargetNavigationFocus) {
926 content::WebContents* opener =
927 browser()->tab_strip_model()->GetActiveWebContents();
928 ui_test_utils::NavigateToURL(
929 browser(), embedded_test_server()->GetURL("/link_with_target.html"));
930
931 {
932 content::TestNavigationObserver new_tab_observer(nullptr, 1);
933 new_tab_observer.StartWatchingNewWebContents();
934 ASSERT_TRUE(ExecuteScript(
935 opener, "document.getElementsByTagName('a')[0].click();"));
936 new_tab_observer.Wait();
937 }
938
939 content::WebContents* new_contents =
940 browser()->tab_strip_model()->GetActiveWebContents();
941 EXPECT_NE(new_contents, opener);
942
943 // Re-focusing the opener and clicking again should re-focus the popup.
944 opener->GetDelegate()->ActivateContents(opener);
945 EXPECT_EQ(opener, browser()->tab_strip_model()->GetActiveWebContents());
946 {
947 content::TestNavigationObserver new_tab_observer(new_contents, 1);
948 ASSERT_TRUE(ExecuteScript(
949 opener, "document.getElementsByTagName('a')[0].click();"));
950 new_tab_observer.Wait();
951 }
952 EXPECT_EQ(new_contents, browser()->tab_strip_model()->GetActiveWebContents());
953}