playwright 1.56.0-alpha-2025-10-01 → 1.56.0-beta-1759412259000
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/lib/agents/generator.md +3 -3
- package/lib/mcp/browser/context.js +12 -4
- package/lib/mcp/browser/response.js +42 -0
- package/lib/mcp/browser/tools/common.js +2 -2
- package/lib/mcp/browser/tools/dialogs.js +1 -1
- package/lib/mcp/browser/tools/evaluate.js +1 -1
- package/lib/mcp/browser/tools/files.js +1 -1
- package/lib/mcp/browser/tools/form.js +1 -1
- package/lib/mcp/browser/tools/install.js +1 -1
- package/lib/mcp/browser/tools/keyboard.js +2 -2
- package/lib/mcp/browser/tools/mouse.js +3 -3
- package/lib/mcp/browser/tools/navigate.js +2 -2
- package/lib/mcp/browser/tools/screenshot.js +4 -10
- package/lib/mcp/browser/tools/snapshot.js +4 -4
- package/lib/mcp/browser/tools/tabs.js +1 -1
- package/lib/mcp/browser/tools/verify.js +4 -4
- package/lib/mcp/browser/tools/wait.js +1 -1
- package/lib/mcp/program.js +1 -6
- package/lib/mcp/sdk/bundle.js +3 -0
- package/lib/mcp/sdk/mdb.js +42 -67
- package/lib/mcp/sdk/tool.js +9 -4
- package/lib/mcp/test/generatorTools.js +6 -24
- package/lib/mcp/test/plannerTools.js +2 -2
- package/lib/mcp/test/seed.js +1 -2
- package/lib/mcp/test/testBackend.js +9 -7
- package/lib/mcp/test/testContext.js +23 -14
- package/lib/mcpBundleImpl.js +12 -12
- package/lib/program.js +2 -2
- package/package.json +2 -2
- package/lib/mcp/vscode/host.js +0 -187
- package/lib/mcp/vscode/main.js +0 -77
|
@@ -28,7 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
var generatorTools_exports = {};
|
|
30
30
|
__export(generatorTools_exports, {
|
|
31
|
-
generatorLogStep: () => generatorLogStep,
|
|
32
31
|
generatorReadLog: () => generatorReadLog,
|
|
33
32
|
generatorWriteTest: () => generatorWriteTest,
|
|
34
33
|
setupPage: () => setupPage
|
|
@@ -52,27 +51,9 @@ const setupPage = (0, import_testTool.defineTestTool)({
|
|
|
52
51
|
type: "readOnly"
|
|
53
52
|
},
|
|
54
53
|
handle: async (context, params, progress) => {
|
|
55
|
-
const seed = await context.getOrCreateSeedFile(params);
|
|
54
|
+
const seed = await context.getOrCreateSeedFile(params.seedFile, params.project);
|
|
56
55
|
context.generatorJournal = new import_testContext.GeneratorJournal(context.rootPath, params.plan, seed);
|
|
57
|
-
await context.runSeedTest(seed.file,
|
|
58
|
-
return { content: [] };
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
const generatorLogStep = (0, import_testTool.defineTestTool)({
|
|
62
|
-
schema: {
|
|
63
|
-
name: "generator_log_step",
|
|
64
|
-
title: "Log a test step",
|
|
65
|
-
description: "Log a successful test step.",
|
|
66
|
-
inputSchema: import_bundle.z.object({
|
|
67
|
-
title: import_bundle.z.string().describe("Title of the test step"),
|
|
68
|
-
code: import_bundle.z.string().describe("The code for the last step only, as a markdown code block")
|
|
69
|
-
}),
|
|
70
|
-
type: "readOnly"
|
|
71
|
-
},
|
|
72
|
-
handle: async (context, params) => {
|
|
73
|
-
if (!context.generatorJournal)
|
|
74
|
-
throw new Error(`Please setup page using "${setupPage.schema.name}" first.`);
|
|
75
|
-
context.generatorJournal.logStep(params.title, params.code);
|
|
56
|
+
await context.runSeedTest(seed.file, seed.projectName, progress);
|
|
76
57
|
return { content: [] };
|
|
77
58
|
}
|
|
78
59
|
});
|
|
@@ -103,7 +84,7 @@ const generatorWriteTest = (0, import_testTool.defineTestTool)({
|
|
|
103
84
|
fileName: import_bundle.z.string().describe("The file to write the test to"),
|
|
104
85
|
code: import_bundle.z.string().describe("The generated test code")
|
|
105
86
|
}),
|
|
106
|
-
type: "
|
|
87
|
+
type: "readOnly"
|
|
107
88
|
},
|
|
108
89
|
handle: async (context, params) => {
|
|
109
90
|
if (!context.generatorJournal)
|
|
@@ -117,7 +98,9 @@ const generatorWriteTest = (0, import_testTool.defineTestTool)({
|
|
|
117
98
|
const testDir = import_path.default.relative(context.rootPath, project.project.testDir).replace(/\\/g, "/");
|
|
118
99
|
const fileName = params.fileName.replace(/\\/g, "/");
|
|
119
100
|
if (fileName.startsWith(testDir)) {
|
|
120
|
-
|
|
101
|
+
const resolvedFile = import_path.default.resolve(context.rootPath, fileName);
|
|
102
|
+
await import_fs.default.promises.mkdir(import_path.default.dirname(resolvedFile), { recursive: true });
|
|
103
|
+
await import_fs.default.promises.writeFile(resolvedFile, params.code);
|
|
121
104
|
return {
|
|
122
105
|
content: [{
|
|
123
106
|
type: "text",
|
|
@@ -133,7 +116,6 @@ Test written to ${params.fileName}`
|
|
|
133
116
|
});
|
|
134
117
|
// Annotate the CommonJS export names for ESM import in node:
|
|
135
118
|
0 && (module.exports = {
|
|
136
|
-
generatorLogStep,
|
|
137
119
|
generatorReadLog,
|
|
138
120
|
generatorWriteTest,
|
|
139
121
|
setupPage
|
|
@@ -35,8 +35,8 @@ const setupPage = (0, import_testTool.defineTestTool)({
|
|
|
35
35
|
type: "readOnly"
|
|
36
36
|
},
|
|
37
37
|
handle: async (context, params, progress) => {
|
|
38
|
-
const seed = await context.getOrCreateSeedFile(params);
|
|
39
|
-
await context.runSeedTest(seed.file,
|
|
38
|
+
const seed = await context.getOrCreateSeedFile(params.seedFile, params.project);
|
|
39
|
+
await context.runSeedTest(seed.file, seed.projectName, progress);
|
|
40
40
|
return { content: [] };
|
|
41
41
|
}
|
|
42
42
|
});
|
package/lib/mcp/test/seed.js
CHANGED
|
@@ -44,8 +44,7 @@ function seedProject(config, projectName) {
|
|
|
44
44
|
throw new Error(`Project ${projectName} not found`);
|
|
45
45
|
return project;
|
|
46
46
|
}
|
|
47
|
-
async function ensureSeedTest(
|
|
48
|
-
const project = seedProject(config, projectName);
|
|
47
|
+
async function ensureSeedTest(project, logNew) {
|
|
49
48
|
const files = await (0, import_projectUtils.collectFilesForProject)(project);
|
|
50
49
|
const seed = files.find((file) => import_path.default.basename(file).includes("seed"));
|
|
51
50
|
if (seed)
|
|
@@ -38,6 +38,7 @@ var generatorTools = __toESM(require("./generatorTools.js"));
|
|
|
38
38
|
var plannerTools = __toESM(require("./plannerTools.js"));
|
|
39
39
|
var import_tools = require("../browser/tools");
|
|
40
40
|
var import_configLoader = require("../../common/configLoader");
|
|
41
|
+
var import_response = require("../browser/response");
|
|
41
42
|
class TestServerBackend {
|
|
42
43
|
constructor(configOption, options) {
|
|
43
44
|
this.name = "Playwright";
|
|
@@ -45,7 +46,6 @@ class TestServerBackend {
|
|
|
45
46
|
this._tools = [
|
|
46
47
|
plannerTools.setupPage,
|
|
47
48
|
generatorTools.setupPage,
|
|
48
|
-
generatorTools.generatorLogStep,
|
|
49
49
|
generatorTools.generatorReadLog,
|
|
50
50
|
generatorTools.generatorWriteTest,
|
|
51
51
|
testTools.listTests,
|
|
@@ -55,11 +55,6 @@ class TestServerBackend {
|
|
|
55
55
|
this._context = new import_testContext.TestContext(options);
|
|
56
56
|
this._configOption = configOption;
|
|
57
57
|
}
|
|
58
|
-
static {
|
|
59
|
-
this.allowedOnPause = [
|
|
60
|
-
generatorTools.generatorLogStep.schema.name
|
|
61
|
-
];
|
|
62
|
-
}
|
|
63
58
|
async initialize(server, clientInfo) {
|
|
64
59
|
const rootPath = mcp.firstRootPath(clientInfo);
|
|
65
60
|
if (this._configOption) {
|
|
@@ -75,9 +70,16 @@ class TestServerBackend {
|
|
|
75
70
|
async listTools() {
|
|
76
71
|
return [
|
|
77
72
|
...this._tools.map((tool) => mcp.toMcpTool(tool.schema)),
|
|
78
|
-
...import_tools.browserTools.map((tool) => mcp.toMcpTool(tool.schema))
|
|
73
|
+
...import_tools.browserTools.map((tool) => mcp.toMcpTool(tool.schema, { addIntent: true }))
|
|
79
74
|
];
|
|
80
75
|
}
|
|
76
|
+
async afterCallTool(name, args, result) {
|
|
77
|
+
if (!import_tools.browserTools.find((tool) => tool.schema.name === name))
|
|
78
|
+
return;
|
|
79
|
+
const response = (0, import_response.parseResponse)(result);
|
|
80
|
+
if (response && !response.isError && response.code && typeof args?.["intent"] === "string")
|
|
81
|
+
this._context.generatorJournal?.logStep(args["intent"], response.code);
|
|
82
|
+
}
|
|
81
83
|
async callTool(name, args, progress) {
|
|
82
84
|
const tool = this._tools.find((tool2) => tool2.schema.name === name);
|
|
83
85
|
if (!tool)
|
|
@@ -49,7 +49,8 @@ class GeneratorJournal {
|
|
|
49
49
|
this._steps = [];
|
|
50
50
|
}
|
|
51
51
|
logStep(title, code) {
|
|
52
|
-
|
|
52
|
+
if (title)
|
|
53
|
+
this._steps.push({ title, code });
|
|
53
54
|
}
|
|
54
55
|
journal() {
|
|
55
56
|
const result = [];
|
|
@@ -61,7 +62,9 @@ class GeneratorJournal {
|
|
|
61
62
|
result.push("```");
|
|
62
63
|
result.push(`# Steps`);
|
|
63
64
|
result.push(this._steps.map((step) => `### ${step.title}
|
|
64
|
-
|
|
65
|
+
\`\`\`ts
|
|
66
|
+
${step.code}
|
|
67
|
+
\`\`\``).join("\n\n"));
|
|
65
68
|
return result.join("\n\n");
|
|
66
69
|
}
|
|
67
70
|
}
|
|
@@ -88,30 +91,36 @@ class TestContext {
|
|
|
88
91
|
this._testRunner = testRunner;
|
|
89
92
|
return testRunner;
|
|
90
93
|
}
|
|
91
|
-
async getOrCreateSeedFile(
|
|
94
|
+
async getOrCreateSeedFile(seedFile, projectName) {
|
|
92
95
|
const configDir = this.configLocation.configDir;
|
|
93
96
|
const testRunner = await this.createTestRunner();
|
|
94
97
|
const config = await testRunner.loadConfig();
|
|
95
|
-
|
|
96
|
-
if (!
|
|
97
|
-
seedFile = await (0, import_seed.ensureSeedTest)(
|
|
98
|
+
const project = (0, import_seed.seedProject)(config, projectName);
|
|
99
|
+
if (!seedFile) {
|
|
100
|
+
seedFile = await (0, import_seed.ensureSeedTest)(project, false);
|
|
98
101
|
} else {
|
|
99
102
|
const candidateFiles = [];
|
|
100
|
-
const testDir =
|
|
101
|
-
candidateFiles.push(import_path.default.resolve(testDir,
|
|
102
|
-
candidateFiles.push(import_path.default.resolve(configDir,
|
|
103
|
-
candidateFiles.push(import_path.default.resolve(this.rootPath,
|
|
103
|
+
const testDir = project.project.testDir;
|
|
104
|
+
candidateFiles.push(import_path.default.resolve(testDir, seedFile));
|
|
105
|
+
candidateFiles.push(import_path.default.resolve(configDir, seedFile));
|
|
106
|
+
candidateFiles.push(import_path.default.resolve(this.rootPath, seedFile));
|
|
107
|
+
let resolvedSeedFile;
|
|
104
108
|
for (const candidateFile of candidateFiles) {
|
|
105
109
|
if (await (0, import_util.fileExistsAsync)(candidateFile)) {
|
|
106
|
-
|
|
110
|
+
resolvedSeedFile = candidateFile;
|
|
107
111
|
break;
|
|
108
112
|
}
|
|
109
113
|
}
|
|
110
|
-
if (!
|
|
114
|
+
if (!resolvedSeedFile)
|
|
111
115
|
throw new Error("seed test not found.");
|
|
116
|
+
seedFile = resolvedSeedFile;
|
|
112
117
|
}
|
|
113
118
|
const seedFileContent = await import_fs.default.promises.readFile(seedFile, "utf8");
|
|
114
|
-
return {
|
|
119
|
+
return {
|
|
120
|
+
file: seedFile,
|
|
121
|
+
content: seedFileContent,
|
|
122
|
+
projectName: project.project.name
|
|
123
|
+
};
|
|
115
124
|
}
|
|
116
125
|
async runSeedTest(seedFile, projectName, progress) {
|
|
117
126
|
const { screen } = this.createScreen(progress);
|
|
@@ -121,7 +130,7 @@ class TestContext {
|
|
|
121
130
|
const result = await testRunner.runTests(reporter, {
|
|
122
131
|
headed: !this.options?.headless,
|
|
123
132
|
locations: ["/" + (0, import_utils.escapeRegExp)(seedFile) + "/"],
|
|
124
|
-
projects:
|
|
133
|
+
projects: [projectName],
|
|
125
134
|
timeout: 0,
|
|
126
135
|
workers: 1,
|
|
127
136
|
pauseAtEnd: true,
|