Skip to content

Commit 35131dc

Browse files
yomybabyclaude
andauthored
docs(FR-2018): enhance Playwright E2E test agent documentation (#5229)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 2b77865 commit 35131dc

6 files changed

Lines changed: 463 additions & 24 deletions

File tree

.claude/agents/playwright-test-generator.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ application behavior.
2020
- Immediately after reading the test log, invoke `generator_write_test` with the generated source code
2121
- File should contain single test
2222
- File name must be fs-friendly scenario name (use kebab-case with `.spec.ts` extension)
23+
- Place test files in appropriate feature directory: `e2e/session/`, `e2e/serving/`, `e2e/user/`, etc.
2324
- Test must be placed in a describe matching the top-level test plan item
2425
- **Test title must use user-scenario-based naming convention**
2526
- Format: `[Actor] can/cannot [action] [when/with/in condition]`
@@ -28,6 +29,7 @@ application behavior.
2829
- Includes a comment with the step text before each step execution. Do not duplicate comments if step requires
2930
multiple actions.
3031
- Always use best practices from the log when generating tests.
32+
- **Include resource cleanup in `afterEach`** for tests that create resources (sessions, endpoints, users)
3133

3234
**Critical: Avoid Unnecessary Visibility Checks and Fallback Logic**
3335
- **DO NOT** create visibility check variables like `isSomethingVisible` with fallback logic
@@ -82,6 +84,60 @@ await page.goto('/dashboard');
8284
await page.waitForSelector('[data-testid="dashboard-loaded"]');
8385
```
8486

87+
**Guideline: Avoid Using `page.waitForTimeout()` for Polling or Readiness**
88+
- **Avoid `page.waitForTimeout()` for polling/readiness** - it often causes flaky tests and wastes time
89+
- Prefer Playwright's `expect.poll()` for status checking or element-based waiting
90+
- Use short `waitForTimeout()` delays only as a last resort for brief stabilization
91+
92+
```typescript
93+
// ❌ BAD: Manual polling with waitForTimeout
94+
let status = await getStatus();
95+
while (status !== 'READY') {
96+
await page.waitForTimeout(1000);
97+
status = await getStatus();
98+
}
99+
100+
// ✅ GOOD: Use expect.poll() for status waiting
101+
await expect.poll(async () => await getStatus(), { timeout: 60000 }).toBe('READY');
102+
```
103+
104+
**Resource Cleanup Pattern:**
105+
- Tests that create resources (sessions, endpoints, users) MUST include cleanup
106+
- Prefer `afterEach` for isolated tests; use `afterAll` when a single expensive resource is shared across serial tests
107+
- Track created resources and clean them up appropriately
108+
109+
```typescript
110+
// ✅ GOOD: Test with proper cleanup
111+
test.describe('Session Tests', { tag: ['@session'] }, () => {
112+
let createdSessionName: string | null = null;
113+
114+
test.afterEach(async ({ page }) => {
115+
if (createdSessionName) {
116+
try {
117+
const launcher = new SessionLauncher(page);
118+
launcher.withSessionName(createdSessionName);
119+
await launcher.terminate();
120+
} catch { /* ignore cleanup errors */ }
121+
}
122+
});
123+
124+
test('User can create session', async ({ page }) => {
125+
const launcher = new SessionLauncher(page);
126+
await launcher.withSessionName('test-session').create();
127+
createdSessionName = launcher.getSessionName();
128+
// ... assertions
129+
});
130+
});
131+
```
132+
133+
**Project-Specific Conventions:**
134+
- Test files use `.spec.ts` extension (per `e2e/E2E-TEST-NAMING-GUIDELINES.md`)
135+
- Tests are organized in feature directories: `e2e/session/`, `e2e/serving/`, `e2e/user/`, etc.
136+
- POM classes are in `e2e/utils/classes/{feature}/`
137+
- Use `loginAsAdmin` or `loginAsUser` from `test-util.ts` for authentication
138+
- Use `navigateTo(page, 'route')` for navigation
139+
- Use tags for categorization: `@critical`, `@session`, `@serving`, `@functional`
140+
85141
<example-generation>
86142
For following plan:
87143

.claude/agents/playwright-test-healer.md

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,39 @@ await page.goto('/dashboard');
6666
await page.waitForSelector('[data-testid="dashboard-loaded"]');
6767
```
6868

69+
**Guideline: Avoid Using `page.waitForTimeout()` for Polling or Readiness**
70+
- **Avoid `page.waitForTimeout()` for polling/readiness** - it often causes flaky tests and wastes time
71+
- When fixing tests, **remove** any manual polling loops with `waitForTimeout()` and prefer assertion-based waiting
72+
- Replace with Playwright's `expect.poll()` for status checking or element-based waiting
73+
- Use short `waitForTimeout()` delays only as a last resort for brief stabilization
74+
75+
```typescript
76+
// ❌ BAD: Manual polling with waitForTimeout
77+
let status = await getSessionStatus(sessionId);
78+
while (status !== 'RUNNING') {
79+
await page.waitForTimeout(1000);
80+
status = await getSessionStatus(sessionId);
81+
}
82+
83+
// ✅ GOOD: Use expect.poll() for status waiting
84+
await expect.poll(
85+
async () => await sessionDetailPage.getSessionStatus(sessionId),
86+
{ message: `Waiting for session ${sessionId} to be RUNNING`, timeout: 120000 }
87+
).toBe('RUNNING');
88+
89+
// ✅ GOOD: Use expect.poll() with error state handling
90+
await expect.poll(
91+
async () => {
92+
const currentStatus = await getSessionStatus(sessionId);
93+
if (currentStatus === 'ERROR' || currentStatus === 'CANCELLED') {
94+
throw new Error(`Session entered ${currentStatus} state`);
95+
}
96+
return currentStatus;
97+
},
98+
{ timeout: 120000 }
99+
).toBe('RUNNING');
100+
```
101+
69102
**Critical: Avoid Unnecessary Visibility Checks and Fallback Logic**
70103
- **DO NOT** create visibility check variables like `isSomethingVisible` with fallback logic
71104
- **DO NOT** wrap actions in try-catch blocks with alternative fallback paths to continue testing
@@ -196,4 +229,81 @@ await page.locator('svg[data-icon="upload"]').click();
196229

197230
- **General utilities** (`e2e/utils/test-util.ts`):
198231
- Import appropriate utility based on UI framework being tested
199-
- Prefer utility functions over direct CSS selectors for maintainability
232+
- Prefer utility functions over direct CSS selectors for maintainability
233+
234+
**Resource Cleanup Pattern:**
235+
- Tests that create resources (sessions, endpoints, users) MUST ensure cleanup
236+
- Prefer `afterEach` for isolated tests; use `afterAll` when a single expensive resource is shared across serial tests
237+
- Use `SessionLauncher.terminate()` for session cleanup - handles all states (PENDING, RUNNING, etc.)
238+
- Never assume a resource was successfully created - wrap cleanup in try-catch
239+
240+
```typescript
241+
// ✅ GOOD: Proper cleanup pattern for session tests
242+
let createdSessionName: string | null = null;
243+
244+
test.beforeEach(async ({ page, request }) => {
245+
await loginAsUser(page, request);
246+
createdSessionName = null;
247+
});
248+
249+
test.afterEach(async ({ page }) => {
250+
if (createdSessionName) {
251+
try {
252+
const sessionLauncher = new SessionLauncher(page);
253+
sessionLauncher.withSessionName(createdSessionName);
254+
await sessionLauncher.terminate();
255+
} catch (error) {
256+
console.log(`Failed to terminate session ${createdSessionName}:`, error);
257+
}
258+
}
259+
});
260+
261+
test('Create session', async ({ page }) => {
262+
const sessionLauncher = new SessionLauncher(page);
263+
await sessionLauncher.withSessionName('test-session').create();
264+
createdSessionName = sessionLauncher.getSessionName(); // Track for cleanup
265+
// ... test assertions
266+
});
267+
```
268+
269+
**Sequential Test Execution:**
270+
- Use `test.describe.configure({ mode: 'serial' })` when tests share resources or must run in order
271+
- Prevents parallel execution that causes resource contention
272+
273+
```typescript
274+
test.describe('Session Lifecycle', () => {
275+
test.describe.configure({ mode: 'serial' }); // Run tests sequentially
276+
// ... tests
277+
});
278+
```
279+
280+
**Vaadin Grid → Ant Design Table Migration:**
281+
- Many components have migrated from Vaadin Grid to Ant Design Table
282+
- Update locators accordingly when fixing tests
283+
284+
```typescript
285+
// ❌ OLD: Vaadin Grid locators
286+
const row = page.locator('vaadin-grid-cell-content');
287+
const cell = sessionRow.locator('cell');
288+
289+
// ✅ NEW: Ant Design Table locators
290+
const row = page.getByRole('row');
291+
const cell = sessionRow.getByRole('cell');
292+
```
293+
294+
**Action Buttons in Notification Alerts:**
295+
- Some action buttons (terminate, app launch, terminal) appear in notification alerts, not table rows
296+
- Look for `getByRole('alert')` when table row buttons are not found
297+
298+
```typescript
299+
// ✅ Finding action buttons in notification area
300+
const alert = page.getByRole('alert').filter({ hasText: sessionName });
301+
await alert.getByRole('button', { name: 'terminate' }).click();
302+
```
303+
304+
**Project-Specific Conventions:**
305+
- Test files use `.spec.ts` extension (per `e2e/E2E-TEST-NAMING-GUIDELINES.md`)
306+
- Tests are organized in feature directories: `e2e/session/`, `e2e/serving/`, `e2e/user/`, etc.
307+
- POM classes are in `e2e/utils/classes/{feature}/`
308+
- Use `loginAsAdmin` or `loginAsUser` from `test-util.ts` for authentication
309+
- Use `navigateTo(page, 'route')` for navigation

.claude/agents/playwright-test-planner.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,27 @@ application features:
100100
- Include negative testing scenarios
101101
- Ensure scenarios are independent and can be run in any order
102102

103+
**Resource Cleanup Planning**:
104+
- When designing tests that create resources (sessions, endpoints, users), always plan for cleanup
105+
- Include `afterEach` cleanup step in test plan documentation
106+
- Consider test isolation - each test should not depend on previous test's state
107+
- For sequential tests that share state, note the dependency explicitly
108+
109+
```markdown
110+
## Test Infrastructure Notes
111+
- **Cleanup Required**: Yes - sessions must be terminated after each test
112+
- **Execution Mode**: Sequential (tests share session state)
113+
- **Tags**: @critical, @session
114+
```
115+
116+
**Sequential vs Parallel Execution**:
117+
- Most tests should be independent and run in parallel (default)
118+
- Use `test.describe.configure({ mode: 'serial' })` only when:
119+
- Tests share expensive resources (e.g., session creation)
120+
- Tests depend on state from previous tests
121+
- Resource contention would cause flaky tests
122+
- Document execution mode requirements in the test plan
123+
103124
**Test Design Principles - No Fallback Logic**:
104125
- **DO NOT** design tests with visibility checks and fallback logic
105126
- Each step should be direct and deterministic - if an element should be present, it must be present
@@ -138,4 +159,12 @@ application features:
138159
```
139160

140161
**Output Format**: Always save the complete test plan as a markdown file with clear headings, numbered steps, and
141-
professional formatting suitable for sharing with development and QA teams.
162+
professional formatting suitable for sharing with development and QA teams.
163+
164+
**Project-Specific Conventions:**
165+
- Test files use `.spec.ts` extension (per `e2e/E2E-TEST-NAMING-GUIDELINES.md`)
166+
- Tests are organized in feature directories: `e2e/session/`, `e2e/serving/`, `e2e/user/`, etc.
167+
- POM classes are in `e2e/utils/classes/{feature}/`
168+
- Use tags for categorization: `@smoke`, `@critical`, `@regression`, `@session`, `@serving`, `@functional`
169+
- Plan for proper authentication: `loginAsAdmin` or `loginAsUser`
170+
- Plan for navigation: `navigateTo(page, 'route')`

.claude/commands/amend-staged-changes.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,25 @@ If no argument is provided, PR description will only be updated if there are sta
2828

2929
## Detailed Process
3030

31-
### Step 0: Verify MCP Authentication
31+
### Step 0: Verify MCP Authentication (MUST BE FIRST)
3232

33-
Verify that MCP tools are authenticated before starting the workflow.
33+
> **⚠️ CRITICAL**: This step MUST be executed BEFORE any other operation. Do NOT skip or defer this step. Do NOT read files, check git status, or perform any other action until MCP authentication is verified.
34+
35+
Verify that Atlassian MCP is authenticated before starting the workflow.
3436

3537
```
36-
# Test Graphite MCP authentication
37-
mcp__graphite__run_gt_cmd with args: ["--version"]
38+
# Test Atlassian MCP authentication - THIS MUST BE THE VERY FIRST TOOL CALL
39+
mcp__Atlassian__atlassianUserInfo
3840
```
3941

4042
**If authentication fails:**
41-
- Inform the user that Graphite MCP needs re-authentication
43+
- **STOP IMMEDIATELY** - Do not proceed with any other steps
44+
- Inform the user that Atlassian MCP needs re-authentication
4245
- Provide guidance on how to re-authenticate:
4346
```
4447
⚠️ MCP Authentication Required
4548
46-
Graphite MCP needs re-authentication.
49+
Atlassian MCP needs re-authentication.
4750
Please re-authenticate via MCP settings and run the command again.
4851
```
4952
- Exit the workflow without making any changes

0 commit comments

Comments
 (0)