vue-playwright-testing
Comprehensive guide for testing Vue 3 applications with Playwright (2025). This skill should be used when writing end-to-end tests or component tests for Vue apps, testing Vue Router navigation, reactive state changes, authentication flows, or setting up Playwright in Vue projects.
Best use case
vue-playwright-testing is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Comprehensive guide for testing Vue 3 applications with Playwright (2025). This skill should be used when writing end-to-end tests or component tests for Vue apps, testing Vue Router navigation, reactive state changes, authentication flows, or setting up Playwright in Vue projects.
Teams using vue-playwright-testing should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/vue-playwright-testing/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How vue-playwright-testing Compares
| Feature / Agent | vue-playwright-testing | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Comprehensive guide for testing Vue 3 applications with Playwright (2025). This skill should be used when writing end-to-end tests or component tests for Vue apps, testing Vue Router navigation, reactive state changes, authentication flows, or setting up Playwright in Vue projects.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Vue 3 + Playwright Testing
## Overview
To build reliable tests for Vue 3 applications, use Playwright for both end-to-end testing and experimental component testing. Playwright integrates seamlessly with Vue's reactivity system, Vue Router navigation, and Vite build pipeline. This skill provides Vue-specific guidance for writing maintainable tests while avoiding common pitfalls like timeout anti-patterns.
**Current Versions:** Playwright 1.48+, Vue 3.5+, Vite 6+
**Standard Approach:** Semantic locators, conditional waits, API mocking
**Key Philosophy:** Never use arbitrary timeouts to fix flaky tests
## Decision Tree: What Type of Test?
```
Vue Test Request → What are you testing?
|
├─ End-to-end user flow (login, forms, navigation)?
│ ├─ Single page interaction? → Use Quick Start: E2E Test
│ └─ Multi-page workflow? → Load references/e2e-patterns.md
│
├─ Individual Vue component in isolation?
│ └─ Load references/component-testing.md
│
├─ Vue Router navigation or page transitions?
│ └─ Load references/vue-specific-patterns.md → Router section
│
├─ Reactive state changes or Pinia store?
│ └─ Load references/vue-specific-patterns.md → State Management
│
├─ Authentication flow?
│ └─ Load references/vue-specific-patterns.md → Authentication
│
├─ Test is failing intermittently/flaky?
│ └─ Load references/best-practices.md → Debugging Flaky Tests section
│
└─ Setting up Playwright in Vue project?
└─ Use Quick Start: Project Setup
```
## Quick Start: Project Setup
### Initialize Playwright in Vue Project
```bash
npm init playwright@latest -- --ct
```
This command:
- Installs `@playwright/test` and `@playwright/experimental-ct-vue`
- Downloads browsers
- Creates `playwright.config.ts`
- Sets up test structure
For Vue projects with Vite, ensure `playwright.config.ts` includes:
```typescript
import { defineConfig, devices } from '@playwright/test';
import react from '@vitejs/plugin-react';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: 'http://localhost:5173',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
webServer: {
command: 'npm run dev',
url: 'http://localhost:5173',
reuseExistingServer: !process.env.CI,
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});
```
## Quick Start: E2E Test
### Basic E2E Test Example
```typescript
import { test, expect } from '@playwright/test';
test.describe('Login Flow', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('user can login successfully', async ({ page }) => {
// Use semantic locators (getByLabel, getByRole)
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('password123');
// Click submit button
await page.getByRole('button', { name: 'Sign in' }).click();
// Wait for URL change (condition-based, not timeout)
await expect(page).toHaveURL('/dashboard');
// Assert Vue app rendered correctly
await expect(page.getByRole('heading', { name: /Welcome/i })).toBeVisible();
});
test('invalid credentials show error', async ({ page }) => {
await page.getByLabel('Email').fill('bad@email.com');
await page.getByLabel('Password').fill('wrong');
await page.getByRole('button', { name: 'Sign in' }).click();
// Wait for error message to appear
await expect(page.getByRole('alert')).toContainText('Invalid credentials');
});
});
```
## Quick Start: Component Test
### Testing Vue Component in Isolation
```typescript
import { test, expect } from '@playwright/experimental-ct-vue';
import Button from './Button.vue';
test('button emits click event', async ({ mount }) => {
const messages: string[] = [];
const component = await mount(Button, {
props: { label: 'Click me' },
on: {
click: () => messages.push('clicked')
}
});
await component.getByRole('button').click();
expect(messages).toEqual(['clicked']);
});
```
## Core Vue 3 + Playwright Principles
### 1. Never Use Arbitrary Timeouts to Fix Flaky Tests
**❌ BAD: Masking the real issue**
```typescript
// This is a code smell - something is wrong
await page.waitForTimeout(3000);
await page.click('button');
```
**✅ GOOD: Wait for the specific condition**
```typescript
// Wait for button to be enabled
await page.locator('button:not([disabled])').waitFor();
await page.getByRole('button').click();
// Or use Playwright's auto-waiting
await page.getByRole('button', { name: 'Submit' }).click();
```
**Why?** Arbitrary timeouts hide race conditions, selector problems, or network issues. When you see a flaky test, investigate the root cause:
- Is the selector wrong? Use dev tools to verify
- Is data loading? Wait for the API response
- Is Vue not mounted yet? Check the condition
- Is the element disabled? Wait for the disabled attribute to be removed
### 2. Use Semantic Locators for Stability
Priority order (most stable to least):
```typescript
// ✅ 1. User-facing text/roles (most stable)
await page.getByRole('button', { name: 'Save' });
await page.getByLabel('Email');
await page.getByPlaceholder('Search...');
await page.getByText('Welcome');
// ✅ 2. Test IDs (when semantic locators insufficient)
await page.getByTestId('product-card');
// ❌ 3. CSS/XPath selectors (avoid - fragile)
await page.locator('css=.dynamic-button');
```
### 3. Test Vue-Specific Behavior
Wait for Vue app to be ready before interactions:
```typescript
// Wait for Vue app to mount
test('app loads correctly', async ({ page }) => {
await page.goto('/');
// Playwright auto-waits, but be explicit for Vue:
await page.waitForFunction(() => {
// Check Vue app is mounted
return !!(window as any).__VUE_DEVTOOLS_GLOBAL_HOOK__?.enabled;
});
// Now safe to interact
await page.getByRole('button').click();
});
```
### 4. Test Reactive State Changes
Test observable behavior from reactive updates:
```typescript
test('counter increments', async ({ page }) => {
await page.goto('/counter');
// Initial state
await expect(page.getByText('Count: 0')).toBeVisible();
// Click increment
await page.getByRole('button', { name: 'Increment' }).click();
// Reactive update (Playwright auto-waits for DOM change)
await expect(page.getByText('Count: 1')).toBeVisible();
});
```
### 5. Mock Network Requests
Control external APIs for consistent tests:
```typescript
test('fetches and displays data', async ({ page }) => {
// Intercept API calls
await page.route('**/api/users', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'Test User' }])
});
});
await page.goto('/users');
// Assert mocked data is displayed
await expect(page.getByText('Test User')).toBeVisible();
});
```
## Common Vue Testing Patterns
### Pattern: Testing Vue Router Navigation
```typescript
test('navigates to product details', async ({ page }) => {
await page.goto('/products');
// Click product link
await page.getByRole('link', { name: 'Product A' }).click();
// Wait for URL change (conditional, not timeout)
await expect(page).toHaveURL('/products/1');
// Assert component mounted with correct data
await expect(page.getByRole('heading', { name: 'Product A' })).toBeVisible();
});
```
### Pattern: Testing Form Validation
```typescript
test('validates form before submit', async ({ page }) => {
await page.goto('/contact');
// Leave required field empty
await page.getByLabel('Email').fill('');
await page.getByLabel('Message').fill('Hello');
// Try to submit
await page.getByRole('button', { name: 'Send' }).click();
// Error message should appear
await expect(page.getByText('Email is required')).toBeVisible();
// Form should not submit
await expect(page).toHaveURL('/contact');
});
```
### Pattern: Testing Modal Dialogs
```typescript
test('modal closes on cancel', async ({ page }) => {
await page.goto('/');
// Open modal
await page.getByRole('button', { name: 'Open Dialog' }).click();
await expect(page.getByRole('dialog')).toBeVisible();
// Close modal
await page.getByRole('button', { name: 'Cancel' }).click();
// Modal should disappear
await expect(page.getByRole('dialog')).not.toBeVisible();
});
```
## When to Load Reference Files
Load these strategically to optimize context usage:
### references/e2e-patterns.md
- Building multi-page E2E workflows
- Implementing Page Object Model for Vue tests
- Testing complex user journeys
- Multi-step authentication flows
### references/component-testing.md
- Testing Vue components in isolation
- Setting up experimental component testing
- Testing props, events, slots
- Testing composables with components
### references/vue-specific-patterns.md
- Vue Router testing patterns
- Pinia state management testing
- Vue reactivity and computed properties
- Authentication testing in Vue
- Understanding wait patterns for Vue
### references/best-practices.md
- Debugging flaky tests (and why timeouts aren't the answer)
- Selector strategies and troubleshooting
- API mocking patterns
- CI/CD configuration
- Performance optimization
## Tips for Success
1. **Start with semantic locators** - They're more stable and maintainable
2. **Never reach for timeouts first** - If tests are flaky, investigate the root cause
3. **Test user behavior** - Not implementation details or Vue internals
4. **Mock external APIs** - For consistency and speed
5. **Run tests in parallel** - Playwright supports parallel execution by default
6. **Use traces and videos** - For debugging failed tests
7. **Review flaky tests immediately** - Don't ignore intermittent failures
8. **Keep tests focused** - One test should verify one behavior
9. **Set up CI/CD early** - Use provided GitHub Actions workflow
10. **Reference the Vue-specific patterns** - Understand how to wait for Vue correctly
## File Structure
```
my-vue-app/
├── tests/
│ ├── e2e/
│ │ ├── login.spec.ts
│ │ ├── products.spec.ts
│ │ └── checkout.spec.ts
│ ├── fixtures/
│ │ ├── auth.ts
│ │ └── data.ts
│ └── pages/
│ ├── LoginPage.ts
│ ├── ProductsPage.ts
│ └── CheckoutPage.ts
├── playwright.config.ts
└── package.json
```
## Resources
This skill includes references, templates, and scripts:
### references/e2e-patterns.md
Comprehensive guide to E2E testing for Vue applications using Page Object Model and multi-page workflows.
### references/component-testing.md
Guide to testing Vue components in isolation using Playwright's experimental component testing.
### references/vue-specific-patterns.md
Vue-specific testing patterns including Router navigation, Pinia state management, reactivity testing, and proper wait strategies.
### references/best-practices.md
Best practices including timeout anti-patterns, debugging flaky tests, selector strategies, and CI/CD setup.
### assets/playwright.config.template.ts
Production-ready Playwright configuration optimized for Vue with Vite.
### assets/workflows/playwright-vue.yml
GitHub Actions workflow for automated Playwright testing in CI/CD pipeline.
### scripts/init-vue-playwright.ts
Setup script to initialize Playwright in an existing Vue project with proper configuration.Related Skills
webapp-testing
Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
web3-testing
Test smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or va...
vitest-testing
Vitest unit testing for TypeScript/JavaScript in Oh My Brand! theme. Test setup, Web Component testing, mocking patterns, and coverage. Use when writing unit tests for frontend code.
unit-testing-test-automator
Master AI-powered test automation with modern frameworks, self-healing tests, and comprehensive quality engineering. Build scalable testing strategies with advanced CI/CD integration. Use PROACTIVELY for testing automation or quality assurance. Use when: the task directly matches test automator responsibilities within plugin unit-testing. Do not use when: a more specific framework or task-focused skill is clearly a better match.
typescript-testing
Comprehensive testing guidance for TypeScript projects including unit testing patterns, mocking strategies, and test organization best practices
testing-tauri-apps
Guides developers through testing Tauri applications including unit testing with mock runtime, mocking Tauri APIs, WebDriver end-to-end testing with Selenium and WebdriverIO, and CI integration with GitHub Actions.
testing-strategy-python
Python/FastAPI/Django testing conventions. pytest, fixtures, httpx, TestClient, factory_boy. Use when writing or reviewing Python tests.
testing-strategy-builder
Use this skill when creating comprehensive testing strategies for applications. Provides test planning templates, coverage targets, test case structures, and guidance for unit, integration, E2E, and performance testing. Ensures robust quality assurance across the development lifecycle.
testing-skills-activation
Use when creating or refining Claude Code skills to validate that skill descriptions trigger correctly - provides systematic testing methodology for skill activation patterns using test cases and automated evaluation
Testing Skill
Automatiza pruebas y diagnósticos del sistema SmartK et sin perder tiempo
testing-qa
Comprehensive testing and QA workflow covering unit testing, integration testing, E2E testing, browser automation, and quality assurance.
testing-principles
Language-agnostic testing principles including TDD, test quality, coverage standards, and test design patterns. Use when writing tests, designing test strategies, or reviewing test quality.