Skip to main content

Automated Design Testing with MCP Tools

Complete setup guide for implementing automated design testing using Model Context Protocol (MCP) tools, focusing on visual regression, accessibility, and performance monitoring.

MCP Tools Overview

Model Context Protocol (MCP) enables AI agents to interact with external tools and services through a standardized interface. For design testing, this creates powerful automation capabilities.

Key Benefits

  • AI-Driven Test Creation: Generate tests from natural language descriptions
  • Visual Regression Detection: Automated screenshot comparison
  • Accessibility Auditing: WCAG compliance verification
  • Performance Monitoring: Core Web Vitals tracking
  • Cross-Browser Testing: Consistent experience validation

Playwright MCP Server Setup

Installation

Option 1: Microsoft Official Implementation

npm install -g @playwright/mcp
npm install -g @executeautomation/playwright-mcp-server

Claude Desktop Configuration

Add to your Claude Desktop configuration:

{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@executeautomation/playwright-mcp-server"]
}
}
}

VS Code Integration

For development environments:

code --add-mcp '{"name":"playwright","command":"npx","args":["@executeautomation/playwright-mcp-server"]}'

Core Testing Framework

1. Visual Regression Testing

npm install --save-dev @percy/cli @percy/playwright

Percy Configuration (percy.config.yml):

version: 2
discovery:
allowed-hostnames:
- mm.dreamineering.com
snapshot:
widths: [375, 768, 1280, 1920]
min-height: 1024
percy-css: |
.dynamic-timestamp { display: none; }

Playwright Test with Percy:

const { test } = require('@playwright/test');
const { percySnapshot } = require('@percy/playwright');

test('Landing page visual regression', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

// Wait for content to load
await page.waitForLoadState('networkidle');

// Take Percy snapshot
await percySnapshot(page, 'Landing Page - Desktop', {
widths: [1280, 1920]
});

// Test mobile view
await page.setViewportSize({ width: 375, height: 667 });
await percySnapshot(page, 'Landing Page - Mobile');
});

Chromatic Setup (For Storybook Components)

npm install --save-dev chromatic

Package.json script:

{
"scripts": {
"chromatic": "chromatic --project-token=YOUR_PROJECT_TOKEN"
}
}

2. Accessibility Testing

Axe-Core Integration

npm install --save-dev @axe-core/playwright

Comprehensive Accessibility Test:

const { test, expect } = require('@playwright/test');
const AxeBuilder = require('@axe-core/playwright').default;

test('Landing page accessibility audit', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

const accessibilityScanResults = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
.exclude('.third-party-widget') // Exclude external widgets
.analyze();

expect(accessibilityScanResults.violations).toEqual([]);
});

test('Color contrast verification', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

const contrastResults = await new AxeBuilder({ page })
.withRules(['color-contrast'])
.analyze();

expect(contrastResults.violations).toEqual([]);
});

test('Keyboard navigation', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

// Test tab navigation
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');
await page.keyboard.press('Tab');

// Verify focus is visible
const focusedElement = await page.locator(':focus');
await expect(focusedElement).toBeVisible();
});

3. Performance Testing

Lighthouse Integration

npm install --save-dev @lhci/cli

Lighthouse CI Configuration (.lighthouserc.js):

module.exports = {
ci: {
collect: {
url: ['https://mm.dreamineering.com/'],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['warn', { minScore: 0.9 }],
'categories:accessibility': ['error', { minScore: 0.9 }],
'categories:best-practices': ['warn', { minScore: 0.9 }],
'categories:seo': ['warn', { minScore: 0.9 }],
},
},
upload: {
target: 'filesystem',
outputDir: './lighthouse-reports',
},
},
};

Core Web Vitals Test:

