Claude
Skills
Sign in
Back

mobile-responsive-testing

Included with Lifetime
$97 forever

Comprehensive mobile responsiveness testing - scrolling, screenshots at all breakpoints, touch targets, and visual verification

General

What this skill does


# Mobile Responsive Testing Skill

Use this skill to perform thorough mobile responsiveness testing including scrolling through entire pages, capturing screenshots at multiple breakpoints, and verifying touch interactions.

## When to Use
- After implementing UI features
- After fixing responsive layout bugs
- Before deploying frontend changes
- During comprehensive QA validation
- When user reports mobile issues

## What This Skill Does

### 1. Multi-Breakpoint Testing
Tests at ALL standard breakpoints:
- **Mobile Portrait**: 375px × 667px (iPhone SE)
- **Mobile Portrait Large**: 414px × 896px (iPhone 11 Pro)
- **Mobile Landscape**: 667px × 375px
- **Tablet Portrait**: 768px × 1024px (iPad)
- **Tablet Landscape**: 1024px × 768px
- **Small Desktop**: 1280px × 720px
- **Large Desktop**: 1920px × 1080px

### 2. Comprehensive Scrolling
For EACH breakpoint:
- Scroll to top of page
- Take screenshot of viewport
- Scroll down by viewport height
- Take screenshot
- Repeat until bottom of page
- Verify no horizontal scrolling
- Check all content is accessible

### 3. Touch Target Verification
Validates mobile usability:
- All buttons minimum 44px × 44px
- Adequate spacing between tappable elements (8px minimum)
- No overlapping interactive elements
- Touch targets not too close to screen edges

### 4. Visual Verification
Captures evidence of:
- Layout at each breakpoint
- Component stacking on mobile
- Text readability without zooming
- Image scaling and aspect ratios
- Modal/dialog behavior on small screens
- Navigation menu responsiveness

### 5. Scroll Behavior Testing
Verifies smooth scrolling:
- No janky animations
- Sticky headers work correctly
- Infinite scroll (if applicable)
- Pull-to-refresh doesn't interfere
- Scroll position maintained on navigation

## Available Playwright MCP Tools

- `mcp__playwright__browser_navigate` - Navigate to page
- `mcp__playwright__browser_resize` - Change viewport size **CRITICAL FOR THIS SKILL**
- `mcp__playwright__browser_take_screenshot` - Capture visual state **USE EXTENSIVELY**
- `mcp__playwright__browser_evaluate` - Run JavaScript to scroll and measure
- `mcp__playwright__browser_snapshot` - Get page accessibility tree
- `mcp__playwright__browser_scroll` - Scroll programmatically
- `mcp__playwright__browser_wait_for` - Wait for scroll completion
- `mcp__playwright__browser_close` - Close browser when done

## Testing Workflow

### Step 1: Initialize Browser
```
mcp__playwright__browser_navigate(url)
```

### Step 2: Test Each Breakpoint
For each breakpoint (375px, 414px, 768px, 1024px, 1280px, 1920px):

```javascript
// Resize to breakpoint
mcp__playwright__browser_resize(width, height)

// Wait for layout to settle
mcp__playwright__browser_wait_for(selector: "body", state: "stable")

// Get page height
const pageHeight = await mcp__playwright__browser_evaluate(`
  document.documentElement.scrollHeight
`)

// Get viewport height
const viewportHeight = await mcp__playwright__browser_evaluate(`
  window.innerHeight
`)

// Calculate number of screenshots needed
const numScreenshots = Math.ceil(pageHeight / viewportHeight)

// Scroll and screenshot
for (let i = 0; i < numScreenshots; i++) {
  // Scroll to position
  await mcp__playwright__browser_evaluate(`
    window.scrollTo(0, ${i * viewportHeight})
  `)

  // Wait for scroll to complete
  await mcp__playwright__browser_wait_for(timeout: 500)

  // Take screenshot
  await mcp__playwright__browser_take_screenshot(
    filename: `${breakpoint}_scroll_${i}.png`
  )

  // Check for horizontal scroll (BAD!)
  const hasHorizontalScroll = await mcp__playwright__browser_evaluate(`
    document.documentElement.scrollWidth > window.innerWidth
  `)

  if (hasHorizontalScroll) {
    // CRITICAL ISSUE - Report immediately
    console.error(`Horizontal scroll detected at ${breakpoint}px`)
  }
}
```

