ワンクリックで
angular-visual-regression
Capture baseline screenshots of all app pages and pixel-diff on subsequent runs to detect unintended UI changes
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Capture baseline screenshots of all app pages and pixel-diff on subsequent runs to detect unintended UI changes
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Reusable MCP Playwright code snippets for testing this Angular + DaisyUI + Supabase app — auth helpers, form filling, toast checking, table extraction
Simulate full user journeys (signup -> login -> dashboard -> purchase) via MCP Playwright with screenshots and timing at each step
Guide for exposing services via ASD tunnels — asd expose, asd.yaml network config, with/without Caddy, auth rules
| name | angular-visual-regression |
| description | Capture baseline screenshots of all app pages and pixel-diff on subsequent runs to detect unintended UI changes |
| user_invocable | true |
| arg_description | Action: baseline | diff | single <page> (default: baseline) |
Capture baseline screenshots of every page in the ASD Angular Supabase app, then diff against baselines on subsequent runs to catch unintended visual changes.
http://localhost:4200
This skill file must be kept up to date by Claude. When you encounter selectors or page structures that no longer match, or new pages are added to the app, update this SKILL.md immediately. Outdated skills waste time — fix them as you find them.
~/tmp/visual-regression/asd-angular-supabase/
baseline/
home.png
pricing.png
auth-login.png
auth-signup.png
dashboard.png
dashboard-orders.png
dashboard-orders-empty.png
dashboard-settings.png
payment-callback.png
current/
(same structure, captured on diff runs)
diffs/
(pixel-diff images, only for pages with changes)
| Page | URL | Render Mode | Auth Required | Key Elements to Wait For |
|---|---|---|---|---|
| Home | / | Prerender | No | h1.text-5xl, .btn.btn-primary |
| Pricing | /pricing | Prerender | No | h1:has-text("Pricing"), .card (3x) |
| Auth Login | /auth/login | Prerender | No | h2:has-text("Sign In"), input#email |
| Auth Signup | /auth/signup | Prerender | No | h2:has-text("Create Account"), input#email |
| Dashboard | /dashboard | Client | Yes | h1:has-text("Dashboard"), .stat-card |
| Dashboard Orders | /dashboard/orders | Client | Yes | h2:has-text("Order History"), table.table OR :text("No orders yet.") |
| Dashboard Settings | /dashboard/settings | Client | Yes | h2:has-text("Account Settings"), .btn.btn-error |
| Payment Callback | /payment/callback | Client | No | h1:has-text("Payment Submitted") |
baseline (default)Capture fresh baseline screenshots for all pages.
baseline/ directorydiffCompare current state against baselines.
current/ directorybaseline/ versiondiffs/ directory (only for changed pages)single <page>Capture or diff a single page. Page names: home, pricing, auth-login, auth-signup, dashboard, dashboard-orders, dashboard-settings, payment-callback.
// 1. Navigate
await page.goto(url)
await page.waitForLoadState('networkidle')
// 2. Wait for key elements (ensures page is fully rendered)
for (const selector of keyElements) {
await page.waitForSelector(selector, { timeout: 10000 })
}
// 3. Wait for animations/transitions to settle
await page.waitForTimeout(300)
// 4. Hide dynamic content that causes false positives
await page.evaluate(() => {
// Hide toast notifications
document.querySelectorAll('.toast').forEach((el) => (el.style.display = 'none'))
})
// 5. Capture screenshot
await page.screenshot({
path: screenshotPath,
fullPage: true,
})
// Login before capturing dashboard pages
await page.goto('http://localhost:4200/auth/login')
await page.waitForSelector('input#email')
await page.fill('input#email', testEmail)
await page.fill('input#password', testPassword)
await page.click('button.btn.btn-primary[type="submit"]')
await page.waitForURL('**/dashboard', { timeout: 10000 })
// Using page.screenshot comparison
// Threshold: 0.1% pixel difference = PASS (accounts for anti-aliasing)
// Above threshold = FAIL, generate diff image
function compareScreenshots(baseline, current) {
// Use Playwright's built-in screenshot comparison if available
// Or use pixelmatch library for pixel-level comparison
// Return: { match: boolean, diffPercent: number, diffImagePath: string }
}
Before capturing any screenshots, verify the theme is consistent:
const theme = await page.evaluate(() => document.documentElement.getAttribute('data-theme'))
console.log('Current theme:', theme || 'default')
// Store theme name with baseline metadata for comparison
Visual Regression Baselines Captured
=====================================
Theme: [theme-name]
Viewport: 1400x900
Date: [timestamp]
| Page | File | Size |
| ------------------- | -------------------------- | ------ |
| Home | baseline/home.png | 245 KB |
| Pricing | baseline/pricing.png | 312 KB |
| ... | ... | ... |
Total: 9 pages captured
Visual Regression Diff Results
===============================
Baseline date: [date]
Current date: [date]
Theme: [theme-name]
Viewport: 1400x900
| Page | Status | Diff % | Diff Image |
| ------------------- | ------ | ------- | ---------------------------- |
| Home | PASS | 0.00% | - |
| Pricing | FAIL | 2.34% | diffs/pricing-diff.png |
| ... | ... | ... | ... |
Result: 1 of 9 pages changed
DaisyUI button classes repeat across navbar and page content. When clicking elements during capture flows, scope selectors with parent containers:
.hero-content a.btn-primary (not a.btn-primary[href="/auth/login"]).navbar a.btn-sm or .navbar button.btn-sm.card-body a.btn-ghost:has-text("Back to Home")pnpm dev on port 4200)data-theme attribute is checked and recorded to catch unintentional theme changeshttp://localhost:54324): Supabase local email capture — useful for verifying auth emails after signup in visual tests