← スキル一覧に戻る

e2e-testing
by marcusta
⭐ 0🍴 0📅 2026年1月14日
SKILL.md
name: e2e-testing description: Guide E2E testing with Playwright for TapScore frontend. Use when writing or running frontend tests for user flows, navigation, forms, or mobile responsiveness. Ensures tests follow Page Object Model and proper async patterns.
TapScore E2E Testing Skill
This skill guides E2E testing with Playwright. Use when writing or running ANY frontend tests.
Testing Workflow
Copy this checklist and track your progress:
E2E Testing Progress:
- [ ] Step 1: Read testing patterns
- [ ] Step 2: Set up test structure
- [ ] Step 3: Write tests with proper selectors
- [ ] Step 4: Run tests and verify
- [ ] Step 5: Test mobile responsiveness
Step 1: Read Testing Patterns
MANDATORY - Read this file before testing:
cat docs/testing/FRONTEND_TEST_GUIDE.md
What to extract:
- Page Object Model patterns
- Playwright test structure
- Selector best practices (data-testid)
- Async handling patterns
Step 2: Set Up Test Structure
Test File Organization
import { test, expect } from '@playwright/test';
test.describe('Feature Name', () => {
test.beforeEach(async ({ page }) => {
// Navigate to starting point
await page.goto('/relevant/path');
});
test('specific behavior description', async ({ page }) => {
// Arrange, Act, Assert
});
});
Use data-testid Selectors
// ✅ CORRECT - Stable selector
const button = page.locator('[data-testid="save-button"]');
// ❌ WRONG - Fragile selectors
const button = page.locator('.btn-primary'); // CSS class
const button = page.locator('button:has-text("Save")'); // Text content
Step 3: Write Tests with Proper Selectors
Test User Flows
test('completes score entry workflow', async ({ page }) => {
// Navigate
await page.goto('/admin/competitions/1');
// Enter scores for all holes
for (let hole = 1; hole <= 18; hole++) {
await page.locator(`[data-testid="score-hole-${hole}"]`).fill('4');
}
// Save
await page.click('[data-testid="save-scores"]');
// Verify
await expect(page.locator('[data-testid="success-message"]'))
.toBeVisible();
});
Test Navigation
test('navigates between pages correctly', async ({ page }) => {
await page.goto('/player');
// Click tab
await page.click('[data-testid="nav-tab-competitions"]');
// Verify URL
await expect(page).toHaveURL(/\/player\/competitions/);
// Click detail link
await page.click('[data-testid="competition-1"]');
await expect(page).toHaveURL(/\/player\/competitions\/1/);
// Back button
await page.click('[data-testid="back-button"]');
await expect(page).toHaveURL(/\/player\/competitions/);
});
Test Forms
test('submits form with validation', async ({ page }) => {
await page.goto('/admin/competitions');
await page.click('[data-testid="create-button"]');
// Fill form
await page.fill('[data-testid="name-input"]', 'Test Competition');
await page.fill('[data-testid="date-input"]', '2025-09-15');
await page.selectOption('[data-testid="course-select"]', '1');
// Submit
await page.click('[data-testid="submit-button"]');
// Verify success
await expect(page).toHaveURL(/\/admin\/competitions\/\d+/);
});
Async Handling
// ✅ CORRECT - Wait for elements
await page.waitForSelector('[data-testid="leaderboard"]');
const entries = await page.locator('[data-testid="entry"]').all();
// ✅ CORRECT - Built-in retry
await expect(page.locator('[data-testid="score"]'))
.toHaveText('72');
// ❌ WRONG - Hard timeout
await page.waitForTimeout(2000); // Don't use this
Step 4: Run Tests and Verify
Run Commands
cd frontend
# Run all tests
npm run test:e2e
# Run with UI (debugging)
npm run test:e2e -- --ui
# Run specific test file
npm run test:e2e -- competitions.spec.ts
# Run in headed mode (see browser)
npm run test:e2e -- --headed
Verify Test Quality
- Uses
data-testidselectors (not CSS classes or text) - Waits properly (no hard timeouts)
- Tests user flows (not implementation details)
- Independent tests (no shared state)
- Descriptive test names
Step 5: Test Mobile Responsiveness
Mobile Viewport Tests
test.describe('Mobile responsive', () => {
test.use({ viewport: { width: 375, height: 667 } }); // iPhone SE
test('mobile navigation works', async ({ page }) => {
await page.goto('/player');
// Mobile menu visible
await expect(page.locator('[data-testid="mobile-menu"]'))
.toBeVisible();
// Desktop nav hidden
await expect(page.locator('[data-testid="desktop-nav"]'))
.not.toBeVisible();
});
test('touch targets meet minimum size', async ({ page }) => {
await page.goto('/player');
const button = page.locator('[data-testid="menu-button"]');
const box = await button.boundingBox();
expect(box!.height).toBeGreaterThanOrEqual(44);
expect(box!.width).toBeGreaterThanOrEqual(44);
});
});
Key Testing Patterns
Page Object Model
Extract reusable page interactions:
// e2e/pages/CompetitionPage.ts
export class CompetitionPage {
constructor(private page: Page) {}
async goto(id: number) {
await this.page.goto(`/admin/competitions/${id}`);
}
async enterScore(hole: number, score: number) {
await this.page.locator(`[data-testid="score-hole-${hole}"]`)
.fill(String(score));
}
async save() {
await this.page.click('[data-testid="save-scores"]');
}
}
// In test
const competitionPage = new CompetitionPage(page);
await competitionPage.goto(1);
await competitionPage.enterScore(1, 4);
await competitionPage.save();
Test Critical Paths
Focus on user workflows:
- Score entry and saving
- Navigation between pages
- Form submission
- Leaderboard display
- Mobile menu interaction
Anti-Patterns to Avoid
- ❌ Using CSS classes as selectors (fragile)
- ❌ Using text content as selectors (may change)
- ❌ Hard-coded timeouts (
waitForTimeout) - ❌ Testing implementation details
- ❌ Shared state between tests
- ❌ Skipping mobile testing
- ❌ Not waiting for async operations
Summary
E2E testing approach: Playwright tests focusing on critical user flows with stable selectors, proper async handling, and mobile testing.
Every test must:
- Use
data-testidselectors - Wait properly (no hard timeouts)
- Test user flows (not implementation)
- Be independent and isolated
- Work on mobile viewports
- Run reliably in CI/CD
For detailed patterns, see docs/testing/FRONTEND_TEST_GUIDE.md.
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です