Claude
Skills
Sign in
Back

visual-qa-testing

Included with Lifetime
$97 forever

Visual QA testing with comprehensive screenshot capture, comparison, and verification across multiple states and breakpoints

Code Review

What this skill does


# Visual QA Testing Skill

Use this skill to perform visual quality assurance by capturing screenshots of UI states, comparing layouts, and verifying visual correctness across different scenarios.

## When to Use
- After UI implementation
- After CSS/styling changes
- Before deployments
- For regression testing
- When user reports visual bugs
- During comprehensive QA validation

## What This Skill Does

### 1. State-Based Screenshot Capture
Captures screenshots for ALL UI states:
- **Initial/Empty State** - No data loaded
- **Loading State** - Spinners, skeletons active
- **Data Loaded State** - Content displayed
- **Error State** - Error messages shown
- **Validation State** - Form validation errors
- **Success State** - Success messages
- **Hover State** - Interactive element hover
- **Focus State** - Keyboard focus indicators
- **Active/Selected State** - Selected items
- **Disabled State** - Disabled elements

### 2. Multi-Breakpoint Screenshot Matrix
For EACH state, capture at ALL breakpoints:
- Mobile Portrait (375px)
- Mobile Large (414px)
- Tablet (768px)
- Desktop (1280px)
- Large Desktop (1920px)

Result: Comprehensive screenshot matrix (10 states × 5 breakpoints = 50 screenshots per page)

### 3. Component-Level Capture
Screenshot specific components:
- Forms (empty, filled, with errors)
- Modals/Dialogs
- Navigation menus
- Data tables/grids
- Cards and lists
- Buttons (all variants)
- Input fields (all states)

### 4. User Workflow Capture
Screenshot each step of user journeys:
- Login flow
- Create/Edit/Delete workflows
- Multi-step forms
- Checkout processes
- Onboarding flows

### 5. Visual Regression Detection
Compare screenshots to identify:
- Layout shifts
- Broken layouts
- Missing styles
- Color inconsistencies
- Font rendering issues
- Icon/image problems

## Available Playwright MCP Tools

- `mcp__playwright__browser_navigate` - Navigate to pages
- `mcp__playwright__browser_resize` - Change viewport **CRITICAL**
- `mcp__playwright__browser_take_screenshot` - Capture screenshots **PRIMARY TOOL**
- `mcp__playwright__browser_click` - Trigger interactions
- `mcp__playwright__browser_type` - Fill inputs
- `mcp__playwright__browser_fill_form` - Fill forms
- `mcp__playwright__browser_evaluate` - Manipulate DOM/trigger states
- `mcp__playwright__browser_wait_for` - Wait for state changes
- `mcp__playwright__browser_snapshot` - Get accessibility tree

## Testing Workflow

### Step 1: Initialize Test Session
```javascript
const testSession = {
  feature: 'Schedule Calendar',
  url: 'http://172.18.0.5:80/schedules',
  breakpoints: [375, 414, 768, 1280, 1920],
  states: ['empty', 'loading', 'loaded', 'error'],
  screenshots: []
}

// Navigate
mcp__playwright__browser_navigate(testSession.url)
```

### Step 2: Capture Empty State
```javascript
// For each breakpoint
for (const width of testSession.breakpoints) {
  // Resize
  mcp__playwright__browser_resize(width, 800)
  await mcp__playwright__browser_wait_for(timeout: 300)

  // Screenshot
  await mcp__playwright__browser_take_screenshot(
    filename: `empty_state_${width}px.png`,
    fullPage: true
  )

  testSession.screenshots.push({
    state: 'empty',
    breakpoint: width,
    filename: `empty_state_${width}px.png`
  })
}
```

### Step 3: Capture Loading State
```javascript
// Trigger loading state (if possible)
await mcp__playwright__browser_evaluate(`
  // Show loading skeletons or spinners
  document.querySelector('.loading-indicator')?.classList.add('visible')
  // Or trigger a slow API call
`)

// Capture at all breakpoints
for (const width of testSession.breakpoints) {
  mcp__playwright__browser_resize(width, 800)
  await mcp__playwright__browser_wait_for(timeout: 300)

  await mcp__playwright__browser_take_screenshot(
    filename: `loading_state_${width}px.png`,
    fullPage: true
  )
}
```

