실수 12/14: visual regressions를 잡지 못하고 있습니다

발행: (2026년 4월 16일 PM 10:22 GMT+9)
3 분 소요
원문: Dev.to

Source: Dev.to

Problem

간단한 CSS 변경으로 모바일에서 결제 버튼이 깨졌습니다. 모든 기능 테스트는 통과했지만, 화면에 보이지 않는 div가 겹쳐서 모바일 화면에서는 버튼이 보이지 않았습니다. 버튼은 올바른 텍스트와 함께 DOM에 존재했지만, 사용자는 볼 수도 클릭할 수도 없었습니다. 이런 종류의 버그는 고객이 실제로 결제를 시도할 때만 프로덕션에서 드러나는 경우가 많습니다.

기능 테스트는 동작을 검증하는 데는 뛰어나지만, 외관을 확인하지는 못합니다. 앱이 실제로 올바르게 보이는지는 알 수 없습니다.

Visual Regression Testing

시각적 회귀 테스트는 렌더링된 UI의 스크린샷을 비교하여 다양한 디바이스에서 레이아웃 문제를 잡아냅니다. Playwright에 내장된 toHaveScreenshot 매처를 사용하면 이를 간단히 구현할 수 있습니다.

Before (functional test only)

// ❌ Functional test passes, but the button is covered on mobile.
await expect(page.getByRole('button', { name: 'Checkout' })).toBeVisible();
// Passes because the button is in the DOM, even if users can't actually click it.

After (visual regression)

// ✅ Visual regression catches layout issues across devices.
test('cart page looks correct', async ({ page }) => {
  await page.goto('/cart');

  await expect(page).toHaveScreenshot('cart.png', {
    mask: [
      page.getByTestId('timestamp'), // changes every run
      page.getByTestId('order-id'),  // unique per session
    ],
    maxDiffPixelRatio: 0.01,
  });
});

Testing Across Viewports (Playwright config)

// 🧪 Test across viewports in playwright.config.ts
{
  name: 'desktop',
  use: { viewport: { width: 1280, height: 720 } },
},
{
  name: 'mobile',
  use: { viewport: { width: 375, height: 667 } },
},

타임스탬프나 주문 ID와 같이 동적으로 변하는 요소를 마스킹하면 불안정한 false positive를 방지할 수 있습니다.

Takeaway

  • Functional tests는 무언가가 동작하는지를 검증합니다.
  • Visual tests는 사용자가 실제로 보고 상호작용할 수 있는지를 검증합니다.

뷰포트 수준에서 시각적 커버리지를 추가하면 기능 테스트만으로는 잡히지 않는 레이아웃 버그가 배포되는 것을 방지할 수 있습니다.

시각적 테스트가 기능 테스트로는 전혀 잡히지 않았던 버그를 발견한 적이 있나요? 댓글로 경험을 공유해 주세요.

0 조회
Back to Blog

관련 글

더 보기 »

모든 Zapier Zap에 인간 승인을 추가하는 방법

Zapier는 강력합니다. 하나의 Zap으로 리드를 생성하고, CRM 레코드를 업데이트하며, 이메일을 보내고, 수십 개의 앱 간에 데이터를 동기화할 수 있습니다. 하지만 Zap이 뭔가를 할 때는…