playwright 1.56.0-alpha-1757464324000 → 1.56.0-alpha-2025-09-11
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 +2 -2
- package/lib/agents/fixer.md +80 -0
- package/lib/agents/generateAgents.js +203 -0
- package/lib/agents/generator.md +90 -0
- package/lib/agents/planner.md +88 -0
- package/lib/common/expectBundle.js +3 -0
- package/lib/common/expectBundleImpl.js +45 -45
- package/lib/index.js +2 -1
- package/lib/matchers/expect.js +1 -2
- package/lib/matchers/matcherHint.js +42 -15
- package/lib/matchers/matchers.js +12 -6
- package/lib/matchers/toBeTruthy.js +16 -13
- package/lib/matchers/toEqual.js +16 -14
- package/lib/matchers/toHaveURL.js +12 -27
- package/lib/matchers/toMatchAriaSnapshot.js +26 -27
- package/lib/matchers/toMatchSnapshot.js +5 -7
- package/lib/matchers/toMatchText.js +30 -33
- package/lib/mcp/browser/browserServerBackend.js +0 -1
- package/lib/mcp/browser/config.js +2 -0
- package/lib/mcp/browser/context.js +0 -1
- package/lib/mcp/browser/tab.js +6 -6
- package/lib/mcp/browser/tools/files.js +3 -2
- package/lib/mcp/browser/tools/snapshot.js +16 -1
- package/lib/mcp/browser/tools/tool.js +1 -1
- package/lib/mcp/browser/tools/verify.js +4 -4
- package/lib/mcp/browser/tools.js +4 -4
- package/lib/mcp/test/browserBackend.js +19 -42
- package/lib/mcp/test/testBackend.js +2 -4
- package/lib/program.js +14 -0
- package/lib/util.js +0 -10
- package/package.json +2 -2
- package/lib/mcp/test/browserTool.js +0 -30
- package/lib/mcp/test/browserTools.js +0 -120
|
@@ -30,7 +30,7 @@ const uploadFile = (0, import_tool.defineTabTool)({
|
|
|
30
30
|
title: "Upload files",
|
|
31
31
|
description: "Upload one or multiple files",
|
|
32
32
|
inputSchema: import_bundle.z.object({
|
|
33
|
-
paths: import_bundle.z.array(import_bundle.z.string()).describe("The absolute paths to the files to upload. Can be
|
|
33
|
+
paths: import_bundle.z.array(import_bundle.z.string()).optional().describe("The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.")
|
|
34
34
|
}),
|
|
35
35
|
type: "destructive"
|
|
36
36
|
},
|
|
@@ -42,7 +42,8 @@ const uploadFile = (0, import_tool.defineTabTool)({
|
|
|
42
42
|
response.addCode(`await fileChooser.setFiles(${JSON.stringify(params.paths)})`);
|
|
43
43
|
tab.clearModalState(modalState);
|
|
44
44
|
await tab.waitForCompletion(async () => {
|
|
45
|
-
|
|
45
|
+
if (params.paths)
|
|
46
|
+
await modalState.fileChooser.setFiles(params.paths);
|
|
46
47
|
});
|
|
47
48
|
},
|
|
48
49
|
clearsModalState: "fileChooser"
|
|
@@ -154,12 +154,27 @@ const selectOption = (0, import_tool.defineTabTool)({
|
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
});
|
|
157
|
+
const pickLocator = (0, import_tool.defineTabTool)({
|
|
158
|
+
capability: "testing",
|
|
159
|
+
schema: {
|
|
160
|
+
name: "browser_generate_locator",
|
|
161
|
+
title: "Create locator for element",
|
|
162
|
+
description: "Generate locator for the given element to use in tests",
|
|
163
|
+
inputSchema: elementSchema,
|
|
164
|
+
type: "readOnly"
|
|
165
|
+
},
|
|
166
|
+
handle: async (tab, params, response) => {
|
|
167
|
+
const locator = await tab.refLocator(params);
|
|
168
|
+
response.addResult(await (0, import_utils.generateLocator)(locator));
|
|
169
|
+
}
|
|
170
|
+
});
|
|
157
171
|
var snapshot_default = [
|
|
158
172
|
snapshot,
|
|
159
173
|
click,
|
|
160
174
|
drag,
|
|
161
175
|
hover,
|
|
162
|
-
selectOption
|
|
176
|
+
selectOption,
|
|
177
|
+
pickLocator
|
|
163
178
|
];
|
|
164
179
|
// Annotate the CommonJS export names for ESM import in node:
|
|
165
180
|
0 && (module.exports = {
|
|
@@ -29,7 +29,7 @@ function defineTabTool(tool) {
|
|
|
29
29
|
return {
|
|
30
30
|
...tool,
|
|
31
31
|
handle: async (context, params, response) => {
|
|
32
|
-
const tab = context.
|
|
32
|
+
const tab = await context.ensureTab();
|
|
33
33
|
const modalStates = tab.modalStates().map((state) => state.type);
|
|
34
34
|
if (tool.clearsModalState && !modalStates.includes(tool.clearsModalState))
|
|
35
35
|
response.addError(`Error: The tool "${tool.schema.name}" can only be used when there is related modal state present.
|
|
@@ -36,7 +36,7 @@ var import_tool = require("./tool");
|
|
|
36
36
|
var javascript = __toESM(require("../codegen"));
|
|
37
37
|
var import_utils = require("./utils");
|
|
38
38
|
const verifyElement = (0, import_tool.defineTabTool)({
|
|
39
|
-
capability: "
|
|
39
|
+
capability: "testing",
|
|
40
40
|
schema: {
|
|
41
41
|
name: "browser_verify_element_visible",
|
|
42
42
|
title: "Verify element visible",
|
|
@@ -58,7 +58,7 @@ const verifyElement = (0, import_tool.defineTabTool)({
|
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
const verifyText = (0, import_tool.defineTabTool)({
|
|
61
|
-
capability: "
|
|
61
|
+
capability: "testing",
|
|
62
62
|
schema: {
|
|
63
63
|
name: "browser_verify_text_visible",
|
|
64
64
|
title: "Verify text visible",
|
|
@@ -79,7 +79,7 @@ const verifyText = (0, import_tool.defineTabTool)({
|
|
|
79
79
|
}
|
|
80
80
|
});
|
|
81
81
|
const verifyList = (0, import_tool.defineTabTool)({
|
|
82
|
-
capability: "
|
|
82
|
+
capability: "testing",
|
|
83
83
|
schema: {
|
|
84
84
|
name: "browser_verify_list_visible",
|
|
85
85
|
title: "Verify list visible",
|
|
@@ -111,7 +111,7 @@ ${itemTexts.map((t) => ` - listitem: ${javascript.escapeWithQuotes(t, '"')}`).j
|
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
113
|
const verifyValue = (0, import_tool.defineTabTool)({
|
|
114
|
-
capability: "
|
|
114
|
+
capability: "testing",
|
|
115
115
|
schema: {
|
|
116
116
|
name: "browser_verify_value",
|
|
117
117
|
title: "Verify value",
|
package/lib/mcp/browser/tools.js
CHANGED
|
@@ -28,7 +28,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var tools_exports = {};
|
|
30
30
|
__export(tools_exports, {
|
|
31
|
-
|
|
31
|
+
browserTools: () => browserTools,
|
|
32
32
|
filteredTools: () => filteredTools
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(tools_exports);
|
|
@@ -50,7 +50,7 @@ var import_tabs = __toESM(require("./tools/tabs"));
|
|
|
50
50
|
var import_tracing = __toESM(require("./tools/tracing"));
|
|
51
51
|
var import_wait = __toESM(require("./tools/wait"));
|
|
52
52
|
var import_verify = __toESM(require("./tools/verify"));
|
|
53
|
-
const
|
|
53
|
+
const browserTools = [
|
|
54
54
|
...import_common.default,
|
|
55
55
|
...import_console.default,
|
|
56
56
|
...import_dialogs.default,
|
|
@@ -71,10 +71,10 @@ const allTools = [
|
|
|
71
71
|
...import_verify.default
|
|
72
72
|
];
|
|
73
73
|
function filteredTools(config) {
|
|
74
|
-
return
|
|
74
|
+
return browserTools.filter((tool) => tool.capability.startsWith("core") || config.capabilities?.includes(tool.capability));
|
|
75
75
|
}
|
|
76
76
|
// Annotate the CommonJS export names for ESM import in node:
|
|
77
77
|
0 && (module.exports = {
|
|
78
|
-
|
|
78
|
+
browserTools,
|
|
79
79
|
filteredTools
|
|
80
80
|
});
|
|
@@ -28,66 +28,43 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var browserBackend_exports = {};
|
|
30
30
|
__export(browserBackend_exports, {
|
|
31
|
-
BrowserBackend: () => BrowserBackend,
|
|
32
31
|
runBrowserBackendOnError: () => runBrowserBackendOnError
|
|
33
32
|
});
|
|
34
33
|
module.exports = __toCommonJS(browserBackend_exports);
|
|
35
34
|
var mcp = __toESM(require("../sdk/exports"));
|
|
36
|
-
var mcpBundle = __toESM(require("../sdk/bundle"));
|
|
37
35
|
var import_globals = require("../../common/globals");
|
|
38
|
-
var import_browserTools = require("./browserTools");
|
|
39
36
|
var import_util = require("../../util");
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
constructor(page) {
|
|
43
|
-
this.name = "Playwright";
|
|
44
|
-
this.version = "0.0.1";
|
|
45
|
-
this._tools = tools;
|
|
46
|
-
this._page = page;
|
|
47
|
-
}
|
|
48
|
-
async initialize() {
|
|
49
|
-
}
|
|
50
|
-
async listTools() {
|
|
51
|
-
return [...this._tools.map((tool) => mcp.toMcpTool(tool.schema)), mcp.toMcpTool(doneToolSchema)];
|
|
52
|
-
}
|
|
53
|
-
async callTool(name, args) {
|
|
54
|
-
if (name === "done") {
|
|
55
|
-
this.requestSelfDestruct?.();
|
|
56
|
-
return {
|
|
57
|
-
content: [{ type: "text", text: "Done" }]
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const tool = this._tools.find((tool2) => tool2.schema.name === name);
|
|
61
|
-
if (!tool)
|
|
62
|
-
throw new Error(`Tool not found: ${name}. Available tools: ${this._tools.map((tool2) => tool2.schema.name).join(", ")}`);
|
|
63
|
-
const parsedArguments = tool.schema.inputSchema.parse(args || {});
|
|
64
|
-
return await tool.handle(this._page, parsedArguments);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const doneToolSchema = mcp.defineToolSchema({
|
|
68
|
-
name: "done",
|
|
69
|
-
title: "Done",
|
|
70
|
-
description: "Done",
|
|
71
|
-
inputSchema: mcpBundle.z.object({}),
|
|
72
|
-
type: "destructive"
|
|
73
|
-
});
|
|
37
|
+
var import_config = require("../browser/config");
|
|
38
|
+
var import_browserServerBackend = require("../browser/browserServerBackend");
|
|
74
39
|
async function runBrowserBackendOnError(page, message) {
|
|
75
40
|
const testInfo = (0, import_globals.currentTestInfo)();
|
|
76
41
|
if (!testInfo || !testInfo._pauseOnError())
|
|
77
42
|
return;
|
|
78
|
-
const
|
|
43
|
+
const browserContextFactory = {
|
|
44
|
+
createContext: async (clientInfo, abortSignal, toolName) => {
|
|
45
|
+
return {
|
|
46
|
+
browserContext: page.context(),
|
|
47
|
+
close: async () => {
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const config = {
|
|
53
|
+
...import_config.defaultConfig,
|
|
54
|
+
capabilities: ["testing"]
|
|
55
|
+
};
|
|
56
|
+
const snapshot = await page._snapshotForAI();
|
|
79
57
|
const introMessage = `### Paused on error:
|
|
80
58
|
${(0, import_util.stripAnsiEscapes)(message())}
|
|
81
59
|
|
|
82
60
|
### Current page snapshot:
|
|
83
|
-
${
|
|
61
|
+
${snapshot}
|
|
84
62
|
|
|
85
63
|
### Task
|
|
86
|
-
Try recovering from the error prior to continuing
|
|
87
|
-
await mcp.runOnPauseBackendLoop(new
|
|
64
|
+
Try recovering from the error prior to continuing`;
|
|
65
|
+
await mcp.runOnPauseBackendLoop(new import_browserServerBackend.BrowserServerBackend(config, browserContextFactory), introMessage);
|
|
88
66
|
}
|
|
89
67
|
// Annotate the CommonJS export names for ESM import in node:
|
|
90
68
|
0 && (module.exports = {
|
|
91
|
-
BrowserBackend,
|
|
92
69
|
runBrowserBackendOnError
|
|
93
70
|
});
|
|
@@ -34,7 +34,7 @@ module.exports = __toCommonJS(testBackend_exports);
|
|
|
34
34
|
var mcp = __toESM(require("../sdk/exports"));
|
|
35
35
|
var import_testContext = require("./testContext");
|
|
36
36
|
var import_testTools = require("./testTools.js");
|
|
37
|
-
var
|
|
37
|
+
var import_tools = require("../browser/tools");
|
|
38
38
|
class TestServerBackend {
|
|
39
39
|
constructor(resolvedLocation, options) {
|
|
40
40
|
this.name = "Playwright";
|
|
@@ -45,9 +45,7 @@ class TestServerBackend {
|
|
|
45
45
|
async listTools() {
|
|
46
46
|
return [
|
|
47
47
|
...this._tools.map((tool) => mcp.toMcpTool(tool.schema)),
|
|
48
|
-
mcp.toMcpTool(
|
|
49
|
-
mcp.toMcpTool(import_browserTools.pickLocator.schema),
|
|
50
|
-
mcp.toMcpTool(import_browserTools.evaluate.schema)
|
|
48
|
+
...import_tools.browserTools.map((tool) => mcp.toMcpTool(tool.schema))
|
|
51
49
|
];
|
|
52
50
|
}
|
|
53
51
|
async callTool(name, args) {
|
package/lib/program.js
CHANGED
|
@@ -49,6 +49,7 @@ var import_reporters = require("./runner/reporters");
|
|
|
49
49
|
var import_exports = require("./mcp/sdk/exports");
|
|
50
50
|
var import_testBackend = require("./mcp/test/testBackend");
|
|
51
51
|
var import_program3 = require("./mcp/program");
|
|
52
|
+
var import_generateAgents = require("./agents/generateAgents");
|
|
52
53
|
const packageJSON = require("../package.json");
|
|
53
54
|
function addTestCommand(program3) {
|
|
54
55
|
const command = program3.command("test [test-filter...]");
|
|
@@ -168,6 +169,18 @@ function addTestMCPServerCommand(program3) {
|
|
|
168
169
|
console.error("MCP Listening on: ", mdbUrl);
|
|
169
170
|
});
|
|
170
171
|
}
|
|
172
|
+
function addInitAgentsCommand(program3) {
|
|
173
|
+
const command = program3.command("init-agents", { hidden: true });
|
|
174
|
+
command.description("Initialize repository agents for the Claude Code");
|
|
175
|
+
command.option("--claude", "Initialize repository agents for the Claude Code");
|
|
176
|
+
command.option("--opencode", "Initialize repository agents for the Opencode");
|
|
177
|
+
command.action(async (opts) => {
|
|
178
|
+
if (opts.opencode)
|
|
179
|
+
await (0, import_generateAgents.initOpencodeRepo)();
|
|
180
|
+
else
|
|
181
|
+
await (0, import_generateAgents.initClaudeCodeRepo)();
|
|
182
|
+
});
|
|
183
|
+
}
|
|
171
184
|
async function runTests(args, opts) {
|
|
172
185
|
await (0, import_utils.startProfiling)();
|
|
173
186
|
const cliOverrides = overridesFromOptions(opts);
|
|
@@ -371,6 +384,7 @@ addBrowserMCPServerCommand(import_program.program);
|
|
|
371
384
|
addTestMCPServerCommand(import_program.program);
|
|
372
385
|
addDevServerCommand(import_program.program);
|
|
373
386
|
addTestServerCommand(import_program.program);
|
|
387
|
+
addInitAgentsCommand(import_program.program);
|
|
374
388
|
// Annotate the CommonJS export names for ESM import in node:
|
|
375
389
|
0 && (module.exports = {
|
|
376
390
|
program
|
package/lib/util.js
CHANGED
|
@@ -30,7 +30,6 @@ var util_exports = {};
|
|
|
30
30
|
__export(util_exports, {
|
|
31
31
|
addSuffixToFilePath: () => addSuffixToFilePath,
|
|
32
32
|
ansiRegex: () => ansiRegex,
|
|
33
|
-
callLogText: () => callLogText,
|
|
34
33
|
createFileFiltersFromArguments: () => createFileFiltersFromArguments,
|
|
35
34
|
createFileMatcher: () => createFileMatcher,
|
|
36
35
|
createFileMatcherFromArguments: () => createFileMatcherFromArguments,
|
|
@@ -227,14 +226,6 @@ function getContainedPath(parentPath, subPath = "") {
|
|
|
227
226
|
return null;
|
|
228
227
|
}
|
|
229
228
|
const debugTest = (0, import_utilsBundle.debug)("pw:test");
|
|
230
|
-
const callLogText = (log) => {
|
|
231
|
-
if (!log || !log.some((l) => !!l))
|
|
232
|
-
return "";
|
|
233
|
-
return `
|
|
234
|
-
Call log:
|
|
235
|
-
${import_utilsBundle.colors.dim(log.join("\n"))}
|
|
236
|
-
`;
|
|
237
|
-
};
|
|
238
229
|
const folderToPackageJsonPath = /* @__PURE__ */ new Map();
|
|
239
230
|
function getPackageJsonPath(folderPath) {
|
|
240
231
|
const cached = folderToPackageJsonPath.get(folderPath);
|
|
@@ -376,7 +367,6 @@ function stripAnsiEscapes(str) {
|
|
|
376
367
|
0 && (module.exports = {
|
|
377
368
|
addSuffixToFilePath,
|
|
378
369
|
ansiRegex,
|
|
379
|
-
callLogText,
|
|
380
370
|
createFileFiltersFromArguments,
|
|
381
371
|
createFileMatcher,
|
|
382
372
|
createFileMatcherFromArguments,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playwright",
|
|
3
|
-
"version": "1.56.0-alpha-
|
|
3
|
+
"version": "1.56.0-alpha-2025-09-11",
|
|
4
4
|
"description": "A high-level API to automate web browsers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"license": "Apache-2.0",
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"playwright-core": "1.56.0-alpha-
|
|
67
|
+
"playwright-core": "1.56.0-alpha-2025-09-11"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
70
|
"fsevents": "2.3.2"
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var browserTool_exports = {};
|
|
20
|
-
__export(browserTool_exports, {
|
|
21
|
-
defineBrowserTool: () => defineBrowserTool
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(browserTool_exports);
|
|
24
|
-
function defineBrowserTool(tool) {
|
|
25
|
-
return tool;
|
|
26
|
-
}
|
|
27
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
28
|
-
0 && (module.exports = {
|
|
29
|
-
defineBrowserTool
|
|
30
|
-
});
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var browserTools_exports = {};
|
|
30
|
-
__export(browserTools_exports, {
|
|
31
|
-
elementSchema: () => elementSchema,
|
|
32
|
-
evaluate: () => evaluate,
|
|
33
|
-
pickLocator: () => pickLocator,
|
|
34
|
-
snapshot: () => snapshot
|
|
35
|
-
});
|
|
36
|
-
module.exports = __toCommonJS(browserTools_exports);
|
|
37
|
-
var import_utils = require("playwright-core/lib/utils");
|
|
38
|
-
var import_browserTool = require("./browserTool.js");
|
|
39
|
-
var mcpBundle = __toESM(require("../sdk/bundle"));
|
|
40
|
-
const { z } = mcpBundle;
|
|
41
|
-
const snapshot = (0, import_browserTool.defineBrowserTool)({
|
|
42
|
-
schema: {
|
|
43
|
-
name: "playwright_test_browser_snapshot",
|
|
44
|
-
title: "Capture page snapshot",
|
|
45
|
-
description: "Capture page snapshot for debugging",
|
|
46
|
-
inputSchema: z.object({}),
|
|
47
|
-
type: "readOnly"
|
|
48
|
-
},
|
|
49
|
-
handle: async (page, params) => {
|
|
50
|
-
const snapshot2 = await page._snapshotForAI();
|
|
51
|
-
return {
|
|
52
|
-
content: [
|
|
53
|
-
{
|
|
54
|
-
type: "text",
|
|
55
|
-
text: snapshot2
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
const elementSchema = z.object({
|
|
62
|
-
element: z.string().describe("Human-readable element description used to obtain permission to interact with the element"),
|
|
63
|
-
ref: z.string().describe("Exact target element reference from the page snapshot")
|
|
64
|
-
});
|
|
65
|
-
const pickLocator = (0, import_browserTool.defineBrowserTool)({
|
|
66
|
-
schema: {
|
|
67
|
-
name: "playwright_test_generate_locator",
|
|
68
|
-
title: "Create locator for element",
|
|
69
|
-
description: "Generate locator for the given element to use in tests",
|
|
70
|
-
inputSchema: elementSchema,
|
|
71
|
-
type: "readOnly"
|
|
72
|
-
},
|
|
73
|
-
handle: async (page, params) => {
|
|
74
|
-
const locator = await refLocator(page, params);
|
|
75
|
-
try {
|
|
76
|
-
const { resolvedSelector } = await locator._resolveSelector();
|
|
77
|
-
const locatorString = (0, import_utils.asLocator)("javascript", resolvedSelector);
|
|
78
|
-
return { content: [{ type: "text", text: locatorString }] };
|
|
79
|
-
} catch (e) {
|
|
80
|
-
throw new Error(`Ref not found, likely because element was removed. Use ${snapshot.schema.name} to see what elements are currently on the page.`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
const evaluateSchema = z.object({
|
|
85
|
-
function: z.string().describe("() => { /* code */ } or (element) => { /* code */ } when element is provided"),
|
|
86
|
-
element: z.string().optional().describe("Human-readable element description used to obtain permission to interact with the element"),
|
|
87
|
-
ref: z.string().optional().describe("Exact target element reference from the page snapshot")
|
|
88
|
-
});
|
|
89
|
-
const evaluate = (0, import_browserTool.defineBrowserTool)({
|
|
90
|
-
schema: {
|
|
91
|
-
name: "playwright_test_evaluate_on_pause",
|
|
92
|
-
title: "Evaluate in page",
|
|
93
|
-
description: "Evaluate JavaScript expression on page or element",
|
|
94
|
-
inputSchema: evaluateSchema,
|
|
95
|
-
type: "destructive"
|
|
96
|
-
},
|
|
97
|
-
handle: async (page, params) => {
|
|
98
|
-
let locator;
|
|
99
|
-
if (params.ref && params.element)
|
|
100
|
-
locator = await refLocator(page, { ref: params.ref, element: params.element });
|
|
101
|
-
const receiver = locator ?? page;
|
|
102
|
-
const result = await receiver._evaluateFunction(params.function);
|
|
103
|
-
return {
|
|
104
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) || "undefined" }]
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
async function refLocator(page, elementRef) {
|
|
109
|
-
const snapshot2 = await page._snapshotForAI();
|
|
110
|
-
if (!snapshot2.includes(`[ref=${elementRef.ref}]`))
|
|
111
|
-
throw new Error(`Ref ${elementRef.ref} not found in the current page snapshot. Try capturing new snapshot.`);
|
|
112
|
-
return page.locator(`aria-ref=${elementRef.ref}`).describe(elementRef.element);
|
|
113
|
-
}
|
|
114
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
115
|
-
0 && (module.exports = {
|
|
116
|
-
elementSchema,
|
|
117
|
-
evaluate,
|
|
118
|
-
pickLocator,
|
|
119
|
-
snapshot
|
|
120
|
-
});
|