Claude
Skills
Sign in
Back

playwright-skill

Included with Lifetime
$97 forever

Automatisation complète du navigateur et tests web avec Playwright. Détecte automatiquement les serveurs de développement, gère le cycle de vie des serveurs, écrit des scripts de test propres dans /tmp. Tester des pages, remplir des formulaires, capturer des screenshots, vérifier le responsive design, valider l'UX, tester les flux de connexion, vérifier les liens, déboguer des webapps dynamiques, automatiser toute tâche navigateur. À utiliser quand l'utilisateur veut tester des sites web, automatiser des interactions navigateur, valider des fonctionnalités web ou effectuer tout test basé sur le navigateur.

Design

What this skill does


# Playwright Web Testing & Automation

Comprehensive web testing skill using Playwright. Write custom JavaScript code for any testing or automation task.

## Prerequisites

- **Node.js**: required — install from https://nodejs.org
- **playwright** npm package: `npm install playwright` (installs headless Chromium automatically)

## Decision Tree: Choosing Your Approach

```
User task → Is server already running?
    ├─ Yes → Direct Testing
    │   ├─ Static HTML? → Navigate directly (file:// or http://)
    │   └─ Dynamic webapp? → Use Reconnaissance-Then-Action pattern
    │
    └─ No → Server Management Required
        ├─ Single server → Start server, then test
        └─ Multiple servers → Start all servers, coordinate testing
```

## CRITICAL WORKFLOW

1. **CheckTesting  if server is running** - Detect running dev servers OR start servers if needed
2. **Write scripts to /tmp** - NEVER write test files to skill directory; always use `/tmp/playwright-test-*.js`
3. **Use visible browser by default** - Always use `headless: false` unless user specifically requests headless mode
4. **Wait for dynamic content** - Use `waitForLoadState('networkidle')` before inspecting dynamic webapps
5. **Parameterize URLs** - Always make URLs configurable via constant at top of script

## Reconnaissance-Then-Action Pattern

For dynamic webapps where you don't know the DOM structure upfront:

```javascript
// /tmp/playwright-test-reconnaissance.js
const { chromium } = require('playwright');

const TARGET_URL = 'http://localhost:3000';

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  // STEP 1: Navigate and wait for dynamic content
  await page.goto(TARGET_URL);
  await page.waitForLoadState('networkidle'); // CRITICAL for dynamic apps

  // STEP 2: Reconnaissance - discover what's on the page
  await page.screenshot({ path: '/tmp/inspect.png', fullPage: true });
  
  const buttons = await page.locator('button').all();
  console.log(`Found ${buttons.length} buttons`);
  
  for (let i = 0; i < buttons.length; i++) {
    const text = await buttons[i].textContent();
    console.log(`  Button ${i}: "${text}"`);
  }

  // STEP 3: Action - interact with discovered elements
  const loginButton = page.locator('button:has-text("Login")');
  if (await loginButton.isVisible()) {
    await loginButton.click();
    console.log('✅ Clicked login button');
  }

  await browser.close();
})();
```

## Server Management

### Check for Running Servers

```bash
# Check if port is in use
lsof -i :3000  # Mac/Linux
netstat -ano | findstr :3000  # Windows
```

### Start Server Before Testing

```javascript
// /tmp/playwright-test-with-server.js
const { chromium } = require('playwright');
const { spawn } = require('child_process');

const TARGET_URL = 'http://localhost:3000';

(async () => {
  // Start server
  console.log('Starting server...');
  const server = spawn('npm', ['run', 'dev'], { shell: true });
  
  server.stdout.on('data', (data) => console.log(`Server: ${data}`));
  server.stderr.on('data', (data) => console.error(`Server Error: ${data}`));

  // Wait for server to be ready
  await new Promise(resolve => setTimeout(resolve, 3000));

  // Run tests
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();
  
  await page.goto(TARGET_URL);
  await page.waitForLoadState('networkidle');
  
  // Your test logic here
  console.log('Title:', await page.title());
  
  await browser.close();
  
  // Clean up server
  server.kill();
  console.log('✅ Tests complete, server stopped');
})();
```

