| // Copyright 2017 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/test/metrics/histogram_tester.h" | 
 | #include "base/test/scoped_feature_list.h" | 
 | #include "build/build_config.h" | 
 | #include "chrome/app/chrome_command_ids.h" | 
 | #include "chrome/browser/extensions/bookmark_app_helper.h" | 
 | #include "chrome/browser/extensions/bookmark_app_navigation_browsertest.h" | 
 | #include "chrome/browser/extensions/bookmark_app_navigation_throttle_utils.h" | 
 | #include "chrome/browser/extensions/launch_util.h" | 
 | #include "chrome/browser/prefs/session_startup_pref.h" | 
 | #include "chrome/browser/prerender/prerender_manager.h" | 
 | #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h" | 
 | #include "chrome/browser/ui/browser_commands.h" | 
 | #include "chrome/browser/ui/browser_finder.h" | 
 | #include "chrome/browser/ui/browser_list.h" | 
 | #include "chrome/browser/ui/extensions/app_launch_params.h" | 
 | #include "chrome/browser/ui/extensions/application_launch.h" | 
 | #include "chrome/browser/ui/tabs/tab_strip_model.h" | 
 | #include "chrome/browser/web_applications/components/web_app_helpers.h" | 
 | #include "chrome/browser/web_applications/extensions/bookmark_app_util.h" | 
 | #include "chrome/common/chrome_features.h" | 
 | #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | 
 | #include "chrome/test/base/ui_test_utils.h" | 
 | #include "content/public/browser/navigation_handle.h" | 
 | #include "content/public/browser/notification_details.h" | 
 | #include "content/public/browser/notification_service.h" | 
 | #include "content/public/browser/render_frame_host.h" | 
 | #include "content/public/common/context_menu_params.h" | 
 | #include "content/public/test/browser_test_utils.h" | 
 | #include "content/public/test/test_frame_navigation_observer.h" | 
 | #include "content/public/test/test_navigation_observer.h" | 
 | #include "content/public/test/test_utils.h" | 
 | #include "extensions/browser/extension_registry.h" | 
 | #include "extensions/browser/notification_types.h" | 
 | #include "extensions/common/constants.h" | 
 | #include "net/base/escape.h" | 
 | #include "net/http/http_request_headers.h" | 
 | #include "net/url_request/url_fetcher.h" | 
 | #include "services/network/public/cpp/resource_request_body.h" | 
 | #include "testing/gmock/include/gmock/gmock.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace extensions { | 
 | namespace test { | 
 |  | 
 | enum class StartIn { | 
 |   BROWSER, | 
 |   APP, | 
 | }; | 
 |  | 
 | enum class WindowAccessResult { | 
 |   CAN_ACCESS, | 
 |   CANNOT_ACCESS, | 
 |   // Used for when there was an unexpected issue when accessing the other window | 
 |   // e.g. there is no other window, or the other window's URL does not match the | 
 |   // expected URL. | 
 |   OTHER, | 
 | }; | 
 |  | 
 | namespace { | 
 |  | 
 | const char kTextPlainEncType[] = "text/plain"; | 
 |  | 
 | const char kQueryParam[] = "test="; | 
 | const char kQueryParamName[] = "test"; | 
 |  | 
 | // On macOS the Meta key is used as a modifier instead of Control. | 
 | #if defined(OS_MACOSX) | 
 | constexpr int kCtrlOrMeta = blink::WebInputEvent::kMetaKey; | 
 | #else | 
 | constexpr int kCtrlOrMeta = blink::WebInputEvent::kControlKey; | 
 | #endif | 
 |  | 
 | // Subclass of TestNavigationObserver that saves extra information about the | 
 | // navigation and watches all navigations to |target_url|. | 
 | class BookmarkAppNavigationObserver : public content::TestNavigationObserver { | 
 |  public: | 
 |   // Creates an observer that watches navigations to |target_url| on all | 
 |   // existing and newly added WebContents. | 
 |   explicit BookmarkAppNavigationObserver(const GURL& target_url) | 
 |       : content::TestNavigationObserver(target_url), | 
 |         last_navigation_is_post_(false) { | 
 |     WatchExistingWebContents(); | 
 |     StartWatchingNewWebContents(); | 
 |   } | 
 |  | 
 |   bool last_navigation_is_post() const { return last_navigation_is_post_; } | 
 |  | 
 |   const net::HttpRequestHeaders& last_request_headers() const { | 
 |     return last_request_headers_; | 
 |   } | 
 |  | 
 |   const scoped_refptr<network::ResourceRequestBody>& | 
 |   last_resource_request_body() const { | 
 |     return last_resource_request_body_; | 
 |   } | 
 |  | 
 |  private: | 
 |   void OnDidFinishNavigation( | 
 |       content::NavigationHandle* navigation_handle) override { | 
 |     last_navigation_is_post_ = navigation_handle->IsPost(); | 
 |     last_request_headers_ = navigation_handle->GetRequestHeaders(); | 
 |     last_resource_request_body_ = navigation_handle->GetResourceRequestBody(); | 
 |     content::TestNavigationObserver::OnDidFinishNavigation(navigation_handle); | 
 |   } | 
 |  | 
 |   // True if the last navigation was a post. | 
 |   bool last_navigation_is_post_; | 
 |  | 
 |   // The request headers of the last navigation. | 
 |   net::HttpRequestHeaders last_request_headers_; | 
 |  | 
 |   // The request body of the last navigation if it was a post request. | 
 |   scoped_refptr<network::ResourceRequestBody> last_resource_request_body_; | 
 | }; | 
 |  | 
 | void ExpectNavigationResultHistogramEquals( | 
 |     const base::HistogramTester& histogram_tester, | 
 |     const std::vector<std::pair<BookmarkAppNavigationThrottleResult, | 
 |                                 base::HistogramBase::Count>>& expected_counts) { | 
 |   std::vector<base::Bucket> expected_bucket_counts; | 
 |   for (const auto& pair : expected_counts) { | 
 |     expected_bucket_counts.push_back(base::Bucket( | 
 |         static_cast<base::HistogramBase::Sample>(pair.first), pair.second)); | 
 |   } | 
 |  | 
 |   EXPECT_THAT( | 
 |       histogram_tester.GetAllSamples("Extensions.BookmarkApp.NavigationResult"), | 
 |       testing::UnorderedElementsAreArray(expected_bucket_counts)); | 
 | } | 
 |  | 
 | // When an app is launched, whether it's in response to a navigation or click | 
 | // in a launch surface e.g. App Shelf, the first navigation in the app is | 
 | // an AUTO_BOOKMARK navigation. | 
 | std::pair<BookmarkAppNavigationThrottleResult, base::HistogramBase::Count> | 
 | GetAppLaunchedEntry() { | 
 |   return {BookmarkAppNavigationThrottleResult::kProceedTransitionAutoBookmark, | 
 |           1}; | 
 | } | 
 |  | 
 | std::string CreateClientRedirect(const GURL& target_url) { | 
 |   const char* const kClientRedirectBase = "/client-redirect?"; | 
 |   return kClientRedirectBase + | 
 |          net::EscapeQueryParamValue(target_url.spec(), false); | 
 | } | 
 |  | 
 | // Inserts an iframe in the main frame of |web_contents|. | 
 | void InsertIFrame(content::WebContents* web_contents) { | 
 |   ASSERT_TRUE( | 
 |       content::ExecuteScript(web_contents, | 
 |                              "let iframe = document.createElement('iframe');" | 
 |                              "document.body.appendChild(iframe);")); | 
 | } | 
 |  | 
 | void ExecuteContextMenuLinkCommandAndWait(content::WebContents* web_contents, | 
 |                                           const GURL& target_url, | 
 |                                           int command_id) { | 
 |   auto observer = | 
 |       BookmarkAppNavigationBrowserTest::GetTestNavigationObserver(target_url); | 
 |   content::ContextMenuParams params; | 
 |   params.page_url = web_contents->GetLastCommittedURL(); | 
 |   params.link_url = target_url; | 
 |   TestRenderViewContextMenu menu(web_contents->GetMainFrame(), params); | 
 |   menu.Init(); | 
 |   menu.ExecuteCommand(command_id, 0 /* event_flags */); | 
 |   observer->WaitForNavigationFinished(); | 
 | } | 
 |  | 
 | void OpenPopupAndWait(content::WebContents* web_contents, | 
 |                       const GURL& target_url) { | 
 |   auto observer = | 
 |       BookmarkAppNavigationBrowserTest::GetTestNavigationObserver(target_url); | 
 |   const std::string script = base::StringPrintf( | 
 |       "(() => {" | 
 |       "  window.openedWindow = window.open('%s', '_blank', 'toolbar=no');" | 
 |       "})();", | 
 |       target_url.spec().c_str()); | 
 |   ASSERT_TRUE(content::ExecuteScript(web_contents, script)); | 
 |   observer->WaitForNavigationFinished(); | 
 | } | 
 |  | 
 | // Calls window.open() with |target_url| on the main frame of |web_contents|. | 
 | // Returns once the new window has navigated to |target_url|. | 
 | void WindowOpenAndWait(content::WebContents* web_contents, | 
 |                        const GURL& target_url) { | 
 |   auto observer = | 
 |       BookmarkAppNavigationBrowserTest::GetTestNavigationObserver(target_url); | 
 |   const std::string script = base::StringPrintf( | 
 |       "(() => {" | 
 |       "  window.openedWindow = window.open('%s');" | 
 |       "})();", | 
 |       target_url.spec().c_str()); | 
 |   ASSERT_TRUE(content::ExecuteScript(web_contents, script)); | 
 |   observer->WaitForNavigationFinished(); | 
 | } | 
 |  | 
 | // Calls window.open() with |target_url| on the main frame of |web_contents|. | 
 | // Returns true if the resulting child window is allowed to access members of | 
 | // its opener. | 
 | WindowAccessResult CanChildWindowAccessOpener( | 
 |     content::WebContents* web_contents, | 
 |     const GURL& target_url) { | 
 |   WindowOpenAndWait(web_contents, target_url); | 
 |  | 
 |   content::WebContents* new_contents = | 
 |       chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   const std::string script = base::StringPrintf( | 
 |       "(() => {" | 
 |       "  const [CAN_ACCESS, CANNOT_ACCESS, OTHER] = [0, 1, 2];" | 
 |       "  let result = OTHER;" | 
 |       "  try {" | 
 |       "    if (window.opener.location.href === '%s')" | 
 |       "      result = CAN_ACCESS;" | 
 |       "  } catch (e) {" | 
 |       "    if (e.name === 'SecurityError')" | 
 |       "      result = CANNOT_ACCESS;" | 
 |       "  }" | 
 |       "  window.domAutomationController.send(result);" | 
 |       "})();", | 
 |       web_contents->GetLastCommittedURL().spec().c_str()); | 
 |  | 
 |   int access_result; | 
 |   CHECK(content::ExecuteScriptAndExtractInt(new_contents, script, | 
 |                                             &access_result)); | 
 |  | 
 |   switch (access_result) { | 
 |     case 0: | 
 |       return WindowAccessResult::CAN_ACCESS; | 
 |     case 1: | 
 |       return WindowAccessResult::CANNOT_ACCESS; | 
 |     case 2: | 
 |       return WindowAccessResult::OTHER; | 
 |     default: | 
 |       NOTREACHED(); | 
 |       return WindowAccessResult::OTHER; | 
 |   } | 
 | } | 
 |  | 
 | // Adds a query parameter to |base_url|. | 
 | GURL AddTestQueryParam(const GURL& base_url) { | 
 |   GURL::Replacements replacements; | 
 |   std::string query(kQueryParam); | 
 |   replacements.SetQuery(query.c_str(), url::Component(0, query.length())); | 
 |   return base_url.ReplaceComponents(replacements); | 
 | } | 
 |  | 
 | // Creates a <form> element with a |target_url| action and |method| method. Adds | 
 | // the form to the DOM with a button and clicks the button. Returns once | 
 | // |target_url| has been loaded. | 
 | // | 
 | // If |method| is net::URLFetcher::RequestType::GET, |target_url| should contain | 
 | // an empty query string, since that URL will be loaded when submitting the form | 
 | // e.g. "https://www.example.com/?". | 
 | void SubmitFormAndWait(content::WebContents* web_contents, | 
 |                        const GURL& target_url, | 
 |                        net::URLFetcher::RequestType method) { | 
 |   bool is_post = true; | 
 |   if (method == net::URLFetcher::RequestType::GET) { | 
 |     is_post = false; | 
 |     ASSERT_TRUE(target_url.has_query()); | 
 |     ASSERT_EQ(kQueryParam, target_url.query()); | 
 |   } | 
 |  | 
 |   BookmarkAppNavigationObserver observer(target_url); | 
 |   std::string script = base::StringPrintf( | 
 |       "(() => {" | 
 |       "const form = document.createElement('form');" | 
 |       "form.action = '%s';" | 
 |       "form.method = '%s';" | 
 |       "form.enctype = '%s';" | 
 |       "const input = document.createElement('input');" | 
 |       "input.name = '%s';" | 
 |       "form.appendChild(input);" | 
 |       "const button = document.createElement('input');" | 
 |       "button.type = 'submit';" | 
 |       "form.appendChild(button);" | 
 |       "document.body.appendChild(form);" | 
 |       "button.dispatchEvent(new MouseEvent('click', {'view': window}));" | 
 |       "})();", | 
 |       target_url.spec().c_str(), | 
 |       method == net::URLFetcher::RequestType::POST ? "post" : "get", | 
 |       kTextPlainEncType, kQueryParamName); | 
 |   ASSERT_TRUE(content::ExecuteScript(web_contents, script)); | 
 |   observer.WaitForNavigationFinished(); | 
 |  | 
 |   EXPECT_EQ(is_post, observer.last_navigation_is_post()); | 
 |   if (is_post) { | 
 |     const net::HttpRequestHeaders& headers = observer.last_request_headers(); | 
 |     std::string post_content_type; | 
 |     headers.GetHeader(net::HttpRequestHeaders::kContentType, | 
 |                       &post_content_type); | 
 |     EXPECT_EQ(kTextPlainEncType, post_content_type); | 
 |  | 
 |     const std::vector<network::DataElement>* elements = | 
 |         observer.last_resource_request_body()->elements(); | 
 |     EXPECT_EQ(1u, elements->size()); | 
 |     const auto& element = elements->front(); | 
 |  | 
 |     // The text/plain enconding algorithm appends "\r\n". | 
 |     EXPECT_EQ(std::string(kQueryParam) + "\r\n", | 
 |               std::string(element.bytes(), element.length())); | 
 |   } | 
 | } | 
 |  | 
 | // Uses |params| to navigate to a URL. Blocks until the URL is loaded. | 
 | void NavigateToURLAndWait(NavigateParams* params) { | 
 |   auto observer = | 
 |       BookmarkAppNavigationBrowserTest::GetTestNavigationObserver(params->url); | 
 |   ui_test_utils::NavigateToURL(params); | 
 |   observer->WaitForNavigationFinished(); | 
 | } | 
 |  | 
 | // Wrapper so that we can use base::BindOnce with NavigateToURL. | 
 | void NavigateToURLWrapper(NavigateParams* params) { | 
 |   ui_test_utils::NavigateToURL(params); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Tests for the behavior when the kDesktopPWAsLinkCapturing flag is on. | 
 | class BookmarkAppNavigationThrottleExperimentalBrowserTest | 
 |     : public BookmarkAppNavigationBrowserTest { | 
 |  public: | 
 |   void SetUp() override { | 
 |     scoped_feature_list_.InitWithFeatures( | 
 |         {features::kDesktopPWAWindowing, features::kDesktopPWAsLinkCapturing}, | 
 |         {}); | 
 |     BookmarkAppNavigationBrowserTest::SetUp(); | 
 |   } | 
 |  | 
 |  private: | 
 |   base::test::ScopedFeatureList scoped_feature_list_; | 
 | }; | 
 |  | 
 | // Tests that the result is the same regardless of the 'rel' attribute of links. | 
 | class BookmarkAppNavigationThrottleExperimentalLinkBrowserTest | 
 |     : public BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |       public ::testing::WithParamInterface<std::string> {}; | 
 |  | 
 | // Tests that navigating to the Web App's app_url doesn't open a new window | 
 | // if features::kDesktopPWAsLinkCapturing is disabled before installing the app. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        FeatureDisable_BeforeInstall) { | 
 |   base::test::ScopedFeatureList feature_list; | 
 |   feature_list.InitWithFeatures({}, {features::kDesktopPWAsLinkCapturing}); | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that navigating to the Web App's app_url doesn't open a new window | 
 | // if features::kDesktopPWAWindowing is disabled after installing the app. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        FeatureDisable_AfterInstall) { | 
 |   InstallTestBookmarkApp(); | 
 |   base::test::ScopedFeatureList feature_list; | 
 |   feature_list.InitWithFeatures({}, {features::kDesktopPWAsLinkCapturing}); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that most transition types for navigations to in-scope or | 
 | // out-of-scope URLs do not result in new app windows. | 
 | class BookmarkAppNavigationThrottleExperimentalTransitionBrowserTest | 
 |     : public BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |       public ::testing::WithParamInterface< | 
 |           std::tuple<std::string, ui::PageTransition>> {}; | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleExperimentalTransitionBrowserTest, | 
 |     testing::Combine( | 
 |         testing::Values( | 
 |             BookmarkAppNavigationBrowserTest::GetInScopeUrlPath(), | 
 |             BookmarkAppNavigationBrowserTest::GetOutOfScopeUrlPath()), | 
 |         testing::Range(ui::PAGE_TRANSITION_FIRST, | 
 |                        ui::PAGE_TRANSITION_LAST_CORE))); | 
 |  | 
 | #if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX) | 
 | #define MAYBE_MainFrameNavigations DISABLED_MainFrameNavigations | 
 | #else | 
 | #define MAYBE_MainFrameNavigations MainFrameNavigations | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     BookmarkAppNavigationThrottleExperimentalTransitionBrowserTest, | 
 |     MAYBE_MainFrameNavigations) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   GURL target_url = | 
 |       https_server().GetURL(GetAppUrlHost(), std::get<0>(GetParam())); | 
 |   ui::PageTransition transition = std::get<1>(GetParam()); | 
 |   NavigateParams params(browser(), target_url, transition); | 
 |  | 
 |   if (!ui::PageTransitionIsMainFrame(transition)) { | 
 |     // Subframe navigations require a different setup. See | 
 |     // BookmarkAppNavigationThrottleExperimentalBrowserTest.SubframeNavigation. | 
 |     return; | 
 |   } | 
 |  | 
 |   if (ui::PageTransitionCoreTypeIs(ui::PAGE_TRANSITION_LINK, transition) && | 
 |       target_url == | 
 |           https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath())) { | 
 |     TestTabActionOpensAppWindow(target_url, | 
 |                                 base::BindOnce(&NavigateToURLAndWait, ¶ms)); | 
 |   } else { | 
 |     TestTabActionDoesNotOpenAppWindow( | 
 |         target_url, base::BindOnce(&NavigateToURLAndWait, ¶ms)); | 
 |   } | 
 | } | 
 |  | 
 | // Tests that navigations in subframes don't open new app windows. | 
 | // | 
 | // The transition type for subframe navigations is not set until | 
 | // after NavigationThrottles run. Because of this, our | 
 | // BookmarkAppNavigationThrottle will not see the transition type as | 
 | // PAGE_TRANSITION_AUTO_SUBFRAME/PAGE_TRANSITION_MANUAL_SUBFRAME, even though, | 
 | // by the end of the navigation, the transition type is | 
 | // PAGE_TRANSITION_AUTO_SUBFRAME/PAGE_TRANSITON_MANUAL_SUBFRAME. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        AutoSubframeNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   InsertIFrame(initial_tab); | 
 |  | 
 |   content::RenderFrameHost* iframe = GetIFrame(initial_tab); | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |  | 
 |   NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_LINK); | 
 |   params.frame_tree_node_id = iframe->GetFrameTreeNodeId(); | 
 |   content::TestFrameNavigationObserver observer(iframe); | 
 |   TestIFrameActionDoesNotOpenAppWindow( | 
 |       app_url, base::BindOnce(&NavigateToURLWrapper, ¶ms)); | 
 |  | 
 |   ASSERT_TRUE(ui::PageTransitionCoreTypeIs(observer.transition_type(), | 
 |                                            ui::PAGE_TRANSITION_AUTO_SUBFRAME)); | 
 |  | 
 |   // Subframe navigations are completely ignored, so there should be no change | 
 |   // in the histogram. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        ManualSubframeNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   InsertIFrame(initial_tab); | 
 |  | 
 |   { | 
 |     // Navigate the iframe once, so that the next navigation is a | 
 |     // MANUAL_SUBFRAME navigation. | 
 |     content::RenderFrameHost* iframe = GetIFrame(initial_tab); | 
 |     NavigateParams params(browser(), GetLaunchingPageURL(), | 
 |                           ui::PAGE_TRANSITION_LINK); | 
 |     params.frame_tree_node_id = iframe->GetFrameTreeNodeId(); | 
 |     ASSERT_TRUE(TestIFrameActionDoesNotOpenAppWindow( | 
 |         GetLaunchingPageURL(), base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |   } | 
 |  | 
 |   content::RenderFrameHost* iframe = GetIFrame(initial_tab); | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |  | 
 |   NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_LINK); | 
 |   params.frame_tree_node_id = iframe->GetFrameTreeNodeId(); | 
 |   content::TestFrameNavigationObserver observer(iframe); | 
 |   TestIFrameActionDoesNotOpenAppWindow( | 
 |       app_url, base::BindOnce(&NavigateToURLWrapper, ¶ms)); | 
 |  | 
 |   ASSERT_TRUE(ui::PageTransitionCoreTypeIs( | 
 |       observer.transition_type(), ui::PAGE_TRANSITION_MANUAL_SUBFRAME)); | 
 |  | 
 |   // Subframe navigations are completely ignored, so there should be no change | 
 |   // in the histogram. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that pasting an in-scope URL into the address bar and navigating to it, | 
 | // does not open an app window. | 
 | // https://crbug.com/782004 | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        LinkNavigationFromAddressBar) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   // Fake a navigation with a TRANSITION_LINK core type and a | 
 |   // TRANSITION_FROM_ADDRESS_BAR qualifier. This matches the transition that | 
 |   // results from pasting a URL into the address and navigating to it. | 
 |   NavigateParams params( | 
 |       browser(), app_url, | 
 |       ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK | | 
 |                                 ui::PAGE_TRANSITION_FROM_ADDRESS_BAR)); | 
 |   ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |       app_url, base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedTransitionFromAddressBar, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that going back to an in-scope URL does not open a new app window. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        BackNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToTestAppURL(); | 
 |  | 
 |   // Navigate to an in-scope URL to generate a link navigation that didn't | 
 |   // get intercepted. The navigation won't get intercepted because the target | 
 |   // URL is in-scope of the app for the current URL. | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      in_scope_url, LinkTarget::SELF, "" /* rel */))); | 
 |  | 
 |   // Navigate to an out-of-scope URL. | 
 |   { | 
 |     const GURL out_of_scope_url = | 
 |         https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |     NavigateParams params(browser(), out_of_scope_url, | 
 |                           ui::PAGE_TRANSITION_TYPED); | 
 |     ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |         out_of_scope_url, base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |   } | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce( | 
 |           [](content::WebContents* web_contents, const GURL& in_scope_url) { | 
 |             auto observer = GetTestNavigationObserver(in_scope_url); | 
 |             web_contents->GetController().GoBack(); | 
 |             observer->WaitForNavigationFinished(); | 
 |           }, | 
 |           browser()->tab_strip_model()->GetActiveWebContents(), in_scope_url)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedTransitionForwardBack, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking a link to an app that launches in a tab does not open a | 
 | // a new app window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        TabApp) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   // Set a pref indicating that the user wants to launch in a regular tab. | 
 |   extensions::SetLaunchType(browser()->profile(), test_bookmark_app()->id(), | 
 |                             extensions::LAUNCH_TYPE_REGULAR); | 
 |  | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   // Non-windowed apps are not considered when looking for a target app, so it's | 
 |   // as if there was no app installed for the URL. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that clicking a link to an app that isn't locally installed does not | 
 | // open a new app window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        NotLocallyInstalledApp) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   // Part of the installation process (setting that this is a locally installed | 
 |   // app) runs asynchronously. Wait for that to complete before setting locally | 
 |   // installed to false. | 
 |   base::RunLoop().RunUntilIdle(); | 
 |   SetBookmarkAppIsLocallyInstalled(browser()->profile(), test_bookmark_app(), | 
 |                                    false /* is_locally_installed */); | 
 |  | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   // Non-locally installed apps are not considered when looking for a target | 
 |   // app, so it's as if there was no app installed for the URL. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_self" to the app's app_url opens the | 
 | // Bookmark App. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        AppUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_blank" to the app's app_url opens | 
 | // the Bookmark App. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        AppUrlBlank) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::BLANK, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kDeferMovingContentsToNewAppWindow, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that Ctrl + Clicking a link to the app's app_url opens a new background | 
 | // tab and not the app. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        AppUrlCtrlClick) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlPath()); | 
 |   TestTabActionOpensBackgroundTab( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkWithModifiersAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, LinkTarget::SELF, GetParam(), kCtrlOrMeta)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), {{BookmarkAppNavigationThrottleResult:: | 
 |                                 kProceedDispositionNewBackgroundTab, | 
 |                             1}}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_self" and for which the server | 
 | // redirects to the app's app_url opens the Bookmark App. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        ServerRedirectToAppUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   const GURL redirecting_url = https_server().GetURL( | 
 |       GetLaunchingPageHost(), CreateServerRedirect(app_url)); | 
 |   TestTabActionOpensAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWaitForURL, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      redirecting_url, app_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_blank" and for which the server | 
 | // redirects to the app's app_url opens the Bookmark App. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        ServerRedirectToAppUrlBlank) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   const GURL redirecting_url = https_server().GetURL( | 
 |       GetLaunchingPageHost(), CreateServerRedirect(app_url)); | 
 |   TestTabActionOpensAppWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ClickLinkAndWaitForURL, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      redirecting_url, app_url, LinkTarget::BLANK, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kDeferMovingContentsToNewAppWindow, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_self" and for which the client | 
 | // redirects to the app's app_url opens the Bookmark App. The initial tab will | 
 | // be left on the redirecting URL. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        ClientRedirectToAppUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   GURL initial_url = initial_tab->GetLastCommittedURL(); | 
 |   int num_tabs = browser()->tab_strip_model()->count(); | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   const GURL redirecting_url = https_server().GetURL( | 
 |       GetLaunchingPageHost(), CreateClientRedirect(app_url)); | 
 |   ClickLinkAndWaitForURL(browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                          redirecting_url, app_url, LinkTarget::SELF, | 
 |                          GetParam()); | 
 |  | 
 |   EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count()); | 
 |   EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile())); | 
 |   EXPECT_NE(browser(), chrome::FindLastActive()); | 
 |  | 
 |   EXPECT_EQ(redirecting_url, initial_tab->GetLastCommittedURL()); | 
 |   EXPECT_EQ(app_url, chrome::FindLastActive() | 
 |                          ->tab_strip_model() | 
 |                          ->GetActiveWebContents() | 
 |                          ->GetLastCommittedURL()); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_blank" and for which the client | 
 | // redirects to the app's app_url opens the Bookmark App. The new tab will be | 
 | // left on the redirecting URL. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        ClientRedirectToAppUrlBlank) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   GURL initial_url = initial_tab->GetLastCommittedURL(); | 
 |   int num_tabs = browser()->tab_strip_model()->count(); | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   const GURL redirecting_url = https_server().GetURL( | 
 |       GetLaunchingPageHost(), CreateClientRedirect(app_url)); | 
 |   ClickLinkAndWaitForURL(browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                          redirecting_url, app_url, LinkTarget::BLANK, | 
 |                          GetParam()); | 
 |  | 
 |   EXPECT_EQ(++num_tabs, browser()->tab_strip_model()->count()); | 
 |   EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile())); | 
 |   EXPECT_NE(browser(), chrome::FindLastActive()); | 
 |  | 
 |   content::WebContents* new_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   EXPECT_NE(new_tab, initial_tab); | 
 |  | 
 |   EXPECT_EQ(redirecting_url, new_tab->GetLastCommittedURL()); | 
 |   EXPECT_EQ(app_url, chrome::FindLastActive() | 
 |                          ->tab_strip_model() | 
 |                          ->GetActiveWebContents() | 
 |                          ->GetLastCommittedURL()); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_self" to a URL in the Web App's | 
 | // scope opens a new browser window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        InScopeUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   TestTabActionOpensAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      in_scope_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a link with target="_self" to a URL out of the Web App's | 
 | // scope but with the same origin doesn't open a new browser window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        OutOfScopeUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL out_of_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       out_of_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      out_of_scope_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that prerender links don't open the app. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        PrerenderLinks) { | 
 |   prerender::PrerenderManager::SetMode( | 
 |       prerender::PrerenderManager::PRERENDER_MODE_ENABLED); | 
 |  | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   TestTabActionDoesNotNavigateOrOpenAppWindow(base::BindOnce( | 
 |       [](content::WebContents* web_contents, const GURL& target_url) { | 
 |         std::string script = base::StringPrintf( | 
 |             "(() => {" | 
 |             "const prerender_link = document.createElement('link');" | 
 |             "prerender_link.rel = 'prerender';" | 
 |             "prerender_link.href = '%s';" | 
 |             "prerender_link.addEventListener('webkitprerenderstop'," | 
 |             "() => window.domAutomationController.send(true));" | 
 |             "document.body.appendChild(prerender_link);" | 
 |             "})();", | 
 |             target_url.spec().c_str()); | 
 |         bool result; | 
 |         ASSERT_TRUE(content::ExecuteScriptAndExtractBool(web_contents, script, | 
 |                                                          &result)); | 
 |         ASSERT_TRUE(result); | 
 |       }, | 
 |       browser()->tab_strip_model()->GetActiveWebContents(), | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()))); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelPrerenderContents, 1}}); | 
 | } | 
 |  | 
 | // Tests fetch calls don't open a new App window. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        Fetch) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   TestTabActionDoesNotNavigateOrOpenAppWindow(base::BindOnce( | 
 |       [](content::WebContents* web_contents, const GURL& target_url) { | 
 |         std::string script = base::StringPrintf( | 
 |             "(() => {" | 
 |             "fetch('%s').then(response => {" | 
 |             "  window.domAutomationController.send(response.ok);" | 
 |             "});" | 
 |             "})();", | 
 |             target_url.spec().c_str()); | 
 |         bool result; | 
 |         ASSERT_TRUE(content::ExecuteScriptAndExtractBool(web_contents, script, | 
 |                                                          &result)); | 
 |         ASSERT_TRUE(result); | 
 |       }, | 
 |       browser()->tab_strip_model()->GetActiveWebContents(), | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()))); | 
 |  | 
 |   // Fetch requests don't go through our NavigationHandle. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that clicking "Open link in new tab" to an in-scope URL opens a new | 
 | // tab in the background. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        ContextMenuNewTab) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensBackgroundTab( | 
 |       app_url, | 
 |       base::BindOnce(&ExecuteContextMenuLinkCommandAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedStartedFromContextMenu, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking "Open link in new window" to an in-scope URL opens a new | 
 | // window in the foreground. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        ContextMenuNewWindow) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensForegroundWindow( | 
 |       app_url, | 
 |       base::BindOnce(&ExecuteContextMenuLinkCommandAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedStartedFromContextMenu, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking "Open link in new tab" in an app to an in-scope URL opens | 
 | // a new foreground tab in a regular browser window. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        InAppContextMenuNewTab) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestAppActionOpensForegroundTab( | 
 |       app_browser, app_url, | 
 |       base::BindOnce(&ExecuteContextMenuLinkCommandAndWait, | 
 |                      app_browser->tab_strip_model()->GetActiveWebContents(), | 
 |                      app_url, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedStartedFromContextMenu, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking "Open link in incognito window" to an in-scope URL opens | 
 | // an incognito window and not an app window. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        OpenInIncognito) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToLaunchingPage(); | 
 |  | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |   int num_tabs = browser()->tab_strip_model()->count(); | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   GURL initial_url = initial_tab->GetLastCommittedURL(); | 
 |  | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   auto observer = GetTestNavigationObserver(in_scope_url); | 
 |   content::ContextMenuParams params; | 
 |   params.page_url = initial_url; | 
 |   params.link_url = in_scope_url; | 
 |   TestRenderViewContextMenu menu(initial_tab->GetMainFrame(), params); | 
 |   menu.Init(); | 
 |   menu.ExecuteCommand(IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD, | 
 |                       0 /* event_flags */); | 
 |   observer->WaitForNavigationFinished(); | 
 |  | 
 |   Browser* incognito_browser = chrome::FindLastActive(); | 
 |   EXPECT_EQ(incognito_browser->profile(), profile()->GetOffTheRecordProfile()); | 
 |   EXPECT_NE(browser(), incognito_browser); | 
 |   EXPECT_EQ(in_scope_url, incognito_browser->tab_strip_model() | 
 |                               ->GetActiveWebContents() | 
 |                               ->GetLastCommittedURL()); | 
 |  | 
 |   EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile())); | 
 |   EXPECT_EQ(num_tabs, browser()->tab_strip_model()->count()); | 
 |   EXPECT_EQ(initial_tab, browser()->tab_strip_model()->GetActiveWebContents()); | 
 |   EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL()); | 
 |  | 
 |   // Incognito navigations are completely ignored. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that clicking a link to an in-scope URL when in incognito does not open | 
 | // an App window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        InScopeUrlIncognito) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* incognito_browser = CreateIncognitoBrowser(); | 
 |   NavigateToLaunchingPage(incognito_browser); | 
 |  | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   TestActionDoesNotOpenAppWindow( | 
 |       incognito_browser, in_scope_url, | 
 |       base::BindOnce( | 
 |           &ClickLinkAndWait, | 
 |           incognito_browser->tab_strip_model()->GetActiveWebContents(), | 
 |           in_scope_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   // Incognito navigations are completely ignored. | 
 |   ExpectNavigationResultHistogramEquals(global_histogram(), {}); | 
 | } | 
 |  | 
 | // Tests that clicking a target=_self link from a URL out of the Web App's scope | 
 | // but with the same origin to an in-scope URL results in a new App window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        FromOutOfScopeUrlToInScopeUrlSelf) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   // Navigate to out-of-scope URL. Shouldn't open a new window. | 
 |   const GURL out_of_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |   NavigateParams params(browser(), out_of_scope_url, ui::PAGE_TRANSITION_TYPED); | 
 |   ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |       out_of_scope_url, base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |  | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      in_scope_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kCancelOpenedApp, 1}, | 
 |        GetAppLaunchedEntry()}); | 
 | } | 
 |  | 
 | // Tests that clicking a target=_blank link from a URL out of the Web App's | 
 | // scope but with the same origin to an in-scope URL results in a new App | 
 | // window. | 
 | // TODO(crbug.com/837277): Deflake and reenable. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        DISABLED_FromOutOfScopeUrlToInScopeUrlBlank) { | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   // Navigate to out-of-scope URL. Shouldn't open a new window. | 
 |   const GURL out_of_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |   NavigateParams params(browser(), out_of_scope_url, ui::PAGE_TRANSITION_TYPED); | 
 |   ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |       out_of_scope_url, base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |  | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   TestTabActionOpensAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      in_scope_url, LinkTarget::BLANK, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kDeferMovingContentsToNewAppWindow, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that clicking links inside a website for an installed app doesn't open | 
 | // a new browser window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |                        InWebsiteNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   NavigateToTestAppURL(); | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       in_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      in_scope_url, LinkTarget::SELF, GetParam())); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedInBrowserSameScope, 1}}); | 
 | } | 
 |  | 
 | class BookmarkAppNavigationThrottleExperimentalWindowOpenBrowserTest | 
 |     : public BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |       public ::testing::WithParamInterface<std::string> {}; | 
 |  | 
 | // Tests that same-origin or cross-origin apps created with window.open() from | 
 | // a regular browser window have an opener. | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     BookmarkAppNavigationThrottleExperimentalWindowOpenBrowserTest, | 
 |     WindowOpenInBrowser) { | 
 |   InstallTestBookmarkApp(); | 
 |   InstallOtherTestBookmarkApp(); | 
 |  | 
 |   NavigateToTestAppURL(); | 
 |  | 
 |   // Call window.open() with |target_url|. | 
 |   const GURL target_url = https_server().GetURL(GetParam(), GetAppUrlPath()); | 
 |   TestTabActionOpensAppWindowWithOpener( | 
 |       target_url, | 
 |       base::BindOnce(&WindowOpenAndWait, | 
 |                      browser()->tab_strip_model()->GetActiveWebContents(), | 
 |                      target_url)); | 
 | } | 
 |  | 
 | // Tests that same-origin or cross-origin apps created with window.open() from | 
 | // another app window have an opener. | 
 | #if defined(OS_MACOSX) | 
 | #define MAYBE_WindowOpenInApp DISABLED_WindowOpenInApp | 
 | #else | 
 | #define MAYBE_WindowOpenInApp WindowOpenInApp | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     BookmarkAppNavigationThrottleExperimentalWindowOpenBrowserTest, | 
 |     MAYBE_WindowOpenInApp) { | 
 |   InstallTestBookmarkApp(); | 
 |   InstallOtherTestBookmarkApp(); | 
 |  | 
 |   // Open app window. | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |   content::WebContents* app_web_contents = | 
 |       app_browser->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   // Call window.open() with |target_url|. | 
 |   const GURL target_url = https_server().GetURL(GetParam(), GetAppUrlPath()); | 
 |   TestAppActionOpensAppWindowWithOpener( | 
 |       app_browser, target_url, | 
 |       base::BindOnce(&WindowOpenAndWait, app_web_contents, target_url)); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleExperimentalWindowOpenBrowserTest, | 
 |     testing::Values(BookmarkAppNavigationBrowserTest::GetAppUrlHost(), | 
 |                     BookmarkAppNavigationBrowserTest::GetOtherAppUrlHost())); | 
 |  | 
 | // Tests that a child window can access its opener, when the opener is a regular | 
 | // browser tab. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        AccessOpenerBrowserWindowFromChildWindow) { | 
 |   InstallTestBookmarkApp(); | 
 |   InstallOtherTestBookmarkApp(); | 
 |  | 
 |   NavigateToTestAppURL(); | 
 |  | 
 |   content::WebContents* current_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   EXPECT_EQ(WindowAccessResult::CAN_ACCESS, | 
 |             CanChildWindowAccessOpener(current_tab, app_url)); | 
 |  | 
 |   const GURL other_app_url = | 
 |       https_server().GetURL(GetOtherAppUrlHost(), GetAppUrlPath()); | 
 |   EXPECT_EQ(WindowAccessResult::CANNOT_ACCESS, | 
 |             CanChildWindowAccessOpener(current_tab, other_app_url)); | 
 | } | 
 |  | 
 | // Tests that a child window can access its opener, when the opener is another | 
 | // app. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        AccessOpenerAppWindowFromChildWindow) { | 
 |   InstallTestBookmarkApp(); | 
 |   InstallOtherTestBookmarkApp(); | 
 |  | 
 |   // Open app window. | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |   content::WebContents* app_web_contents = | 
 |       app_browser->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   const GURL app_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |   EXPECT_EQ(WindowAccessResult::CAN_ACCESS, | 
 |             CanChildWindowAccessOpener(app_web_contents, app_url)); | 
 |  | 
 |   const GURL other_app_url = | 
 |       https_server().GetURL(GetOtherAppUrlHost(), GetAppUrlPath()); | 
 |   EXPECT_EQ(WindowAccessResult::CANNOT_ACCESS, | 
 |             CanChildWindowAccessOpener(app_web_contents, other_app_url)); | 
 | } | 
 |  | 
 | // Tests that in-browser navigations with all the following characteristics | 
 | // don't open a new app window or move the tab: | 
 | //  1. Are to in-scope URLs | 
 | //  2. Result in a AUTO_BOOKMARK transtion | 
 | //  3. Redirect to another in-scope URL. | 
 | // | 
 | // Clicking on sites in the New Tab Page is one of the ways to trigger this | 
 | // type of navigation. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        AutoBookmarkInScopeRedirect) { | 
 |   const Extension* app = | 
 |       InstallImmediateRedirectingApp(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |  | 
 |   const GURL app_url = AppLaunchInfo::GetFullLaunchURL(app); | 
 |   NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_AUTO_BOOKMARK); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()), | 
 |       base::BindOnce(&NavigateToURLWrapper, ¶ms)); | 
 |  | 
 |   // The first AUTO_BOOKMARK navigation is the one we triggered and the second | 
 |   // one is the redirect. | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedTransitionAutoBookmark, | 
 |         2}}); | 
 | } | 
 |  | 
 | // Tests that in-browser navigations with all the following characteristics | 
 | // don't open a new app window or move the tab: | 
 | //  1. Are to in-scope URLs | 
 | //  2. Result in a AUTO_BOOKMARK transtion | 
 | //  3. Redirect to an out-of-scope URL. | 
 | // | 
 | // Clicking on sites in the New Tab Page is one of the ways to trigger this | 
 | // type of navigation. | 
 | IN_PROC_BROWSER_TEST_F(BookmarkAppNavigationThrottleExperimentalBrowserTest, | 
 |                        AutoBookmarkOutOfScopeRedirect) { | 
 |   const Extension* app = InstallImmediateRedirectingApp(GetLaunchingPageHost(), | 
 |                                                         GetLaunchingPagePath()); | 
 |  | 
 |   const GURL app_url = AppLaunchInfo::GetFullLaunchURL(app); | 
 |   NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_AUTO_BOOKMARK); | 
 |   TestTabActionDoesNotOpenAppWindow( | 
 |       GetLaunchingPageURL(), base::BindOnce(&NavigateToURLWrapper, ¶ms)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       global_histogram(), | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedTransitionAutoBookmark, | 
 |         1}}); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleExperimentalLinkBrowserTest, | 
 |     testing::Values("", "noopener", "noreferrer", "nofollow")); | 
 |  | 
 | // Base class for testing the behavior is the same regardless of the | 
 | // kDesktopPWAsLinkCapturing feature flag. | 
 | class BookmarkAppNavigationThrottleBaseCommonBrowserTest | 
 |     : public BookmarkAppNavigationBrowserTest { | 
 |  protected: | 
 |   void EnableFeaturesForTest(bool should_enable_link_capturing) { | 
 |     // These tests expect that navigation to an out of scope URL will open in a | 
 |     // new window, however, this behaviour is in the process of being changed | 
 |     // (with the flag desktop-pwas-stay-in-window), so until the change is made | 
 |     // permanent and these tests are removed, explicitly disable the flag. | 
 |     if (should_enable_link_capturing) { | 
 |       scoped_feature_list_.InitWithFeatures( | 
 |           {features::kDesktopPWAWindowing, features::kDesktopPWAsLinkCapturing}, | 
 |           {features::kDesktopPWAsStayInWindow}); | 
 |     } else { | 
 |       scoped_feature_list_.InitWithFeatures( | 
 |           {features::kDesktopPWAWindowing}, | 
 |           {features::kDesktopPWAsLinkCapturing, | 
 |            features::kDesktopPWAsStayInWindow}); | 
 |     } | 
 |   } | 
 |  | 
 |  private: | 
 |   base::test::ScopedFeatureList scoped_feature_list_; | 
 | }; | 
 |  | 
 | // Class for testing the behavior is the same regardless of the | 
 | // kDesktopPWAsLinkCapturing feature flag. | 
 | class BookmarkAppNavigationThrottleCommonBrowserTest | 
 |     : public BookmarkAppNavigationThrottleBaseCommonBrowserTest, | 
 |       public ::testing::WithParamInterface<bool> { | 
 |  public: | 
 |   void SetUp() override { | 
 |     EnableFeaturesForTest(GetParam()); | 
 |     BookmarkAppNavigationThrottleBaseCommonBrowserTest::SetUp(); | 
 |   } | 
 | }; | 
 |  | 
 | // Tests that an app that immediately redirects to an out-of-scope URL opens a | 
 | // new foreground tab. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |                        ImmediateOutOfScopeRedirect) { | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |   int num_tabs_browser = browser()->tab_strip_model()->count(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   GURL initial_url = initial_tab->GetLastCommittedURL(); | 
 |  | 
 |   const Extension* redirecting_app = InstallImmediateRedirectingApp( | 
 |       GetLaunchingPageHost(), GetLaunchingPagePath()); | 
 |  | 
 |   auto observer = GetTestNavigationObserver(GetLaunchingPageURL()); | 
 |   LaunchAppBrowser(redirecting_app); | 
 |   observer->WaitForNavigationFinished(); | 
 |  | 
 |   EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile())); | 
 |  | 
 |   EXPECT_EQ(browser(), chrome::FindLastActive()); | 
 |   EXPECT_EQ(++num_tabs_browser, browser()->tab_strip_model()->count()); | 
 |  | 
 |   EXPECT_EQ(initial_url, initial_tab->GetLastCommittedURL()); | 
 |  | 
 |   content::WebContents* new_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |   EXPECT_NE(initial_tab, new_tab); | 
 |   EXPECT_EQ(GetLaunchingPageURL(), new_tab->GetLastCommittedURL()); | 
 |  | 
 |   // When kDesktopPWAsLinkCapturing is enabled, app launches get histogrammed, | 
 |   // but when it's disabled, they don't. | 
 |   if (GetParam()) { | 
 |     ExpectNavigationResultHistogramEquals( | 
 |         global_histogram(), {GetAppLaunchedEntry(), | 
 |                              {BookmarkAppNavigationThrottleResult:: | 
 |                                   kOpenInChromeProceedOutOfScopeLaunch, | 
 |                               1}}); | 
 |   } else { | 
 |     ExpectNavigationResultHistogramEquals( | 
 |         global_histogram(), {{BookmarkAppNavigationThrottleResult:: | 
 |                                   kOpenInChromeProceedOutOfScopeLaunch, | 
 |                               1}}); | 
 |   } | 
 | } | 
 |  | 
 | // Tests that popups to out-of-scope URLs are opened in regular popup windows | 
 | // and not in app windows. | 
 | // TODO(crbug.com/849163) Times out flakily on MacOS. | 
 | #if defined(OS_MACOSX) | 
 | #define MAYBE_OutOfScopePopup DISABLED_OutOfScopePopup | 
 | #else | 
 | #define MAYBE_OutOfScopePopup OutOfScopePopup | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |                        MAYBE_OutOfScopePopup) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |  | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |   int num_tabs_browser = browser()->tab_strip_model()->count(); | 
 |   int num_tabs_app_browser = app_browser->tab_strip_model()->count(); | 
 |  | 
 |   content::WebContents* app_web_contents = | 
 |       app_browser->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   content::WebContents* initial_tab = | 
 |       browser()->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   GURL initial_app_url = app_web_contents->GetLastCommittedURL(); | 
 |   GURL initial_tab_url = initial_tab->GetLastCommittedURL(); | 
 |  | 
 |   // Open a popup to an out-of-scope URL. | 
 |   const GURL out_of_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |   OpenPopupAndWait(app_web_contents, out_of_scope_url); | 
 |  | 
 |   EXPECT_EQ(++num_browsers, chrome::GetBrowserCount(profile())); | 
 |  | 
 |   Browser* new_popup_browser = chrome::FindLastActive(); | 
 |   EXPECT_NE(new_popup_browser, browser()); | 
 |   EXPECT_NE(new_popup_browser, app_browser); | 
 |   EXPECT_TRUE(new_popup_browser->is_type_popup()); | 
 |   EXPECT_FALSE(new_popup_browser->is_app()); | 
 |  | 
 |   EXPECT_EQ(num_tabs_browser, browser()->tab_strip_model()->count()); | 
 |   EXPECT_EQ(num_tabs_app_browser, app_browser->tab_strip_model()->count()); | 
 |  | 
 |   EXPECT_EQ(initial_app_url, app_web_contents->GetLastCommittedURL()); | 
 |  | 
 |   content::WebContents* new_popup_web_contents = | 
 |       new_popup_browser->tab_strip_model()->GetActiveWebContents(); | 
 |   EXPECT_EQ(out_of_scope_url, new_popup_web_contents->GetLastCommittedURL()); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult:: | 
 |             kReparentIntoPopupProceedOutOfScopeInitialNavigation, | 
 |         1}}); | 
 | } | 
 |  | 
 | // Tests that popups to in-scope URLs are opened in App windows. | 
 | // TODO(crbug.com/849163) Times out flakily on MacOS. | 
 | #if defined(OS_MACOSX) | 
 | #define MAYBE_InScopePopup DISABLED_InScopePopup | 
 | #else | 
 | #define MAYBE_InScopePopup InScopePopup | 
 | #endif | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |                        MAYBE_InScopePopup) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |  | 
 |   // Open a popup to an out-of-scope URL. | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   TestAppActionOpensAppWindowWithOpener( | 
 |       app_browser, in_scope_url, | 
 |       base::Bind(&OpenPopupAndWait, | 
 |                  app_browser->tab_strip_model()->GetActiveWebContents(), | 
 |                  in_scope_url)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedInAppSameScope, 1}}); | 
 | } | 
 |  | 
 | // Apps are only restored during startup on Chrome OS. | 
 | #if defined(OS_CHROMEOS) | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |                        PRE_RestoreApp) { | 
 |   InstallTestBookmarkApp(); | 
 |   OpenTestBookmarkApp(); | 
 |   SessionStartupPref::SetStartupPref( | 
 |       profile(), SessionStartupPref(SessionStartupPref::LAST)); | 
 | } | 
 |  | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |                        RestoreApp) { | 
 |   // There should be two windows. The app window and a regular browser window | 
 |   // the test opens. | 
 |   EXPECT_EQ(2u, chrome::GetBrowserCount(profile())); | 
 |   Browser* app_browser = nullptr; | 
 |   for (auto* browser : *BrowserList::GetInstance()) { | 
 |     if (browser->is_app()) { | 
 |       EXPECT_FALSE(app_browser) << "Found multiple app browsers."; | 
 |       app_browser = browser; | 
 |     } | 
 |   } | 
 |   ASSERT_TRUE(app_browser); | 
 |  | 
 |   const Extension* app = | 
 |       ExtensionRegistry::Get(profile())->enabled_extensions().GetByID( | 
 |           web_app::GetAppIdFromApplicationName(app_browser->app_name())); | 
 |   EXPECT_EQ(GetAppName(), app->name()); | 
 | } | 
 | #endif  // OS_CHROMEOS | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleCommonBrowserTest, | 
 |     testing::Bool()); | 
 |  | 
 | // Set of tests to make sure form submissions have the correct behavior | 
 | // regardless of the kDesktopPWAsLinkCapturing feature flag. | 
 | class BookmarkAppNavigationThrottleCommonFormSubmissionBrowserTest | 
 |     : public BookmarkAppNavigationThrottleBaseCommonBrowserTest, | 
 |       public ::testing::WithParamInterface< | 
 |           std::tuple<bool, | 
 |                      StartIn, | 
 |                      std::string, | 
 |                      net::URLFetcher::RequestType, | 
 |                      std::string>> { | 
 |  public: | 
 |   void SetUp() override { | 
 |     EnableFeaturesForTest(std::get<0>(GetParam())); | 
 |     BookmarkAppNavigationThrottleBaseCommonBrowserTest::SetUp(); | 
 |   } | 
 | }; | 
 |  | 
 | IN_PROC_BROWSER_TEST_P( | 
 |     BookmarkAppNavigationThrottleCommonFormSubmissionBrowserTest, | 
 |     FormSubmission) { | 
 |   bool should_enable_link_capturing; | 
 |   StartIn start_in; | 
 |   std::string start_url_path; | 
 |   net::URLFetcher::RequestType request_type; | 
 |   std::string target_url_path; | 
 |   std::tie(should_enable_link_capturing, start_in, start_url_path, request_type, | 
 |            target_url_path) = GetParam(); | 
 |  | 
 |   InstallTestBookmarkApp(); | 
 |  | 
 |   // Pick where the test should start. | 
 |   Browser* current_browser; | 
 |   if (start_in == StartIn::APP) | 
 |     current_browser = OpenTestBookmarkApp(); | 
 |   else | 
 |     current_browser = browser(); | 
 |  | 
 |   // If in a regular browser window, navigate to the start URL. | 
 |   if (start_in == StartIn::BROWSER) { | 
 |     GURL start_url; | 
 |     if (start_url_path == GetLaunchingPagePath()) | 
 |       start_url = GetLaunchingPageURL(); | 
 |     else | 
 |       start_url = https_server().GetURL(GetAppUrlHost(), GetAppUrlPath()); | 
 |  | 
 |     NavigateParams params(current_browser, start_url, | 
 |                           ui::PAGE_TRANSITION_TYPED); | 
 |     ASSERT_TRUE(TestTabActionDoesNotOpenAppWindow( | 
 |         start_url, base::BindOnce(&NavigateToURLWrapper, ¶ms))); | 
 |   } else if (start_url_path == GetLaunchingPagePath()) { | 
 |     // Return early here since the app window can't start with an out-of-scope | 
 |     // URL. | 
 |     return; | 
 |   } | 
 |  | 
 |   // If the submit method is GET then add an query params. | 
 |   GURL target_url = https_server().GetURL(GetAppUrlHost(), target_url_path); | 
 |   if (request_type == net::URLFetcher::RequestType::GET) { | 
 |     target_url = AddTestQueryParam(target_url); | 
 |   } | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |  | 
 |   // All form submissions that start in the browser should be kept in the | 
 |   // browser. | 
 |   if (start_in == StartIn::BROWSER) { | 
 |     TestActionDoesNotOpenAppWindow( | 
 |         current_browser, target_url, | 
 |         base::BindOnce( | 
 |             &SubmitFormAndWait, | 
 |             current_browser->tab_strip_model()->GetActiveWebContents(), | 
 |             target_url, request_type)); | 
 |  | 
 |     // Navigations to out-of-scope URLs are considered regular navigations and | 
 |     // therefore not recorded. Nothing gets histogrammed when | 
 |     // kDesktopPWAsLinkCapturing is disabled, because the navigation is not | 
 |     // happening in an app window. | 
 |     if (target_url_path == GetInScopeUrlPath() && | 
 |         should_enable_link_capturing) { | 
 |       ExpectNavigationResultHistogramEquals( | 
 |           scoped_histogram, {{BookmarkAppNavigationThrottleResult:: | 
 |                                   kProceedInBrowserFormSubmission, | 
 |                               1}}); | 
 |     } | 
 |     return; | 
 |   } | 
 |  | 
 |   // When in an app, in-scope navigations should always be kept in the app | 
 |   // window. | 
 |   if (target_url_path == GetInScopeUrlPath()) { | 
 |     TestActionDoesNotOpenAppWindow( | 
 |         current_browser, target_url, | 
 |         base::BindOnce( | 
 |             &SubmitFormAndWait, | 
 |             current_browser->tab_strip_model()->GetActiveWebContents(), | 
 |             target_url, request_type)); | 
 |  | 
 |     ExpectNavigationResultHistogramEquals( | 
 |         scoped_histogram, | 
 |         {{BookmarkAppNavigationThrottleResult::kProceedInAppSameScope, 1}}); | 
 |     return; | 
 |   } | 
 |  | 
 |   // When in an app, out-of-scope navigations should always open a new | 
 |   // foreground tab. | 
 |   DCHECK_EQ(target_url_path, GetOutOfScopeUrlPath()); | 
 |   TestAppActionOpensForegroundTab( | 
 |       current_browser, target_url, | 
 |       base::BindOnce(&SubmitFormAndWait, | 
 |                      current_browser->tab_strip_model()->GetActiveWebContents(), | 
 |                      target_url, request_type)); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kDeferOpenNewTabInAppOutOfScope, | 
 |         1}}); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleCommonFormSubmissionBrowserTest, | 
 |     testing::Combine( | 
 |         testing::Bool(), | 
 |         testing::Values(StartIn::BROWSER, StartIn::APP), | 
 |         testing::Values( | 
 |             BookmarkAppNavigationBrowserTest::GetLaunchingPagePath(), | 
 |             BookmarkAppNavigationBrowserTest::GetAppUrlPath()), | 
 |         testing::Values(net::URLFetcher::RequestType::GET, | 
 |                         net::URLFetcher::RequestType::POST), | 
 |         testing::Values( | 
 |             BookmarkAppNavigationBrowserTest::GetOutOfScopeUrlPath(), | 
 |             BookmarkAppNavigationBrowserTest::GetInScopeUrlPath()))); | 
 |  | 
 | // Tests that the result is the same regardless of the 'rel' attribute of links | 
 | // and of the kDesktopPWAsLinkCapturing feature flag. | 
 | class BookmarkAppNavigationThrottleCommonLinkBrowserTest | 
 |     : public BookmarkAppNavigationThrottleBaseCommonBrowserTest, | 
 |       public ::testing::WithParamInterface<std::tuple<bool, std::string>> { | 
 |  public: | 
 |   void SetUp() override { | 
 |     EnableFeaturesForTest(std::get<0>(GetParam())); | 
 |     BookmarkAppNavigationThrottleBaseCommonBrowserTest::SetUp(); | 
 |   } | 
 | }; | 
 |  | 
 | // Tests that clicking links inside the app to in-scope URLs doesn't open new | 
 | // browser windows. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonLinkBrowserTest, | 
 |                        InAppInScopeNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |   content::WebContents* app_web_contents = | 
 |       app_browser->tab_strip_model()->GetActiveWebContents(); | 
 |  | 
 |   int num_tabs_browser = browser()->tab_strip_model()->count(); | 
 |   int num_tabs_app_browser = app_browser->tab_strip_model()->count(); | 
 |   size_t num_browsers = chrome::GetBrowserCount(profile()); | 
 |  | 
 |   base::HistogramTester scoped_histogram; | 
 |   const GURL in_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); | 
 |   ClickLinkAndWait(app_web_contents, in_scope_url, LinkTarget::SELF, | 
 |                    std::get<1>(GetParam())); | 
 |  | 
 |   EXPECT_EQ(num_tabs_browser, browser()->tab_strip_model()->count()); | 
 |   EXPECT_EQ(num_tabs_app_browser, app_browser->tab_strip_model()->count()); | 
 |   EXPECT_EQ(num_browsers, chrome::GetBrowserCount(profile())); | 
 |   EXPECT_EQ(app_browser, chrome::FindLastActive()); | 
 |  | 
 |   EXPECT_EQ(in_scope_url, app_web_contents->GetLastCommittedURL()); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kProceedInAppSameScope, 1}}); | 
 | } | 
 |  | 
 | // Tests that clicking links inside the app to out-of-scope URLs opens a new | 
 | // tab in an existing browser window, instead of navigating the existing | 
 | // app window. | 
 | IN_PROC_BROWSER_TEST_P(BookmarkAppNavigationThrottleCommonLinkBrowserTest, | 
 |                        InAppOutOfScopeNavigation) { | 
 |   InstallTestBookmarkApp(); | 
 |   Browser* app_browser = OpenTestBookmarkApp(); | 
 |  | 
 |   const base::HistogramTester scoped_histogram; | 
 |   const GURL out_of_scope_url = | 
 |       https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); | 
 |   TestAppActionOpensForegroundTab( | 
 |       app_browser, out_of_scope_url, | 
 |       base::BindOnce(&ClickLinkAndWait, | 
 |                      app_browser->tab_strip_model()->GetActiveWebContents(), | 
 |                      out_of_scope_url, LinkTarget::SELF, | 
 |                      std::get<1>(GetParam()))); | 
 |  | 
 |   ExpectNavigationResultHistogramEquals( | 
 |       scoped_histogram, | 
 |       {{BookmarkAppNavigationThrottleResult::kDeferOpenNewTabInAppOutOfScope, | 
 |         1}}); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_CASE_P( | 
 |     /* no prefix */, | 
 |     BookmarkAppNavigationThrottleCommonLinkBrowserTest, | 
 |     testing::Combine( | 
 |         testing::Bool(), | 
 |         testing::Values("", "noopener", "noreferrer", "nofollow"))); | 
 |  | 
 | }  // namespace test | 
 | }  // namespace extensions |