test('Core Web Vitals compliance', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

// Measure performance metrics
const metrics = await page.evaluate(() => {
return new Promise((resolve) => {
new PerformanceObserver((list) => {
const entries = list.getEntries();
const vitals = {};

entries.forEach((entry) => {
if (entry.entryType === 'largest-contentful-paint') {
vitals.lcp = entry.startTime;
}
if (entry.entryType === 'layout-shift') {
vitals.cls = entry.value;
}
});

resolve(vitals);
}).observe({ entryTypes: ['largest-contentful-paint', 'layout-shift'] });
});
});

// Assertions based on Core Web Vitals thresholds
expect(metrics.lcp).toBeLessThan(2500); // LCP < 2.5s
expect(metrics.cls).toBeLessThan(0.1); // CLS < 0.1
});

Cross-Browser Testing Matrix

Browser Configuration

// playwright.config.js
module.exports = {
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{
name: 'mobile-chrome',
use: { ...devices['Pixel 5'] },
},
{
name: 'mobile-safari',
use: { ...devices['iPhone 12'] },
},
],
};

Responsive Design Tests

test('Responsive design verification', async ({ page }) => {
const viewports = [
{ width: 375, height: 667, name: 'Mobile' },
{ width: 768, height: 1024, name: 'Tablet' },
{ width: 1280, height: 720, name: 'Desktop' },
{ width: 1920, height: 1080, name: 'Large Desktop' },
];

for (const viewport of viewports) {
await page.setViewportSize(viewport);
await page.goto('https://mm.dreamineering.com/');

// Verify no horizontal scrollbars
const scrollWidth = await page.evaluate(() =>
document.documentElement.scrollWidth
);
const clientWidth = await page.evaluate(() =>
document.documentElement.clientWidth
);

expect(scrollWidth).toBeLessThanOrEqual(clientWidth + 1);

// Take screenshot for visual verification
await page.screenshot({
path: `screenshots/${viewport.name}-${viewport.width}x${viewport.height}.png`,
fullPage: true
});
}
});

CI/CD Integration

GitHub Actions Workflow

# .github/workflows/design-tests.yml
name: Design Quality Tests

on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]

jobs:
visual-regression:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Install Playwright Browsers
run: npx playwright install --with-deps

- name: Run visual regression tests
run: npx percy exec -- npx playwright test
env:
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}

accessibility-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install dependencies
run: npm ci

- name: Install Playwright Browsers
run: npx playwright install --with-deps

- name: Run accessibility tests
run: npx playwright test --grep="accessibility"

performance-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'

- name: Install Lighthouse CI
run: npm install -g @lhci/cli

- name: Run Lighthouse CI
run: lhci autorun

Monitoring & Alerting

Performance Monitoring Setup

// monitoring/performance-monitor.js
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');

async function runPerformanceAudit() {
const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] });

const options = {
logLevel: 'info',
output: 'html',
onlyCategories: ['performance', 'accessibility'],
port: chrome.port,
};

const runnerResult = await lighthouse('https://mm.dreamineering.com/', options);

// Check thresholds
const performance = runnerResult.lhr.categories.performance.score;
const accessibility = runnerResult.lhr.categories.accessibility.score;

if (performance < 0.9 || accessibility < 0.9) {
// Send alert (Slack, email, etc.)
await sendAlert({
performance: performance * 100,
accessibility: accessibility * 100,
url: 'https://mm.dreamineering.com/',
timestamp: new Date().toISOString(),
});
}

await chrome.kill();
}

// Run every hour
setInterval(runPerformanceAudit, 60 * 60 * 1000);

Visual Regression Monitoring

// monitoring/visual-monitor.js
const { chromium } = require('playwright');
const pixelmatch = require('pixelmatch');
const PNG = require('pngjs').PNG;

