@playwright/mcp 0.0.17 → 0.0.19
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.
- package/README.md +14 -2
- package/cli.js +1 -1
- package/config.d.ts +1 -1
- package/index.js +2 -2
- package/lib/config.js +37 -40
- package/lib/context.js +36 -48
- package/lib/index.js +41 -44
- package/lib/javascript.js +3 -8
- package/lib/manualPromise.js +2 -7
- package/lib/pageSnapshot.js +6 -13
- package/lib/program.js +12 -14
- package/lib/resources/resource.js +1 -2
- package/lib/server.js +11 -16
- package/lib/tab.js +6 -7
- package/lib/tools/common.js +12 -14
- package/lib/tools/console.js +5 -7
- package/lib/tools/dialogs.js +7 -9
- package/lib/tools/files.js +6 -8
- package/lib/tools/install.js +9 -14
- package/lib/tools/keyboard.js +6 -8
- package/lib/tools/navigate.js +10 -12
- package/lib/tools/network.js +5 -7
- package/lib/tools/pdf.js +8 -43
- package/lib/tools/screen.js +23 -58
- package/lib/tools/snapshot.js +31 -67
- package/lib/tools/tabs.js +14 -16
- package/lib/tools/testing.js +58 -0
- package/lib/tools/tool.js +1 -4
- package/lib/tools/utils.js +7 -7
- package/lib/transport.js +31 -31
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ A Model Context Protocol (MCP) server that provides browser automation capabilit
|
|
|
17
17
|
|
|
18
18
|
<!--
|
|
19
19
|
// Generate using:
|
|
20
|
-
node utils/
|
|
20
|
+
node utils/generate-links.js
|
|
21
21
|
-->
|
|
22
22
|
|
|
23
23
|
[<img src="https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF" alt="Install in VS Code">](https://insiders.vscode.dev/redirect?url=vscode%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522%2540playwright%252Fmcp%2540latest%2522%255D%257D) [<img alt="Install in VS Code Insiders" src="https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Server&color=24bfa5">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522playwright%2522%252C%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522%2540playwright%252Fmcp%2540latest%2522%255D%257D)
|
|
@@ -142,7 +142,8 @@ The Playwright MCP server can be configured using a JSON configuration file. Her
|
|
|
142
142
|
'history' | // Browser history
|
|
143
143
|
'wait' | // Wait utilities
|
|
144
144
|
'files' | // File handling
|
|
145
|
-
'install'
|
|
145
|
+
'install' | // Browser installation
|
|
146
|
+
'testing' // Testing
|
|
146
147
|
>;
|
|
147
148
|
|
|
148
149
|
// Enable vision mode (screenshots instead of accessibility snapshots)
|
|
@@ -485,4 +486,15 @@ X Y coordinate space, based on the provided screenshot.
|
|
|
485
486
|
- `accept` (boolean): Whether to accept the dialog.
|
|
486
487
|
- `promptText` (string, optional): The text of the prompt in case of a prompt dialog.
|
|
487
488
|
|
|
489
|
+
### Testing
|
|
490
|
+
|
|
491
|
+
<!-- NOTE: This has been generated via update-readme.js -->
|
|
492
|
+
|
|
493
|
+
- **browser_generate_playwright_test**
|
|
494
|
+
- Description: Generate a Playwright test for given scenario
|
|
495
|
+
- Parameters:
|
|
496
|
+
- `name` (string): The name of the test
|
|
497
|
+
- `description` (string): The description of the test
|
|
498
|
+
- `steps` (array): The steps of the test
|
|
499
|
+
|
|
488
500
|
<!--- End of generated section -->
|
package/cli.js
CHANGED
package/config.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import type * as playwright from 'playwright';
|
|
18
18
|
|
|
19
|
-
export type ToolCapability = 'core' | 'tabs' | 'pdf' | 'history' | 'wait' | 'files' | 'install';
|
|
19
|
+
export type ToolCapability = 'core' | 'tabs' | 'pdf' | 'history' | 'wait' | 'files' | 'install' | 'testing';
|
|
20
20
|
|
|
21
21
|
export type Config = {
|
|
22
22
|
/**
|
package/index.js
CHANGED
package/lib/config.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,38 +13,31 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
exports.outputFile = outputFile;
|
|
24
|
-
const fs_1 = __importDefault(require("fs"));
|
|
25
|
-
const net_1 = __importDefault(require("net"));
|
|
26
|
-
const os_1 = __importDefault(require("os"));
|
|
27
|
-
const path_1 = __importDefault(require("path"));
|
|
28
|
-
const playwright_1 = require("playwright");
|
|
29
|
-
const utils_1 = require("./tools/utils");
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import net from 'net';
|
|
18
|
+
import os from 'os';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { devices } from 'playwright';
|
|
21
|
+
import { sanitizeForFilePath } from './tools/utils.js';
|
|
30
22
|
const defaultConfig = {
|
|
31
23
|
browser: {
|
|
32
24
|
browserName: 'chromium',
|
|
33
|
-
userDataDir:
|
|
25
|
+
userDataDir: os.tmpdir(),
|
|
34
26
|
launchOptions: {
|
|
35
27
|
channel: 'chrome',
|
|
36
|
-
headless:
|
|
28
|
+
headless: os.platform() === 'linux' && !process.env.DISPLAY,
|
|
37
29
|
},
|
|
38
30
|
contextOptions: {
|
|
39
31
|
viewport: null,
|
|
40
32
|
},
|
|
41
33
|
},
|
|
42
34
|
};
|
|
43
|
-
async function resolveConfig(cliOptions) {
|
|
35
|
+
export async function resolveConfig(cliOptions) {
|
|
44
36
|
const config = await loadConfig(cliOptions.config);
|
|
45
37
|
const cliOverrides = await configFromCLIOptions(cliOptions);
|
|
46
38
|
return mergeConfig(defaultConfig, mergeConfig(config, cliOverrides));
|
|
47
39
|
}
|
|
48
|
-
async function configFromCLIOptions(cliOptions) {
|
|
40
|
+
export async function configFromCLIOptions(cliOptions) {
|
|
49
41
|
let browserName;
|
|
50
42
|
let channel;
|
|
51
43
|
switch (cliOptions.browser) {
|
|
@@ -74,11 +66,11 @@ async function configFromCLIOptions(cliOptions) {
|
|
|
74
66
|
const launchOptions = {
|
|
75
67
|
channel,
|
|
76
68
|
executablePath: cliOptions.executablePath,
|
|
77
|
-
headless: cliOptions.headless
|
|
69
|
+
headless: cliOptions.headless,
|
|
78
70
|
};
|
|
79
71
|
if (browserName === 'chromium')
|
|
80
72
|
launchOptions.webSocketPort = await findFreePort();
|
|
81
|
-
const contextOptions = cliOptions.device ?
|
|
73
|
+
const contextOptions = cliOptions.device ? devices[cliOptions.device] : undefined;
|
|
82
74
|
return {
|
|
83
75
|
browser: {
|
|
84
76
|
browserName,
|
|
@@ -97,7 +89,7 @@ async function configFromCLIOptions(cliOptions) {
|
|
|
97
89
|
}
|
|
98
90
|
async function findFreePort() {
|
|
99
91
|
return new Promise((resolve, reject) => {
|
|
100
|
-
const server =
|
|
92
|
+
const server = net.createServer();
|
|
101
93
|
server.listen(0, () => {
|
|
102
94
|
const { port } = server.address();
|
|
103
95
|
server.close(() => resolve(port));
|
|
@@ -109,7 +101,7 @@ async function loadConfig(configFile) {
|
|
|
109
101
|
if (!configFile)
|
|
110
102
|
return {};
|
|
111
103
|
try {
|
|
112
|
-
return JSON.parse(await
|
|
104
|
+
return JSON.parse(await fs.promises.readFile(configFile, 'utf8'));
|
|
113
105
|
}
|
|
114
106
|
catch (error) {
|
|
115
107
|
throw new Error(`Failed to load config file: ${configFile}, ${error}`);
|
|
@@ -118,40 +110,45 @@ async function loadConfig(configFile) {
|
|
|
118
110
|
async function createUserDataDir(options) {
|
|
119
111
|
let cacheDirectory;
|
|
120
112
|
if (process.platform === 'linux')
|
|
121
|
-
cacheDirectory = process.env.XDG_CACHE_HOME ||
|
|
113
|
+
cacheDirectory = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');
|
|
122
114
|
else if (process.platform === 'darwin')
|
|
123
|
-
cacheDirectory =
|
|
115
|
+
cacheDirectory = path.join(os.homedir(), 'Library', 'Caches');
|
|
124
116
|
else if (process.platform === 'win32')
|
|
125
|
-
cacheDirectory = process.env.LOCALAPPDATA ||
|
|
117
|
+
cacheDirectory = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
126
118
|
else
|
|
127
119
|
throw new Error('Unsupported platform: ' + process.platform);
|
|
128
|
-
const result =
|
|
129
|
-
await
|
|
120
|
+
const result = path.join(cacheDirectory, 'ms-playwright', `mcp-${options.channel ?? options.browserName}-profile`);
|
|
121
|
+
await fs.promises.mkdir(result, { recursive: true });
|
|
130
122
|
return result;
|
|
131
123
|
}
|
|
132
|
-
async function outputFile(config, name) {
|
|
133
|
-
const result = config.outputDir ??
|
|
134
|
-
await
|
|
135
|
-
const fileName =
|
|
136
|
-
return
|
|
124
|
+
export async function outputFile(config, name) {
|
|
125
|
+
const result = config.outputDir ?? os.tmpdir();
|
|
126
|
+
await fs.promises.mkdir(result, { recursive: true });
|
|
127
|
+
const fileName = sanitizeForFilePath(name);
|
|
128
|
+
return path.join(result, fileName);
|
|
129
|
+
}
|
|
130
|
+
function pickDefined(obj) {
|
|
131
|
+
return Object.fromEntries(Object.entries(obj ?? {}).filter(([_, v]) => v !== undefined));
|
|
137
132
|
}
|
|
138
133
|
function mergeConfig(base, overrides) {
|
|
139
134
|
const browser = {
|
|
140
|
-
...base.browser,
|
|
141
|
-
...overrides.browser,
|
|
135
|
+
...pickDefined(base.browser),
|
|
136
|
+
...pickDefined(overrides.browser),
|
|
142
137
|
launchOptions: {
|
|
143
|
-
...base.browser?.launchOptions,
|
|
144
|
-
...overrides.browser?.launchOptions,
|
|
138
|
+
...pickDefined(base.browser?.launchOptions),
|
|
139
|
+
...pickDefined(overrides.browser?.launchOptions),
|
|
145
140
|
...{ assistantMode: true },
|
|
146
141
|
},
|
|
147
142
|
contextOptions: {
|
|
148
|
-
...base.browser?.contextOptions,
|
|
149
|
-
...overrides.browser?.contextOptions,
|
|
143
|
+
...pickDefined(base.browser?.contextOptions),
|
|
144
|
+
...pickDefined(overrides.browser?.contextOptions),
|
|
150
145
|
},
|
|
151
146
|
};
|
|
147
|
+
if (browser.browserName !== 'chromium')
|
|
148
|
+
delete browser.launchOptions.channel;
|
|
152
149
|
return {
|
|
153
|
-
...base,
|
|
154
|
-
...overrides,
|
|
150
|
+
...pickDefined(base),
|
|
151
|
+
...pickDefined(overrides),
|
|
155
152
|
browser,
|
|
156
153
|
};
|
|
157
154
|
}
|
package/lib/context.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,47 +13,12 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Object.defineProperty(o, k2, desc);
|
|
24
|
-
}) : (function(o, m, k, k2) {
|
|
25
|
-
if (k2 === undefined) k2 = k;
|
|
26
|
-
o[k2] = m[k];
|
|
27
|
-
}));
|
|
28
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
-
}) : function(o, v) {
|
|
31
|
-
o["default"] = v;
|
|
32
|
-
});
|
|
33
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
-
var ownKeys = function(o) {
|
|
35
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
-
var ar = [];
|
|
37
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
-
return ar;
|
|
39
|
-
};
|
|
40
|
-
return ownKeys(o);
|
|
41
|
-
};
|
|
42
|
-
return function (mod) {
|
|
43
|
-
if (mod && mod.__esModule) return mod;
|
|
44
|
-
var result = {};
|
|
45
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
-
__setModuleDefault(result, mod);
|
|
47
|
-
return result;
|
|
48
|
-
};
|
|
49
|
-
})();
|
|
50
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
-
exports.Context = void 0;
|
|
52
|
-
exports.generateLocator = generateLocator;
|
|
53
|
-
const playwright = __importStar(require("playwright"));
|
|
54
|
-
const utils_1 = require("./tools/utils");
|
|
55
|
-
const manualPromise_1 = require("./manualPromise");
|
|
56
|
-
const tab_1 = require("./tab");
|
|
57
|
-
class Context {
|
|
16
|
+
import * as playwright from 'playwright';
|
|
17
|
+
import { waitForCompletion } from './tools/utils.js';
|
|
18
|
+
import { ManualPromise } from './manualPromise.js';
|
|
19
|
+
import { Tab } from './tab.js';
|
|
20
|
+
import { outputFile } from './config.js';
|
|
21
|
+
export class Context {
|
|
58
22
|
tools;
|
|
59
23
|
config;
|
|
60
24
|
_browser;
|
|
@@ -64,6 +28,7 @@ class Context {
|
|
|
64
28
|
_currentTab;
|
|
65
29
|
_modalStates = [];
|
|
66
30
|
_pendingAction;
|
|
31
|
+
_downloads = [];
|
|
67
32
|
constructor(tools, config) {
|
|
68
33
|
this.tools = tools;
|
|
69
34
|
this.config = config;
|
|
@@ -149,7 +114,7 @@ class Context {
|
|
|
149
114
|
let actionResult;
|
|
150
115
|
try {
|
|
151
116
|
if (waitForNetwork)
|
|
152
|
-
actionResult = await
|
|
117
|
+
actionResult = await waitForCompletion(this, tab.page, async () => racingAction?.()) ?? undefined;
|
|
153
118
|
else
|
|
154
119
|
actionResult = await racingAction?.() ?? undefined;
|
|
155
120
|
}
|
|
@@ -172,6 +137,16 @@ ${code.join('\n')}
|
|
|
172
137
|
}],
|
|
173
138
|
};
|
|
174
139
|
}
|
|
140
|
+
if (this._downloads.length) {
|
|
141
|
+
result.push('', '### Downloads');
|
|
142
|
+
for (const entry of this._downloads) {
|
|
143
|
+
if (entry.finished)
|
|
144
|
+
result.push(`- Downloaded file ${entry.download.suggestedFilename()} to ${entry.outputFile}`);
|
|
145
|
+
else
|
|
146
|
+
result.push(`- Downloading file ${entry.download.suggestedFilename()} ...`);
|
|
147
|
+
}
|
|
148
|
+
result.push('');
|
|
149
|
+
}
|
|
175
150
|
if (this.tabs().length > 1)
|
|
176
151
|
result.push(await this.listTabsMarkdown(), '');
|
|
177
152
|
if (this.tabs().length > 1)
|
|
@@ -198,7 +173,7 @@ ${code.join('\n')}
|
|
|
198
173
|
}
|
|
199
174
|
async _raceAgainstModalDialogs(action) {
|
|
200
175
|
this._pendingAction = {
|
|
201
|
-
dialogShown: new
|
|
176
|
+
dialogShown: new ManualPromise(),
|
|
202
177
|
};
|
|
203
178
|
let result;
|
|
204
179
|
try {
|
|
@@ -223,8 +198,18 @@ ${code.join('\n')}
|
|
|
223
198
|
}, tab);
|
|
224
199
|
this._pendingAction?.dialogShown.resolve();
|
|
225
200
|
}
|
|
201
|
+
async downloadStarted(tab, download) {
|
|
202
|
+
const entry = {
|
|
203
|
+
download,
|
|
204
|
+
finished: false,
|
|
205
|
+
outputFile: await outputFile(this.config, download.suggestedFilename())
|
|
206
|
+
};
|
|
207
|
+
this._downloads.push(entry);
|
|
208
|
+
await download.saveAs(entry.outputFile);
|
|
209
|
+
entry.finished = true;
|
|
210
|
+
}
|
|
226
211
|
_onPageCreated(page) {
|
|
227
|
-
const tab = new
|
|
212
|
+
const tab = new Tab(this, page, tab => this._onPageClosed(tab));
|
|
228
213
|
this._tabs.push(tab);
|
|
229
214
|
if (!this._currentTab)
|
|
230
215
|
this._currentTab = tab;
|
|
@@ -264,8 +249,12 @@ ${code.join('\n')}
|
|
|
264
249
|
return this._browserContext;
|
|
265
250
|
}
|
|
266
251
|
async _createBrowserContext() {
|
|
267
|
-
if (!this._createBrowserContextPromise)
|
|
252
|
+
if (!this._createBrowserContextPromise) {
|
|
268
253
|
this._createBrowserContextPromise = this._innerCreateBrowserContext();
|
|
254
|
+
void this._createBrowserContextPromise.catch(() => {
|
|
255
|
+
this._createBrowserContextPromise = undefined;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
269
258
|
return this._createBrowserContextPromise;
|
|
270
259
|
}
|
|
271
260
|
async _innerCreateBrowserContext() {
|
|
@@ -288,7 +277,6 @@ ${code.join('\n')}
|
|
|
288
277
|
return { browserContext };
|
|
289
278
|
}
|
|
290
279
|
}
|
|
291
|
-
exports.Context = Context;
|
|
292
280
|
async function launchPersistentContext(browserConfig) {
|
|
293
281
|
try {
|
|
294
282
|
const browserType = browserConfig?.browserName ? playwright[browserConfig.browserName] : playwright.chromium;
|
|
@@ -300,6 +288,6 @@ async function launchPersistentContext(browserConfig) {
|
|
|
300
288
|
throw error;
|
|
301
289
|
}
|
|
302
290
|
}
|
|
303
|
-
async function generateLocator(locator) {
|
|
291
|
+
export async function generateLocator(locator) {
|
|
304
292
|
return locator._generateLocatorString();
|
|
305
293
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,55 +13,53 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const pdf_1 = __importDefault(require("./tools/pdf"));
|
|
32
|
-
const snapshot_1 = __importDefault(require("./tools/snapshot"));
|
|
33
|
-
const tabs_1 = __importDefault(require("./tools/tabs"));
|
|
34
|
-
const screen_1 = __importDefault(require("./tools/screen"));
|
|
16
|
+
import { createServerWithTools } from './server.js';
|
|
17
|
+
import common from './tools/common.js';
|
|
18
|
+
import console from './tools/console.js';
|
|
19
|
+
import dialogs from './tools/dialogs.js';
|
|
20
|
+
import files from './tools/files.js';
|
|
21
|
+
import install from './tools/install.js';
|
|
22
|
+
import keyboard from './tools/keyboard.js';
|
|
23
|
+
import navigate from './tools/navigate.js';
|
|
24
|
+
import network from './tools/network.js';
|
|
25
|
+
import pdf from './tools/pdf.js';
|
|
26
|
+
import snapshot from './tools/snapshot.js';
|
|
27
|
+
import tabs from './tools/tabs.js';
|
|
28
|
+
import screen from './tools/screen.js';
|
|
29
|
+
import testing from './tools/testing.js';
|
|
35
30
|
const snapshotTools = [
|
|
36
|
-
...(
|
|
37
|
-
...
|
|
38
|
-
...(
|
|
39
|
-
...(
|
|
40
|
-
...
|
|
41
|
-
...(
|
|
42
|
-
...(
|
|
43
|
-
...
|
|
44
|
-
...
|
|
45
|
-
...
|
|
46
|
-
...(
|
|
31
|
+
...common(true),
|
|
32
|
+
...console,
|
|
33
|
+
...dialogs(true),
|
|
34
|
+
...files(true),
|
|
35
|
+
...install,
|
|
36
|
+
...keyboard(true),
|
|
37
|
+
...navigate(true),
|
|
38
|
+
...network,
|
|
39
|
+
...pdf,
|
|
40
|
+
...snapshot,
|
|
41
|
+
...tabs(true),
|
|
42
|
+
...testing,
|
|
47
43
|
];
|
|
48
44
|
const screenshotTools = [
|
|
49
|
-
...(
|
|
50
|
-
...
|
|
51
|
-
...(
|
|
52
|
-
...(
|
|
53
|
-
...
|
|
54
|
-
...(
|
|
55
|
-
...(
|
|
56
|
-
...
|
|
57
|
-
...
|
|
58
|
-
...
|
|
59
|
-
...(
|
|
45
|
+
...common(false),
|
|
46
|
+
...console,
|
|
47
|
+
...dialogs(false),
|
|
48
|
+
...files(false),
|
|
49
|
+
...install,
|
|
50
|
+
...keyboard(false),
|
|
51
|
+
...navigate(false),
|
|
52
|
+
...network,
|
|
53
|
+
...pdf,
|
|
54
|
+
...screen,
|
|
55
|
+
...tabs(false),
|
|
56
|
+
...testing,
|
|
60
57
|
];
|
|
61
|
-
|
|
62
|
-
async function createServer(config = {}) {
|
|
58
|
+
import packageJSON from '../package.json' with { type: 'json' };
|
|
59
|
+
export async function createServer(config = {}) {
|
|
63
60
|
const allTools = config.vision ? screenshotTools : snapshotTools;
|
|
64
61
|
const tools = allTools.filter(tool => !config.capabilities || tool.capability === 'core' || config.capabilities.includes(tool.capability));
|
|
65
|
-
return
|
|
62
|
+
return createServerWithTools({
|
|
66
63
|
name: 'Playwright',
|
|
67
64
|
version: packageJSON.version,
|
|
68
65
|
tools,
|
package/lib/javascript.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,15 +13,11 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.escapeWithQuotes = escapeWithQuotes;
|
|
19
|
-
exports.quote = quote;
|
|
20
|
-
exports.formatObject = formatObject;
|
|
21
16
|
// adapted from:
|
|
22
17
|
// - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/utils/isomorphic/stringUtils.ts
|
|
23
18
|
// - https://github.com/microsoft/playwright/blob/76ee48dc9d4034536e3ec5b2c7ce8be3b79418a8/packages/playwright-core/src/server/codegen/javascript.ts
|
|
24
19
|
// NOTE: this function should not be used to escape any selectors.
|
|
25
|
-
function escapeWithQuotes(text, char = '\'') {
|
|
20
|
+
export function escapeWithQuotes(text, char = '\'') {
|
|
26
21
|
const stringified = JSON.stringify(text);
|
|
27
22
|
const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
|
|
28
23
|
if (char === '\'')
|
|
@@ -33,10 +28,10 @@ function escapeWithQuotes(text, char = '\'') {
|
|
|
33
28
|
return char + escapedText.replace(/[`]/g, '`') + char;
|
|
34
29
|
throw new Error('Invalid escape char');
|
|
35
30
|
}
|
|
36
|
-
function quote(text) {
|
|
31
|
+
export function quote(text) {
|
|
37
32
|
return escapeWithQuotes(text, '\'');
|
|
38
33
|
}
|
|
39
|
-
function formatObject(value, indent = ' ') {
|
|
34
|
+
export function formatObject(value, indent = ' ') {
|
|
40
35
|
if (typeof value === 'string')
|
|
41
36
|
return quote(value);
|
|
42
37
|
if (Array.isArray(value))
|
package/lib/manualPromise.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,9 +13,7 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
exports.LongStandingScope = exports.ManualPromise = void 0;
|
|
19
|
-
class ManualPromise extends Promise {
|
|
16
|
+
export class ManualPromise extends Promise {
|
|
20
17
|
_resolve;
|
|
21
18
|
_reject;
|
|
22
19
|
_isDone;
|
|
@@ -49,8 +46,7 @@ class ManualPromise extends Promise {
|
|
|
49
46
|
return 'ManualPromise';
|
|
50
47
|
}
|
|
51
48
|
}
|
|
52
|
-
|
|
53
|
-
class LongStandingScope {
|
|
49
|
+
export class LongStandingScope {
|
|
54
50
|
_terminateError;
|
|
55
51
|
_closeError;
|
|
56
52
|
_terminatePromises = new Map();
|
|
@@ -98,7 +94,6 @@ class LongStandingScope {
|
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
96
|
}
|
|
101
|
-
exports.LongStandingScope = LongStandingScope;
|
|
102
97
|
function cloneError(error, frames) {
|
|
103
98
|
const clone = new Error();
|
|
104
99
|
clone.name = error.name;
|
package/lib/pageSnapshot.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,13 +13,8 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.PageSnapshot = void 0;
|
|
22
|
-
const yaml_1 = __importDefault(require("yaml"));
|
|
23
|
-
class PageSnapshot {
|
|
16
|
+
import yaml from 'yaml';
|
|
17
|
+
export class PageSnapshot {
|
|
24
18
|
_frameLocators = [];
|
|
25
19
|
_text;
|
|
26
20
|
constructor() {
|
|
@@ -45,18 +39,18 @@ class PageSnapshot {
|
|
|
45
39
|
async _snapshotFrame(frame) {
|
|
46
40
|
const frameIndex = this._frameLocators.push(frame) - 1;
|
|
47
41
|
const snapshotString = await frame.locator('body').ariaSnapshot({ ref: true, emitGeneric: true });
|
|
48
|
-
const snapshot =
|
|
42
|
+
const snapshot = yaml.parseDocument(snapshotString);
|
|
49
43
|
const visit = async (node) => {
|
|
50
|
-
if (
|
|
44
|
+
if (yaml.isPair(node)) {
|
|
51
45
|
await Promise.all([
|
|
52
46
|
visit(node.key).then(k => node.key = k),
|
|
53
47
|
visit(node.value).then(v => node.value = v)
|
|
54
48
|
]);
|
|
55
49
|
}
|
|
56
|
-
else if (
|
|
50
|
+
else if (yaml.isSeq(node) || yaml.isMap(node)) {
|
|
57
51
|
node.items = await Promise.all(node.items.map(visit));
|
|
58
52
|
}
|
|
59
|
-
else if (
|
|
53
|
+
else if (yaml.isScalar(node)) {
|
|
60
54
|
if (typeof node.value === 'string') {
|
|
61
55
|
const value = node.value;
|
|
62
56
|
if (frameIndex > 0)
|
|
@@ -93,4 +87,3 @@ class PageSnapshot {
|
|
|
93
87
|
return frame.locator(`aria-ref=${ref}`);
|
|
94
88
|
}
|
|
95
89
|
}
|
|
96
|
-
exports.PageSnapshot = PageSnapshot;
|
package/lib/program.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,14 +13,13 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
commander_1.program
|
|
16
|
+
import { program } from 'commander';
|
|
17
|
+
import { createServer } from './index.js';
|
|
18
|
+
import { ServerList } from './server.js';
|
|
19
|
+
import { startHttpTransport, startStdioTransport } from './transport.js';
|
|
20
|
+
import { resolveConfig } from './config.js';
|
|
21
|
+
import packageJSON from '../package.json' with { type: 'json' };
|
|
22
|
+
program
|
|
25
23
|
.version('Version ' + packageJSON.version)
|
|
26
24
|
.name(packageJSON.name)
|
|
27
25
|
.option('--browser <browser>', 'Browser or chrome channel to use, possible values: chrome, firefox, webkit, msedge.')
|
|
@@ -36,13 +34,13 @@ commander_1.program
|
|
|
36
34
|
.option('--vision', 'Run server that uses screenshots (Aria snapshots are used by default)')
|
|
37
35
|
.option('--config <path>', 'Path to the configuration file.')
|
|
38
36
|
.action(async (options) => {
|
|
39
|
-
const config = await
|
|
40
|
-
const serverList = new
|
|
37
|
+
const config = await resolveConfig(options);
|
|
38
|
+
const serverList = new ServerList(() => createServer(config));
|
|
41
39
|
setupExitWatchdog(serverList);
|
|
42
40
|
if (options.port)
|
|
43
|
-
|
|
41
|
+
startHttpTransport(+options.port, options.host, serverList);
|
|
44
42
|
else
|
|
45
|
-
await
|
|
43
|
+
await startStdioTransport(serverList);
|
|
46
44
|
});
|
|
47
45
|
function setupExitWatchdog(serverList) {
|
|
48
46
|
const handleExit = async () => {
|
|
@@ -54,4 +52,4 @@ function setupExitWatchdog(serverList) {
|
|
|
54
52
|
process.on('SIGINT', handleExit);
|
|
55
53
|
process.on('SIGTERM', handleExit);
|
|
56
54
|
}
|
|
57
|
-
|
|
55
|
+
program.parse(process.argv);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Copyright (c) Microsoft Corporation.
|
|
4
3
|
*
|
|
@@ -14,4 +13,4 @@
|
|
|
14
13
|
* See the License for the specific language governing permissions and
|
|
15
14
|
* limitations under the License.
|
|
16
15
|
*/
|
|
17
|
-
|
|
16
|
+
export {};
|