playwright-test-maintainer
Maintain, refactor, and improve existing Playwright E2E tests. Handles tasks like updating locators across test suites, extracting reusable utilities, improving test stability, removing code duplication, and enforcing best practices throughout the test codebase.
What this skill does
## When to Use This Skill
Use this skill when you need to:
- Update data-testid locators across multiple tests
- Refactor duplicate code into utilities or Page Objects
- Improve flaky or unstable tests
- Extract common test patterns into reusable fixtures
- Update tests after UI changes
- Migrate tests to use Page Object Model
- Consolidate similar tests
- Improve test readability and maintainability
Do NOT use this skill when:
- Creating new tests from scratch (use test-generator skill)
- Building new Page Objects (use page-object-builder skill)
- Debugging test failures (use test-debugger skill)
## Prerequisites
Before using this skill:
1. Access to existing test files
2. Understanding of what changes are needed
3. Knowledge of the current test structure
4. Optional: Test execution results to identify flaky tests
## Instructions
### Step 1: Assess Current State
Gather information about:
- **Test files** requiring maintenance
- **Type of maintenance** needed (refactor, update locators, fix flakiness)
- **Scope** of changes (single file, multiple files, entire suite)
- **Current issues** (duplication, poor practices, flakiness)
- **Desired end state** (what should the tests look like after)
### Step 2: Identify Maintenance Type
Determine the maintenance task:
**Locator Updates:**
- Changing data-testid values
- Updating selectors after UI changes
- Migrating from CSS/XPath to data-testid
**Code Refactoring:**
- Extracting duplicate code to utilities
- Creating Page Objects from inline selectors
- Consolidating similar tests
- Improving test structure
**Stability Improvements:**
- Adding explicit waits
- Fixing race conditions
- Removing hardcoded waits
- Improving assertions
**Best Practices:**
- Enforcing data-testid usage
- Implementing AAA pattern
- Adding proper TypeScript types
- Improving test isolation
### Step 3: Plan the Changes
Before making changes:
1. **Identify all affected files**
2. **Backup or commit current state** (git commit)
3. **Create checklist** of changes to make
4. **Plan refactoring strategy** (bottom-up or top-down)
5. **Consider impact** on other tests
### Step 4: Apply Maintenance
Execute the maintenance based on type:
#### Locator Updates
```typescript
// Task: Update data-testid from "btn-submit" to "submit-button"
// Before (multiple files)
await page.locator('[data-testid="btn-submit"]').click();
// After (updated in all files)
await page.locator('[data-testid="submit-button"]').click();
// Use search and replace across files
// Find: '[data-testid="btn-submit"]'
// Replace: '[data-testid="submit-button"]'
```
#### Extract Utilities
```typescript
// Before: Duplicate login code in multiple tests
test("test 1", async ({ page }) => {
await page.goto("/login");
await page.locator('[data-testid="email"]').fill("[email protected]");
await page.locator('[data-testid="password"]').fill("password");
await page.locator('[data-testid="login-button"]').click();
await page.waitForURL("/dashboard");
// ... test continues
});
// After: Extract to utility function
// In utils/auth.ts
export async function login(page: Page, email: string, password: string) {
await page.goto("/login");
await page.locator('[data-testid="email"]').fill(email);
await page.locator('[data-testid="password"]').fill(password);
await page.locator('[data-testid="login-button"]').click();
await page.waitForURL("/dashboard");
}
// In tests
test("test 1", async ({ page }) => {
await login(page, "[email protected]", "password");
// ... test continues
});
```
#### Migrate to Page Objects
```typescript
// Before: Inline selectors throughout tests
test("update profile", async ({ page }) => {
await page.goto("/profile");
await page.locator('[data-testid="name-input"]').fill("John Doe");
await page.locator('[data-testid="email-input"]').fill("[email protected]");
await page.locator('[data-testid="save-button"]').click();
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
});
// After: Using Page Object
// Create ProfilePage.ts (see page-object-builder skill)
test("update profile", async ({ page }) => {
const profilePage = new ProfilePage(page);
await profilePage.goto();
await profilePage.updateProfile({
name: "John Doe",
email: "[email protected]",
});
await expect(profilePage.getSuccessMessage()).toBeVisible();
});
```
#### Fix Flaky Tests
```typescript
// Before: Flaky due to race condition
await page.locator('[data-testid="submit"]').click();
await expect(page.locator('[data-testid="result"]')).toContainText("Success");
// After: Add proper waits
await page.locator('[data-testid="submit"]').click();
await page.waitForLoadState("networkidle");
await expect(page.locator('[data-testid="result"]')).toContainText("Success", {
timeout: 10000,
});
```
### Step 5: Ensure Consistency
After changes:
- [ ] All tests use data-testid locators
- [ ] Consistent naming conventions
- [ ] Follow AAA pattern
- [ ] Proper TypeScript types
- [ ] No code duplication
- [ ] Tests are isolated
- [ ] Proper waits (no hardcoded timeouts)
### Step 6: Verify Changes
Run tests to ensure:
1. **All tests pass** after refactoring
2. **No regressions** introduced
3. **Improved stability** (run multiple times)
4. **Better readability** and maintainability
5. **Reduced code duplication**
## Examples
### Example 1: Update Locators Across Test Suite
**Input:**
"The development team changed all button data-testids from format 'btn-action' to 'action-button'. Update all tests."
**Changes:**
```typescript
// Create mapping of old to new testids
const locatorUpdates = {
"btn-submit": "submit-button",
"btn-cancel": "cancel-button",
"btn-delete": "delete-button",
"btn-edit": "edit-button",
"btn-save": "save-button",
};
// Apply to all test files:
// Find all instances in: tests/**/*.spec.ts
// Example in login.spec.ts:
// Before
await page.locator('[data-testid="btn-submit"]').click();
// After
await page.locator('[data-testid="submit-button"]').click();
// Use global find and replace for each mapping
```
**Verification:**
```bash
# Search for old pattern to ensure all updated
grep -r "btn-" tests/
# Run all tests
npx playwright test
# Check for any failures
```
### Example 2: Extract Common Test Utilities
**Input:**
"Multiple tests have duplicate code for filling forms. Extract to reusable utilities."
**Solution:**
```typescript
// Identify duplicate pattern across tests:
// Pattern 1: Form filling
await page.locator('[data-testid="field1"]').fill(value1);
await page.locator('[data-testid="field2"]').fill(value2);
await page.locator('[data-testid="field3"]').fill(value3);
// Create utils/form-helpers.ts:
import { Page } from "@playwright/test";
export async function fillForm(
page: Page,
fields: Record<string, string>,
): Promise<void> {
for (const [testId, value] of Object.entries(fields)) {
await page.locator(`[data-testid="${testId}"]`).fill(value);
}
}
export async function submitForm(
page: Page,
submitButtonTestId: string,
): Promise<void> {
await page
.locator(`[data-testid="${submitButtonTestId}"]`)
.waitFor({ state: "visible" });
await page.locator(`[data-testid="${submitButtonTestId}"]`).click();
}
// Update all tests to use utilities:
import { fillForm, submitForm } from "../utils/form-helpers";
test("contact form submission", async ({ page }) => {
await page.goto("/contact");
await fillForm(page, {
"name-input": "John Doe",
"email-input": "[email protected]",
"message-input": "Hello!",
});
await submitForm(page, "submit-button");
await expect(page.locator('[data-testid="success"]')).toBeVisible();
});
```
### Example 3: Consolidate Similar Tests
**Input:**
"We have 5 tests that test form validation with different invalid inputs. Consolidate using test.each."
**Before:**
```typescript
test("should show error for empty email", async ({ page }) => {
await page.goto("/register");
awaiRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.