symfonia-ai-tools 1.0.0
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 +489 -0
- package/bin/cli.mjs +35 -0
- package/lib/installer.mjs +495 -0
- package/lib/questions.mjs +332 -0
- package/lib/ui.mjs +76 -0
- package/lib/utils.mjs +231 -0
- package/package.json +26 -0
- package/templates/base/CLAUDE.md +34 -0
- package/templates/base/_ai/_guidelines_header.md +70 -0
- package/templates/base/_ai/context/README.md +20 -0
- package/templates/base/_ai/prompts/codereview.prompt.md +324 -0
- package/templates/base/_ai/prompts/duplicate-code-analysis.prompt.md +128 -0
- package/templates/base/_ai/prompts/figma-analysis.prompt.md +155 -0
- package/templates/base/_ai/prompts/security-review.prompt.md +46 -0
- package/templates/base/_ai/skills/README.md +80 -0
- package/templates/base/_ai/skills/TEMPLATE.md +106 -0
- package/templates/base/_ai/skills/babysit-prs/SKILL.md +105 -0
- package/templates/base/_ai/skills/debug/SKILL.md +93 -0
- package/templates/base/_ai/skills/fill-worklogs/SKILL.md +158 -0
- package/templates/base/_ai/skills/hotfix/SKILL.md +52 -0
- package/templates/base/_ai/skills/jira-task/SKILL.md +170 -0
- package/templates/base/_ai/skills/my-prs/SKILL.md +78 -0
- package/templates/base/_ai/skills/pr-dashboard/SKILL.md +43 -0
- package/templates/base/_ai/skills/pr-prepare/SKILL.md +106 -0
- package/templates/base/_ai/skills/refactor/SKILL.md +87 -0
- package/templates/base/_ai/skills/write-tests/SKILL.md +109 -0
- package/templates/base/_claude/settings.local.json +37 -0
- package/templates/base/_cursor/rules/global.mdc +7 -0
- package/templates/base/_editorconfig +18 -0
- package/templates/base/_gemini/settings.json +3 -0
- package/templates/base/_github/copilot-instructions.md +1 -0
- package/templates/base/_github/pull_request_template.md +23 -0
- package/templates/base/_gitignore +22 -0
- package/templates/base/_junie/guidelines.md +1 -0
- package/templates/base/commit-instructions.md +92 -0
- package/templates/packs/docker/_ai/instructions/docker.instructions.md +193 -0
- package/templates/packs/docker/_guidelines.md +10 -0
- package/templates/packs/docker/pack.json +8 -0
- package/templates/packs/laravel/_ai/instructions/api-resource.instructions.md +251 -0
- package/templates/packs/laravel/_ai/instructions/module.instructions.md +133 -0
- package/templates/packs/laravel/_ai/instructions/service-repository.instructions.md +215 -0
- package/templates/packs/laravel/_ai/instructions/testing.instructions.md +278 -0
- package/templates/packs/laravel/_ai/skills/migration/SKILL.md +172 -0
- package/templates/packs/laravel/_ai/skills/new-endpoint/SKILL.md +165 -0
- package/templates/packs/laravel/_ai/skills/new-module/SKILL.md +208 -0
- package/templates/packs/laravel/_ai/skills/queued-job/SKILL.md +248 -0
- package/templates/packs/laravel/_ai/skills/testing-feature/SKILL.md +196 -0
- package/templates/packs/laravel/_ai/skills/testing-manual/SKILL.md +186 -0
- package/templates/packs/laravel/_ai/skills/testing-unit/SKILL.md +200 -0
- package/templates/packs/laravel/_guidelines.md +25 -0
- package/templates/packs/laravel/pack.json +6 -0
- package/templates/packs/playwright/_ai/instructions/playwright.instructions.md +219 -0
- package/templates/packs/playwright/_ai/skills/playwright/README.md +194 -0
- package/templates/packs/playwright/_ai/skills/playwright/SKILL.md +1245 -0
- package/templates/packs/playwright/_ai/skills/playwright-codereview/SKILL.md +642 -0
- package/templates/packs/playwright/_ai/skills/playwright-record/README.md +87 -0
- package/templates/packs/playwright/_ai/skills/playwright-record/SKILL.md +564 -0
- package/templates/packs/playwright/_guidelines.md +12 -0
- package/templates/packs/playwright/pack.json +9 -0
- package/templates/packs/storybook/_ai/instructions/storybook.instructions.md +181 -0
- package/templates/packs/storybook/pack.json +6 -0
- package/templates/packs/vitest/_ai/instructions/vitest.instructions.md +688 -0
- package/templates/packs/vitest/pack.json +6 -0
- package/templates/packs/vue3/_ai/instructions/api.instructions.md +163 -0
- package/templates/packs/vue3/_ai/instructions/coding-conventions.instructions.md +160 -0
- package/templates/packs/vue3/_ai/instructions/composables.instructions.md +218 -0
- package/templates/packs/vue3/_ai/instructions/forms.instructions.md +227 -0
- package/templates/packs/vue3/_ai/instructions/store.instructions.md +504 -0
- package/templates/packs/vue3/_ai/instructions/vue.instructions.md +339 -0
- package/templates/packs/vue3/_ai/skills/api-integration/SKILL.md +195 -0
- package/templates/packs/vue3/_ai/skills/new-component/SKILL.md +133 -0
- package/templates/packs/vue3/_ai/skills/new-module/SKILL.md +177 -0
- package/templates/packs/vue3/_guidelines.md +45 -0
- package/templates/packs/vue3/pack.json +11 -0
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: playwright-codereview
|
|
3
|
+
description: Reviews Playwright test code for quality, best practices, maintainability, and adherence to project conventions. Provides actionable feedback on Page Object Models, selectors, test structure, data management, and performance optimization.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Playwright Code Review
|
|
7
|
+
|
|
8
|
+
Expert skill for reviewing Playwright E2E test code quality and ensuring adherence to best practices.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use this skill when the user:
|
|
13
|
+
|
|
14
|
+
- Requests code review for Playwright tests
|
|
15
|
+
- Asks "review my test code"
|
|
16
|
+
- Wants feedback on test quality or maintainability
|
|
17
|
+
- Needs help improving existing tests
|
|
18
|
+
- Asks about test refactoring opportunities
|
|
19
|
+
- Wants to verify compliance with project standards
|
|
20
|
+
- Requests optimization suggestions
|
|
21
|
+
- Asks "is this test written correctly?"
|
|
22
|
+
|
|
23
|
+
## Review Checklist
|
|
24
|
+
|
|
25
|
+
### 1. File Organization & Naming
|
|
26
|
+
|
|
27
|
+
**Check:**
|
|
28
|
+
- File follows `NN_NN_NN_TestName.spec.ts` format
|
|
29
|
+
- Located in correct module directory (`tests/NN_Module/`)
|
|
30
|
+
- Numbers align with module hierarchy
|
|
31
|
+
- Descriptive name with underscores
|
|
32
|
+
|
|
33
|
+
**Example Issues:**
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Wrong: Incorrect naming
|
|
37
|
+
// File: login-test.spec.ts
|
|
38
|
+
|
|
39
|
+
// Correct
|
|
40
|
+
// File: 01_01_01_Login_scenarios.spec.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Test Structure & Organization
|
|
44
|
+
|
|
45
|
+
**Check:**
|
|
46
|
+
- Uses `test.describe()` with descriptive name
|
|
47
|
+
- Has appropriate tags (`@verified`, `@smoke`, `@module`)
|
|
48
|
+
- Uses `test.step()` for multi-step tests
|
|
49
|
+
- Clear test names with scenario description
|
|
50
|
+
- Proper `beforeEach`/`afterEach` setup
|
|
51
|
+
|
|
52
|
+
**Example Review:**
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Poor structure
|
|
56
|
+
test('login test', async ({ page }) => {
|
|
57
|
+
await page.goto('/login');
|
|
58
|
+
await page.fill('#email', 'test@test.com');
|
|
59
|
+
await page.click('#submit');
|
|
60
|
+
expect(page.url()).toContain('/dashboard');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Good structure
|
|
64
|
+
test.describe('01_Login - tests', { tag: ['@login', '@verified'] }, () => {
|
|
65
|
+
let loginPage: LoginPage;
|
|
66
|
+
|
|
67
|
+
test.beforeEach(async ({ page }) => {
|
|
68
|
+
loginPage = new LoginPage(page);
|
|
69
|
+
await page.goto('/login');
|
|
70
|
+
await clearBrowserStorage(page);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('01_01_01: Login - positive result', async ({ page }) => {
|
|
74
|
+
const credentials = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
75
|
+
|
|
76
|
+
await test.step('Fill credentials', async () => {
|
|
77
|
+
await loginPage.fillEmail(credentials.email.right);
|
|
78
|
+
await loginPage.fillPassword(credentials.password.right);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await test.step('Submit and verify', async () => {
|
|
82
|
+
await loginPage.clickLoginButton();
|
|
83
|
+
await loginPage.verifySuccessfulLogin();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 3. Page Object Model (POM) Usage
|
|
90
|
+
|
|
91
|
+
**Check:**
|
|
92
|
+
- Uses Page Objects instead of direct page interactions
|
|
93
|
+
- POMs exported from `pages/index.ts`
|
|
94
|
+
- Locators defined as `private readonly`
|
|
95
|
+
- Methods are descriptive and focused
|
|
96
|
+
- No business logic in tests
|
|
97
|
+
|
|
98
|
+
**Example Review:**
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// No POM - direct page interactions
|
|
102
|
+
test('login', async ({ page }) => {
|
|
103
|
+
await page.locator('[data-testid="email-input"]').fill('test@test.com');
|
|
104
|
+
await page.locator('[data-testid="password-input"]').fill('password');
|
|
105
|
+
await page.locator('[data-testid="submit-button"]').click();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Proper POM usage
|
|
109
|
+
test('01_01_01: Login - positive result', async ({ page }) => {
|
|
110
|
+
const loginPage = new LoginPage(page);
|
|
111
|
+
const credentials = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
112
|
+
|
|
113
|
+
await loginPage.login(credentials.email.right, credentials.password.right);
|
|
114
|
+
await loginPage.verifySuccessfulLogin();
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**POM Quality Check:**
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
// Poor POM - public locators, no encapsulation
|
|
122
|
+
export class LoginPage {
|
|
123
|
+
public emailInput: Locator;
|
|
124
|
+
public passwordInput: Locator;
|
|
125
|
+
|
|
126
|
+
constructor(public page: Page) {
|
|
127
|
+
this.emailInput = page.locator('#email');
|
|
128
|
+
this.passwordInput = page.locator('#password');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Good POM - encapsulated, descriptive methods
|
|
133
|
+
export class LoginPage {
|
|
134
|
+
protected page: Page;
|
|
135
|
+
|
|
136
|
+
private readonly emailInput: Locator;
|
|
137
|
+
private readonly passwordInput: Locator;
|
|
138
|
+
private readonly submitButton: Locator;
|
|
139
|
+
|
|
140
|
+
constructor(page: Page) {
|
|
141
|
+
this.page = page;
|
|
142
|
+
this.emailInput = page.locator('[data-testid="login-email-input"]');
|
|
143
|
+
this.passwordInput = page.locator('[data-testid="login-password-input"]');
|
|
144
|
+
this.submitButton = page.locator('[data-testid="login-submit-button"]');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Fill email input field
|
|
149
|
+
*/
|
|
150
|
+
async fillEmail(email: string): Promise<void> {
|
|
151
|
+
await this.emailInput.waitFor({ state: 'visible' });
|
|
152
|
+
await this.emailInput.clear();
|
|
153
|
+
await this.emailInput.fill(email);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Complete login flow
|
|
158
|
+
*/
|
|
159
|
+
async login(email: string, password: string): Promise<void> {
|
|
160
|
+
await this.fillEmail(email);
|
|
161
|
+
await this.fillPassword(password);
|
|
162
|
+
await this.submitButton.click();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 4. Selectors & Locators
|
|
168
|
+
|
|
169
|
+
**Check:**
|
|
170
|
+
- Uses `data-testid` selectors (preferred)
|
|
171
|
+
- Follows naming convention: `module-element-type`
|
|
172
|
+
- Uses `getByDataTestId()` helper
|
|
173
|
+
- Provides fallbacks for legacy selectors
|
|
174
|
+
- Avoids fragile CSS class selectors
|
|
175
|
+
|
|
176
|
+
**Example Review:**
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// Bad selectors
|
|
180
|
+
private emailInput = this.page.locator('.form-input.email-field');
|
|
181
|
+
private submitBtn = this.page.locator('button.btn-primary');
|
|
182
|
+
private error = this.page.locator('div.alert.alert-danger');
|
|
183
|
+
|
|
184
|
+
// Good selectors
|
|
185
|
+
private readonly emailInput: Locator = this.page.locator('[data-testid="login-email-input"]');
|
|
186
|
+
private readonly submitButton: Locator = this.page.locator('[data-testid="login-submit-button"]');
|
|
187
|
+
private readonly errorAlert: Locator = this.page.locator('[data-testid="login-error-alert"]');
|
|
188
|
+
|
|
189
|
+
// Even better - with helper and fallbacks
|
|
190
|
+
private readonly emailInput: Locator = this.page
|
|
191
|
+
.locator('[data-testid="loginViewEmailStepInput"], [data-testid="loginEmailInput"]')
|
|
192
|
+
.first();
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Naming Convention Check:**
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// Wrong naming
|
|
199
|
+
data-testid="emailInput" // Missing module prefix
|
|
200
|
+
data-testid="login_email_input" // Wrong separator (underscore)
|
|
201
|
+
data-testid="loginEmailInput" // camelCase instead of kebab-case
|
|
202
|
+
|
|
203
|
+
// Correct naming
|
|
204
|
+
data-testid="login-email-input"
|
|
205
|
+
data-testid="login-password-input"
|
|
206
|
+
data-testid="login-submit-button"
|
|
207
|
+
data-testid="tasks-add-new-button"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 5. Test Data & Fixtures
|
|
211
|
+
|
|
212
|
+
**Check:**
|
|
213
|
+
- Uses `{{CREDENTIALS_LOADER}}` for credentials
|
|
214
|
+
- No hardcoded credentials
|
|
215
|
+
- Dynamic data loading from fixtures
|
|
216
|
+
- Uses environment variables appropriately
|
|
217
|
+
- Proper TypeScript interfaces for data
|
|
218
|
+
|
|
219
|
+
**Example Review:**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// Hardcoded credentials
|
|
223
|
+
test('login', async ({ page }) => {
|
|
224
|
+
await loginPage.login('test@example.com', 'Password123!');
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Dynamic credentials
|
|
228
|
+
test('01_01_01: Login', async ({ page }) => {
|
|
229
|
+
const credentials = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
230
|
+
await loginPage.login(credentials.email.right, credentials.password.right);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Hardcoded test data
|
|
234
|
+
const userData = {
|
|
235
|
+
name: 'John Doe',
|
|
236
|
+
email: 'john@test.com'
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Fixture-based test data
|
|
240
|
+
const appData = await {{CREDENTIALS_LOADER}}.getAllData();
|
|
241
|
+
const testUser = appData.users.admin;
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 6. Waits & Stability
|
|
245
|
+
|
|
246
|
+
**Check:**
|
|
247
|
+
- Waits for visibility before interactions
|
|
248
|
+
- Uses `waitForLoadState('networkidle')` when needed
|
|
249
|
+
- Proper timeout configuration
|
|
250
|
+
- No arbitrary `page.waitForTimeout()`
|
|
251
|
+
- Handles async operations correctly
|
|
252
|
+
|
|
253
|
+
**Example Review:**
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// No waits - flaky test
|
|
257
|
+
await page.locator('[data-testid="button"]').click();
|
|
258
|
+
await expect(page.locator('[data-testid="result"]')).toBeVisible();
|
|
259
|
+
|
|
260
|
+
// Arbitrary timeout
|
|
261
|
+
await page.waitForTimeout(3000);
|
|
262
|
+
await page.locator('[data-testid="button"]').click();
|
|
263
|
+
|
|
264
|
+
// Proper waits
|
|
265
|
+
await page.locator('[data-testid="button"]').waitFor({ state: 'visible' });
|
|
266
|
+
await page.locator('[data-testid="button"]').click();
|
|
267
|
+
await page.waitForLoadState('networkidle');
|
|
268
|
+
await expect(page.locator('[data-testid="result"]')).toBeVisible();
|
|
269
|
+
|
|
270
|
+
// In POM method
|
|
271
|
+
async clickSubmitButton(): Promise<void> {
|
|
272
|
+
await this.submitButton.waitFor({ state: 'visible' });
|
|
273
|
+
await this.submitButton.click();
|
|
274
|
+
await this.page.waitForLoadState('networkidle');
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 7. Assertions & Verifications
|
|
279
|
+
|
|
280
|
+
**Check:**
|
|
281
|
+
- Uses specific Playwright assertions
|
|
282
|
+
- Meaningful assertion messages
|
|
283
|
+
- Verifies state changes
|
|
284
|
+
- Tests both positive and negative scenarios
|
|
285
|
+
- Appropriate timeout for assertions
|
|
286
|
+
|
|
287
|
+
**Example Review:**
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
// Generic assertions
|
|
291
|
+
expect(await page.url()).toBe('{{BASE_URL}}/dashboard');
|
|
292
|
+
expect(await page.locator('.alert').isVisible()).toBe(true);
|
|
293
|
+
|
|
294
|
+
// Specific Playwright assertions
|
|
295
|
+
await expect(page).toHaveURL(/\/dashboard/);
|
|
296
|
+
await expect(page.locator('[data-testid="error-alert"]')).toBeVisible();
|
|
297
|
+
await expect(page.locator('[data-testid="submit-button"]')).toBeDisabled();
|
|
298
|
+
|
|
299
|
+
// Verification methods in POM
|
|
300
|
+
async verifySuccessfulLogin(): Promise<void> {
|
|
301
|
+
await this.page.waitForURL(/\/dashboard/, { timeout: 15000 });
|
|
302
|
+
await this.page.waitForLoadState('networkidle');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async verifyErrorAlert(): Promise<void> {
|
|
306
|
+
await this.errorAlert.waitFor({ state: 'visible', timeout: 5000 });
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### 8. Browser State Management
|
|
311
|
+
|
|
312
|
+
**Check:**
|
|
313
|
+
- Clears browser storage in `beforeEach`
|
|
314
|
+
- Navigates to clean state before tests
|
|
315
|
+
- Uses session management when appropriate
|
|
316
|
+
- Proper cleanup in `afterEach` if needed
|
|
317
|
+
|
|
318
|
+
**Example Review:**
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// No cleanup - state leaks between tests
|
|
322
|
+
test.beforeEach(async ({ page }) => {
|
|
323
|
+
await page.goto('/login');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Proper cleanup
|
|
327
|
+
test.beforeEach(async ({ page }) => {
|
|
328
|
+
loginPage = new LoginPage(page);
|
|
329
|
+
await page.goto('/login');
|
|
330
|
+
|
|
331
|
+
// Clear all browser storage
|
|
332
|
+
await clearBrowserStorage(page);
|
|
333
|
+
|
|
334
|
+
// Wait for page ready state
|
|
335
|
+
await loginPage.waitForPageReady();
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 9. TypeScript Best Practices
|
|
340
|
+
|
|
341
|
+
**Check:**
|
|
342
|
+
- Proper type annotations
|
|
343
|
+
- Interfaces for complex objects
|
|
344
|
+
- No `any` types
|
|
345
|
+
- Async/await consistency
|
|
346
|
+
- Proper error handling
|
|
347
|
+
|
|
348
|
+
**Example Review:**
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
// Poor TypeScript
|
|
352
|
+
async function getLoginData() {
|
|
353
|
+
const data: any = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
354
|
+
return data;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Good TypeScript
|
|
358
|
+
interface ILoginData {
|
|
359
|
+
validEmail: string;
|
|
360
|
+
validPassword: string;
|
|
361
|
+
invalidEmail: string;
|
|
362
|
+
invalidPassword: string;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async function getLoginData(): Promise<ILoginData> {
|
|
366
|
+
const credentials = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
validEmail: credentials.email.right,
|
|
370
|
+
validPassword: credentials.password.right,
|
|
371
|
+
invalidEmail: credentials.email.wrong,
|
|
372
|
+
invalidPassword: credentials.password.wrong,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### 10. Tags & Test Categories
|
|
378
|
+
|
|
379
|
+
**Check:**
|
|
380
|
+
- Appropriate tags assigned
|
|
381
|
+
- `@verified` for stable tests
|
|
382
|
+
- `@smoke` for critical paths
|
|
383
|
+
- Module-specific tags (`@login`, `@tasks`)
|
|
384
|
+
- Tags at describe or test level
|
|
385
|
+
|
|
386
|
+
**Example Review:**
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
// No tags
|
|
390
|
+
test.describe('Login tests', () => {
|
|
391
|
+
test('successful login', async ({ page }) => {
|
|
392
|
+
// test
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Proper tagging
|
|
397
|
+
test.describe('01_Login - tests', { tag: ['@login', '@verified', '@smoke'] }, () => {
|
|
398
|
+
test('01_01_01: Login - positive result', async ({ page }) => {
|
|
399
|
+
// test
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Override tags for specific test
|
|
403
|
+
test('01_01_02: Login - edge case', { tag: '@login' }, async ({ page }) => {
|
|
404
|
+
// test
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Code Review Process
|
|
410
|
+
|
|
411
|
+
### Step 1: Initial Assessment
|
|
412
|
+
|
|
413
|
+
1. Check file location and naming
|
|
414
|
+
2. Verify test structure basics
|
|
415
|
+
3. Identify obvious anti-patterns
|
|
416
|
+
4. Note missing imports or utilities
|
|
417
|
+
|
|
418
|
+
### Step 2: Deep Review
|
|
419
|
+
|
|
420
|
+
1. Analyze POM usage and quality
|
|
421
|
+
2. Review selector strategy
|
|
422
|
+
3. Check data management
|
|
423
|
+
4. Verify waits and stability
|
|
424
|
+
5. Assess assertions quality
|
|
425
|
+
|
|
426
|
+
### Step 3: Provide Feedback
|
|
427
|
+
|
|
428
|
+
**Format:**
|
|
429
|
+
|
|
430
|
+
```markdown
|
|
431
|
+
## Review Summary
|
|
432
|
+
|
|
433
|
+
### Strengths
|
|
434
|
+
- Good use of Page Objects
|
|
435
|
+
- Proper test.step() usage
|
|
436
|
+
- Clear test naming
|
|
437
|
+
|
|
438
|
+
### Issues Found
|
|
439
|
+
|
|
440
|
+
**1. Selector Quality (High Priority)**
|
|
441
|
+
- Line 15: Using CSS class selector instead of data-testid
|
|
442
|
+
- Line 23: Hardcoded selector without fallback
|
|
443
|
+
|
|
444
|
+
**2. Missing Waits (Medium Priority)**
|
|
445
|
+
- Line 30: Click without waiting for visibility
|
|
446
|
+
- Line 45: No networkidle wait after navigation
|
|
447
|
+
|
|
448
|
+
**3. Hardcoded Data (Low Priority)**
|
|
449
|
+
- Line 12: Hardcoded email instead of {{CREDENTIALS_LOADER}}
|
|
450
|
+
|
|
451
|
+
### Suggested Changes
|
|
452
|
+
|
|
453
|
+
[Provide specific code examples]
|
|
454
|
+
|
|
455
|
+
### Quality Score: 7/10
|
|
456
|
+
|
|
457
|
+
**Areas for Improvement:**
|
|
458
|
+
1. Improve selector strategy
|
|
459
|
+
2. Add proper waits
|
|
460
|
+
3. Use dynamic test data
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Step 4: Suggest Refactoring
|
|
464
|
+
|
|
465
|
+
Provide concrete refactoring examples:
|
|
466
|
+
|
|
467
|
+
```typescript
|
|
468
|
+
// BEFORE
|
|
469
|
+
test('login test', async ({ page }) => {
|
|
470
|
+
await page.goto('/login');
|
|
471
|
+
await page.locator('.email-input').fill('test@test.com');
|
|
472
|
+
await page.locator('.password-input').fill('pass123');
|
|
473
|
+
await page.locator('.submit-btn').click();
|
|
474
|
+
expect(page.url()).toContain('/dashboard');
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// AFTER
|
|
478
|
+
test('01_01_01: Login - positive result', async ({ page }) => {
|
|
479
|
+
const credentials = await {{CREDENTIALS_LOADER}}.getCredentials();
|
|
480
|
+
|
|
481
|
+
await test.step('Login with valid credentials', async () => {
|
|
482
|
+
await loginPage.login(credentials.email.right, credentials.password.right);
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
await test.step('Verify successful redirect', async () => {
|
|
486
|
+
await loginPage.verifySuccessfulLogin();
|
|
487
|
+
await expect(page).toHaveURL(/\/dashboard/);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Common Review Findings
|
|
493
|
+
|
|
494
|
+
### Critical Issues (Must Fix)
|
|
495
|
+
|
|
496
|
+
1. **Hardcoded Credentials**
|
|
497
|
+
- Impact: Security risk, inflexibility
|
|
498
|
+
- Fix: Use `{{CREDENTIALS_LOADER}}.getCredentials()`
|
|
499
|
+
|
|
500
|
+
2. **No Page Objects**
|
|
501
|
+
- Impact: Poor maintainability, code duplication
|
|
502
|
+
- Fix: Create proper POM classes
|
|
503
|
+
|
|
504
|
+
3. **CSS Class Selectors**
|
|
505
|
+
- Impact: Fragile tests, high maintenance
|
|
506
|
+
- Fix: Use `data-testid` selectors
|
|
507
|
+
|
|
508
|
+
4. **Missing Waits**
|
|
509
|
+
- Impact: Flaky tests, unreliable CI/CD
|
|
510
|
+
- Fix: Add `.waitFor({ state: 'visible' })`
|
|
511
|
+
|
|
512
|
+
### Medium Issues (Should Fix)
|
|
513
|
+
|
|
514
|
+
1. **No Test Steps**
|
|
515
|
+
- Impact: Poor reporting, hard to debug
|
|
516
|
+
- Fix: Wrap logic in `test.step()`
|
|
517
|
+
|
|
518
|
+
2. **Missing Tags**
|
|
519
|
+
- Impact: Can't filter tests effectively
|
|
520
|
+
- Fix: Add appropriate tags
|
|
521
|
+
|
|
522
|
+
3. **No Browser Cleanup**
|
|
523
|
+
- Impact: State leaks between tests
|
|
524
|
+
- Fix: Use `clearBrowserStorage()` in `beforeEach`
|
|
525
|
+
|
|
526
|
+
### Low Issues (Nice to Have)
|
|
527
|
+
|
|
528
|
+
1. **Missing JSDoc**
|
|
529
|
+
- Impact: Reduced code clarity
|
|
530
|
+
- Fix: Add documentation comments
|
|
531
|
+
|
|
532
|
+
2. **Inconsistent Naming**
|
|
533
|
+
- Impact: Harder to navigate
|
|
534
|
+
- Fix: Follow NN_NN_NN convention
|
|
535
|
+
|
|
536
|
+
3. **No TypeScript Interfaces**
|
|
537
|
+
- Impact: Reduced type safety
|
|
538
|
+
- Fix: Define proper interfaces
|
|
539
|
+
|
|
540
|
+
## Review Templates
|
|
541
|
+
|
|
542
|
+
### Quick Review Template
|
|
543
|
+
|
|
544
|
+
```markdown
|
|
545
|
+
## Playwright Test Review
|
|
546
|
+
|
|
547
|
+
**File**: `[file path]`
|
|
548
|
+
**Reviewer**: AI Agent
|
|
549
|
+
**Date**: [date]
|
|
550
|
+
|
|
551
|
+
### Summary
|
|
552
|
+
[Brief overview]
|
|
553
|
+
|
|
554
|
+
### Checklist
|
|
555
|
+
- [ ] File naming convention
|
|
556
|
+
- [ ] Test structure (describe, tags, steps)
|
|
557
|
+
- [ ] Page Object usage
|
|
558
|
+
- [ ] Selector quality (data-testid)
|
|
559
|
+
- [ ] Test data management
|
|
560
|
+
- [ ] Waits and stability
|
|
561
|
+
- [ ] Assertions quality
|
|
562
|
+
- [ ] Browser cleanup
|
|
563
|
+
- [ ] TypeScript types
|
|
564
|
+
|
|
565
|
+
### Key Findings
|
|
566
|
+
1. [Issue 1]
|
|
567
|
+
2. [Issue 2]
|
|
568
|
+
3. [Issue 3]
|
|
569
|
+
|
|
570
|
+
### Recommendations
|
|
571
|
+
[List of action items]
|
|
572
|
+
|
|
573
|
+
### Overall Score: X/10
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Detailed Review Template
|
|
577
|
+
|
|
578
|
+
Use the 10-point checklist above and provide specific line-by-line feedback.
|
|
579
|
+
|
|
580
|
+
## Performance Review
|
|
581
|
+
|
|
582
|
+
### Check for Performance Issues
|
|
583
|
+
|
|
584
|
+
1. **Unnecessary waits**
|
|
585
|
+
- Avoid `page.waitForTimeout()` unless absolutely needed
|
|
586
|
+
- Use specific waits (`waitFor`, `waitForLoadState`)
|
|
587
|
+
|
|
588
|
+
2. **Inefficient selectors**
|
|
589
|
+
- Use data-testid instead of complex CSS
|
|
590
|
+
- Avoid xpath when possible
|
|
591
|
+
|
|
592
|
+
3. **Redundant navigation**
|
|
593
|
+
- Navigate once in `beforeEach`, not in every test
|
|
594
|
+
|
|
595
|
+
4. **Missing parallel execution support**
|
|
596
|
+
- Tests should be independent
|
|
597
|
+
- No shared state between tests
|
|
598
|
+
|
|
599
|
+
## Maintainability Review
|
|
600
|
+
|
|
601
|
+
### Check for Maintainability
|
|
602
|
+
|
|
603
|
+
1. **Code duplication**
|
|
604
|
+
- Repeated selectors -> Move to POM
|
|
605
|
+
- Repeated actions -> Create helper methods
|
|
606
|
+
- Repeated data -> Use fixtures
|
|
607
|
+
|
|
608
|
+
2. **Magic numbers/strings**
|
|
609
|
+
- Hardcoded values -> Use constants or fixtures
|
|
610
|
+
- Inline timeouts -> Use config defaults
|
|
611
|
+
|
|
612
|
+
3. **Poor naming**
|
|
613
|
+
- Unclear variable names
|
|
614
|
+
- Generic method names
|
|
615
|
+
- Missing context
|
|
616
|
+
|
|
617
|
+
4. **Missing documentation**
|
|
618
|
+
- No JSDoc for complex methods
|
|
619
|
+
- No comments for non-obvious logic
|
|
620
|
+
|
|
621
|
+
## Quick Reference: Review Priorities
|
|
622
|
+
|
|
623
|
+
| Priority | Issue | Impact | Fix Effort |
|
|
624
|
+
|----------|-------|--------|------------|
|
|
625
|
+
| Critical | Hardcoded credentials | Security | Low |
|
|
626
|
+
| Critical | No POM usage | Maintainability | High |
|
|
627
|
+
| Critical | CSS class selectors | Fragility | Medium |
|
|
628
|
+
| Medium | Missing waits | Flakiness | Low |
|
|
629
|
+
| Medium | No test steps | Debugging | Low |
|
|
630
|
+
| Medium | Missing tags | Filtering | Low |
|
|
631
|
+
| Low | No JSDoc | Clarity | Medium |
|
|
632
|
+
| Low | Inconsistent naming | Navigation | Low |
|
|
633
|
+
|
|
634
|
+
## Resources
|
|
635
|
+
|
|
636
|
+
- **Main Playwright Skill**: `.github/skills/playwright/SKILL.md`
|
|
637
|
+
- **Project README**: `{{PLAYWRIGHT_DIR}}/README.md`
|
|
638
|
+
- **Playwright Best Practices**: https://playwright.dev/docs/best-practices
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
**Remember**: Code review should be constructive and educational. Provide specific examples and actionable feedback.
|