
write-e2e-test
by agentconfig
Elevate your AI assistants by configuring them for any role or workflow. Explore the primitives that unlock their full potential.
SKILL.md
name: write-e2e-test description: Write Playwright E2E tests following project patterns for components and user interactions. Use when adding tests for new features, testing accessibility, or validating responsive behavior.
Write E2E Test
Create Playwright E2E tests for agentconfig.org following project patterns.
Test File Location
All E2E tests live in site/tests/e2e/:
site/tests/e2e/
├── app.spec.ts
├── comparison.spec.ts
├── fileTree.spec.ts
├── navigation.spec.ts
├── primitiveCards.spec.ts
└── theme.spec.ts
Test File Structure
import { test, expect } from '@playwright/test'
test.describe('Feature Name', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/')
})
test('should do something specific', async ({ page }) => {
// Arrange
const element = page.getByRole('button', { name: 'Click me' })
// Act
await element.click()
// Assert
await expect(page.getByText('Success')).toBeVisible()
})
})
Locator Strategy (Priority Order)
Use the most resilient locators, in this order of preference:
1. Role + Name (most resilient)
page.getByRole('button', { name: 'Submit' })
page.getByRole('heading', { name: 'Welcome' })
page.getByRole('navigation')
2. Label/Placeholder (for form elements)
page.getByLabel('Email address')
page.getByPlaceholder('Enter your email')
3. Text content (for static text)
page.getByText('Learn more')
page.getByText(/welcome/i) // regex for flexible matching
4. Test ID (when others don't work)
page.getByTestId('file-tree-node')
5. CSS selectors (last resort)
page.locator('.custom-component')
Common Test Patterns
Navigation
test('should scroll to section when nav link is clicked', async ({ page }) => {
const navLink = page.getByRole('link', { name: 'File Tree' })
const section = page.getByRole('region', { name: 'File Tree' })
await navLink.click()
await expect(section).toBeInViewport()
})
Theme Toggle
test('should toggle between light and dark mode', async ({ page }) => {
const toggle = page.getByRole('button', { name: /theme/i })
await expect(page.locator('html')).toHaveAttribute('data-theme', 'light')
await toggle.click()
await expect(page.locator('html')).toHaveAttribute('data-theme', 'dark')
})
Expandable Content
test('should expand tree node on click', async ({ page }) => {
const treeNode = page.getByRole('button', { name: '.github/' })
const childNode = page.getByRole('button', { name: 'copilot-instructions.md' })
await expect(childNode).not.toBeVisible()
await treeNode.click()
await expect(childNode).toBeVisible()
})
Copy to Clipboard
test('should copy template to clipboard', async ({ page, context }) => {
await context.grantPermissions(['clipboard-read', 'clipboard-write'])
const copyButton = page.getByRole('button', { name: 'Copy template' })
await copyButton.click()
const clipboardText = await page.evaluate(() => navigator.clipboard.readText())
expect(clipboardText).toContain('expected content')
})
Responsive Testing
Test at multiple viewport sizes:
test.describe('Mobile viewport', () => {
test.use({ viewport: { width: 375, height: 667 } })
test('should show mobile navigation', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Menu' })).toBeVisible()
})
})
test.describe('Desktop viewport', () => {
test.use({ viewport: { width: 1280, height: 720 } })
test('should show full navigation', async ({ page }) => {
await expect(page.getByRole('navigation')).toBeVisible()
})
})
Theme Testing
Test both light and dark modes:
test.describe('Dark mode', () => {
test.use({ colorScheme: 'dark' })
test('should render with dark theme colors', async ({ page }) => {
// Verify dark mode specific styling
})
})
test.describe('Light mode', () => {
test.use({ colorScheme: 'light' })
test('should render with light theme colors', async ({ page }) => {
// Verify light mode specific styling
})
})
Test Independence
Each test must be independent:
- Don't rely on state from previous tests
- Use
beforeEachfor common setup - Clean up any side effects
Assertions
Use Playwright's built-in assertions (auto-waiting):
// Good - auto-waits for element
await expect(page.getByText('Hello')).toBeVisible()
await expect(page.getByRole('button')).toBeEnabled()
await expect(page.locator('.item')).toHaveCount(3)
await expect(page.getByRole('link')).toHaveAttribute('href', '/about')
// Bad - doesn't auto-wait
const text = await page.textContent('.item')
expect(text).toBe('Hello')
Test Naming
Use descriptive names that explain the expected behavior:
// Good
test('should expand tree node when clicked', ...)
test('should scroll to File Tree section when nav link is clicked', ...)
test('should display error message when copy fails', ...)
// Bad
test('click test', ...)
test('tree works', ...)
test('test 1', ...)
Running Tests
cd site
bun run test # Run all tests
bun run test:ui # Interactive test UI
Checklist
Before considering tests complete:
- Uses resilient locators (role > text > testid > css)
- Each test is independent
- Test name describes expected behavior
- Uses Playwright auto-waiting assertions
- Covers happy path and edge cases
- Tests responsive behavior if relevant
- Tests both themes if relevant
- No hardcoded waits (
page.waitForTimeout)
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon
