blob: 8f2269dc57aed58478a885bd283e34e9231d2937 [file] [log] [blame]
// Copyright 2020 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/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/devtools/devtools_window_testing.h"
#include "chrome/browser/policy/policy_test_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/api/messaging/messaging_delegate.h"
namespace policy {
namespace {
// Utility for waiting until the dev-mode controls are visible/hidden
// Uses a MutationObserver on the attributes of the DOM element.
void WaitForExtensionsDevModeControlsVisibility(
content::WebContents* contents,
const char* dev_controls_accessor_js,
const char* dev_controls_visibility_check_js,
bool expected_visible) {
bool done = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
contents,
base::StringPrintf(
"var screenElement = %s;"
"function SendReplyIfAsExpected() {"
" var is_visible = %s;"
" if (is_visible != %s)"
" return false;"
" observer.disconnect();"
" domAutomationController.send(true);"
" return true;"
"}"
"var observer = new MutationObserver(SendReplyIfAsExpected);"
"if (!SendReplyIfAsExpected()) {"
" var options = { 'attributes': true };"
" observer.observe(screenElement, options);"
"}",
dev_controls_accessor_js, dev_controls_visibility_check_js,
(expected_visible ? "true" : "false")),
&done));
}
} // namespace
IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledByLegacyPolicy) {
// Verifies that access to the developer tools can be disabled by setting the
// legacy DeveloperToolsDisabled policy.
// Open devtools.
EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
DevToolsWindow* devtools_window =
DevToolsWindow::GetInstanceForInspectedWebContents(contents);
EXPECT_TRUE(devtools_window);
// Disable devtools via policy.
PolicyMap policies;
policies.Set(key::kDeveloperToolsDisabled, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD, base::Value(true),
nullptr);
content::WebContentsDestroyedWatcher close_observer(
DevToolsWindowTesting::Get(devtools_window)->main_web_contents());
UpdateProviderPolicy(policies);
// wait for devtools close
close_observer.Wait();
// The existing devtools window should have closed.
EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents));
// And it's not possible to open it again.
EXPECT_FALSE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS));
EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents));
}
IN_PROC_BROWSER_TEST_F(PolicyTest,
DeveloperToolsDisabledByDeveloperToolsAvailability) {
// Verifies that access to the developer tools can be disabled by setting the
// DeveloperToolsAvailability policy.
// Open devtools.
EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
DevToolsWindow* devtools_window =
DevToolsWindow::GetInstanceForInspectedWebContents(contents);
EXPECT_TRUE(devtools_window);
// Disable devtools via policy.
PolicyMap policies;
policies.Set(key::kDeveloperToolsAvailability, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
base::Value(2 /* DeveloperToolsDisallowed */), nullptr);
content::WebContentsDestroyedWatcher close_observer(
DevToolsWindowTesting::Get(devtools_window)->main_web_contents());
UpdateProviderPolicy(policies);
// wait for devtools close
close_observer.Wait();
// The existing devtools window should have closed.
EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents));
// And it's not possible to open it again.
EXPECT_FALSE(chrome::ExecuteCommand(browser(), IDC_DEV_TOOLS));
EXPECT_FALSE(DevToolsWindow::GetInstanceForInspectedWebContents(contents));
}
IN_PROC_BROWSER_TEST_F(PolicyTest, DeveloperToolsDisabledExtensionsDevMode) {
// Verifies that when DeveloperToolsDisabled policy is set, the "dev mode"
// in chrome://extensions is actively turned off and the checkbox
// is disabled.
// Note: We don't test the indicator as it is tested in the policy pref test
// for kDeveloperToolsDisabled and kDeveloperToolsAvailability.
// This test depends on the following helper methods to locate the DOM
// elements to be tested.
const char define_helpers_js[] =
R"(function getToolbar() {
const manager = document.querySelector('extensions-manager');
return manager.$$('extensions-toolbar');
}
function getToggle() {
return getToolbar().$.devMode;
}
function getControls() {
return getToolbar().$.devDrawer;
}
)";
const char toggle_dev_mode_accessor_js[] = "getToggle()";
const char dev_controls_accessor_js[] = "getControls()";
const char dev_controls_visibility_check_js[] =
"getControls().hasAttribute('expanded')";
// Navigate to the extensions frame and enabled "Developer mode"
ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUIExtensionsURL));
content::WebContents* contents =
browser()->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(content::ExecuteScript(contents, std::string(define_helpers_js)));
EXPECT_TRUE(content::ExecuteScript(
contents, base::StringPrintf("domAutomationController.send(%s.click());",
toggle_dev_mode_accessor_js)));
WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js,
dev_controls_visibility_check_js,
true);
// Disable devtools via policy.
PolicyMap policies;
policies.Set(key::kDeveloperToolsAvailability, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
base::Value(2 /*DeveloperToolsDisallowed*/), nullptr);
UpdateProviderPolicy(policies);
// Expect devcontrols to be hidden now...
WaitForExtensionsDevModeControlsVisibility(contents, dev_controls_accessor_js,
dev_controls_visibility_check_js,
false);
// ... and checkbox is disabled
bool is_toggle_dev_mode_checkbox_disabled = false;
EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
contents,
base::StringPrintf(
"domAutomationController.send(%s.hasAttribute('disabled'))",
toggle_dev_mode_accessor_js),
&is_toggle_dev_mode_checkbox_disabled));
EXPECT_TRUE(is_toggle_dev_mode_checkbox_disabled);
}
} // namespace policy