← Back to Home

AI Coding Workflow

chrome-devtools-mcpPlaywrightClaude CodeMCPbrowser automation

After the previous post on browser automation with chrome-devtools-mcp and Claude Code, many readers asked: can we automatically run Playwright to verify UI behavior after AI generates code, instead of manually checking the browser? This article breaks down the full implementation path and real pitfalls of this combo.

Why This Combo Matters

The core problem with pure AI code generation: Claude Code writes HTML/JS/CSS, but whether it actually works can only be verified by human eyes. With Playwright in the loop, AI can run automated assertions against its own output — click verification, screenshot diff, network request interception, all driven by test scripts with no manual intervention needed.

In my testing, this combo roughly doubled UI iteration speed for front-end tasks (personal measurement, not precise). The core value: AI shifts from "generate → human verify" to "generate → automated verify → fix → re-verify."

🏗️ Architecture: chrome-devtools-mcp × Playwright × Claude Code

Three-layer split:

Data flow: Claude Code → MCP → chrome-devtools CDP Session → Playwright Node.js API → verify results → Claude Code fixes

🛠️ Prerequisites (Verified)

Verified versions:

Full install commands:

# Global Playwright + Chromium
npm install -g playwright
npx playwright install chromium --with-deps

# Verify Chrome remote debugging port
google-chrome --remote-debugging-port=9222 &
sleep 2
curl http://localhost:9222/json/version
# Expected output contains "Browser" and "Protocol-Version" fields

# Add chrome-devtools-mcp to Claude Code
# Method 1: /mcp add inside Claude Code
# Method 2: standalone MCP server
npx @modelcontextprotocol/server-chrome-devtools

**Note**: If you have multiple Chrome instances running (e.g. regular Chrome + debugging Chrome), ports will conflict. Use --user-data-dir=/tmp/chrome-devtools to isolate.

📁 Project Structure

ai-ui-test/
├── src/
│   ├── button.spec.ts       # Playwright test cases
│   ├── login-flow.ts        # Page logic under test
│   └── mcp-helper.ts        # chrome-devtools MCP wrapper
├── playwright.config.ts     # Playwright config
├── mcp-servers.json         # MCP server connection config
└── package.json

Use @playwright/test (not bare playwright) for test() syntax and parallel execution.

🚀 Core Integration Code

#### 1. Playwright Config (playwright.config.ts)

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './src',
  timeout: 30000,
  retries: 2,
  use: {
    baseURL: 'http://localhost:3000',
    // Key: only record Trace on first failure, for AI analysis
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'off',  // Disable video to avoid large files
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
  ],
});

#### 2. chrome-devtools MCP + Playwright Bridge (mcp-helper.ts)

// mcp-helper.ts
// Wraps chrome-devtools-mcp capabilities, bridges Playwright and CDP

export interface CDPClient {
  getDocument(): Promise<{ root: any }>;
  setRequestInterception(patterns: string[]): Promise;
  startProfiling(): Promise;
  stopProfiling(): Promise;
  evaluate(expression: string): Promise;
}

/**
 * Connect to chrome-devtools-mcp debug port
 * @param port Default 9222, matches Chrome --remote-debugging-port
 */
export async function createCDPSession(port = 9222): Promise {
  const resp = await fetch(`http://localhost:${port}/json`);
  const tabs = await resp.json();
  if (!tabs.length) throw new Error(`No Chrome tabs found on port ${port}`);

  // Actual use requires `ws` library to connect to webSocketDebuggerUrl
  // This returns the interface definition; for real implementation use Puppeteer's CDPSession
  // which already wraps ws → CDP protocol translation
  const wsUrl = tabs[0].webSocketDebuggerUrl;
  return {
    wsUrl,
  } as unknown as CDPClient;
}

#### 3. Playwright Test Cases (button.spec.ts)

import { test, expect } from '@playwright/test';

/**
 * Scenario: AI generates a login button, Claude Code uses chrome-devtools-mcp to verify
 * DOM changes before and after click match expectations
 */