async function compareScreenshots() {
const browser = await chromium.launch();
const page = await browser.newPage();

await page.goto('https://mm.dreamineering.com/');
await page.waitForLoadState('networkidle');

const currentScreenshot = await page.screenshot({ fullPage: true });

// Compare with baseline
const baselineBuffer = fs.readFileSync('baseline-screenshot.png');
const baseline = PNG.sync.read(baselineBuffer);
const current = PNG.sync.read(currentScreenshot);

const diff = new PNG({ width: baseline.width, height: baseline.height });
const pixelDiff = pixelmatch(
baseline.data,
current.data,
diff.data,
baseline.width,
baseline.height,
{ threshold: 0.1 }
);

if (pixelDiff > 1000) { // Threshold for significant changes
await sendVisualAlert({
pixelDifference: pixelDiff,
diffImage: PNG.sync.write(diff),
timestamp: new Date().toISOString(),
});
}

await browser.close();
}

Best Practices & Guidelines

Test Organization

tests/
├── visual/
│ ├── landing-page.spec.js
│ ├── navigation.spec.js
│ └── responsive.spec.js
├── accessibility/
│ ├── wcag-compliance.spec.js
│ ├── keyboard-navigation.spec.js
│ └── screen-reader.spec.js
├── performance/
│ ├── core-web-vitals.spec.js
│ ├── lighthouse.spec.js
│ └── load-testing.spec.js
└── cross-browser/
├── compatibility.spec.js
└── feature-detection.spec.js

Test Data Management

// test-data/selectors.js
export const selectors = {
navigation: {
logo: '[data-testid="logo"]',
mainMenu: '[data-testid="main-menu"]',
ctaButton: '[data-testid="cta-primary"]',
},
content: {
heroHeadline: '[data-testid="hero-headline"]',
valueProposition: '[data-testid="value-prop"]',
testimonials: '[data-testid="testimonials"]',
},
};

// test-data/scenarios.js
export const scenarios = {
firstTimeVisitor: {
viewport: { width: 1280, height: 720 },
userAgent: 'new-visitor',
actions: ['land', 'read-hero', 'scroll-explore'],
},
returningUser: {
viewport: { width: 1280, height: 720 },
userAgent: 'returning-visitor',
actions: ['land', 'navigate-direct'],
},
};

Reporting & Documentation

// reporting/test-reporter.js
class DesignTestReporter {
constructor() {
this.results = {
visual: {},
accessibility: {},
performance: {},
crossBrowser: {},
};
}

async generateReport() {
const report = {
timestamp: new Date().toISOString(),
summary: this.generateSummary(),
details: this.results,
recommendations: this.generateRecommendations(),
};

await this.saveReport(report);
await this.sendNotifications(report);
}

generateSummary() {
return {
totalTests: this.getTotalTestCount(),
passedTests: this.getPassedTestCount(),
failedTests: this.getFailedTestCount(),
coverage: this.calculateCoverage(),
};
}
}

Troubleshooting Guide

Common Issues

Visual Test Flakiness

// Solutions for reducing flaky visual tests
test('Stable visual test', async ({ page }) => {
await page.goto('https://mm.dreamineering.com/');

// Wait for fonts to load
await page.waitForFunction(() => document.fonts.ready);

// Wait for animations to complete
await page.waitForTimeout(1000);

// Hide dynamic content
await page.addStyleTag({
content: '.dynamic-content { display: none !important; }'
});

await percySnapshot(page, 'Stable Landing Page');
});

Performance Test Variability

// Multiple runs for reliable performance metrics
test('Reliable performance test', async ({ page }) => {
const runs = [];

for (let i = 0; i < 3; i++) {
await page.goto('https://mm.dreamineering.com/', {
waitUntil: 'networkidle'
});

const metrics = await page.evaluate(() =>
JSON.parse(JSON.stringify(performance.getEntriesByType('navigation')[0]))
);

runs.push(metrics);
}

// Use median values for stability
const medianLoadTime = runs
.map(r => r.loadEventEnd - r.loadEventStart)
.sort()[Math.floor(runs.length / 2)];

expect(medianLoadTime).toBeLessThan(3000);
});

This comprehensive automated testing setup ensures consistent design quality and provides early detection of regressions across visual, accessibility, and performance dimensions.