playwright 1.57.0-alpha-2025-10-27 → 1.57.0-alpha-2025-10-29

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,34 @@
1
+ name: "Copilot Setup Steps"
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ push:
6
+ paths:
7
+ - .github/workflows/copilot-setup-steps.yml
8
+ pull_request:
9
+ paths:
10
+ - .github/workflows/copilot-setup-steps.yml
11
+
12
+ jobs:
13
+ copilot-setup-steps:
14
+ runs-on: ubuntu-latest
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: actions/setup-node@v4
23
+ with:
24
+ node-version: lts/*
25
+
26
+ - name: Install dependencies
27
+ run: npm ci
28
+
29
+ - name: Install Playwright Browsers
30
+ run: npx playwright install --with-deps
31
+
32
+ # Customize this step as needed
33
+ - name: Build application
34
+ run: npx run build
@@ -28,8 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var generateAgents_exports = {};
30
30
  __export(generateAgents_exports, {
31
- AgentGenerator: () => AgentGenerator,
32
31
  ClaudeGenerator: () => ClaudeGenerator,
32
+ CopilotGenerator: () => CopilotGenerator,
33
33
  OpencodeGenerator: () => OpencodeGenerator,
34
34
  VSCodeGenerator: () => VSCodeGenerator
35
35
  });
@@ -48,7 +48,7 @@ class AgentParser {
48
48
  const source = await import_fs.default.promises.readFile(filePath, "utf-8");
49
49
  const { header, content } = this.extractYamlAndContent(source);
50
50
  const { instructions, examples } = this.extractInstructionsAndExamples(content);
51
- return { source, header, instructions, examples };
51
+ return { header, instructions, examples };
52
52
  }
53
53
  static extractYamlAndContent(markdown) {
54
54
  const lines = markdown.split("\n");
@@ -92,14 +92,17 @@ class AgentParser {
92
92
  }
93
93
  }
94
94
  class ClaudeGenerator {
95
- static async init(config, projectName) {
95
+ static async init(config, projectName, prompts) {
96
96
  await initRepo(config, projectName, {
97
- promptsFolder: ".claude/prompts"
97
+ promptsFolder: prompts ? ".claude/prompts" : void 0
98
98
  });
99
99
  const agents = await AgentParser.loadAgents();
100
100
  await import_fs.default.promises.mkdir(".claude/agents", { recursive: true });
101
101
  for (const agent of agents)
102
- await writeFile(`.claude/agents/${agent.header.name}.agent.md`, ClaudeGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
102
+ await writeFile(`.claude/agents/${agent.header.name}.md`, ClaudeGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
103
+ await deleteFile(`.claude/agents/playwright-test-planner.md`, "legacy planner agent");
104
+ await deleteFile(`.claude/agents/playwright-test-generator.md`, "legacy generator agent");
105
+ await deleteFile(`.claude/agents/playwright-test-healer.md`, "legacy healer agent");
103
106
  await writeFile(".mcp.json", JSON.stringify({
104
107
  mcpServers: {
105
108
  "playwright-test": {
@@ -112,10 +115,8 @@ class ClaudeGenerator {
112
115
  }
113
116
  static agentSpec(agent) {
114
117
  const claudeToolMap = /* @__PURE__ */ new Map([
115
- ["search", ["Glob", "Grep"]],
116
- ["read", ["Read"]],
117
- ["edit", ["Edit", "MultiEdit"]],
118
- ["write", ["Write"]]
118
+ ["search", ["Glob", "Grep", "Read", "LS"]],
119
+ ["edit", ["Edit", "MultiEdit", "Write"]]
119
120
  ]);
120
121
  function asClaudeTool(tool) {
121
122
  const [first, second] = tool.split("/");
@@ -123,41 +124,45 @@ class ClaudeGenerator {
123
124
  return (claudeToolMap.get(first) || [first]).join(", ");
124
125
  return `mcp__${first}__${second}`;
125
126
  }
127
+ const examples = agent.examples.length ? ` Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}` : "";
126
128
  const lines = [];
129
+ const header = {
130
+ name: agent.header.name,
131
+ description: agent.header.description + examples,
132
+ tools: agent.header.tools.map((tool) => asClaudeTool(tool)).join(", "),
133
+ model: agent.header.model,
134
+ color: agent.header.color
135
+ };
127
136
  lines.push(`---`);
128
- lines.push(`name: ${agent.header.name}`);
129
- lines.push(`description: ${agent.header.description}. Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}`);
130
- lines.push(`tools: ${agent.header.tools.map((tool) => asClaudeTool(tool)).join(", ")}`);
131
- lines.push(`model: ${agent.header.model}`);
132
- lines.push(`color: ${agent.header.color}`);
133
- lines.push(`---`);
137
+ lines.push(import_utilsBundle.yaml.stringify(header, { lineWidth: 1e5 }) + `---`);
134
138
  lines.push("");
135
139
  lines.push(agent.instructions);
136
140
  return lines.join("\n");
137
141
  }
