- Move cross-cutting docs (personas, design system, implementation phases, Ideen.md) to .specify/memory/ - Move cross-cutting research and plans to .specify/memory/research/ and .specify/memory/plans/ - Extract 5 setup tasks from spec/setup-tasks.md into individual specs/001-005/spec.md files with spec-kit template format - Extract 20 user stories from spec/userstories.md into individual specs/006-026/spec.md files with spec-kit template format - Relocate feature-specific research and plan docs into specs/[feature]/ - Add spec-kit constitution, templates, scripts, and slash commands - Slim down CLAUDE.md to Claude-Code-specific config, delegate principles to .specify/memory/constitution.md - Update ralph.sh with stream-json output and per-iteration logging - Delete old spec/ and docs/agents/ directories - Gitignore Ralph iteration JSONL logs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
date, git_commit, branch, topic, tags, status
| date | git_commit | branch | topic | tags | status | |||||
|---|---|---|---|---|---|---|---|---|---|---|
| 2026-03-05T10:14:52+00:00 | ffea279b54 |
master | End-to-End Testing for Vue 3 with Playwright |
|
complete |
Research: End-to-End Testing for Vue 3 with Playwright
Research Question
How to set up and structure end-to-end tests for the fete Vue 3 + Vite frontend using Playwright?
Summary
Playwright is Vue 3's officially recommended E2E testing framework. It integrates with Vite projects through a webServer config block (no Vite plugin needed), supports Chromium/Firefox/WebKit under a single API, and is fully free including parallelism. The fete project's existing vitest.config.ts already excludes e2e/**, making the integration path clean.
Detailed Findings
1. Current Frontend Test Infrastructure
The project uses Vitest 4.0.18 with jsdom for unit/component tests:
- Config:
frontend/vitest.config.ts— merges with vite.config, uses jsdom environment, bail on first failure - Exclusion: Already excludes
e2e/**from Vitest's test discovery (vitest.config.ts:10) - Existing tests: 3 test files with ~25 tests total:
src/composables/__tests__/useEventStorage.spec.ts(6 tests)src/views/__tests__/EventCreateView.spec.ts(11 tests)src/views/__tests__/EventStubView.spec.ts(8 tests)
- No E2E framework is currently configured
2. Why Playwright
Vue's official testing guide (vuejs.org/guide/scaling-up/testing) positions Playwright as the primary E2E recommendation. Key advantages over Cypress:
| Dimension | Playwright | Cypress |
|---|---|---|
| Browser support | Chromium, Firefox, WebKit | Chrome-family, Firefox (WebKit experimental) |
| Parallelism | Free, native | Requires paid Cypress Cloud |
| Architecture | Out-of-process (CDP/BiDi) | In-browser (same process) |
| Speed | 35-45% faster in parallel | Slower at scale |
| Pricing | 100% free, Apache 2.0 | Cloud features cost money |
| Privacy | No account, no cloud dependency | Cloud service integration |
Playwright aligns with fete's privacy constraints (no cloud dependency, no account required).
3. Playwright + Vite Integration
Playwright does not use a Vite plugin. Integration is purely through process management:
- Playwright reads
webServer.commandand spawns the Vite dev server - Polls
webServer.urluntil ready - Runs tests against
use.baseURL - Kills the server after all tests finish
The existing Vite dev proxy (/api → localhost:8080) works transparently — E2E tests can hit the real backend or intercept via page.route() mocks.
Note: @playwright/experimental-ct-vue exists for component-level testing (mounting individual Vue components without a server), but is still experimental and is a different category from E2E.
4. Installation
cd frontend
npm install --save-dev @playwright/test
npx playwright install --with-deps chromium
Using npm init playwright@latest generates scaffolding automatically, but for an existing project manual setup is cleaner.
5. Project Structure
frontend/
playwright.config.ts # Playwright config
e2e/ # E2E test directory
home.spec.ts
event-create.spec.ts
event-view.spec.ts
fixtures/ # shared test fixtures (optional)
helpers/ # page object models (optional)
playwright-report/ # generated HTML report (gitignored)
test-results/ # generated artifacts (gitignored)
The e2e/ directory is already excluded from Vitest via vitest.config.ts:10.
6. Recommended playwright.config.ts
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: process.env.CI ? 'github' : 'html',
use: {
baseURL: 'http://localhost:5173',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
// Uncomment for cross-browser coverage:
// { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
// { name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
webServer: {
command: 'npm run dev',
url: 'http://localhost:5173',
reuseExistingServer: !process.env.CI,
timeout: 120_000,
stdout: 'pipe',
},
})
Key decisions:
testDir: './e2e'— separates E2E from Vitest unit testsforbidOnly: !!process.env.CI— preventstest.onlyfrom shipping to CIworkers: process.env.CI ? 1 : undefined— single worker in CI avoids shared-state flakiness; locally uses all coresreporter: 'github'— GitHub Actions annotations in CIcommand: 'npm run dev'— runsgenerate:apifirst (via the existing npm script), then starts VitereuseExistingServer: !process.env.CI— reuses running dev server locally for fast iteration
7. package.json Scripts
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test:e2e:debug": "playwright test --debug"
8. .gitignore Additions
playwright-report/
test-results/
9. TypeScript Configuration
The existing tsconfig.app.json excludes src/**/__tests__/*. Since E2E tests live in e2e/ (outside src/), they are already excluded from the app build.
A separate tsconfig for E2E tests is not strictly required — Playwright's own TypeScript support handles it. If needed, a minimal e2e/tsconfig.json can extend tsconfig.node.json.
10. Vue-Specific Testing Patterns
Router navigation:
await page.goto('/events/abc-123')
await page.waitForURL('/events/abc-123') // confirms SPA router resolved
Waiting for reactive content (auto-retry):
await expect(page.getByRole('heading', { name: 'My Event' })).toBeVisible()
// Playwright auto-retries assertions for up to the configured timeout
URL assertions:
await expect(page).toHaveURL(/\/events\/.+/)
API mocking (for isolated E2E tests):
await page.route('/api/events/**', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ title: 'Test Event', date: '2026-04-01' }),
})
})
Locator strategy — prefer accessible locators:
page.getByRole('button', { name: 'RSVP' }) // best
page.getByLabel('Event Title') // form fields
page.getByTestId('event-card') // data-testid fallback
page.locator('.some-class') // last resort
11. CI Integration
GitHub Actions workflow:
- name: Install Playwright browsers
run: npx playwright install --with-deps chromium
# --with-deps installs OS-level libraries (libglib, libnss, etc.)
# Specify 'chromium' to save ~2min vs installing all browsers
- name: Run E2E tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: frontend/playwright-report/
retention-days: 30
Docker: Use official images mcr.microsoft.com/playwright:v1.x.x-noble (Ubuntu 24.04). Alpine is unsupported (browsers need glibc). Key flag: --ipc=host prevents Chromium memory exhaustion. The Playwright Docker image version must match the @playwright/test package version exactly.
For the fete project, E2E tests run as a separate CI step, not inside the app's Dockerfile.
12. Integration with Existing Backend
Two approaches for E2E tests:
- Mocked backend (via
page.route()): Fast, isolated, no backend dependency. Good for frontend-only testing. - Real backend: Start Spring Boot alongside Vite. Tests hit
/apithrough the Vite proxy. More realistic but requires Java in CI. Could use Docker Compose.
The Vite proxy config (vite.config.ts:19-23) already forwards /api to localhost:8080, so both approaches work without changes.
Code References
frontend/vitest.config.ts:10— E2E exclusion pattern already in placefrontend/vite.config.ts:19-23— API proxy configuration for backend integrationfrontend/package.json:8-9—devscript runsgenerate:apibefore Vitefrontend/src/router/index.ts— Route definitions (Home, Create, Event views)frontend/src/api/client.ts— openapi-fetch client using/apibase URLfrontend/tsconfig.app.json— App TypeScript config (excludes test files)
Architecture Documentation
Test Pyramid in fete
| Layer | Framework | Directory | Purpose |
|---|---|---|---|
| Unit | Vitest + jsdom | src/**/__tests__/ |
Composables, isolated logic |
| Component | Vitest + @vue/test-utils | src/**/__tests__/ |
Vue component behavior |
| E2E | Playwright (proposed) | e2e/ |
Full browser, user flows |
| Visual | browser-interactive-testing skill | .agent-tests/ |
Agent-driven screenshots |
Decision Points for Implementation
- Start with Chromium only — add Firefox/WebKit later if needed
- Use
npm run devas webServer command (includes API type generation) - API mocking by default — use
page.route()for E2E isolation; full-stack tests as a separate concern data-testidattributes on key interactive elements for stable selectors- Page Object Model recommended once the test suite grows beyond 5-10 tests
Sources
- Testing | Vue.js — official E2E recommendation
- Installation | Playwright
- webServer | Playwright — Vite integration
- CI Intro | Playwright
- Docker | Playwright
- Cypress vs Playwright 2026 | BugBug
- Playwright vs Cypress | Katalon
Decisions (2026-03-05)
- Mocked backend only — E2E tests use
page.route()to mock API responses. No real Spring Boot backend in E2E. - Mocking stack:
@msw/playwright+@msw/source— reads OpenAPI spec at runtime, generates MSW handlers, per-test overrides vianetwork.use(). - US-1 flows first — Event creation is the only implemented user story; E2E tests cover that flow.
- No CI caching yet — Playwright browser binaries are not cached; CI runner needs reconfiguration first.
- E2E tests are part of frontend tasks — every frontend user story includes E2E test coverage going forward.
- OpenAPI examples mandatory — all response schemas in the OpenAPI spec must include
example:fields (required for@msw/sourcemock generation).