chromium/chrome/browser/ash/system_web_apps/apps/os_feedback_app_integration_browsertest.cc

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ash/constants/ash_features.h"
#include "ash/shell.h"
#include "ash/webui/os_feedback_ui/url_constants.h"
#include "ash/webui/sample_system_web_app_ui/url_constants.h"
#include "base/strings/escape.h"
#include "base/strings/strcat.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/ash/system_web_apps/system_web_app_manager.h"
#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_browsertest_base.h"
#include "chrome/browser/ash/system_web_apps/test_support/system_web_app_integration_test.h"
#include "chrome/browser/ui/ash/system_web_apps/system_web_app_ui_utils.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/webapps/browser/install_result_code.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_navigation_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/screen.h"
#include "ui/display/test/display_manager_test_api.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"

class OSFeedbackAppIntegrationTest : public ash::SystemWebAppIntegrationTest {
 public:
  OSFeedbackAppIntegrationTest() {
    feedback_url_ = GURL(ash::kChromeUIOSFeedbackUrl);
  }

 protected:
  // Find the url of the active tab of the browser if any.
  GURL FindActiveUrl(Browser* browser) {
    if (browser) {
      return browser->tab_strip_model()->GetActiveWebContents()->GetURL();
    }
    return GURL();
  }

  Browser* FindFeedbackAppBrowser() {
    return ash::FindSystemWebAppBrowser(browser()->profile(),
                                        ash::SystemWebAppType::OS_FEEDBACK);
  }

  // Launch the Feedback SWA and wait for launching is completed.
  // Returns the browser of the Feedback SWA if exists.
  Browser* LaunchAndWait() {
    WaitForTestSystemAppInstall();

    content::TestNavigationObserver navigation_observer(feedback_url_);
    navigation_observer.StartWatchingNewWebContents();
    ui_test_utils::SendToOmniboxAndSubmit(browser(), feedback_url_.spec());
    navigation_observer.Wait();

    return FindFeedbackAppBrowser();
  }

  Browser* ExpectFeedbackAppLaunched(const GURL& old_url) {
    // browser() tab contents should be unaffected.
    EXPECT_EQ(1, browser()->tab_strip_model()->count());
    EXPECT_EQ(old_url, FindActiveUrl(browser()));

    // We now have two browsers, one for the chrome window, one for the Feedback
    // app.
    EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
    Browser* app_browser = FindFeedbackAppBrowser();
    EXPECT_TRUE(app_browser);
    EXPECT_EQ(feedback_url_, FindActiveUrl(app_browser));

    return app_browser;
  }

  void ExpectNoFeedbackAppLaunched(const GURL& old_url) {
    // browser() tab contents should be unaffected.
    EXPECT_EQ(1, browser()->tab_strip_model()->count());
    EXPECT_EQ(old_url, FindActiveUrl(browser()));

    // We now still have one browser.
    EXPECT_EQ(1u, chrome::GetTotalBrowserCount());

    EXPECT_EQ(nullptr, FindFeedbackAppBrowser());
  }

  void SendKeyPressAltShiftI(Browser* browser) {
    ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
        browser, ui::VKEY_I, /* control= */ false, /* shift= */ true,
        /* alt= */ true, /* command= */ false));
  }

  GURL feedback_url_;
  base::HistogramTester histogram_tester_;
};

// This test verifies that the Feedback app is opened in a new browser window.
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest, NavigateToFeedback) {
  WaitForTestSystemAppInstall();
  GURL old_url = FindActiveUrl(browser());

  LaunchAndWait();
  ExpectFeedbackAppLaunched(old_url);
}

