| // Copyright 2018 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/bind.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "chrome/browser/ui/views/frame/toolbar_button_provider.h" |
| #include "chrome/browser/ui/views/intent_picker_bubble_view.h" |
| #include "chrome/browser/ui/views/location_bar/intent_picker_view.h" |
| #include "chrome/browser/ui/views/location_bar/location_bar_view.h" |
| #include "chrome/browser/ui/views/page_action/page_action_icon_view.h" |
| #include "chrome/browser/ui/web_applications/test/web_app_navigation_browsertest.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/web_application_info.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "url/gurl.h" |
| |
| class IntentPickerBubbleViewBrowserTest |
| : public web_app::WebAppNavigationBrowserTest, |
| public ::testing::WithParamInterface<std::string> { |
| public: |
| void SetUp() override { |
| // TODO(schenney): Stop disabling Paint Holding. crbug.com/1001189 |
| scoped_feature_list_.InitAndDisableFeature(blink::features::kPaintHolding); |
| web_app::WebAppNavigationBrowserTest::SetUp(); |
| } |
| |
| void OpenNewTab(const GURL& url) { |
| chrome::NewTab(browser()); |
| content::WebContents* web_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| NavigateToLaunchingPage(browser()); |
| TestTabActionDoesNotOpenAppWindow( |
| url, base::BindOnce(&ClickLinkAndWait, web_contents, url, |
| LinkTarget::SELF, GetParam())); |
| } |
| |
| // Inserts an iframe in the main frame of |web_contents|. |
| bool InsertIFrame(content::WebContents* web_contents) { |
| return content::ExecuteScript( |
| web_contents, |
| "let iframe = document.createElement('iframe');" |
| "iframe.id = 'iframe';" |
| "document.body.appendChild(iframe);"); |
| } |
| |
| PageActionIconView* GetIntentPickerIcon() { |
| return BrowserView::GetBrowserViewForBrowser(browser()) |
| ->toolbar_button_provider() |
| ->GetPageActionIconView(PageActionIconType::kIntentPicker); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // Tests that clicking a link from a tabbed browser to within the scope of an |
| // installed app shows the intent picker icon in Omnibox. The intent picker |
| // bubble will only show up for android apps which is too hard to test. |
| IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest, |
| NavigationToInScopeLinkShowsIntentPicker) { |
| InstallTestWebApp(); |
| |
| const GURL in_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); |
| content::WebContents* web_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| NavigateToLaunchingPage(browser()); |
| TestTabActionDoesNotOpenAppWindow( |
| in_scope_url, base::BindOnce(&ClickLinkAndWait, web_contents, |
| in_scope_url, LinkTarget::SELF, GetParam())); |
| |
| PageActionIconView* intent_picker_view = GetIntentPickerIcon(); |
| EXPECT_TRUE(intent_picker_view->GetVisible()); |
| |
| IntentPickerBubbleView* intent_picker = |
| IntentPickerBubbleView::intent_picker_bubble(); |
| EXPECT_FALSE(intent_picker); |
| } |
| |
| // Tests that clicking a link from a tabbed browser to outside the scope of an |
| // installed app does not show the intent picker. |
| IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest, |
| NavigationToOutofScopeLinkDoesNotShowIntentPicker) { |
| InstallTestWebApp(); |
| |
| const GURL out_of_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); |
| NavigateToLaunchingPage(browser()); |
| TestTabActionDoesNotOpenAppWindow( |
| out_of_scope_url, |
| base::BindOnce(&ClickLinkAndWait, |
| browser()->tab_strip_model()->GetActiveWebContents(), |
| out_of_scope_url, LinkTarget::SELF, GetParam())); |
| |
| EXPECT_EQ(nullptr, IntentPickerBubbleView::intent_picker_bubble()); |
| } |
| |
| // Tests that clicking a link from an app browser to either within or outside |
| // the scope of an installed app does not show the intent picker, even when an |
| // outside of scope link is opened within the context of the PWA. |
| IN_PROC_BROWSER_TEST_P( |
| IntentPickerBubbleViewBrowserTest, |
| NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker) { |
| InstallTestWebApp(); |
| |
| // No intent picker should be seen when first opening the web app. |
| Browser* app_browser = OpenTestWebApp(); |
| EXPECT_EQ(nullptr, IntentPickerBubbleView::intent_picker_bubble()); |
| |
| { |
| const GURL in_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); |
| TestActionDoesNotOpenAppWindow( |
| app_browser, in_scope_url, |
| base::BindOnce(&ClickLinkAndWait, |
| app_browser->tab_strip_model()->GetActiveWebContents(), |
| in_scope_url, LinkTarget::SELF, GetParam())); |
| |
| EXPECT_EQ(nullptr, IntentPickerBubbleView::intent_picker_bubble()); |
| } |
| |
| { |
| const GURL out_of_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); |
| TestActionDoesNotOpenAppWindow( |
| app_browser, out_of_scope_url, |
| base::BindOnce(&ClickLinkAndWait, |
| app_browser->tab_strip_model()->GetActiveWebContents(), |
| out_of_scope_url, LinkTarget::SELF, GetParam())); |
| |
| EXPECT_EQ(nullptr, IntentPickerBubbleView::intent_picker_bubble()); |
| } |
| } |
| |
| // Tests that the intent icon updates its visibiliy when switching between |
| // tabs. |
| IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest, |
| IconVisibilityAfterTabSwitching) { |
| InstallTestWebApp(); |
| |
| const GURL in_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); |
| const GURL out_of_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); |
| |
| PageActionIconView* intent_picker_view = GetIntentPickerIcon(); |
| |
| // OpenNewTab opens a new tab and focus on the new tab. |
| OpenNewTab(in_scope_url); |
| EXPECT_TRUE(intent_picker_view->GetVisible()); |
| OpenNewTab(out_of_scope_url); |
| EXPECT_FALSE(intent_picker_view->GetVisible()); |
| |
| chrome::SelectPreviousTab(browser()); |
| EXPECT_TRUE(intent_picker_view->GetVisible()); |
| |
| chrome::SelectNextTab(browser()); |
| EXPECT_FALSE(intent_picker_view->GetVisible()); |
| } |
| |
| // Tests that the navigation in iframe doesn't affect intent picker icon |
| IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest, |
| IframeNavigationDoesNotAffectIntentPicker) { |
| InstallTestWebApp(); |
| |
| const GURL in_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetInScopeUrlPath()); |
| const GURL out_of_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); |
| |
| PageActionIconView* intent_picker_view = GetIntentPickerIcon(); |
| |
| OpenNewTab(out_of_scope_url); |
| content::WebContents* initial_tab = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_TRUE(InsertIFrame(initial_tab)); |
| |
| EXPECT_TRUE( |
| content::NavigateIframeToURL(initial_tab, "iframe", in_scope_url)); |
| EXPECT_FALSE(intent_picker_view->GetVisible()); |
| |
| OpenNewTab(in_scope_url); |
| content::WebContents* new_tab = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_TRUE(InsertIFrame(new_tab)); |
| |
| EXPECT_TRUE( |
| content::NavigateIframeToURL(initial_tab, "iframe", out_of_scope_url)); |
| EXPECT_TRUE(intent_picker_view->GetVisible()); |
| } |
| |
| // Tests that the intent picker icon is not visible if the navigatation |
| // redirects to a URL that doesn't have an installed PWA. |
| IN_PROC_BROWSER_TEST_P(IntentPickerBubbleViewBrowserTest, |
| DoesNotShowIntentPickerWhenRedirectedOutOfScope) { |
| InstallTestWebApp(GetOtherAppUrlHost(), /*app_scope=*/"/"); |
| |
| const GURL out_of_scope_url = |
| https_server().GetURL(GetAppUrlHost(), GetOutOfScopeUrlPath()); |
| const GURL in_scope_url = https_server().GetURL(GetOtherAppUrlHost(), "/"); |
| const GURL redirect_url = https_server().GetURL( |
| GetOtherAppUrlHost(), CreateServerRedirect(out_of_scope_url)); |
| |
| PageActionIconView* intent_picker_view = GetIntentPickerIcon(); |
| |
| OpenNewTab(in_scope_url); |
| EXPECT_TRUE(intent_picker_view->GetVisible()); |
| |
| ClickLinkAndWaitForURL(browser()->tab_strip_model()->GetActiveWebContents(), |
| redirect_url, out_of_scope_url, LinkTarget::SELF, |
| GetParam()); |
| EXPECT_FALSE(intent_picker_view->GetVisible()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| IntentPickerBubbleViewBrowserTest, |
| testing::Values("", "noopener", "noreferrer", "nofollow")); |