blob: e905a7cb376ae6be22133598bf5254e0e8b86c44 [file] [log] [blame]
Dominick Ngc4a60b32018-04-19 05:18:491// Copyright 2018 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
5#include "chrome/browser/extensions/bookmark_app_navigation_browsertest.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/strings/utf_string_conversions.h"
10#include "chrome/browser/profiles/profile_io_data.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/browser/ui/browser_finder.h"
13#include "chrome/browser/ui/tabs/tab_strip_model.h"
14#include "chrome/common/web_application_info.h"
15#include "chrome/test/base/ui_test_utils.h"
16#include "content/public/browser/render_frame_host.h"
17#include "content/public/browser/web_contents.h"
18#include "content/public/common/content_switches.h"
19#include "content/public/test/browser_test_utils.h"
20#include "content/public/test/test_navigation_observer.h"
21#include "net/base/escape.h"
22#include "net/dns/mock_host_resolver.h"
23#include "net/test/embedded_test_server/http_request.h"
24#include "net/test/embedded_test_server/http_response.h"
25
26namespace {
27
28const char kLaunchingPageHost[] = "launching-page.com";
29const char kLaunchingPagePath[] = "/index.html";
30
31const char kAppUrlHost[] = "app.com";
32const char kOtherAppUrlHost[] = "other-app.com";
33const char kAppScopePath[] = "/in_scope/";
34const char kAppUrlPath[] = "/in_scope/index.html";
35const char kInScopeUrlPath[] = "/in_scope/other.html";
36const char kOutOfScopeUrlPath[] = "/out_of_scope/index.html";
37
38const char kAppName[] = "Test app";
39
40const base::FilePath::CharType kDocRoot[] =
41 FILE_PATH_LITERAL("chrome/test/data");
42
43bool HasOpenedWindowAndOpener(content::WebContents* opener_contents,
44 content::WebContents* opened_contents) {
45 bool has_opener;
46 CHECK(content::ExecuteScriptAndExtractBool(
47 opened_contents, "window.domAutomationController.send(!!window.opener);",
48 &has_opener));
49
50 bool has_openedWindow;
51 CHECK(content::ExecuteScriptAndExtractBool(
52 opener_contents,
53 "window.domAutomationController.send(!!window.openedWindow.window)",
54 &has_openedWindow));
55
56 return has_opener && has_openedWindow;
57}
58
59// Wrapper so that we can use base::BindOnce with NavigateToURL.
60void NavigateToURLWrapper(NavigateParams* params) {
61 ui_test_utils::NavigateToURL(params);
62}
63
64} // anonymous namespace
65
66namespace extensions {
67namespace test {
68
69// static
70const char* BookmarkAppNavigationBrowserTest::GetLaunchingPageHost() {
71 return kLaunchingPageHost;
72}
73
74// static
75const char* BookmarkAppNavigationBrowserTest::GetLaunchingPagePath() {
76 return kLaunchingPagePath;
77}
78
79// static
80const char* BookmarkAppNavigationBrowserTest::GetAppUrlHost() {
81 return kAppUrlHost;
82}
83
84// static
85const char* BookmarkAppNavigationBrowserTest::GetOtherAppUrlHost() {
86 return kOtherAppUrlHost;
87}
88
89// static
90const char* BookmarkAppNavigationBrowserTest::GetAppScopePath() {
91 return kAppScopePath;
92}
93
94// static
95const char* BookmarkAppNavigationBrowserTest::GetAppUrlPath() {
96 return kAppUrlPath;
97}
98
99// static
100const char* BookmarkAppNavigationBrowserTest::GetInScopeUrlPath() {
101 return kInScopeUrlPath;
102}
103
104// static
105const char* BookmarkAppNavigationBrowserTest::GetOutOfScopeUrlPath() {
106 return kOutOfScopeUrlPath;
107}
108
109// static
110const char* BookmarkAppNavigationBrowserTest::GetAppName() {
111 return kAppName;
112}
113
114// static
115std::string BookmarkAppNavigationBrowserTest::CreateServerRedirect(
116 const GURL& target_url) {
117 const char* const kServerRedirectBase = "/server-redirect?";
118 return kServerRedirectBase +
119 net::EscapeQueryParamValue(target_url.spec(), false);
120}
121
122// static
123std::unique_ptr<content::TestNavigationObserver>
124BookmarkAppNavigationBrowserTest::GetTestNavigationObserver(
125 const GURL& target_url) {
126 auto observer = std::make_unique<content::TestNavigationObserver>(target_url);
127 observer->WatchExistingWebContents();
128 observer->StartWatchingNewWebContents();
129 return observer;
130}
131
132// static
133content::RenderFrameHost* BookmarkAppNavigationBrowserTest::GetIFrame(
134 content::WebContents* web_contents) {
135 const auto all_frames = web_contents->GetAllFrames();
136 const content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
137
138 DCHECK_EQ(2u, all_frames.size());
139 auto it = std::find_if(all_frames.begin(), all_frames.end(),
140 [main_frame](content::RenderFrameHost* frame) {
141 return main_frame != frame;
142 });
143 DCHECK(it != all_frames.end());
144 return *it;
145}
146
147// static
148void BookmarkAppNavigationBrowserTest::ClickLinkWithModifiersAndWaitForURL(
149 content::WebContents* web_contents,
150 const GURL& link_url,
151 const GURL& target_url,
152 BookmarkAppNavigationBrowserTest::LinkTarget target,
153 const std::string& rel,
154 int modifiers) {
155 auto observer = GetTestNavigationObserver(target_url);
156 std::string script = base::StringPrintf(
157 "(() => {"
158 "const link = document.createElement('a');"
159 "link.href = '%s';"
160 "link.target = '%s';"
161 "link.rel = '%s';"
162 // Make a click target that covers the whole viewport.
163 "const click_target = document.createElement('textarea');"
164 "click_target.position = 'absolute';"
165 "click_target.top = 0;"
166 "click_target.left = 0;"
167 "click_target.style.height = '100vh';"
168 "click_target.style.width = '100vw';"
169 "link.appendChild(click_target);"
170 "document.body.appendChild(link);"
171 "})();",
172 link_url.spec().c_str(), target == LinkTarget::SELF ? "_self" : "_blank",
173 rel.c_str());
174 ASSERT_TRUE(content::ExecuteScript(web_contents, script));
175
176 content::SimulateMouseClick(web_contents, modifiers,
177 blink::WebMouseEvent::Button::kLeft);
178
179 observer->WaitForNavigationFinished();
180}
181
182// static
183void BookmarkAppNavigationBrowserTest::ClickLinkAndWaitForURL(
184 content::WebContents* web_contents,
185 const GURL& link_url,
186 const GURL& target_url,
187 BookmarkAppNavigationBrowserTest::LinkTarget target,
188 const std::string& rel) {
189 ClickLinkWithModifiersAndWaitForURL(
190 web_contents, link_url, target_url, target, rel,
191 blink::WebInputEvent::Modifiers::kNoModifiers);
192}
193
194// static
195void BookmarkAppNavigationBrowserTest::ClickLinkAndWait(
196 content::WebContents* web_contents,
197 const GURL& link_url,
198 BookmarkAppNavigationBrowserTest::LinkTarget target,
199 const std::string& rel) {
200 ClickLinkAndWaitForURL(web_contents, link_url, link_url, target, rel);
201}
202
203// static
204void BookmarkAppNavigationBrowserTest::ClickLinkWithModifiersAndWait(
205 content::WebContents* web_contents,
206 const GURL& link_url,
207 BookmarkAppNavigationBrowserTest::LinkTarget target,
208 const std::string& rel,
209 int modifiers) {
210 ClickLinkWithModifiersAndWaitForURL(web_contents, link_url, link_url, target,
211 rel, modifiers);
212}
213
214BookmarkAppNavigationBrowserTest::BookmarkAppNavigationBrowserTest()
John Abd-El-Malek4f6427c2018-08-23 17:06:08215 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
Dominick Ngc4a60b32018-04-19 05:18:49216
217BookmarkAppNavigationBrowserTest::~BookmarkAppNavigationBrowserTest() = default;
218
219void BookmarkAppNavigationBrowserTest::SetUp() {
220 https_server_.AddDefaultHandlers(base::FilePath(kDocRoot));
221 // Register a request handler that will return empty pages. Tests are
222 // responsible for adding elements and firing events on these empty pages.
223 https_server_.RegisterRequestHandler(
224 base::BindRepeating([](const net::test_server::HttpRequest& request) {
225 // Let the default request handlers handle redirections.
226 if (request.GetURL().path() == "/server-redirect" ||
227 request.GetURL().path() == "/client-redirect") {
228 return std::unique_ptr<net::test_server::HttpResponse>();
229 }
230 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
231 response->set_content_type("text/html");
232 response->AddCustomHeader("Access-Control-Allow-Origin", "*");
233 return static_cast<std::unique_ptr<net::test_server::HttpResponse>>(
234 std::move(response));
235 }));
236
237 ExtensionBrowserTest::SetUp();
238}
239
240void BookmarkAppNavigationBrowserTest::SetUpInProcessBrowserTestFixture() {
241 ExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
John Abd-El-Malek4f6427c2018-08-23 17:06:08242 cert_verifier_.SetUpInProcessBrowserTestFixture();
Dominick Ngc4a60b32018-04-19 05:18:49243}
244
245void BookmarkAppNavigationBrowserTest::TearDownInProcessBrowserTestFixture() {
246 ExtensionBrowserTest::TearDownInProcessBrowserTestFixture();
John Abd-El-Malek4f6427c2018-08-23 17:06:08247 cert_verifier_.TearDownInProcessBrowserTestFixture();
Dominick Ngc4a60b32018-04-19 05:18:49248}
249
250void BookmarkAppNavigationBrowserTest::SetUpCommandLine(
251 base::CommandLine* command_line) {
John Abd-El-Malek4f6427c2018-08-23 17:06:08252 cert_verifier_.SetUpCommandLine(command_line);
Dominick Ngc4a60b32018-04-19 05:18:49253}
254
255void BookmarkAppNavigationBrowserTest::SetUpOnMainThread() {
256 ExtensionBrowserTest::SetUpOnMainThread();
257 host_resolver()->AddRule("*", "127.0.0.1");
258 // By default, all SSL cert checks are valid. Can be overriden in tests.
John Abd-El-Malek4f6427c2018-08-23 17:06:08259 cert_verifier_.mock_cert_verifier()->set_default_result(net::OK);
Dominick Ngc4a60b32018-04-19 05:18:49260}
261
262void BookmarkAppNavigationBrowserTest::InstallTestBookmarkApp() {
263 test_bookmark_app_ = InstallTestBookmarkApp(GetAppUrlHost());
264}
265
266void BookmarkAppNavigationBrowserTest::InstallOtherTestBookmarkApp() {
267 InstallTestBookmarkApp(GetOtherAppUrlHost());
268}
269
270const Extension* BookmarkAppNavigationBrowserTest::InstallTestBookmarkApp(
271 const std::string& app_host) {
272 if (!https_server_.Started()) {
273 CHECK(https_server_.Start());
274 }
275
276 WebApplicationInfo web_app_info;
277 web_app_info.app_url = https_server_.GetURL(app_host, GetAppUrlPath());
278 web_app_info.scope = https_server_.GetURL(app_host, GetAppScopePath());
279 web_app_info.title = base::UTF8ToUTF16(GetAppName());
280 web_app_info.description = base::UTF8ToUTF16("Test description");
281 web_app_info.open_as_window = true;
282
283 return InstallBookmarkApp(web_app_info);
284}
285
286const Extension*
287BookmarkAppNavigationBrowserTest::InstallImmediateRedirectingApp(
288 const std::string& target_host,
289 const std::string& target_path) {
290 EXPECT_TRUE(https_server_.Start());
291 const GURL target_url = https_server_.GetURL(target_host, target_path);
292
293 WebApplicationInfo web_app_info;
294 web_app_info.app_url =
295 https_server_.GetURL(GetAppUrlHost(), CreateServerRedirect(target_url));
296 web_app_info.scope = https_server_.GetURL(GetAppUrlHost(), "/");
297 web_app_info.title = base::UTF8ToUTF16("Redirecting Test app");
298 web_app_info.description = base::UTF8ToUTF16("Test description");
299 web_app_info.open_as_window = true;
300
301 return InstallBookmarkApp(web_app_info);
302}
303
304Browser* BookmarkAppNavigationBrowserTest::OpenTestBookmarkApp() {
305 GURL app_url = https_server_.GetURL(GetAppUrlHost(), GetAppUrlPath());
306 auto observer = GetTestNavigationObserver(app_url);
307 Browser* app_browser = LaunchAppBrowser(test_bookmark_app_);
308 observer->WaitForNavigationFinished();
309
310 return app_browser;
311}
312
313void BookmarkAppNavigationBrowserTest::NavigateToLaunchingPage(
314 Browser* browser) {
315 ui_test_utils::NavigateToURL(browser, GetLaunchingPageURL());
316}
317
318void BookmarkAppNavigationBrowserTest::NavigateToLaunchingPage() {
319 NavigateToLaunchingPage(browser());
320}
321
322void BookmarkAppNavigationBrowserTest::NavigateToTestAppURL() {
323 const GURL app_url = https_server_.GetURL(GetAppUrlHost(), GetAppUrlPath());
324 NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_TYPED);
325 ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow(
326 app_url, base::BindOnce(&NavigateToURLWrapper, &params)));
327}
328
329void BookmarkAppNavigationBrowserTest::
330 TestTabActionDoesNotNavigateOrOpenAppWindow(base::OnceClosure action) {
331 size_t num_browsers = chrome::GetBrowserCount(profile());
332 int num_tabs = browser()->tab_strip_model()->count();
333 content::WebContents* initial_tab =
334 browser()->tab_strip_model()->GetActiveWebContents();
335 GURL initial_url = initial_tab->GetLastCommittedURL();
336
337 std::move(action).Run();
338
339 EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile()));
340 EXPECT_EQ(browser(), chrome::FindLastActive());
341 EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count());
342 EXPECT_EQ(initial_tab, browser()->tab_strip_model()->GetActiveWebContents());
343 EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL());
344}
345
346void BookmarkAppNavigationBrowserTest::TestTabActionOpensBackgroundTab(
347 const GURL& target_url,
348 base::OnceClosure action) {
349 size_t num_browsers = chrome::GetBrowserCount(profile());
350 int num_tabs = browser()->tab_strip_model()->count();
351 content::WebContents* initial_tab =
352 browser()->tab_strip_model()->GetActiveWebContents();
353 GURL initial_url = initial_tab->GetLastCommittedURL();
354
355 std::move(action).Run();
356
357 EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile()));
358 EXPECT_EQ(browser(), chrome::FindLastActive());
359 EXPECT_EQ(++num_tabs, browser()->tab_strip_model()->count());
360 EXPECT_EQ(initial_tab, browser()->tab_strip_model()->GetActiveWebContents());
361 EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL());
362
363 content::WebContents* new_tab =
364 browser()->tab_strip_model()->GetWebContentsAt(num_tabs - 1);
365 EXPECT_NE(new_tab, initial_tab);
366 EXPECT_EQ(target_url, new_tab->GetLastCommittedURL());
367}
368
369void BookmarkAppNavigationBrowserTest::TestTabActionOpensForegroundWindow(
370 const GURL& target_url,
371 base::OnceClosure action) {
372 size_t num_browsers = chrome::GetBrowserCount(profile());
373 int num_tabs = browser()->tab_strip_model()->count();
374 content::WebContents* initial_tab =
375 browser()->tab_strip_model()->GetActiveWebContents();
376 GURL initial_url = initial_tab->GetLastCommittedURL();
377
378 std::move(action).Run();
379
380 EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile()));
381
382 Browser* new_window = chrome::FindLastActive();
383 EXPECT_NE(new_window, browser());
384 EXPECT_FALSE(new_window->is_app());
385 EXPECT_EQ(target_url, new_window->tab_strip_model()
386 ->GetActiveWebContents()
387 ->GetLastCommittedURL());
388
389 EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count());
390 EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL());
391}
392
393void BookmarkAppNavigationBrowserTest::TestTabActionOpensAppWindow(
394 const GURL& target_url,
395 base::OnceClosure action) {
396 content::WebContents* initial_tab =
397 browser()->tab_strip_model()->GetActiveWebContents();
398 GURL initial_url = initial_tab->GetLastCommittedURL();
399 int num_tabs = browser()->tab_strip_model()->count();
400 size_t num_browsers = chrome::GetBrowserCount(profile());
401
402 std::move(action).Run();
403
404 EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count());
405 EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile()));
406 EXPECT_NE(browser(), chrome::FindLastActive());
407
408 EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL());
409 EXPECT_EQ(target_url, chrome::FindLastActive()
410 ->tab_strip_model()
411 ->GetActiveWebContents()
412 ->GetLastCommittedURL());
413}
414
415void BookmarkAppNavigationBrowserTest::TestTabActionOpensAppWindowWithOpener(
416 const GURL& target_url,
417 base::OnceClosure action) {
418 TestTabActionOpensAppWindow(target_url, std::move(action));
419
420 content::WebContents* initial_web_contents =
421 browser()->tab_strip_model()->GetActiveWebContents();
422 content::WebContents* app_web_contents =
423 chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents();
424
425 EXPECT_TRUE(HasOpenedWindowAndOpener(initial_web_contents, app_web_contents));
426}
427
428bool BookmarkAppNavigationBrowserTest::TestActionDoesNotOpenAppWindow(
429 Browser* browser,
430 const GURL& target_url,
431 base::OnceClosure action) {
432 content::WebContents* initial_tab =
433 browser->tab_strip_model()->GetActiveWebContents();
434 int num_tabs = browser->tab_strip_model()->count();
435 size_t num_browsers = chrome::GetBrowserCount(browser->profile());
436
437 std::move(action).Run();
438
439 EXPECT_EQ(num_tabs, browser->tab_strip_model()->count());
440 EXPECT_EQ(num_browsers, chrome::GetBrowserCount(browser->profile()));
441 EXPECT_EQ(browser, chrome::FindLastActive());
442 EXPECT_EQ(initial_tab, browser->tab_strip_model()->GetActiveWebContents());
443 EXPECT_EQ(target_url, initial_tab->GetLastCommittedURL());
444
445 return !HasFailure();
446}
447
448void BookmarkAppNavigationBrowserTest::TestAppActionOpensForegroundTab(
449 Browser* app_browser,
450 const GURL& target_url,
451 base::OnceClosure action) {
452 size_t num_browsers = chrome::GetBrowserCount(profile());
453 int num_tabs_browser = browser()->tab_strip_model()->count();
454 int num_tabs_app_browser = app_browser->tab_strip_model()->count();
455
456 content::WebContents* app_web_contents =
457 app_browser->tab_strip_model()->GetActiveWebContents();
458 content::WebContents* initial_tab =
459 browser()->tab_strip_model()->GetActiveWebContents();
460
461 GURL initial_app_url = app_web_contents->GetLastCommittedURL();
462 GURL initial_tab_url = initial_tab->GetLastCommittedURL();
463
464 std::move(action).Run();
465
466 EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile()));
467
468 EXPECT_EQ(browser(), chrome::FindLastActive());
469
470 EXPECT_EQ(++num_tabs_browser, browser()->tab_strip_model()->count());
471 EXPECT_EQ(num_tabs_app_browser, app_browser->tab_strip_model()->count());
472
473 EXPECT_EQ(initial_app_url, app_web_contents->GetLastCommittedURL());
474
475 content::WebContents* new_tab =
476 browser()->tab_strip_model()->GetActiveWebContents();
477 EXPECT_NE(initial_tab, new_tab);
478 EXPECT_EQ(target_url, new_tab->GetLastCommittedURL());
479}
480
481void BookmarkAppNavigationBrowserTest::TestAppActionOpensAppWindowWithOpener(
482 Browser* app_browser,
483 const GURL& target_url,
484 base::OnceClosure action) {
485 size_t num_browsers = chrome::GetBrowserCount(profile());
486 int num_tabs_browser = browser()->tab_strip_model()->count();
487 int num_tabs_app_browser = app_browser->tab_strip_model()->count();
488
489 content::WebContents* app_web_contents =
490 app_browser->tab_strip_model()->GetActiveWebContents();
491 content::WebContents* initial_tab =
492 browser()->tab_strip_model()->GetActiveWebContents();
493
494 GURL initial_app_url = app_web_contents->GetLastCommittedURL();
495 GURL initial_tab_url = initial_tab->GetLastCommittedURL();
496
497 std::move(action).Run();
498
499 EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile()));
500
501 Browser* new_app_browser = chrome::FindLastActive();
502 EXPECT_NE(new_app_browser, browser());
503 EXPECT_NE(new_app_browser, app_browser);
504 EXPECT_TRUE(new_app_browser->is_app());
505
506 EXPECT_EQ(num_tabs_browser, browser()->tab_strip_model()->count());
507 EXPECT_EQ(num_tabs_app_browser, app_browser->tab_strip_model()->count());
508
509 EXPECT_EQ(initial_app_url, app_web_contents->GetLastCommittedURL());
510
511 content::WebContents* new_app_web_contents =
512 new_app_browser->tab_strip_model()->GetActiveWebContents();
513 EXPECT_EQ(target_url, new_app_web_contents->GetLastCommittedURL());
514
515 EXPECT_TRUE(HasOpenedWindowAndOpener(app_web_contents, new_app_web_contents));
516}
517
518bool BookmarkAppNavigationBrowserTest::TestTabActionDoesNotOpenAppWindow(
519 const GURL& target_url,
520 base::OnceClosure action) {
521 return TestActionDoesNotOpenAppWindow(browser(), target_url,
522 std::move(action));
523}
524
525bool BookmarkAppNavigationBrowserTest::TestIFrameActionDoesNotOpenAppWindow(
526 const GURL& target_url,
527 base::OnceClosure action) {
528 size_t num_browsers = chrome::GetBrowserCount(profile());
529 int num_tabs = browser()->tab_strip_model()->count();
530 content::WebContents* initial_tab =
531 browser()->tab_strip_model()->GetActiveWebContents();
532
533 std::move(action).Run();
534
535 EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile()));
536 EXPECT_EQ(browser(), chrome::FindLastActive());
537 EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count());
538
539 // When Site Isolation is enabled, navigating the iframe to a different
540 // origin causes the original iframe's RenderFrameHost to be deleted.
541 // So we retrieve the iframe's RenderFrameHost again.
542 EXPECT_EQ(target_url, GetIFrame(initial_tab)->GetLastCommittedURL());
543
544 return !HasFailure();
545}
546
547GURL BookmarkAppNavigationBrowserTest::GetLaunchingPageURL() {
548 return https_server_.GetURL(GetLaunchingPageHost(), GetLaunchingPagePath());
549}
550
551} // namespace test
552} // namespace extensions