### Step 3: Test Touch Targets (Mobile Only)
For viewports < 768px:

```javascript
// Find all interactive elements
const touchTargets = await mcp__playwright__browser_evaluate(`
  const elements = document.querySelectorAll('button, a, input, select, textarea, [role="button"]')
  Array.from(elements).map(el => {
    const rect = el.getBoundingClientRect()
    return {
      tag: el.tagName,
      text: el.textContent?.substring(0, 20),
      width: rect.width,
      height: rect.height,
      x: rect.x,
      y: rect.y
    }
  })
`)

// Check each touch target
touchTargets.forEach(target => {
  if (target.width < 44 || target.height < 44) {
    console.error(`Touch target too small: ${target.tag} "${target.text}" is ${target.width}x${target.height}px (min 44x44px)`)
  }
})
```

### Step 4: Test Navigation Responsiveness
```javascript
// Check if mobile menu exists on small screens
if (viewport.width < 768) {
  const hasMobileMenu = await mcp__playwright__browser_evaluate(`
    // Look for hamburger icon or mobile nav
    const hamburger = document.querySelector('[aria-label*="menu"], .mobile-menu, .hamburger')
    hamburger !== null
  `)

  if (!hasMobileMenu) {
    console.warn('No mobile menu found on mobile viewport')
  }
}
```

### Step 5: Test Form Layouts
```javascript
// Verify forms are single-column on mobile
if (viewport.width < 768) {
  const formLayouts = await mcp__playwright__browser_evaluate(`
    const forms = document.querySelectorAll('form')
    Array.from(forms).map(form => {
      const inputs = form.querySelectorAll('input, select, textarea')
      const positions = Array.from(inputs).map(input => input.getBoundingClientRect().left)
      const uniqueColumns = [...new Set(positions)].length
      return {
        formId: form.id || 'unknown',
        columns: uniqueColumns
      }
    })
  `)

  formLayouts.forEach(layout => {
    if (layout.columns > 1) {
      console.error(`Form "${layout.formId}" has ${layout.columns} columns on mobile (should be 1)`)
    }
  })
}
```

### Step 6: Generate Report
```javascript
// Compile all findings
const report = {
  breakpoints_tested: ['375px', '414px', '768px', '1024px', '1280px', '1920px'],
  screenshots_captured: totalScreenshots,
  horizontal_scroll_issues: horizontalScrollIssues,
  touch_target_violations: touchTargetViolations,
  layout_issues: layoutIssues,
  status: issues.length === 0 ? 'PASS' : 'FAIL'
}
```

## Docker IP Configuration

**IMPORTANT**: When testing against Docker containers, use the container IP address, NOT localhost.

### Get Docker Container IP:
```bash
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' {container_name}
```

### Use in Playwright:
```
# Instead of:
mcp__playwright__browser_navigate("http://localhost:3003")

# Use:
mcp__playwright__browser_navigate("http://172.18.0.5:80")
```

## Expected Inputs
- URL to test (Docker IP address if using containers)
- Page/feature to test
- Specific breakpoints (or use all standard ones)

## Deliverables
- Screenshot for each breakpoint at each scroll position
- List of horizontal scroll violations
- List of touch target violations (< 44px)
- Form layout issues on mobile
- Navigation responsiveness issues
- Overall PASS/FAIL status
- Detailed report with recommendations

## Example: Complete Mobile Testing Flow

```
// Test URL (using Docker IP)
const url = "http://172.18.0.5:80/schedules"

// Navigate
mcp__playwright__browser_navigate(url)

// Define breakpoints to test
const breakpoints = [
  { name: 'mobile_portrait', width: 375, height: 667 },
  { name: 'mobile_large', width: 414, height: 896 },
  { name: 'tablet_portrait', width: 768, height: 1024 },
  { name: 'desktop', width: 1280, height: 720 },
  { name: 'desktop_large', width: 1920, height: 1080 }
]

// Test each breakpoint
for (const breakpoint of breakpoints) {
  console.log(`Testing ${breakpoint.name} (${breakpoint.width}x${breakpoint.height})`)

  // Resize
  mcp__playwright__browser_resize(breakpoint.width, breakpoint.height)

  // Get page dimensions
  const dimensions = await mcp__playwright__browser_evaluate(`({
    pageHeight: document.documentE

Related in General