electron-playwright-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // electron daemon — launched by playwright-cli.js as a subprocess.
5
+ // assembles a playwright CLI daemon with electron browser support.
6
+ //
7
+ // receives CLI args:
8
+ // --daemon=<socketPath> unix socket path to listen on
9
+ // --config=<configFile> optional path to config JSON file
10
+ // --user-data-dir=<path> optional user data directory
11
+
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+
15
+ const playwrightDir = path.dirname(require.resolve("playwright/package.json"));
16
+
17
+ function resolveInternal(relativePath) {
18
+ return path.join(playwrightDir, relativePath);
19
+ }
20
+
21
+ // --- import playwright internals via absolute paths ---
22
+
23
+ const { BrowserServerBackend } = require(
24
+ resolveInternal("lib/mcp/browser/browserServerBackend.js"),
25
+ );
26
+ const { resolveConfig } = require(resolveInternal("lib/mcp/browser/config.js"));
27
+ const { startMcpDaemonServer } = require(
28
+ resolveInternal("lib/mcp/terminal/daemon.js"),
29
+ );
30
+ const { browserTools } = require(resolveInternal("lib/mcp/browser/tools.js"));
31
+ const { commands } = require(resolveInternal("lib/mcp/terminal/commands.js"));
32
+ const { z } = require("playwright-core/lib/mcpBundle");
33
+
34
+ // --- import our electron extensions ---
35
+
36
+ const { ElectronContextFactory } = require("./electron-context-factory");
37
+ const electronTools = require("./electron-tools");
38
+
39
+ // --- parse CLI args ---
40
+
41
+ const args = require("minimist")(process.argv.slice(2));
42
+ const socketPath = args.daemon;
43
+ if (!socketPath) {
44
+ console.error("--daemon=<socketPath> is required");
45
+ process.exit(1);
46
+ }
47
+
48
+ async function main() {
49
+ // load config file if provided
50
+ let userConfig = {};
51
+ if (args.config && fs.existsSync(args.config)) {
52
+ userConfig = JSON.parse(fs.readFileSync(args.config, "utf-8"));
53
+ }
54
+
55
+ // set user data dir if provided
56
+ if (args["user-data-dir"]) {
57
+ userConfig.browser = userConfig.browser || {};
58
+ userConfig.browser.userDataDir = args["user-data-dir"];
59
+ }
60
+
61
+ // electron uses file: protocol — without this, Context._setupBrowserContext
62
+ // calls _setAllowedProtocols which blocks file: URLs
63
+ userConfig.allowUnrestrictedFileAccess = true;
64
+
65
+ // resolve full config by merging with playwright defaults
66
+ const config = await resolveConfig(userConfig);
67
+
68
+ // apply daemon-mode overrides (matches program.js daemon setup)
69
+ config.outputDir = path.join(process.cwd(), ".playwright-cli");
70
+ config.outputMode = "file";
71
+ config.codegen = "none";
72
+ config.snapshot.mode = "full";
73
+ config.capabilities = ["core", "internal", "tracing", "pdf", "vision"];
74
+
75
+ // register electron tools into the global browserTools array.
76
+ // BrowserServerBackend's constructor calls filteredTools(config) which
77
+ // reads from this same array reference, so pushing here ensures
78
+ // electron tools are included.
79
+ browserTools.push(...electronTools);
80
+
81
+ // register electron CLI commands so the daemon's parseCliCommand can
82
+ // dispatch them. the commands object is shared by reference with daemon.js.
83
+ commands["electron_evaluate"] = {
84
+ name: "electron_evaluate",
85
+ description: "execute JavaScript in the Electron main process",
86
+ args: z.object({
87
+ expression: z
88
+ .string()
89
+ .describe('JS expression, e.g. "electron => electron.app.getName()"'),
90
+ }),
91
+ toolName: "electron_evaluate",
92
+ toolParams: ({ expression }) => ({ expression }),
93
+ };
94
+ commands["electron_windows"] = {
95
+ name: "electron_windows",
96
+ description: "list all open Electron windows",
97
+ args: z.object({}),
98
+ toolName: "electron_windows",
99
+ toolParams: () => ({}),
100
+ };
101
+
102
+ // create the backend factory
103
+ const factory = new ElectronContextFactory(config);
104
+ const serverBackendFactory = {
105
+ create: () => new BrowserServerBackend(config, factory),
106
+ };
107
+
108
+ // start listening on the unix socket
109
+ const resolvedPath = await startMcpDaemonServer(
110
+ socketPath,
111
+ serverBackendFactory,
112
+ );
113
+ console.error(`Electron daemon listening on ${resolvedPath}`);
114
+ }
115
+
116
+ main().catch((e) => {
117
+ console.error(e);
118
+ process.exit(1);
119
+ });
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ // electron-specific tools for the playwright CLI daemon.
4
+ // operate on the electron app instance stored on browserContext._electronApp.
5
+
6
+ const { z } = require("playwright-core/lib/mcpBundle");
7
+
8
+ const electronEvaluate = {
9
+ capability: "core",
10
+ schema: {
11
+ name: "electron_evaluate",
12
+ title: "Evaluate in Electron main process",
13
+ description:
14
+ "Execute a JavaScript expression in the Electron main process. The function receives the Electron module as its argument.",
15
+ inputSchema: z.object({
16
+ expression: z
17
+ .string()
18
+ .describe(
19
+ 'JavaScript expression to evaluate in the main process. Receives electron module as argument, e.g. "electron => electron.app.getName()"',
20
+ ),
21
+ }),
22
+ type: "destructive",
23
+ },
24
+ handle: async (context, params, response) => {
25
+ const browserContext = await context.ensureBrowserContext();
26
+ const electronApp = browserContext._electronApp;
27
+ if (!electronApp)
28
+ throw new Error(
29
+ "Not running in Electron mode. This tool requires an Electron app context.",
30
+ );
31
+
32
+ const result = await electronApp.evaluate(params.expression);
33
+ const text = JSON.stringify(result, null, 2) ?? "undefined";
34
+ response.addTextResult(text);
35
+ },
36
+ };
37
+
38
+ const electronWindows = {
39
+ capability: "core",
40
+ schema: {
41
+ name: "electron_windows",
42
+ title: "List Electron windows",
43
+ description:
44
+ "List all open Electron windows with their title, URL, and index.",
45
+ inputSchema: z.object({}),
46
+ type: "readOnly",
47
+ },
48
+ handle: async (context, params, response) => {
49
+ const browserContext = await context.ensureBrowserContext();
50
+ const electronApp = browserContext._electronApp;
51
+ if (!electronApp)
52
+ throw new Error(
53
+ "Not running in Electron mode. This tool requires an Electron app context.",
54
+ );
55
+
56
+ const windows = electronApp.windows();
57
+ const windowInfos = await Promise.all(
58
+ windows.map(async (page, index) => ({
59
+ index,
60
+ title: await page.title(),
61
+ url: page.url(),
62
+ })),
63
+ );
64
+ const text = JSON.stringify(windowInfos, null, 2);
65
+ response.addTextResult(text);
66
+ },
67
+ };
68
+
69
+ module.exports = [electronEvaluate, electronWindows];
@@ -0,0 +1,272 @@
1
+ ---
2
+ name: electron-playwright-cli
3
+ description: Automates Electron desktop app interactions for testing, screenshots, and data extraction. Use when the user needs to interact with Electron apps, take screenshots, fill forms, click elements, or extract information from desktop applications.
4
+ allowed-tools: Bash(electron-playwright-cli:*)
5
+ ---
6
+
7
+ # Electron App Automation with electron-playwright-cli
8
+
9
+ ## Quick start
10
+
11
+ ```bash
12
+ # take a snapshot of the running electron app (launches via config on first command)
13
+ electron-playwright-cli snapshot
14
+ # interact with the page using refs from the snapshot
15
+ electron-playwright-cli click e15
16
+ electron-playwright-cli type "search query"
17
+ electron-playwright-cli press Enter
18
+ ```
19
+
20
+ ## Configuration
21
+
22
+ Create `.playwright/cli.config.json` in your project root:
23
+
24
+ ```json
25
+ {
26
+ "browser": {
27
+ "launchOptions": {
28
+ "args": ["path/to/your/main.js"]
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ The `args` array is passed to Electron. Point it at your app's main process entry point.
35
+
36
+ Optional launch options:
37
+ - `executablePath`: path to the Electron binary (defaults to the one in node_modules)
38
+ - `cwd`: working directory for the Electron process
39
+ - `env`: additional environment variables
40
+ - `timeout`: launch timeout in milliseconds
41
+
42
+ ## Commands
43
+
44
+ ### Core
45
+
46
+ ```bash
47
+ electron-playwright-cli type "search query"
48
+ electron-playwright-cli click e3
49
+ electron-playwright-cli dblclick e7
50
+ electron-playwright-cli fill e5 "user@example.com"
51
+ electron-playwright-cli drag e2 e8
52
+ electron-playwright-cli hover e4
53
+ electron-playwright-cli select e9 "option-value"
54
+ electron-playwright-cli upload ./document.pdf
55
+ electron-playwright-cli check e12
56
+ electron-playwright-cli uncheck e12
57
+ electron-playwright-cli snapshot
58
+ electron-playwright-cli snapshot --filename=after-click.yaml
59
+ electron-playwright-cli eval "document.title"
60
+ electron-playwright-cli eval "el => el.textContent" e5
61
+ electron-playwright-cli dialog-accept
62
+ electron-playwright-cli dialog-accept "confirmation text"
63
+ electron-playwright-cli dialog-dismiss
64
+ electron-playwright-cli resize 1920 1080
65
+ electron-playwright-cli close
66
+ ```
67
+
68
+ ### Navigation
69
+
70
+ Navigate within the Electron app's webview:
71
+
72
+ ```bash
73
+ electron-playwright-cli goto https://example.com
74
+ electron-playwright-cli go-back
75
+ electron-playwright-cli go-forward
76
+ electron-playwright-cli reload
77
+ ```
78
+
79
+ ### Keyboard
80
+
81
+ ```bash
82
+ electron-playwright-cli press Enter
83
+ electron-playwright-cli press ArrowDown
84
+ electron-playwright-cli keydown Shift
85
+ electron-playwright-cli keyup Shift
86
+ ```
87
+
88
+ ### Mouse
89
+
90
+ ```bash
91
+ electron-playwright-cli mousemove 150 300
92
+ electron-playwright-cli mousedown
93
+ electron-playwright-cli mousedown right
94
+ electron-playwright-cli mouseup
95
+ electron-playwright-cli mouseup right
96
+ electron-playwright-cli mousewheel 0 100
97
+ ```
98
+
99
+ ### Save as
100
+
101
+ ```bash
102
+ electron-playwright-cli screenshot
103
+ electron-playwright-cli screenshot e5
104
+ electron-playwright-cli screenshot --filename=page.png
105
+ ```
106
+
107
+ ### Tabs
108
+
109
+ ```bash
110
+ electron-playwright-cli tab-list
111
+ electron-playwright-cli tab-new
112
+ electron-playwright-cli tab-close
113
+ electron-playwright-cli tab-close 2
114
+ electron-playwright-cli tab-select 0
115
+ ```
116
+
117
+ ### Storage
118
+
119
+ ```bash
120
+ electron-playwright-cli state-save
121
+ electron-playwright-cli state-save auth.json
122
+ electron-playwright-cli state-load auth.json
123
+
124
+ # Cookies
125
+ electron-playwright-cli cookie-list
126
+ electron-playwright-cli cookie-list --domain=example.com
127
+ electron-playwright-cli cookie-get session_id
128
+ electron-playwright-cli cookie-set session_id abc123
129
+ electron-playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
130
+ electron-playwright-cli cookie-delete session_id
131
+ electron-playwright-cli cookie-clear
132
+
133
+ # LocalStorage
134
+ electron-playwright-cli localstorage-list
135
+ electron-playwright-cli localstorage-get theme
136
+ electron-playwright-cli localstorage-set theme dark
137
+ electron-playwright-cli localstorage-delete theme
138
+ electron-playwright-cli localstorage-clear
139
+
140
+ # SessionStorage
141
+ electron-playwright-cli sessionstorage-list
142
+ electron-playwright-cli sessionstorage-get step
143
+ electron-playwright-cli sessionstorage-set step 3
144
+ electron-playwright-cli sessionstorage-delete step
145
+ electron-playwright-cli sessionstorage-clear
146
+ ```
147
+
148
+ ### Network
149
+
150
+ ```bash
151
+ electron-playwright-cli route "**/*.jpg" --status=404
152
+ electron-playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
153
+ electron-playwright-cli route-list
154
+ electron-playwright-cli unroute "**/*.jpg"
155
+ electron-playwright-cli unroute
156
+ ```
157
+
158
+ ### DevTools
159
+
160
+ ```bash
161
+ electron-playwright-cli console
162
+ electron-playwright-cli console warning
163
+ electron-playwright-cli network
164
+ electron-playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
165
+ electron-playwright-cli tracing-start
166
+ electron-playwright-cli tracing-stop
167
+ electron-playwright-cli video-start
168
+ electron-playwright-cli video-stop video.webm
169
+ ```
170
+
171
+ ### Electron
172
+
173
+ ```bash
174
+ electron-playwright-cli electron_evaluate "electron => electron.app.getName()"
175
+ electron-playwright-cli electron_evaluate "electron => electron.app.getPath('userData')"
176
+ electron-playwright-cli electron_windows
177
+ ```
178
+
179
+ ## Snapshots
180
+
181
+ After each command, electron-playwright-cli provides a snapshot of the current app state.
182
+
183
+ ```bash
184
+ > electron-playwright-cli snapshot
185
+ ### Page
186
+ - Page URL: file:///path/to/index.html
187
+ - Page Title: My Electron App
188
+ ### Snapshot
189
+ [Snapshot](.playwright-cli/page-2026-02-14T19-22-42-679Z.yml)
190
+ ```
191
+
192
+ You can also take a snapshot on demand using `electron-playwright-cli snapshot` command.
193
+
194
+ If `--filename` is not provided, a new snapshot file is created with a timestamp. Default to automatic file naming, use `--filename=` when artifact is a part of the workflow result.
195
+
196
+ ## Sessions
197
+
198
+ ```bash
199
+ electron-playwright-cli -s=name <cmd> # run command in named session
200
+ electron-playwright-cli -s=name close # stop a named session
201
+ electron-playwright-cli -s=name delete-data # delete user data for named session
202
+ electron-playwright-cli list # list all sessions
203
+ electron-playwright-cli close-all # close all sessions
204
+ electron-playwright-cli kill-all # forcefully kill all daemon processes
205
+ ```
206
+
207
+ ## Local installation
208
+
209
+ In some cases you might want to install electron-playwright-cli locally. It requires `playwright` as a peer dependency. If running the globally available `electron-playwright-cli` binary fails, use `npx electron-playwright-cli` to run the commands. For example:
210
+
211
+ ```bash
212
+ npx electron-playwright-cli snapshot
213
+ npx electron-playwright-cli click e1
214
+ ```
215
+
216
+ ## Example: Form submission
217
+
218
+ ```bash
219
+ electron-playwright-cli snapshot
220
+
221
+ electron-playwright-cli fill e1 "user@example.com"
222
+ electron-playwright-cli fill e2 "password123"
223
+ electron-playwright-cli click e3
224
+ electron-playwright-cli snapshot
225
+ electron-playwright-cli close
226
+ ```
227
+
228
+ ## Example: Multi-window workflow
229
+
230
+ ```bash
231
+ electron-playwright-cli electron_windows
232
+ electron-playwright-cli tab-select 0
233
+ electron-playwright-cli snapshot
234
+ electron-playwright-cli close
235
+ ```
236
+
237
+ ## Example: Debugging with DevTools
238
+
239
+ ```bash
240
+ electron-playwright-cli snapshot
241
+ electron-playwright-cli click e4
242
+ electron-playwright-cli fill e7 "test"
243
+ electron-playwright-cli console
244
+ electron-playwright-cli network
245
+ electron-playwright-cli close
246
+ ```
247
+
248
+ ```bash
249
+ electron-playwright-cli tracing-start
250
+ electron-playwright-cli click e4
251
+ electron-playwright-cli fill e7 "test"
252
+ electron-playwright-cli tracing-stop
253
+ electron-playwright-cli close
254
+ ```
255
+
256
+ ## Example: Electron main process
257
+
258
+ ```bash
259
+ electron-playwright-cli electron_evaluate "electron => electron.app.getName()"
260
+ electron-playwright-cli electron_evaluate "electron => electron.app.getPath('userData')"
261
+ electron-playwright-cli electron_windows
262
+ ```
263
+
264
+ ## Specific tasks
265
+
266
+ * **Request mocking** [references/request-mocking.md](references/request-mocking.md)
267
+ * **Running Playwright code** [references/running-code.md](references/running-code.md)
268
+ * **Session management** [references/session-management.md](references/session-management.md)
269
+ * **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
270
+ * **Test generation** [references/test-generation.md](references/test-generation.md)
271
+ * **Tracing** [references/tracing.md](references/tracing.md)
272
+ * **Video recording** [references/video-recording.md](references/video-recording.md)
@@ -0,0 +1,87 @@
1
+ # Request Mocking
2
+
3
+ Intercept, mock, modify, and block network requests.
4
+
5
+ ## CLI Route Commands
6
+
7
+ ```bash
8
+ # Mock with custom status
9
+ electron-playwright-cli route "**/*.jpg" --status=404
10
+
11
+ # Mock with JSON body
12
+ electron-playwright-cli route "**/api/users" --body='[{"id":1,"name":"Alice"}]' --content-type=application/json
13
+
14
+ # Mock with custom headers
15
+ electron-playwright-cli route "**/api/data" --body='{"ok":true}' --header="X-Custom: value"
16
+
17
+ # Remove headers from requests
18
+ electron-playwright-cli route "**/*" --remove-header=cookie,authorization
19
+
20
+ # List active routes
21
+ electron-playwright-cli route-list
22
+
23
+ # Remove a route or all routes
24
+ electron-playwright-cli unroute "**/*.jpg"
25
+ electron-playwright-cli unroute
26
+ ```
27
+
28
+ ## URL Patterns
29
+
30
+ ```
31
+ **/api/users - Exact path match
32
+ **/api/*/details - Wildcard in path
33
+ **/*.{png,jpg,jpeg} - Match file extensions
34
+ **/search?q=* - Match query parameters
35
+ ```
36
+
37
+ ## Advanced Mocking with run-code
38
+
39
+ For conditional responses, request body inspection, response modification, or delays:
40
+
41
+ ### Conditional Response Based on Request
42
+
43
+ ```bash
44
+ electron-playwright-cli run-code "async page => {
45
+ await page.route('**/api/login', route => {
46
+ const body = route.request().postDataJSON();
47
+ if (body.username === 'admin') {
48
+ route.fulfill({ body: JSON.stringify({ token: 'mock-token' }) });
49
+ } else {
50
+ route.fulfill({ status: 401, body: JSON.stringify({ error: 'Invalid' }) });
51
+ }
52
+ });
53
+ }"
54
+ ```
55
+
56
+ ### Modify Real Response
57
+
58
+ ```bash
59
+ electron-playwright-cli run-code "async page => {
60
+ await page.route('**/api/user', async route => {
61
+ const response = await route.fetch();
62
+ const json = await response.json();
63
+ json.isPremium = true;
64
+ await route.fulfill({ response, json });
65
+ });
66
+ }"
67
+ ```
68
+
69
+ ### Simulate Network Failures
70
+
71
+ ```bash
72
+ electron-playwright-cli run-code "async page => {
73
+ await page.route('**/api/offline', route => route.abort('internetdisconnected'));
74
+ }"
75
+ # Options: connectionrefused, timedout, connectionreset, internetdisconnected
76
+ ```
77
+
78
+ ### Delayed Response
79
+
80
+ ```bash
81
+ electron-playwright-cli run-code "async page => {
82
+ await page.route('**/api/slow', async route => {
83
+ await new Promise(r => setTimeout(r, 3000));
84
+ route.fulfill({ body: JSON.stringify({ data: 'loaded' }) });
85
+ });
86
+ }"
87
+ ```