### Step 4: Capture Data Loaded State
```javascript
// Wait for data to load
await mcp__playwright__browser_wait_for(
  selector: '.schedule-calendar',
  state: 'visible'
)

// Capture at all breakpoints
for (const width of testSession.breakpoints) {
  mcp__playwright__browser_resize(width, 800)
  await mcp__playwright__browser_wait_for(timeout: 300)

  await mcp__playwright__browser_take_screenshot(
    filename: `loaded_state_${width}px.png`,
    fullPage: true
  )

  console.log(`✅ Captured loaded state at ${width}px`)
}
```

### Step 5: Capture Error State
```javascript
// Trigger error state
// Option 1: Fill form with invalid data
await mcp__playwright__browser_fill_form({
  'employee': '',  // Required field left empty
  'date': 'invalid-date'
})
await mcp__playwright__browser_click(selector: 'button[type="submit"]')

// Wait for error to appear
await mcp__playwright__browser_wait_for(
  selector: '.error-message',
  state: 'visible'
)

// Capture at all breakpoints
for (const width of testSession.breakpoints) {
  mcp__playwright__browser_resize(width, 800)
  await mcp__playwright__browser_wait_for(timeout: 300)

  await mcp__playwright__browser_take_screenshot(
    filename: `error_state_${width}px.png`,
    fullPage: true
  )

  console.log(`✅ Captured error state at ${width}px`)
}
```

### Step 6: Capture Form Validation States
```javascript
// Click into each input field to trigger validation
const formFields = ['employee', 'date', 'startTime', 'endTime']

for (const field of formFields) {
  // Click field
  await mcp__playwright__browser_click(selector: `[name="${field}"]`)

  // Click outside to blur (trigger validation)
  await mcp__playwright__browser_click(selector: 'body')

  // Wait for validation message
  await mcp__playwright__browser_wait_for(timeout: 200)

  // Screenshot at mobile only (375px)
  mcp__playwright__browser_resize(375, 667)
  await mcp__playwright__browser_take_screenshot(
    filename: `validation_${field}_375px.png`
  )

  // Screenshot at desktop (1280px)
  mcp__playwright__browser_resize(1280, 720)
  await mcp__playwright__browser_take_screenshot(
    filename: `validation_${field}_1280px.png`
  )
}
```

### Step 7: Capture Interactive States
```javascript
// Hover state (desktop only)
mcp__playwright__browser_resize(1280, 720)

// Find interactive elements
const interactiveElements = await mcp__playwright__browser_evaluate(`
  Array.from(document.querySelectorAll('button, a, .clickable')).map(el => ({
    selector: el.className || el.tagName,
    text: el.textContent?.substring(0, 20)
  }))
`)

for (const element of interactiveElements.slice(0, 5)) {  // First 5 elements
  // Hover
  await mcp__playwright__browser_evaluate(`
    const el = document.querySelector('${element.selector}')
    el.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }))
  `)

  await mcp__playwright__browser_take_screenshot(
    filename: `hover_${element.selector}_1280px.png`
  )

  console.log(`✅ Captured hover state: ${element.text}`)
}

// Focus state (keyboard navigation)
for (const element of interactiveElements.slice(0, 5)) {
  // Focus
  await mcp__playwright__browser_evaluate(`
    document.querySelector('${element.selector}')?.focus()
  `)

  await mcp__playwright__browser_take_screenshot(
    filename: `focus_${element.selector}_1280px.png`
  )

  console.log(`✅ Captured focus state: ${element.text}`)
}
```

### Step 8: Capture Modal/Dialog States
```javascript
// Open modal
await mcp__playwright__browser_click(selector: 'button[data-testid="create-schedule"]')

// Wait for modal to appear
await mcp__playwright__browser_wait_for(
  selector: '[role="dialog"]',
  state: 'visible'
)

// Capture modal at all breakpoints
for (const width of [375, 768, 1280]) {
  mcp__playwright__browser_resize(width, 800)
  await mcp__playwright__browser_wait_for(timeout: 300)

  await mcp__playwright__browser_take_screenshot(
    filename: `modal_create_${width}px.png`,
    fullPage: true
  )

  console.log(`✅ Captured modal at ${width}px`)
}

// Close modal
await mcp__playwright__browser_click(selector: '[aria-label="Close"]')
```

### Step 9: Capture Scroll States
`

Related in Code Review