Skip to content

Commit e9ef0ea

Browse files
authored
chore(agent): allow submitting structured plans (#38123)
1 parent 0b7307d commit e9ef0ea

File tree

2 files changed

+92
-47
lines changed

2 files changed

+92
-47
lines changed

packages/playwright/src/agents/playwright-test-planner.agent.md

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ model: sonnet
55
color: green
66
tools:
77
- search
8-
- edit
98
- playwright-test/browser_click
109
- playwright-test/browser_close
1110
- playwright-test/browser_console_messages
@@ -24,6 +23,7 @@ tools:
2423
- playwright-test/browser_type
2524
- playwright-test/browser_wait_for
2625
- playwright-test/planner_setup_page
26+
- playwright-test/planner_save_plan
2727
---
2828

2929
You are an expert web test planner with extensive experience in quality assurance, user experience testing, and test
@@ -61,52 +61,7 @@ You will:
6161

6262
5. **Create Documentation**
6363

64-
Save your test plan as requested:
65-
- Executive summary of the tested page/application
66-
- Individual scenarios as separate sections
67-
- Each scenario formatted with numbered steps
68-
- Each test case with proposed file name for implementation
69-
- Clear expected results for verification
70-
71-
<example-spec>
72-
# TodoMVC Application - Comprehensive Test Plan
73-
74-
## Application Overview
75-
76-
The TodoMVC application is a React-based todo list manager that provides core task management functionality. The
77-
application features:
78-
79-
- **Task Management**: Add, edit, complete, and delete individual todos
80-
- **Bulk Operations**: Mark all todos as complete/incomplete and clear all completed todos
81-
- **Filtering**: View todos by All, Active, or Completed status
82-
- **URL Routing**: Support for direct navigation to filtered views via URLs
83-
- **Counter Display**: Real-time count of active (incomplete) todos
84-
- **Persistence**: State maintained during session (browser refresh behavior not tested)
85-
86-
## Test Scenarios
87-
88-
### 1. Adding New Todos
89-
90-
**Seed:** `tests/seed.spec.ts`
91-
92-
#### 1.1 Add Valid Todo
93-
94-
**File** `tests/adding-new-todos/add-valid-todo.spec.ts`
95-
96-
**Steps:**
97-
1. Click in the "What needs to be done?" input field
98-
2. Type "Buy groceries"
99-
3. Press Enter key
100-
101-
**Expected Results:**
102-
- Todo appears in the list with unchecked checkbox
103-
- Counter shows "1 item left"
104-
- Input field is cleared and ready for next entry
105-
- Todo list controls become visible (Mark all as complete checkbox)
106-
107-
#### 1.2
108-
...
109-
</example-spec>
64+
Submit your test plan using `planner_save_plan` tool.
11065

11166
**Quality Standards**:
11267
- Write steps that are specific enough for any tester to follow

packages/playwright/src/mcp/test/plannerTools.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17+
import fs from 'fs';
18+
import path from 'path';
19+
1720
import { z } from '../sdk/bundle';
1821
import { defineTestTool } from './testTool';
1922

@@ -35,3 +38,90 @@ export const setupPage = defineTestTool({
3538
return { content: [] };
3639
},
3740
});
41+
42+
const planSchema = z.object({
43+
overview: z.string().describe('A brief overview of the application to be tested'),
44+
suites: z.array(z.object({
45+
name: z.string().describe('The name of the suite'),
46+
seedFile: z.string().describe('A seed file that was used to setup the page for testing.'),
47+
tests: z.array(z.object({
48+
name: z.string().describe('The name of the test'),
49+
file: z.string().describe('The file the test should be saved to, for example: "tests/<suite-name>/<test-name>.spec.ts".'),
50+
steps: z.array(z.string().describe(`The steps to be executed to perform the test. For example: 'Click on the "Submit" button'`)),
51+
expectedResults: z.array(z.string().describe('The expected results of the steps for test to verify.')),
52+
})),
53+
})),
54+
});
55+
56+
export const submitTestPlan = defineTestTool({
57+
schema: {
58+
name: 'planner_submit_plan',
59+
title: 'Submit test plan',
60+
description: 'Submit the test plan to the test planner',
61+
inputSchema: planSchema,
62+
type: 'readOnly',
63+
},
64+
65+
handle: async (context, params) => {
66+
return {
67+
content: [{
68+
type: 'text',
69+
text: JSON.stringify(params, null, 2),
70+
}],
71+
};
72+
},
73+
});
74+
75+
export const saveTestPlan = defineTestTool({
76+
schema: {
77+
name: 'planner_save_plan',
78+
title: 'Save test plan as markdown file',
79+
description: 'Save the test plan as a markdown file',
80+
inputSchema: planSchema.extend({
81+
name: z.string().describe('The name of the test plan, for example: "Test Plan".'),
82+
fileName: z.string().describe('The file to save the test plan to, for example: "spec/test.plan.md". Relative to the workspace root.'),
83+
}),
84+
type: 'readOnly',
85+
},
86+
87+
handle: async (context, params) => {
88+
const lines: string[] = [];
89+
lines.push(`# ${params.name}`);
90+
lines.push(``);
91+
lines.push(`## Application Overview`);
92+
lines.push(``);
93+
lines.push(params.overview);
94+
lines.push(``);
95+
lines.push(`## Test Scenarios`);
96+
for (let i = 0; i < params.suites.length; i++) {
97+
lines.push(``);
98+
const suite = params.suites[i];
99+
lines.push(`### ${i + 1}. ${suite.name}`);
100+
lines.push(``);
101+
lines.push(`**Seed:** \`${suite.seedFile}\``);
102+
for (let j = 0; j < suite.tests.length; j++) {
103+
lines.push(``);
104+
const test = suite.tests[j];
105+
lines.push(`#### ${i + 1}.${j + 1}. ${test.name}`);
106+
lines.push(``);
107+
lines.push(`**File:** \`${test.file}\``);
108+
lines.push(``);
109+
lines.push(`**Steps:**`);
110+
for (let k = 0; k < test.steps.length; k++)
111+
lines.push(` ${k + 1}. ${test.steps[k]}`);
112+
lines.push(``);
113+
lines.push(`**Expected Results:**`);
114+
for (const result of test.expectedResults)
115+
lines.push(` - ${result}`);
116+
}
117+
}
118+
lines.push(``);
119+
await fs.promises.writeFile(path.resolve(context.rootPath, params.fileName), lines.join('\n'));
120+
return {
121+
content: [{
122+
type: 'text',
123+
text: `Test plan saved to ${params.fileName}`,
124+
}],
125+
};
126+
},
127+
});

0 commit comments

Comments
 (0)