File: user_scripts_uitest.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (181 lines) | stat: -rw-r--r-- 7,785 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/strings/strcat.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "chrome/browser/extensions/api/user_scripts/user_scripts_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/background_script_executor.h"
#include "extensions/common/extension_id.h"
#include "extensions/test/extension_test_message_listener.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/interaction/element_identifier.h"

namespace extensions {

class UserScriptsUITest : public InteractiveBrowserTestT<UserScriptsAPITest> {
 public:
  // Checks that toggle is `!enabled` and then toggles it to `enabled` state.
  auto CheckCurrentToggleStateAndThenToggleItInUI(
      ui::ElementIdentifier page_id,
      const DeepQuery toggle_dom_path,
      bool enabled) {
    return Steps(
        // ClickElement() won't click something off screen so scroll the toggle
        // into view in case it is not.
        ScrollIntoView(page_id, toggle_dom_path),
        // Check the toggle is `!enabled`.
        EnsurePresent(page_id, toggle_dom_path),
        CheckJsResultAt(page_id, toggle_dom_path, "(el) => el.checked",
                        !enabled),
        // Click the toggle and check it is `enabled`.
        ClickElement(page_id, toggle_dom_path),
        CheckJsResultAt(page_id, toggle_dom_path, "(el) => el.checked",
                        enabled));
  }

  // Toggles the extensions_features::kUserScriptUserExtensionToggle toggle to
  // `enabled` state.
  auto TogglePerExtensionToggleInUI(ui::ElementIdentifier page_id,
                                    const ExtensionId& extension_id,
                                    bool enabled) {
    const DeepQuery kPathToUserScriptsToggle{
        "extensions-manager",
        "extensions-detail-view",
        "extensions-toggle-row#allow-user-scripts",
        "cr-toggle#crToggle",
    };

    // Enable the per-extension toggle in the UI.
    return Steps(
        // Navigate to the extensions detail page for the extension (where the
        // toggle lives).
        NavigateWebContents(page_id,
                            GURL(base::StrCat({chrome::kChromeUIExtensionsURL,
                                               "?id=", extension_id.c_str()}))),
        CheckCurrentToggleStateAndThenToggleItInUI(
            page_id, kPathToUserScriptsToggle, enabled));
  }

  // Toggles the (non extensions_features::kUserScriptUserExtensionToggle state)
  // dev mode toggle `enabled` state.
  auto ToggleDevModeInUI(ui::ElementIdentifier page_id, bool enabled) {
    const DeepQuery kPathToDevModeToggle{
        "extensions-manager extensions-toolbar",
        "cr-toggle#devMode",
    };

    // Enable dev mode toggle in the UI.
    return Steps(
        // Navigate to the extensions detail page for the extension.
        NavigateWebContents(page_id, GURL(chrome::kChromeUIExtensionsURL)),
        CheckCurrentToggleStateAndThenToggleItInUI(
            page_id, kPathToDevModeToggle, enabled));
  }

  // Checks that the chrome.userScripts API is not available in the background
  // script.
  auto VerifyUserScriptsIsNotAvailable(const ExtensionId& extension_id) {
    // Register the user script in the extension background script and confirm
    // it registered successfully.
    return CheckResult(
        [this, &extension_id]() -> bool {
          return BackgroundScriptExecutor::ExecuteScript(
                     profile(), extension_id, "verifyApiIsNotAvailable();",
                     BackgroundScriptExecutor::ResultCapture::
                         kSendScriptResult) == "success";
        },
        true, "Checking that the userScripts API is not available");
  }

  // Registers a dynamic user script with the chrome.userScripts API.
  auto RegisterUserScript(const ExtensionId& extension_id) {
    // Register the user script in the extension background script and confirm
    // it registered successfully.
    return CheckResult(
        [this, &extension_id]() -> bool {
          return BackgroundScriptExecutor::ExecuteScript(
                     profile(), extension_id, "registerUserScripts();",
                     BackgroundScriptExecutor::ResultCapture::
                         kSendScriptResult) == "success";
        },
        true, "Registering dynamic user script and checking that it completed");
  }
};

// TODO(crbug.com/416377497): Re-enable the test.
#if BUILDFLAG(IS_MAC)
#define MAYBE_ToggleControls_UserScriptsAPIUsage \
  DISABLED_ToggleControls_UserScriptsAPIUsage
#else
#define MAYBE_ToggleControls_UserScriptsAPIUsage \
  ToggleControls_UserScriptsAPIUsage
#endif
// Tests the toggling the UI toggle (dependent on feature) controls whether the
// user has allowed userScripts API usage.
IN_PROC_BROWSER_TEST_P(UserScriptsUITest,
                       MAYBE_ToggleControls_UserScriptsAPIUsage) {
  // Load extension that has API permission to use the userScripts API, but not
  // the per-extension toggle for userScripts enabled.
  ExtensionTestMessageListener extension_background_started_listener =
      ExtensionTestMessageListener("started");
  const Extension* extension =
      LoadExtension(test_data_dir_.AppendASCII("user_scripts/allowed_tests"));
  ASSERT_TRUE(extension);
  ASSERT_TRUE(extension_background_started_listener.WaitUntilSatisfied());

  const DeepQuery kPathToUserScriptInjectedDiv{
      "#user-script-code",
  };

  // This test verifies that:
  //   1) The userScripts API is initially unavailable.
  //   2) Enabling the toggle allows for a dynamic user script can be registered
  //      and injected.
  //   3) Disabling the toggle causes user scripts to no longer inject
  DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kTab);
  RunTestSequence(
      InstrumentTab(kTab),

      VerifyUserScriptsIsNotAvailable(extension->id()),

      // Enable the toggle depending on feature state.
      GetParam() ? TogglePerExtensionToggleInUI(kTab, extension->id(),
                                                /*enabled=*/true)
                 : ToggleDevModeInUI(kTab, /*enabled=*/true),

      RegisterUserScript(extension->id()),

      // Navigate tab to a webpage where the user script should inject a <div>.
      NavigateWebContents(
          kTab, embedded_test_server()->GetURL("example.com", "/simple.html")),
      // Ensure the user script injected its <div>.
      EnsurePresent(kTab, kPathToUserScriptInjectedDiv),

      // Disable the toggle depending on feature state.
      GetParam() ? TogglePerExtensionToggleInUI(kTab, extension->id(),
                                                /*enabled=*/false)
                 : ToggleDevModeInUI(kTab, /*enabled=*/false),
      // Navigate tab to a webpage where the user script should no longer inject
      // a <div>.
      NavigateWebContents(
          kTab, embedded_test_server()->GetURL("example.com", "/simple.html")),
      // Ensure the user script no longer injects its <div>.
      EnsureNotPresent(kTab, kPathToUserScriptInjectedDiv));
}

INSTANTIATE_TEST_SUITE_P(PerExtensionToggle,
                         UserScriptsUITest,
                         // extensions_features::kUserScriptUserExtensionToggle
                         testing::Values("true"));
INSTANTIATE_TEST_SUITE_P(DevModeToggle,
                         UserScriptsUITest,
                         // extensions_features::kUserScriptUserExtensionToggle
                         testing::Values("false"));

}  // namespace extensions