138
142
  }
139
143
  class OpencodeGenerator {
140
- static async init(config, projectName) {
144
+ static async init(config, projectName, prompts) {
141
145
  await initRepo(config, projectName, {
142
- agentDefault: "Build",
143
- promptsFolder: ".opencode/prompts"
146
+ defaultAgentName: "Build",
147
+ promptsFolder: prompts ? ".opencode/prompts" : void 0
144
148
  });
145
149
  const agents = await AgentParser.loadAgents();
146
150
  for (const agent of agents) {
147
151
  const prompt = [agent.instructions];
148
152
  prompt.push("");
149
153
  prompt.push(...agent.examples.map((example) => `<example>${example}</example>`));
150
- await writeFile(`.opencode/prompts/${agent.header.name}.agent.md`, prompt.join("\n"), "\u{1F916}", "agent definition");
154
+ await writeFile(`.opencode/prompts/${agent.header.name}.md`, prompt.join("\n"), "\u{1F916}", "agent definition");
151
155
  }
156
+ await deleteFile(`.opencode/prompts/playwright-test-planner.md`, "legacy planner agent");
157
+ await deleteFile(`.opencode/prompts/playwright-test-generator.md`, "legacy generator agent");
158
+ await deleteFile(`.opencode/prompts/playwright-test-healer.md`, "legacy healer agent");
152
159
  await writeFile("opencode.json", OpencodeGenerator.configuration(agents), "\u{1F527}", "opencode configuration");
153
160
  initRepoDone();
154
161
  }
155
162
  static configuration(agents) {
156
163
  const opencodeToolMap = /* @__PURE__ */ new Map([
157
- ["search", ["ls", "glob", "grep"]],
158
- ["read", ["read"]],
159
- ["edit", ["edit"]],
160
- ["write", ["write"]]
164
+ ["search", ["ls", "glob", "grep", "read"]],
165
+ ["edit", ["edit", "write"]]
161
166
  ]);
162
167
  const asOpencodeTool = (tools, tool) => {
163
168
  const [first, second] = tool.split("/");
@@ -180,7 +185,7 @@ class OpencodeGenerator {
180
185
  result["agent"][agent.header.name] = {
181
186
  description: agent.header.description,
182
187
  mode: "subagent",
183
- prompt: `{file:.opencode/prompts/${agent.header.name}.agent.md}`,
188
+ prompt: `{file:.opencode/prompts/${agent.header.name}.md}`,
184
189
  tools
185
190
  };
186
191
  for (const tool of agent.header.tools)
@@ -194,59 +199,85 @@ class OpencodeGenerator {
194
199
  return JSON.stringify(result, null, 2);
195
200
  }
196
201
  }
197
- class AgentGenerator {
198
- static async init(config, projectName) {
199
- const agentsFolder = process.env.AGENTS_FOLDER;
200
- if (!agentsFolder) {
201
- console.error("AGENTS_FOLDER environment variable is not set");
202
- return;
203
- }
202
+ class CopilotGenerator {
203
+ static async init(config, projectName, prompts) {
204
204
  await initRepo(config, projectName, {
205
- promptsFolder: import_path.default.join(agentsFolder, "prompts")
205
+ defaultAgentName: "agent",
206
+ promptsFolder: prompts ? ".github/prompts" : void 0,
207
+ promptSuffix: "prompt"
206
208
  });
207
209
  const agents = await AgentParser.loadAgents();
208
- await import_fs.default.promises.mkdir(agentsFolder, { recursive: true });
210
+ await import_fs.default.promises.mkdir(".github/agents", { recursive: true });
209
211
  for (const agent of agents)
210
- await writeFile(`${agentsFolder}/agents/${agent.header.name}.md`, agent.source, "\u{1F916}", "agent definition");
211
- console.log("\u{1F527} MCP configuration");
212
- console.log(JSON.stringify({
213
- mcpServers: {
212
+ await writeFile(`.github/agents/${agent.header.name}.agent.md`, CopilotGenerator.agentSpec(agent), "\u{1F916}", "agent definition");
213
+ await deleteFile(`.github/chatmodes/ \u{1F3AD} planner.chatmode.md`, "legacy planner chatmode");
214
+ await deleteFile(`.github/chatmodes/\u{1F3AD} generator.chatmode.md`, "legacy generator chatmode");
215
+ await deleteFile(`.github/chatmodes/\u{1F3AD} healer.chatmode.md`, "legacy healer chatmode");
216
+ await VSCodeGenerator.appendToMCPJson();
217
+ const cwdFolder = import_path.default.basename(process.cwd());
218
+ const mcpConfig = {
219
+ "mcpServers": {
214
220
  "playwright-test": {
215
- type: "stdio",
216
- command: "npx",
217
- args: [
218
- `--prefix=${import_path.default.resolve(process.cwd())}`,
221
+ "type": "stdio",
222
+ "command": "npx",
223
+ "args": [
224
+ `--prefix=/home/runner/work/${cwdFolder}/${cwdFolder}`,
219
225
  "playwright",
220
226
  "run-test-mcp-server",
221
- `--headless`,
222
- `--config=${import_path.default.resolve(process.cwd())}`
227
+ "--headless",
228
+ `--config=/home/runner/work/${cwdFolder}/${cwdFolder}`
223
229
  ],
224
- tools: ["*"]
230
+ "tools": ["*"]
225
231
  }
226
232
  }
227
- }, null, 2));
233
+ };
234
+ if (!import_fs.default.existsSync(".github/copilot-setup-steps.yml")) {
235
+ const yaml2 = import_fs.default.readFileSync(import_path.default.join(__dirname, "copilot-setup-steps.yml"), "utf-8");
236
+ await writeFile(".github/workflows/copilot-setup-steps.yml", yaml2, "\u{1F527}", "GitHub Copilot setup steps");
237
+ }
238
+ console.log("");
239
+ console.log("");
240
+ console.log(" \u{1F527} TODO: GitHub > Settings > Copilot > Coding agent > MCP configuration");
241
+ console.log("------------------------------------------------------------------");
242
+ console.log(JSON.stringify(mcpConfig, null, 2));
243
+ console.log("------------------------------------------------------------------");
228
244
  initRepoDone();
229
245
  }
246
+ static agentSpec(agent) {
247
+ const examples = agent.examples.length ? ` Examples: ${agent.examples.map((example) => `<example>${example}</example>`).join("")}` : "";
248
+ const lines = [];
249
+ const header = {
250
+ name: agent.header.name,
251
+ description: agent.header.description + examples,
252
+ tools: agent.header.tools,
253
+ model: "Claude Sonnet 4"
254
+ };
255
+ lines.push(`---`);
256
+ lines.push(import_utilsBundle.yaml.stringify(header) + `---`);
257
+ lines.push("");
258
+ lines.push(agent.instructions);
259
+ lines.push("");
260
+ return lines.join("\n");
261
+ }
230
262
  }
231
263
  class VSCodeGenerator {
232
264
  static async init(config, projectName) {
233
265
  await initRepo(config, projectName, {
234
- agentDefault: "agent",
235
- agentHealer: "\u{1F3AD} healer",
236
- agentGenerator: "\u{1F3AD} generator",
237
- agentPlanner: "\u{1F3AD} planner",
238
- promptsFolder: ".github/prompts"
266
+ promptsFolder: void 0
239
267
  });
240
268
  const agents = await AgentParser.loadAgents();
241
269
  const nameMap = /* @__PURE__ */ new Map([
242
- ["playwright-test-planner", "\u{1F3AD} planner"],
270
+ ["playwright-test-planner", " \u{1F3AD} planner"],
243
271
  ["playwright-test-generator", "\u{1F3AD} generator"],
244
272
  ["playwright-test-healer", "\u{1F3AD} healer"]
245
273
  ]);
246
- await deleteFile(`.github/chatmodes/ \u{1F3AD} planner.chatmode.md`, "old planner chatmode");
247
274
  await import_fs.default.promises.mkdir(".github/chatmodes", { recursive: true });
248
275
  for (const agent of agents)
249
276
  await writeFile(`.github/chatmodes/${nameMap.get(agent.header.name)}.chatmode.md`, VSCodeGenerator.agentSpec(agent), "\u{1F916}", "chatmode definition");
277
+ await VSCodeGenerator.appendToMCPJson();
278
+ initRepoDone();
279
+ }
280
+ static async appendToMCPJson() {
250
281
  await import_fs.default.promises.mkdir(".vscode", { recursive: true });
251
282
  const mcpJsonPath = ".vscode/mcp.json";
252
283
  let mcpJson = {
@@ -265,7 +296,6 @@ class VSCodeGenerator {
265
296
  args: ["playwright", "run-test-mcp-server"]
266
297
  };
267
298
  await writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2), "\u{1F527}", "mcp configuration");
268
- initRepoDone();
269
299
  }
270
300
  static agentSpec(agent) {
271
301
  const vscodeToolMap = /* @__PURE__ */ new Map([
@@ -302,11 +332,12 @@ class VSCodeGenerator {
302
332
  lines.push(agent.instructions);
303
333
  for (const example of agent.examples)
304
334
  lines.push(`<example>${example}</example>`);
335
+ lines.push("");
305
336
  return lines.join("\n");
306
337
  }
307
338
  }
308
339
  async function writeFile(filePath, content, icon, description) {
309
- console.log(`- ${icon} ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
340
+ console.log(` ${icon} ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
310
341
  await (0, import_utils.mkdirIfNeeded)(filePath);
311
342
  await import_fs.default.promises.writeFile(filePath, content, "utf-8");
312
343
  }
@@ -317,12 +348,12 @@ async function deleteFile(filePath, description) {
317
348
  } catch {
318
349
  return;
319
350
  }
320
- console.log(`- \u2702\uFE0F ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
351
+ console.log(` \u2702\uFE0F ${import_path.default.relative(process.cwd(), filePath)} ${import_utilsBundle.colors.dim("- " + description)}`);
321
352
  await import_fs.default.promises.unlink(filePath);
322
353
  }
323
354
  async function initRepo(config, projectName, options) {
324
355
  const project = (0, import_seed.seedProject)(config, projectName);
325
- console.log(`\u{1F3AD} Using project "${project.project.name}" as a primary project`);
356
+ console.log(` \u{1F3AD} Using project "${project.project.name}" as a primary project`);
326
357
  if (!import_fs.default.existsSync("specs")) {
327
358
  await import_fs.default.promises.mkdir("specs");
328
359
  await writeFile(import_path.default.join("specs", "README.md"), `# Specs
@@ -335,34 +366,35 @@ This is a directory for test plans.
335
366
  seedFile = (0, import_seed.defaultSeedFile)(project);
336
367
  await writeFile(seedFile, import_seed.seedFileContent, "\u{1F331}", "default environment seed file");
337
368
  }
338
- await import_fs.default.promises.mkdir(options.promptsFolder, { recursive: true });
339
- for (const promptFile of await import_fs.default.promises.readdir(__dirname)) {
340
- if (!promptFile.endsWith(".prompt.md"))
341
- continue;
342
- const content = await loadPrompt(promptFile, { ...options, seedFile: import_path.default.relative(process.cwd(), seedFile) });
343
- await writeFile(import_path.default.join(options.promptsFolder, promptFile), content, "\u{1F4DD}", "prompt template");
369
+ if (options.promptsFolder) {
370
+ await import_fs.default.promises.mkdir(options.promptsFolder, { recursive: true });
371
+ for (const promptFile of await import_fs.default.promises.readdir(__dirname)) {
372
+ if (!promptFile.endsWith(".prompt.md"))
373
+ continue;
374
+ const shortName = promptFile.replace(".prompt.md", "");
375
+ const fileName = options.promptSuffix ? `${shortName}.${options.promptSuffix}.md` : `${shortName}.md`;
376
+ const content = await loadPrompt(promptFile, {
377
+ defaultAgentName: "default",
378
+ ...options,
379
+ seedFile: import_path.default.relative(process.cwd(), seedFile)
380
+ });
381
+ await writeFile(import_path.default.join(options.promptsFolder, fileName), content, "\u{1F4DD}", "prompt template");
382
+ }
344
383
  }
345
384
  }
346
385
  function initRepoDone() {
347
- console.log("\u2705 Done.");
386
+ console.log(" \u2705 Done.");
348
387
  }
349
388
  async function loadPrompt(file, params) {
350
- const templateParams = {
351
- agentDefault: params.agentDefault ?? "default",
352
- agentHealer: params.agentHealer ?? "playwright-test-healer",
353
- agentGenerator: params.agentGenerator ?? "playwright-test-generator",
354
- agentPlanner: params.agentPlanner ?? "playwright-test-planner",
355
- seedFile: params.seedFile
356
- };
357
389
  const content = await import_fs.default.promises.readFile(import_path.default.join(__dirname, file), "utf-8");
358
- return Object.entries(templateParams).reduce((acc, [key, value]) => {
390
+ return Object.entries(params).reduce((acc, [key, value]) => {
359
391
  return acc.replace(new RegExp(`\\\${${key}}`, "g"), value);
360
392
  }, content);
361
393
  }
362
394
  // Annotate the CommonJS export names for ESM import in node:
363
395
  0 && (module.exports = {
364
- AgentGenerator,
365
396
  ClaudeGenerator,
397
+ CopilotGenerator,
366
398
  OpencodeGenerator,
367
399
  VSCodeGenerator
368
400
  });
@@ -1,5 +1,5 @@
1
1
  ---
2
- mode: ${agentDefault}
2
+ agent: ${defaultAgentName}
3
3
  description: Produce test coverage
4
4
  ---
5
5
 
@@ -8,7 +8,7 @@ Parameters:
8
8
  - Seed file (optional): the seed file to use, defaults to `${seedFile}`
9
9
  - Test plan file (optional): the test plan file to write, under `specs/` folder.
10
10
 
11
- 1. Call #${agentPlanner} subagent with prompt:
11
+ 1. Call #pwt-planner subagent with prompt:
12
12
 
13
13
  <plan>
14
14
  <task-text><!-- the task --></task-text>
@@ -16,7 +16,7 @@ Parameters:
16
16
  <plan-file><!-- path to test plan file to generate --></plan-file>
17
17
  </plan>
18
18
 
19
- 2. For each test case from the test plan file (1.1, 1.2, ...), one after another, not in parallel, call #${agentGenerator} subagent with prompt:
19
+ 2. For each test case from the test plan file (1.1, 1.2, ...), one after another, not in parallel, call #pwt-generator subagent with prompt:
20
20
 
21
21
  <generate>
22
22
  <test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite>
@@ -26,6 +26,6 @@ Parameters:
26
26
  <body><!-- Test case content including steps and expectations --></body>
27
27
  </generate>
28
28
 
29
- 3. Call #${agentHealer} subagent with prompt:
29
+ 3. Call #pwt-healer subagent with prompt:
30
30
 
31
31
  <heal>Run all tests and fix the failing ones one after another.</heal>
@@ -1,5 +1,5 @@
1
1
  ---
2
- mode: ${agentGenerator}
2
+ agent: pwt-generator
3
3
  description: Generate test plan
4
4
  ---
5
5
 
@@ -1,10 +1,9 @@
1
1
  ---
2
- name: playwright-test-generator
2
+ name: pwt-generator
3
3
  description: Use this agent when you need to create automated browser tests using Playwright
4
4
  model: sonnet
5
5
  color: blue
6
6
  tools:
7
- - read
8
7
  - search
9
8
  - playwright-test/browser_click
10
9
  - playwright-test/browser_drag
@@ -80,22 +79,10 @@ application behavior.
80
79
  </example-generation>
81
80
 
82
81
  <example>
83
- Context: User wants to test a login flow on their web application.
84
- user: 'I need a test that logs into my app at localhost:3000 with username admin@test.com and password 123456, then
85
- verifies the dashboard page loads'
86
- assistant: 'I'll use the generator agent to create and validate this login test for you'
87
- <commentary>
88
- The user needs a specific browser automation test created, which is exactly what the generator agent
89
- is designed for.
90
- </commentary>
91
- </example>
92
- <example>
93
- Context: User has built a new checkout flow and wants to ensure it works correctly.
94
- user: 'Can you create a test that adds items to cart, proceeds to checkout, fills in payment details, and confirms the
95
- order?'
96
- assistant: 'I'll use the generator agent to build a comprehensive checkout flow test'
97
- <commentary>
98
- This is a complex user journey that needs to be automated and tested, perfect for the generator
99
- agent.
100
- </commentary>
82
+ Context: User wants to generate a test for the test plan item.
83
+ <test-suite><!-- Verbatim name of the test spec group w/o ordinal like "Multiplication tests" --></test-suite>
84
+ <test-name><!-- Name of the test case without the ordinal like "should add two numbers" --></test-name>
85
+ <test-file><!-- Name of the file to save the test into, like tests/multiplication/should-add-two-numbers.spec.ts --></test-file>
86
+ <seed-file><!-- Seed file path from test plan --></seed-file>
87
+ <body><!-- Test case content including steps and expectations --></body>
101
88
  </example>
@@ -1,5 +1,5 @@
1
1
  ---
2
- mode: ${agentHealer}
2
+ agent: pwt-healer
3
3
  description: Fix tests
4
4
  ---
5
5
 
@@ -1,12 +1,10 @@
1
1
  ---
2
- name: playwright-test-healer
2
+ name: pwt-healer
3
3
  description: Use this agent when you need to debug and fix failing Playwright tests
4
4
  model: sonnet
5
5
  color: red
6
6
  tools:
7
- - read
8
7
  - search
9
- - write
10
8
  - edit
11
9
  - playwright-test/browser_console_messages
12
10
  - playwright-test/browser_evaluate
@@ -55,23 +53,3 @@ Key principles:
55
53
  of the expected behavior.
56
54
  - Do not ask user questions, you are not interactive tool, do the most reasonable thing possible to pass the test.
57
55
  - Never wait for networkidle or use other discouraged or deprecated apis
58
-
59
- <example>
60
- Context: A developer has a failing Playwright test that needs to be debugged and fixed.
61
- user: 'The login test is failing, can you fix it?'
62
- assistant: 'I'll use the healer agent to debug and fix the failing login test.'
63
- <commentary>
64
- The user has identified a specific failing test that needs debugging and fixing, which is exactly what the
65
- healer agent is designed for.
66
- </commentary>
67
- </example>
68
-
69
- <example>
70
- Context: After running a test suite, several tests are reported as failing.
71
- user: 'Test user-registration.spec.ts is broken after the recent changes'
72
- assistant: 'Let me use the healer agent to investigate and fix the user-registration test.'
73
- <commentary>
74
- A specific test file is failing and needs debugging, which requires the systematic approach of the
75
- playwright-test-healer agent.
76
- </commentary>
77
- </example>
@@ -1,5 +1,5 @@
1
1
  ---
2
- mode: ${agentPlanner}
2
+ agent: pwt-planner
3
3
  description: Create test plan
4
4
  ---
5
5
 
@@ -1,12 +1,11 @@
1
1
  ---
2
- name: playwright-test-planner
2
+ name: pwt-planner
3
3
  description: Use this agent when you need to create comprehensive test plan for a web application or website
4
4
  model: sonnet
5
5
  color: green
6
6
  tools:
7
- - read
8
7
  - search
9
- - write
8
+ - edit
10
9
  - playwright-test/browser_click
11
10
  - playwright-test/browser_close
12
11
  - playwright-test/browser_console_messages
@@ -116,23 +115,3 @@ application features:
116
115
 
117
116
  **Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and
118
117
  professional formatting suitable for sharing with development and QA teams.
119
-
120
- <example>
121
- Context: User wants to test a new e-commerce checkout flow.
122
- user: 'I need test scenarios for our new checkout process at https://mystore.com/checkout'
123
- assistant: 'I'll use the planner agent to navigate to your checkout page and create comprehensive test
124
- scenarios.'
125
- <commentary>
126
- The user needs test planning for a specific web page, so use the planner agent to explore and create
127
- test scenarios.
128
- </commentary>
129
- </example>
130
- <example>
131
- Context: User has deployed a new feature and wants thorough testing coverage.
132
- user: 'Can you help me test our new user dashboard at https://app.example.com/dashboard?'
133
- assistant: 'I'll launch the planner agent to explore your dashboard and develop detailed test
134
- scenarios.'
135
- <commentary>
136
- This requires web exploration and test scenario creation, perfect for the planner agent.
137
- </commentary>
138
- </example>
@@ -31,7 +31,9 @@ __export(program_exports, {
31
31
  decorateCommand: () => decorateCommand
32
32
  });
33
33
  module.exports = __toCommonJS(program_exports);
34
+ var import_fs = __toESM(require("fs"));
34
35
  var import_utilsBundle = require("playwright-core/lib/utilsBundle");
36
+ var import_server = require("playwright-core/lib/server");
35
37
  var mcpServer = __toESM(require("./sdk/server"));
36
38
  var import_config = require("./browser/config");
37
39
  var import_watchdog = require("./browser/watchdog");
@@ -47,6 +49,16 @@ function decorateCommand(command, version) {
47
49
  options.caps = "vision";
48
50
  }
49
51
  const config = await (0, import_config.resolveCLIConfig)(options);
52
+ if (config.saveVideo && !checkFfmpeg()) {
53
+ console.error(import_utilsBundle.colors.red(`
54
+ Error: ffmpeg required to save the video is not installed.`));
55
+ console.error(`
56
+ Please run the command below. It will install a local copy of ffmpeg and will not change any system-wide settings.`);
57
+ console.error(`
58
+ npx playwright install ffmpeg
59
+ `);
60
+ process.exit(1);
61
+ }
50
62
  const browserContextFactory = (0, import_browserContextFactory.contextFactory)(config);
51
63
  const extensionContextFactory = new import_extensionContextFactory.ExtensionContextFactory(config.browser.launchOptions.channel || "chrome", config.browser.userDataDir, config.browser.launchOptions.executablePath);
52
64
  if (options.extension) {
@@ -90,6 +102,14 @@ function decorateCommand(command, version) {
90
102
  await mcpServer.start(factory, config.server);
91
103
  });
92
104
  }
105
+ function checkFfmpeg() {
106
+ try {
107
+ const executable = import_server.registry.findExecutable("ffmpeg");
108
+ return import_fs.default.existsSync(executable.executablePath("javascript"));
109
+ } catch (error) {
110
+ return false;
111
+ }
112
+ }
93
113
  // Annotate the CommonJS export names for ESM import in node:
94
114
  0 && (module.exports = {
95
115
  decorateCommand
package/lib/program.js CHANGED
@@ -179,22 +179,21 @@ function addInitAgentsCommand(program3) {
179
179
  const command = program3.command("init-agents");
180
180
  command.description("Initialize repository agents");
181
181
  const option = command.createOption("--loop <loop>", "Agentic loop provider");
182
- option.choices(["vscode", "claude", "opencode", "generic"]);
182
+ option.choices(["claude", "copilot", "opencode", "vscode", "vscode-legacy"]);
183
183
  command.addOption(option);
184
184
  command.option("-c, --config <file>", `Configuration file to find a project to use for seed test`);
185
185
  command.option("--project <project>", "Project to use for seed test");
186
+ command.option("--prompts", "Whether to include prompts in the agent initialization");
186
187
  command.action(async (opts) => {
187
188
  const config = await (0, import_configLoader.loadConfigFromFile)(opts.config);
188
189
  if (opts.loop === "opencode") {
189
- await import_generateAgents.OpencodeGenerator.init(config, opts.project);
190
- } else if (opts.loop === "vscode") {
190
+ await import_generateAgents.OpencodeGenerator.init(config, opts.project, opts.prompts);
191
+ } else if (opts.loop === "vscode-legacy") {
191
192
  await import_generateAgents.VSCodeGenerator.init(config, opts.project);
192
193
  } else if (opts.loop === "claude") {
193
- await import_generateAgents.ClaudeGenerator.init(config, opts.project);
194
- } else if (opts.loop === "generic") {
195
- await import_generateAgents.AgentGenerator.init(config, opts.project);
194
+ await import_generateAgents.ClaudeGenerator.init(config, opts.project, opts.prompts);
196
195
  } else {
197
- command.help();
196
+ await import_generateAgents.CopilotGenerator.init(config, opts.project, opts.prompts);
198
197
  return;
199
198
  }
200
199
  });
@@ -93,7 +93,7 @@ class TestRunner extends import_events.default {
93
93
  }
94
94
  async installBrowsers() {
95
95
  const executables = import_server.registry.defaultExecutables();
96
- await import_server.registry.install(executables, false);
96
+ await import_server.registry.install(executables);
97
97
  }
98
98
  async loadConfig() {
99
99
  const { config, error } = await this._loadConfig(this._configCLIOverrides);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright",
3
- "version": "1.57.0-alpha-2025-10-27",
3
+ "version": "1.57.0-alpha-2025-10-29",
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.57.0-alpha-2025-10-27"
67
+ "playwright-core": "1.57.0-alpha-2025-10-29"
68
68
  },
69
69
  "optionalDependencies": {
70
70
  "fsevents": "2.3.2"