test('login button shows loading state correctly on click', async ({ page }) => {
  await page.goto('/login');

  // Screenshot baseline (for AI human review)
  await page.screenshot({ path: 'baseline.png' });

  // Click login button
  await page.click('#login-btn');

  // AI reads loading state via chrome-devtools CDP
  const loadingAttr = await page.getAttribute('#login-btn', 'data-loading');
  expect(loadingAttr).toBe('true');

  // Wait for API response and verify button text restores
  await expect(page.locator('#login-btn')).toHaveText('Login', { timeout: 5000 });
});

/**
 * Scenario: Verify AI-generated error message renders correctly for failed login
 */
test('failed login shows error message', async ({ page }) => {
  await page.goto('/login?error=1');
  await expect(page.locator('.error-message')).toBeVisible();
  await expect(page.locator('.error-message')).toContainText('Invalid password');
});

💣 Troubleshooting (5 Real Pitfalls)

Error 1: chrome-devtools-mcp ECONNREFUSED

Error: connect ECONNREFUSED 127.0.0.1:9222

Cause: Chrome remote debugging port not open.

Fix:

# Kill potentially conflicting Chrome processes
pkill -f "chrome.*remote-debugging"
# Restart Chrome in debug mode
google-chrome --remote-debugging-port=9222 --no-first-run

Error 2: Playwright CDP session conflicts with chrome-devtools-mcp port

Cause: chrome-devtools-mcp occupies 9222, Playwright also tries 9222 by default, causing port contention.

Fix: In playwright.config.ts, use Playwright's launch() method instead of connect(); or switch chrome-devtools-mcp to port 9223.

Error 3: Playwright Trace files too large (>100MB)

Cause: Every test records a full Trace including all network requests and DOM operations.

Fix:

// playwright.config.ts
use: {
  trace: 'on-first-retry',  // Only on first failure
  video: 'off',
  screenshot: 'only-on-failure',
}

**Error 4: Node.js 18 throws fetch is not defined**

Cause: Node.js 18's built-in fetch is experimental.

Fix: Upgrade to Node.js 20+, or launch with:

node --experimental-fetch test.spec.ts

**Error 5: Playwright test says page.goto target not found**

Cause: Test runs but the frontend isn't running (localhost:3000 not responding).

Fix: Start the frontend first, or add webServer to playwright.config.ts:

webServer: {
  command: 'npm run dev',
  port: 3000,
  reuseExistingServer: true,
}

🔍 Complete AI Workflow Loop Demo

5-step closed loop (actually tested):

1. Requirement input: Claude Code receives prompt "login button must show loading on click, restore after 2 seconds"

2. Code generation: Claude Code writes HTML/JS and injects into open Chrome page via chrome-devtools-mcp

3. **UI verification**: Uses DOM.getDocument() + Runtime.evaluate() to check if data-loading attribute exists on button

4. **Playwright assertions**: Runs npx playwright test button.spec.ts to verify click behavior; failure triggers fix loop

5. **Trace analysis**: Playwright generates .zip Trace, Claude Code unzips and analyzes the Trace JSON to locate which DOM operation timed out

# Run Playwright + generate HTML report
npx playwright test --reporter=list && npx playwright show-report

# Re-run single file with Trace after AI fix
npx playwright test button.spec.ts --trace=on

# View Trace (requires Playwright CLI)
npx playwright show-trace trace.zip

Summary

The chrome-devtools-mcp + Playwright combo closes the "generate → verify → fix" loop for AI-generated UI code. Key takeaways:

Related Reading

👉 Join MiniMax Token Plan: AI coding acceleration for businesses

👉 Join Zhipu Coding Plan: GLM-4.6/GLM-5 coding packages, China-stable, pay-per-token unlimited

👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation

📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews

🔗 Recommended Tools

These are carefully selected tools. Using our affiliate links supports us to keep producing quality content:

☁️ DigitalOcean Cloud ⚡ Vultr VPS ⭐ MiniMax Token Plan 🧩 Zhipu Coding Plan 🎁 Zhipu 20M Tokens Gift 🤖 QoderWork CN (Refer & Earn) ☁️ Aliyun AI Products 📚 WordPress Books 🔍 WordPress SEO Books 🌐 Web Hosting Books 🐳 Docker Books 🐧 Linux Books 🐍 Python Books 💰 Affiliate Marketing 💵 Passive Income Books 🖥️ Server Books ☁️ Cloud Computing Books 🚀 DevOps Books
← Back to Home