Files
agent-skills/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

243 lines
6.4 KiB
Markdown

---
title: Use Playwright for E2E Testing - Cross-Browser Support and Better DX
impact: MEDIUM
impactDescription: Cypress has browser limitations and some features require paid subscriptions
type: best-practice
tags: [vue3, testing, e2e, playwright, cypress, end-to-end]
---
# Use Playwright for E2E Testing - Cross-Browser Support and Better DX
**Impact: MEDIUM** - Playwright offers superior cross-browser testing (Chromium, WebKit, Firefox), excellent debugging tools, and is fully open source. Cypress has limitations with WebKit support and requires paid subscriptions for some features.
Use Playwright for new E2E testing setups. Consider Cypress if team already has expertise or for its visual debugging UI.
## Task Checklist
- [ ] Install Playwright with browsers for your target platforms
- [ ] Configure for Vue dev server integration
- [ ] Set up projects for different browsers
- [ ] Use locator strategies that match component test patterns
- [ ] Configure CI for parallel test execution
- [ ] Use trace and screenshot features for debugging
## Quick Setup
```bash
# Install Playwright
npm init playwright@latest
# This will create:
# - playwright.config.ts
# - tests/ directory
# - tests-examples/ directory
```
**playwright.config.ts:**
```typescript
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
// Base URL for navigation
baseURL: 'http://localhost:5173',
// Capture trace on first retry
trace: 'on-first-retry',
// Screenshot on failure
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
// Mobile viewports
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
],
// Run local dev server before tests
webServer: {
command: 'npm run dev',
url: 'http://localhost:5173',
reuseExistingServer: !process.env.CI,
},
})
```
## E2E Test Example
```typescript
// e2e/user-flow.spec.ts
import { test, expect } from '@playwright/test'
test.describe('User Authentication', () => {
test('user can log in and see dashboard', async ({ page }) => {
// Navigate to login
await page.goto('/login')
// Fill login form
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Password').fill('password123')
await page.getByRole('button', { name: 'Sign In' }).click()
// Verify redirect to dashboard
await expect(page).toHaveURL('/dashboard')
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible()
})
test('shows error for invalid credentials', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('Email').fill('wrong@example.com')
await page.getByLabel('Password').fill('wrongpassword')
await page.getByRole('button', { name: 'Sign In' }).click()
await expect(page.getByRole('alert')).toContainText('Invalid credentials')
await expect(page).toHaveURL('/login')
})
})
```
## Playwright vs Cypress Comparison
| Feature | Playwright | Cypress |
|---------|------------|---------|
| Browsers | Chromium, Firefox, WebKit | Chromium, Firefox, Electron (WebKit experimental) |
| Cross-browser | Full support | Limited |
| Parallelization | Built-in | Requires Cypress Cloud |
| Open source | Fully | Core only |
| Mobile testing | Device emulation | Limited |
| Debugging | Inspector, trace viewer | Time-travel UI |
| API testing | Built-in | Plugin required |
| Iframes | Full support | Limited |
## Testing Vue Components with Data-Testid
```typescript
// e2e/product-list.spec.ts
import { test, expect } from '@playwright/test'
test('user can add product to cart', async ({ page }) => {
await page.goto('/products')
// Use data-testid for reliable selectors
await page.getByTestId('product-card').first().click()
// Verify product detail page
await expect(page.getByTestId('product-title')).toBeVisible()
// Add to cart
await page.getByTestId('add-to-cart-button').click()
// Verify cart updated
await expect(page.getByTestId('cart-count')).toHaveText('1')
})
```
## Page Object Pattern for Vue Apps
```typescript
// e2e/pages/LoginPage.ts
import { Page, Locator } from '@playwright/test'
export class LoginPage {
readonly page: Page
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
readonly errorMessage: Locator
constructor(page: Page) {
this.page = page
this.emailInput = page.getByLabel('Email')
this.passwordInput = page.getByLabel('Password')
this.submitButton = page.getByRole('button', { name: 'Sign In' })
this.errorMessage = page.getByRole('alert')
}
async goto() {
await this.page.goto('/login')
}
async login(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
await this.submitButton.click()
}
}
```
```typescript
// e2e/auth.spec.ts
import { test, expect } from '@playwright/test'
import { LoginPage } from './pages/LoginPage'
test('successful login', async ({ page }) => {
const loginPage = new LoginPage(page)
await loginPage.goto()
await loginPage.login('user@example.com', 'password123')
await expect(page).toHaveURL('/dashboard')
})
```
## Visual Regression Testing
```typescript
test('homepage visual regression', async ({ page }) => {
await page.goto('/')
// Full page screenshot comparison
await expect(page).toHaveScreenshot('homepage.png')
// Element-specific screenshot
await expect(page.getByTestId('hero-section')).toHaveScreenshot('hero.png')
})
```
## Running Tests
```bash
# Run all tests
npx playwright test
# Run in headed mode (see browser)
npx playwright test --headed
# Run specific file
npx playwright test e2e/auth.spec.ts
# Run in specific browser
npx playwright test --project=chromium
# Debug mode
npx playwright test --debug
# Generate test from actions
npx playwright codegen localhost:5173
```
## Reference
- [Playwright Documentation](https://playwright.dev/)
- [Vue.js E2E Testing Recommendations](https://vuejs.org/guide/scaling-up/testing#e2e-testing)
- [Playwright Best Practices](https://playwright.dev/docs/best-practices)