🎯

component-testing

🎯Skill

from adaptationio/skrillz

VibeIndex|
What it does

Enables isolated UI component testing for React, Vue, and Svelte using Playwright's experimental component testing framework.

component-testing

Installation

Install skill:
npx skills add https://github.com/adaptationio/skrillz --skill component-testing
2
AddedJan 27, 2026

Skill Details

SKILL.md

Isolated component testing for React, Vue, and Svelte with Playwright. Use when testing UI components in isolation, testing component interactions, or building component test suites.

Overview

# Component Testing with Playwright

Test UI components in isolation using Playwright's experimental component testing feature. Supports React, Vue, Svelte, and Solid.

Quick Start

```typescript

// Button.spec.tsx

import { test, expect } from '@playwright/experimental-ct-react';

import { Button } from './Button';

test('button click triggers callback', async ({ mount }) => {

let clicked = false;

const component = await mount(

);

await component.click();

expect(clicked).toBe(true);

});

```

Installation

React

```bash

npm init playwright@latest -- --ct

# Select React when prompted

```

Or manually:

```bash

npm install -D @playwright/experimental-ct-react

```

Vue

```bash

npm install -D @playwright/experimental-ct-vue

```

Svelte

```bash

npm install -D @playwright/experimental-ct-svelte

```

Configuration

playwright-ct.config.ts:

```typescript

import { defineConfig, devices } from '@playwright/experimental-ct-react';

export default defineConfig({

testDir: './src',

testMatch: '*/.spec.tsx',

use: {

ctPort: 3100,

ctViteConfig: {

// Custom Vite config for component tests

},

},

projects: [

{

name: 'chromium',

use: { ...devices['Desktop Chrome'] },

},

{

name: 'firefox',

use: { ...devices['Desktop Firefox'] },

},

{

name: 'webkit',

use: { ...devices['Desktop Safari'] },

},

],

});

```

React Component Testing

Basic Mount

```typescript

import { test, expect } from '@playwright/experimental-ct-react';

import { UserCard } from './UserCard';

test('displays user info', async ({ mount }) => {

const component = await mount(

name="John Doe"

email="john@example.com"

/>

);

await expect(component.getByText('John Doe')).toBeVisible();

await expect(component.getByText('john@example.com')).toBeVisible();

});

```

With Props

```typescript

test('button variants', async ({ mount }) => {

// Primary variant

const primary = await mount();

await expect(primary).toHaveClass(/btn-primary/);

// Secondary variant

const secondary = await mount();

await expect(secondary).toHaveClass(/btn-secondary/);

});

```

With Event Handlers

```typescript

test('form submission', async ({ mount }) => {

const submittedData: any[] = [];

const component = await mount(

submittedData.push(data)} />

);

await component.getByLabel('Name').fill('John');

await component.getByLabel('Email').fill('john@example.com');

await component.getByRole('button', { name: 'Submit' }).click();

expect(submittedData).toHaveLength(1);

expect(submittedData[0]).toEqual({

name: 'John',

email: 'john@example.com',

});

});

```

With Context Providers

```typescript

// Create wrapper for providers

import { ThemeProvider } from './ThemeContext';

test('themed component', async ({ mount }) => {

const component = await mount(

Click

);

await expect(component).toHaveClass(/dark-theme/);

});

```

With Slots/Children

```typescript

test('card with custom content', async ({ mount }) => {

const component = await mount(

Title

Content here

);

await expect(component.getByText('Title')).toBeVisible();

await expect(component.getByText('Content here')).toBeVisible();

await expect(component.getByRole('button')).toBeVisible();

});

```

Vue Component Testing

```typescript

// Counter.spec.ts

import { test, expect } from '@playwright/experimental-ct-vue';

import Counter from './Counter.vue';

test('counter increments', async ({ mount }) => {

const component = await mount(Counter, {

props: {

initialCount: 0,

},

});

await expect(component.getByText('Count: 0')).toBeVisible();

await component.getByRole('button', { name: '+' }).click();

await expect(component.getByText('Count: 1')).toBeVisible();

});

```

With Slots

```typescript

test('card with slots', async ({ mount }) => {

const component = await mount(Card, {

slots: {

default: '

Card content

',

header: '

Card Title

',

},

});

await expect(component.getByText('Card Title')).toBeVisible();

await expect(component.getByText('Card content')).toBeVisible();

});

```

With Vuex/Pinia

```typescript

import { test, expect } from '@playwright/experimental-ct-vue';

import { createTestingPinia } from '@pinia/testing';

import UserProfile from './UserProfile.vue';

test('displays user from store', async ({ mount }) => {

const component = await mount(UserProfile, {

global: {

plugins: [

createTestingPinia({

initialState: {

user: { name: 'John', email: 'john@example.com' },

},

}),

],

},

});

await expect(component.getByText('John')).toBeVisible();

});

```

Svelte Component Testing

```typescript

// Button.spec.ts

import { test, expect } from '@playwright/experimental-ct-svelte';

import Button from './Button.svelte';

test('button emits click', async ({ mount }) => {

let clicked = false;

const component = await mount(Button, {

props: {

label: 'Click me',

},

on: {

click: () => clicked = true,

},

});

await component.click();

expect(clicked).toBe(true);

});

```