## Common Patterns

### Test a Page (Multiple Viewports)

```javascript
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');

const TARGET_URL = 'http://localhost:3001'; // Auto-detected

(async () => {
  const browser = await chromium.launch({ headless: false, slowMo: 100 });
  const page = await browser.newPage();

  // Desktop test
  await page.setViewportSize({ width: 1920, height: 1080 });
  await page.goto(TARGET_URL);
  console.log('Desktop - Title:', await page.title());
  await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });

  // Mobile test
  await page.setViewportSize({ width: 375, height: 667 });
  await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });

  await browser.close();
})();
```

### Test Login Flow

```javascript
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');

const TARGET_URL = 'http://localhost:3001'; // Auto-detected

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  await page.goto(`${TARGET_URL}/login`);

  await page.fill('input[name="email"]', '[email protected]');
  await page.fill('input[name="password"]', 'password123');
  await page.click('button[type="submit"]');

  // Wait for redirect
  await page.waitForURL('**/dashboard');
  console.log('✅ Login successful, redirected to dashboard');

  await browser.close();
})();
```

### Fill and Submit Form

```javascript
// /tmp/playwright-test-form.js
const { chromium } = require('playwright');

const TARGET_URL = 'http://localhost:3001'; // Auto-detected

(async () => {
  const browser = await chromium.launch({ headless: false, slowMo: 50 });
  const page = await browser.newPage();

  await page.goto(`${TARGET_URL}/contact`);

  await page.fill('input[name="name"]', 'John Doe');
  await page.fill('input[name="email"]', '[email protected]');
  await page.fill('textarea[name="message"]', 'Test message');
  await page.click('button[type="submit"]');

  // Verify submission
  await page.waitForSelector('.success-message');
  console.log('✅ Form submitted successfully');

  await browser.close();
})();
```

### Check for Broken Links

```javascript
const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  await page.goto('http://localhost:3000');

  const links = await page.locator('a[href^="http"]').all();
  const results = { working: 0, broken: [] };

  for (const link of links) {
    const href = await link.getAttribute('href');
    try {
      const response = await page.request.head(href);
      if (response.ok()) {
        results.working++;
      } else {
        results.broken.push({ url: href, status: response.status() });
      }
    } catch (e) {
      results.broken.push({ url: href, error: e.message });
    }
  }

  console.log(`✅ Working links: ${results.working}`);
  console.log(`❌ Broken links:`, results.broken);

  await browser.close();
})();
```

### Take Screenshot with Error Handling

```javascript
const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  try {
    await page.goto('http://localhost:3000', {
      waitUntil: 'networkidle',
      timeout: 10000,
    });

    await page.screenshot({
      path: '/tmp/screenshot.png',
      fullPage: true,
    });

    console.log('📸 Screenshot saved to /tmp/screenshot.png');
  } catch (error) {
    console.error('❌ Error:', error.message);
  } finally {
    await browser.close();
  }
})();
```

### Test Responsive Design

```javascript
// /tmp/playwright-test-responsive-full.js
const { chromium } = require('playwright');

const TARGET_URL = 'http://localhost:3001'; // Auto-detected

(async () => {
  const browser = await chromium.launch({ headless: false });
  const page = await browser.newPage();

  const viewports = [
    { name: 'Desktop', width: 1920, height: 1080 },
    { name: 'Tablet', width: 768, height: 1024 },
    { name: 'Mobile', width: 375, height: 667 },
  ];

  for (const viewport of viewports) {
    console.log(
      `Testing ${viewport.name} (${viewport.width}x${viewport.height})`,
    );
 & Discovery

```javascript
// Check visibility
const isVisible = await p

Related in Design