Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:48:03 +08:00
commit 79a8dc71a5
14 changed files with 4403 additions and 0 deletions

388
commands/sng-e2e-test.md Normal file
View File

@@ -0,0 +1,388 @@
# E2E Test Generator with Playwright
You are helping the user create end-to-end tests using Playwright, leveraging the Playwright MCP server for browser automation capabilities.
## Instructions
1. **Detect the testing setup**: Check if Playwright is already configured in the project
- Look for `playwright.config.ts` or `playwright.config.js`
- Check `package.json` for Playwright dependencies
- If not found, offer to set up Playwright
2. **Analyze the application**: Understand the project structure
- Detect framework (Next.js, React, Vue.js, etc.)
- Identify routes and pages to test
- Check for existing test patterns
3. **Ask for test requirements**: Get specific details from the user
- What user flow should be tested?
- What pages/routes are involved?
- What are the critical interactions to verify?
- What data/state needs to be set up?
4. **Leverage Playwright MCP tools**: Use the available MCP tools for:
- Browser automation
- Page navigation
- Element interaction
- Accessibility snapshot analysis
- Screenshot capture (if needed)
5. **Generate comprehensive E2E tests** with:
- Proper test structure and organization
- Page Object Model (POM) pattern when appropriate
- Accessibility checks using Playwright's built-in tools
- Visual regression tests if applicable
- Mobile viewport testing
- Error handling and retry logic
6. **Include test utilities**:
- Authentication helpers
- Data seeding/cleanup functions
- Custom fixtures
- Reusable test helpers
## Best Practices to Follow
### Test Organization
- Group tests by feature or user flow
- Use descriptive test names that explain the scenario
- Implement Page Object Model for maintainable tests
- Keep tests independent and isolated
### Playwright Best Practices
- Use locators wisely (prefer role-based and accessible selectors)
- Wait for elements properly (avoid fixed timeouts)
- Test across multiple browsers when critical
- Use fixtures for setup/teardown
- Leverage auto-waiting features
- Take screenshots on failure
### Accessibility Testing
- Use Playwright's accessibility tree snapshots
- Test keyboard navigation
- Verify ARIA attributes
- Check focus management
- Test screen reader compatibility
### Performance & Reliability
- Run tests in parallel when possible
- Use headless mode for CI/CD
- Implement proper error handling
- Add retry logic for flaky tests
- Mock external API calls when appropriate
## Example Test Structure
### Basic E2E Test
```typescript
import { test, expect } from '@playwright/test'
test.describe('User Authentication Flow', () => {
test('user can sign up with valid credentials', async ({ page }) => {
await page.goto('/signup')
// Fill form using accessible selectors
await page.getByRole('textbox', { name: /email/i }).fill('user@example.com')
await page.getByRole('textbox', { name: /password/i }).fill('SecurePass123!')
await page.getByRole('textbox', { name: /confirm password/i }).fill('SecurePass123!')
// Submit form
await page.getByRole('button', { name: /sign up/i }).click()
// Verify success
await expect(page).toHaveURL(/\/dashboard/)
await expect(page.getByRole('heading', { name: /welcome/i })).toBeVisible()
})
test('shows validation errors for invalid email', async ({ page }) => {
await page.goto('/signup')
await page.getByRole('textbox', { name: /email/i }).fill('invalid-email')
await page.getByRole('button', { name: /sign up/i }).click()
await expect(page.getByText(/valid email/i)).toBeVisible()
})
})
```
### Page Object Model Example
```typescript
// pages/SignupPage.ts
import { Page, Locator } from '@playwright/test'
export class SignupPage {
readonly page: Page
readonly emailInput: Locator
readonly passwordInput: Locator
readonly confirmPasswordInput: Locator
readonly submitButton: Locator
constructor(page: Page) {
this.page = page
this.emailInput = page.getByRole('textbox', { name: /email/i })
this.passwordInput = page.getByRole('textbox', { name: /^password$/i })
this.confirmPasswordInput = page.getByRole('textbox', { name: /confirm password/i })
this.submitButton = page.getByRole('button', { name: /sign up/i })
}
async goto() {
await this.page.goto('/signup')
}
async signup(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
await this.confirmPasswordInput.fill(password)
await this.submitButton.click()
}
}
// Usage in test
test('user can sign up', async ({ page }) => {
const signupPage = new SignupPage(page)
await signupPage.goto()
await signupPage.signup('user@example.com', 'SecurePass123!')
await expect(page).toHaveURL(/\/dashboard/)
})
```
### Accessibility Testing
```typescript
import { test, expect } from '@playwright/test'
import AxeBuilder from '@axe-core/playwright'
test('checkout page should not have accessibility violations', async ({ page }) => {
await page.goto('/checkout')
const accessibilityScanResults = await new AxeBuilder({ page }).analyze()
expect(accessibilityScanResults.violations).toEqual([])
})
test('navigation works with keyboard only', async ({ page }) => {
await page.goto('/')
// Tab through navigation
await page.keyboard.press('Tab')
await expect(page.getByRole('link', { name: /home/i })).toBeFocused()
await page.keyboard.press('Tab')
await expect(page.getByRole('link', { name: /about/i })).toBeFocused()
// Activate link with Enter
await page.keyboard.press('Enter')
await expect(page).toHaveURL(/\/about/)
})
```
### API Mocking
```typescript
test('displays products from API', async ({ page }) => {
// Mock API response
await page.route('**/api/products', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([
{ id: 1, name: 'Product 1', price: 29.99 },
{ id: 2, name: 'Product 2', price: 39.99 }
])
})
})
await page.goto('/products')
await expect(page.getByText('Product 1')).toBeVisible()
await expect(page.getByText('Product 2')).toBeVisible()
})
```
### Authentication Setup
```typescript
// auth.setup.ts
import { test as setup } from '@playwright/test'
const authFile = 'playwright/.auth/user.json'
setup('authenticate', async ({ page }) => {
await page.goto('/login')
await page.getByRole('textbox', { name: /email/i }).fill('user@example.com')
await page.getByRole('textbox', { name: /password/i }).fill('password123')
await page.getByRole('button', { name: /log in/i }).click()
await page.waitForURL('/dashboard')
// Save authentication state
await page.context().storageState({ path: authFile })
})
// Use in tests
test.use({ storageState: authFile })
```
## File Structure
```
tests/
├── e2e/
│ ├── auth/
│ │ ├── signup.spec.ts
│ │ └── login.spec.ts
│ ├── checkout/
│ │ └── checkout-flow.spec.ts
│ └── navigation/
│ └── main-nav.spec.ts
├── fixtures/
│ ├── auth.ts
│ └── data.ts
├── pages/
│ ├── SignupPage.ts
│ ├── LoginPage.ts
│ └── DashboardPage.ts
└── utils/
├── test-helpers.ts
└── mock-data.ts
```
## Playwright Configuration Example
```typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests/e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'setup',
testMatch: /.*\.setup\.ts/,
},
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
dependencies: ['setup'],
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
dependencies: ['setup'],
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
dependencies: ['setup'],
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
dependencies: ['setup'],
},
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
})
```
## Test Checklist
For each critical user flow, ensure tests cover:
- [ ] Happy path (successful completion)
- [ ] Error handling (validation, network errors)
- [ ] Edge cases (empty states, long content)
- [ ] Accessibility (keyboard navigation, ARIA)
- [ ] Mobile responsiveness
- [ ] Loading states
- [ ] Authentication flows
- [ ] Cross-browser compatibility
## Common Test Scenarios
1. **Authentication Flows**: Login, signup, logout, password reset
2. **Forms**: Validation, submission, error handling
3. **Navigation**: Links, routing, breadcrumbs
4. **E-commerce**: Product browsing, cart, checkout
5. **Data Tables**: Sorting, filtering, pagination
6. **Modals/Dialogs**: Open, close, form submission
7. **File Uploads**: Single/multiple files, drag-and-drop
8. **Real-time Updates**: WebSocket connections, polling
## Security Testing Considerations
- Test authentication boundaries
- Verify protected routes
- Check XSS prevention
- Test CSRF protection
- Validate input sanitization
- Test rate limiting (if applicable)
## CI/CD Integration
```yaml
# Example GitHub Actions workflow
name: Playwright Tests
on:
push:
branches: [ main, dev ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
```
## Output Format
When generating E2E tests, provide:
1. Complete test files with proper imports
2. Page Object Models if multiple tests use same pages
3. Test fixtures and utilities as needed
4. Playwright configuration if not present
5. Clear comments explaining complex interactions
6. Instructions for running the tests
7. CI/CD integration suggestions
## Getting Started
Ask the user: "What user flow or feature would you like to create E2E tests for?"
Once you understand the requirements, use the Playwright MCP tools to:
1. Navigate to the relevant pages
2. Analyze the page structure
3. Generate appropriate test code
4. Verify accessibility
5. Create comprehensive test coverage