Testing Patterns

Visual Regression

```typescript

test('button visual states', async ({ mount }) => {

const component = await mount();

// Default state

await expect(component).toHaveScreenshot('button-default.png');

// Hover state

await component.hover();

await expect(component).toHaveScreenshot('button-hover.png');

// Focus state

await component.focus();

await expect(component).toHaveScreenshot('button-focus.png');

});

```

Accessibility

```typescript

import AxeBuilder from '@axe-core/playwright';

test('button is accessible', async ({ mount, page }) => {

await mount();

const results = await new AxeBuilder({ page }).analyze();

expect(results.violations).toEqual([]);

});

```

Responsive Behavior

```typescript

test('responsive navigation', async ({ mount, page }) => {

const component = await mount();

// Desktop - horizontal nav

await page.setViewportSize({ width: 1280, height: 720 });

await expect(component.locator('.nav-horizontal')).toBeVisible();

// Mobile - hamburger menu

await page.setViewportSize({ width: 375, height: 667 });

await expect(component.locator('.hamburger-menu')).toBeVisible();

});

```

Loading States

```typescript

test('async component states', async ({ mount }) => {

const component = await mount();

// Loading state

await expect(component.getByText('Loading...')).toBeVisible();

// Wait for data

await expect(component.getByRole('table')).toBeVisible();

await expect(component.getByText('Loading...')).not.toBeVisible();

});

```

Error States

```typescript

test('error handling', async ({ mount, page }) => {

// Mock failed API

await page.route('**/api/data', route => {

route.fulfill({ status: 500 });

});

const component = await mount();

await expect(component.getByText(/error/i)).toBeVisible();

await expect(component.getByRole('button', { name: 'Retry' })).toBeVisible();

});

```

Hooks and Fixtures

Before Each Test

```typescript

import { test as base, expect } from '@playwright/experimental-ct-react';

const test = base.extend({

autoMockApi: async ({ page }, use) => {

await page.route('/api/', route => {

route.fulfill({ status: 200, body: '{}' });

});

await use();

},

});

test('component with mocked api', async ({ mount, autoMockApi }) => {

const component = await mount();

// API calls are automatically mocked

});

```

Custom Mount

```typescript

const test = base.extend({

mountWithProviders: async ({ mount }, use) => {

const wrappedMount = async (component: JSX.Element) => {

return mount(

{component}

);

};

await use(wrappedMount);

},

});

test('with providers', async ({ mountWithProviders }) => {

const component = await mountWithProviders();

// Component has access to theme and auth contexts

});

```

Running Tests

```bash

# Run all component tests

npx playwright test -c playwright-ct.config.ts

# Run specific test file

npx playwright test Button.spec.tsx -c playwright-ct.config.ts

# Run with UI mode

npx playwright test -c playwright-ct.config.ts --ui

# Update snapshots

npx playwright test -c playwright-ct.config.ts --update-snapshots

```

Best Practices

  1. Test behavior, not implementation - Focus on user interactions
  2. Keep components isolated - Mock external dependencies
  3. Test all states - Default, loading, error, empty, success
  4. Use semantic queries - getByRole, getByLabel over CSS selectors
  5. Combine with E2E - Component tests for logic, E2E for integration

References

  • references/react-patterns.md - React-specific testing patterns
  • references/vue-patterns.md - Vue-specific testing patterns

More from this repository10

🎯
analysis🎯Skill

Performs comprehensive analysis of code, skills, processes, and data to extract actionable insights, identify patterns, and drive data-driven improvements.

🎯
auto-claude-troubleshooting🎯Skill

Automatically diagnoses and resolves Auto-Claude installation, configuration, and runtime issues across different platforms and environments.

🎯
xai-auth🎯Skill

Authenticates and configures xAI Grok API access using Twitter/X account credentials, enabling seamless integration with OpenAI-compatible SDK methods.

🎯
xai-financial-integration🎯Skill

Retrieve and integrate xAI Grok sentiment with financial data APIs to generate comprehensive market insights and analysis.

🎯
xai-crypto-sentiment🎯Skill

xai-crypto-sentiment skill from adaptationio/skrillz

🎯
twelvedata-api🎯Skill

Retrieves comprehensive financial market data including stocks, forex, crypto, and technical indicators using the Twelve Data API.

🎯
xai-x-search🎯Skill

Enables real-time Twitter/X searches using Grok API to extract insights, track trends, monitor accounts, and analyze social discussions.

🎯
xai-agent-tools🎯Skill

Enables autonomous agents to search X, web, execute code, and analyze documents with server-side tool management.

🎯
auto-claude-optimization🎯Skill

Optimizes Claude AI performance by reducing token usage, managing API costs, and improving build speed through intelligent model and context selection.

🎯
auto-claude-setup🎯Skill

Automates comprehensive installation and setup of Auto-Claude across Windows, macOS, Linux, and WSL with multi-platform support and dependency management.