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
Option 2: Execute Automation Implementation (Recommended)
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
Percy Setup (Recommended for Production)
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.