// This test verifies that the Feedback app is opened in a new browser window.
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest, OpenFeedbackByHotKey) {
  WaitForTestSystemAppInstall();
  GURL old_url = FindActiveUrl(browser());

  WaitForTestSystemAppInstall();

  feedback_url_ = GURL(base::StrCat(
      {ash::kChromeUIOSFeedbackUrl, "/?page_url=",
       base::EscapeQueryParamValue(old_url.spec(), /*use_plus=*/false)}));

  content::TestNavigationObserver navigation_observer(feedback_url_);
  navigation_observer.StartWatchingNewWebContents();
  // Try to press keyboard shortcut to open Feedback app.
  SendKeyPressAltShiftI(browser());
  navigation_observer.Wait();

  ExpectFeedbackAppLaunched(old_url);

  feedback_url_ = GURL(ash::kChromeUIOSFeedbackUrl);
}

// This test verifies that the Feedback app is not opened when
// UserFeedbackAllowed is set to false.
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest, UserFeedbackNotAllowed) {
  WaitForTestSystemAppInstall();

  browser()->profile()->GetPrefs()->SetBoolean(prefs::kUserFeedbackAllowed,
                                               false);
  GURL old_url = FindActiveUrl(browser());

  // Try to navigate to the feedback app in the browser.
  ui_test_utils::SendToOmniboxAndSubmit(browser(), feedback_url_.spec());

  ExpectNoFeedbackAppLaunched(old_url);

  // Try to press keyboard shortcut to open Feedback app.
  SendKeyPressAltShiftI(browser());

  ExpectNoFeedbackAppLaunched(old_url);
}

// Test that the Feedback App has a default bounds of 640(height)x600(width)
// and is in the center of the screen.
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest, DefaultWindowBounds) {
  display::test::DisplayManagerTestApi display_manager_test(
      ash::Shell::Get()->display_manager());
  display_manager_test.UpdateDisplay("1000x2000");

  Browser* app_browser = LaunchAndWait();
  EXPECT_TRUE(app_browser);

  gfx::Rect work_area =
      display::Screen::GetScreen()->GetDisplayForNewWindows().work_area();

  int expected_width = 600;
  int expected_height = 640;
  int x = (work_area.width() - expected_width) / 2;
  int y = (work_area.height() - expected_height) / 2;
  EXPECT_EQ(gfx::Rect(x, y, expected_width, expected_height),
            app_browser->window()->GetBounds());
}

// Test that when the policy UserFeedbackAllowed is true, the Feedback App
//  1) shows in launcher
//  2) shows in search
//  3) is single window
//  4) allows scripts to close the window
//  5) isn't resizable
//  6) isn't maximizable
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest, FeedbackAppAttributes) {
  WaitForTestSystemAppInstall();

  // Check the correct attributes for Feedback App.
  auto* system_app =
      GetManager().GetSystemApp(ash::SystemWebAppType::OS_FEEDBACK);
  EXPECT_FALSE(system_app->ShouldShowInLauncher());
  EXPECT_TRUE(system_app->ShouldShowInSearchAndShelf());
  EXPECT_FALSE(system_app->ShouldShowNewWindowMenuOption());
  EXPECT_TRUE(system_app->ShouldAllowScriptsToCloseWindows());
  EXPECT_FALSE(system_app->ShouldAllowResize());
  EXPECT_FALSE(system_app->ShouldAllowMaximize());
}

// Test that when the policy UserFeedbackAllowed is false, the Feedback App
//  1) does not show in launcher
//  2) does not show in search
IN_PROC_BROWSER_TEST_P(OSFeedbackAppIntegrationTest,
                       HideInLauncherAndSearchWhenUserFeedbackNotAllowed) {
  WaitForTestSystemAppInstall();
  browser()->profile()->GetPrefs()->SetBoolean(prefs::kUserFeedbackAllowed,
                                               false);

  // Check the correct attributes for Feedback App.
  auto* system_app =
      GetManager().GetSystemApp(ash::SystemWebAppType::OS_FEEDBACK);
  EXPECT_FALSE(system_app->ShouldShowInLauncher());
  EXPECT_FALSE(system_app->ShouldShowInSearchAndShelf());
}

INSTANTIATE_SYSTEM_WEB_APP_MANAGER_TEST_SUITE_REGULAR_PROFILE_P(
    OSFeedbackAppIntegrationTest);