Files
2nd/10_Wiki/Topic_Programming/Coding/Testing_Visual_Regression.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.9 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
testing-visual-regression Visual Regression — Percy / Chromatic / Playwright Coding draft B conceptual 2026-05-09 2026-05-09
testing
visual
vrt
screenshot
vibe-coding
language applicable_to
TS / Playwright / Storybook
Frontend
visual regression
VRT
Chromatic
Percy
Applitools
screenshot diff

Visual Regression Testing

디자인 변경 = unit test 가 못 잡음. screenshot 비교 = pixel diff. Chromatic (Storybook), Percy (Browserstack), Applitools (AI), Playwright snapshot.

📖 핵심 개념

  • Baseline: 첫 screenshot.
  • Diff: PR 가 baseline 과 다름 → 사람 review.
  • Approved: 의도된 변경 → 새 baseline.
  • Cross-browser / device: 같은 컴포넌트 다양한 환경.

💻 코드 패턴

Playwright snapshot

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

test('home page visual', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('home.png', {
    maxDiffPixelRatio: 0.01,
    fullPage: true,
  });
});
# 첫 run — baseline 생성
npx playwright test --update-snapshots

# 이후 비교
npx playwright test

Storybook + Chromatic

yarn add -D chromatic
# .github/workflows/chromatic.yml
- run: yarn build-storybook
- uses: chromaui/action@v1
  with:
    projectToken: ${{ secrets.CHROMATIC_TOKEN }}

→ 각 story 자동 screenshot + diff. PR 에 review UI.

Story 기준 component 단위

// Button.stories.tsx
import { Button } from './Button';

export default { component: Button };

export const Primary = { args: { variant: 'primary', children: 'Click' } };
export const Disabled = { args: { variant: 'primary', disabled: true, children: 'Click' } };
export const Long = { args: { children: 'Very long button text here' } };

→ Chromatic 가 모든 story 자동 snapshot.

Multi-viewport / theme

export default {
  component: Card,
  parameters: {
    chromatic: {
      viewports: [320, 768, 1280],
      modes: { light: { theme: 'light' }, dark: { theme: 'dark' } },
    },
  },
};

Flake 방어

// 시간 / random / animation 고정
parameters: {
  chromatic: {
    pauseAnimationAtEnd: true,
    delay: 500, // 데이터 load 기다림
  },
}
// 시간 mock (Playwright)
await page.evaluate(() => {
  const fixedDate = new Date('2026-05-09T10:00:00Z').valueOf();
  Date.now = () => fixedDate;
});

// Font ready
await page.waitForLoadState('networkidle');
await page.evaluate(() => document.fonts.ready);

Threshold

await expect(page).toHaveScreenshot('home.png', {
  maxDiffPixelRatio: 0.005, // 0.5% pixel 차이까지 OK (anti-aliasing)
  threshold: 0.1, // pixel 차이 정도
});

Mask (변경 영역 가리기)

await expect(page).toHaveScreenshot({
  mask: [page.locator('.timestamp'), page.locator('[data-dynamic]')],
});

→ 시간 / random 부분 mask.

Cross-browser

// playwright.config.ts
projects: [
  { name: 'chromium', use: devices['Desktop Chrome'] },
  { name: 'firefox', use: devices['Desktop Firefox'] },
  { name: 'webkit', use: devices['Desktop Safari'] },
],

→ 각 browser 별 baseline.

Applitools (AI 기반)

import { Eyes, Target } from '@applitools/eyes-playwright';

test('home', async ({ page }) => {
  const eyes = new Eyes();
  await eyes.open(page, 'My App', 'home');
  await page.goto('/');
  await eyes.check('main', Target.window().fully());
  await eyes.close();
});

→ AI 가 의미 있는 변경 / 노이즈 구분.

Workflow

1. PR 만듦
2. Chromatic / Percy 가 자동 screenshot
3. PR comment 에 diff URL
4. Designer / dev review
5. Approve = 새 baseline / Reject = 코드 fix

Approve 정책

  • 모든 변경 디자이너 review 또는
  • Spec 변경 시만 review, 일반 = dev approve.

🤔 의사결정 기준

상황 추천
Storybook 사용 중 Chromatic
브라우저 / 디바이스 다양 Percy
정밀 + 의미 분석 Applitools
자체 / 무료 Playwright snapshot
Storybook 없음 Playwright + 페이지 스크린샷
Email rendering Mailosaur / Litmus

안티패턴

  • Animation 안 정지: 매번 다른 frame.
  • 시간 / random data: noise. mock.
  • External 이미지 / font load: lazy. preload + ready check.
  • 모든 page snapshot: 비용 폭발. 핵심 + storybook component.
  • Threshold 0: false positive. 0.5% 정도.
  • Baseline 매번 update: 의도 모름. 변경 review 필수.
  • Cross-browser 무시: Safari rendering 차이.

🤖 LLM 활용 힌트

  • Storybook + Chromatic = 컴포넌트 단위 강력.
  • Pause animation + mask dynamic + font ready 3종.
  • Threshold 0.5% + cross-browser.

🔗 관련 문서