Skip to content

필사 모드: 프론트엔드 테스팅 2026 — Playwright / Cypress / Vitest / Jest / Storybook 9 / Chromatic 심층 비교

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 — "Selenium 한 개로 모든 걸 막던 시대는 끝났다"

2018년쯤에 "프론트엔드 테스팅 뭐 써?"라고 물으면 답은 간단했다. 유닛은 Jest, E2E는 Selenium 또는 Cypress, 시각 회귀는 한다는 사람만 BackstopJS. 그게 전부였다. 컴포넌트 단위 테스트라는 말은 아직 어색했고, "스토리북이 테스트 인프라"라는 발상도 없었다.

2026년 5월 현재, 그 그림은 산산조각 났다. 한 회사의 프론트엔드 테스트 파이프라인을 그려보면 보통 이렇게 생긴다.

- **유닛 테스트** — Vitest 3 또는 Jest 30, Testing Library와 함께.

- **컴포넌트 테스트** — Storybook 9 + Vitest, 혹은 Playwright Component Testing.

- **E2E 테스트** — Playwright 1.50+ (절반 이상), Cypress 14, WebdriverIO 9.

- **시각 회귀** — Chromatic, Percy, Applitools (SaaS) 또는 Loki, BackstopJS, Reg-Suit (OSS).

- **네트워크 모킹** — MSW (Mock Service Worker) 2.x.

- **AI 보조** — Playwright MCP, Browser MCP, Claude/Cursor 에이전트가 직접 테스트 작성.

- **CI 통합** — GitHub Actions + Playwright trace + Chromatic publish.

이 글은 2026년 시점에서 위 도구들이 각각 어디에 서 있는지, 무엇을 잘하고 무엇을 못하는지, 그리고 "우리 팀은 무엇을 골라야 하나"를 정리한다. 단순한 리스트가 아니라 — Playwright의 표준화, Vitest의 부상, Storybook 9의 가벼워짐, AI 에이전트가 브라우저를 직접 모는 새로운 패러다임까지 — 2024~2026 사이에 이 시장을 흔든 4가지 흐름을 함께 본다.

1장 · 2026년 프론트엔드 테스팅 지도 — Unit / Component / E2E / Visual 4축

먼저 큰 그림. 프론트엔드 테스트는 4개의 축으로 나뉜다.

| 축 | 무엇을 검증하나 | 대표 도구 |

| --- | --- | --- |

| Unit | 함수, 훅, 유틸 — 가장 빠른 피드백 | Vitest 3, Jest 30, Mocha |

| Component | 컴포넌트 단위 렌더링·상호작용 | Testing Library, Storybook 9 + Vitest, Playwright CT |

| E2E (End-to-End) | 사용자 플로우, 다중 페이지 | Playwright, Cypress 14, WebdriverIO 9, Selenium 5 |

| Visual Regression | 픽셀 단위 UI 변화 감지 | Chromatic, Percy, Applitools, Loki, BackstopJS, Reg-Suit |

여기에 2024~2026 사이에 새로 끼어든 카테고리가 둘 있다.

- **Network mocking** — API 호출을 가로채는 계층. MSW가 사실상 표준.

- **AI agent testing** — LLM이 직접 브라우저를 운전. Playwright MCP, Browser MCP.

그리고 2026년의 트렌드는 명확하다. **"한 도구로 여러 축을 묶는다"**. Playwright는 E2E + Component + Visual을 한 묶음으로 팔고, Vitest는 Unit + Component를 (Storybook과 함께) 한 묶음으로 묶었다. Cypress도 비슷한 통합을 시도하지만 속도에서 밀린다. 단일 점 도구로 시작해서 플랫폼이 되거나, 처음부터 플랫폼으로 들어오거나 둘 중 하나다.

테스팅 피라미드(Unit 많고, E2E 적은)는 여전히 유효하지만 — 2026년에는 그 모양이 변형됐다. Mike Cohn의 클래식 피라미드는 컴포넌트 단위가 빠지면서 "다이아몬드" 또는 "트로피" 모양이 됐다. Component 테스트가 폭발적으로 증가하면서, 유닛 테스트는 도메인 로직 위주로 가벼워지고, 컴포넌트 테스트가 가운데를 채운다.

2장 · Playwright — 사실상 표준 (VSCode 통합, Trace Viewer)

Playwright는 Microsoft가 만든 E2E 테스트 도구로, 2020년 1.0 출시 이후 빠르게 시장을 장악했다. 2026년 5월 기준 1.50+ 버전이며, State of JS 2024 조사에서 사용 의향이 가장 높은 E2E 도구로 꼽혔다.

핵심 개념

- **Browser context** — 각 테스트마다 독립된 브라우저 컨텍스트. 쿠키·스토리지가 격리.

- **Auto-waiting** — `click`, `fill` 같은 액션이 자동으로 요소를 기다린다. 명시적 sleep 불필요.

- **Locator** — DOM 검색이 매번 새로 평가되는 lazy 객체. stale element 문제 없음.

- **Trace Viewer** — 실패한 테스트의 스냅샷·네트워크·콘솔을 GUI로 재생.

- **Component Testing** — React/Vue/Svelte 컴포넌트를 격리 환경에서 마운트.

강점

- **속도** — Cypress보다 2~3배 빠른 경우가 흔하다. Chromium·Firefox·WebKit을 모두 지원.

- **VSCode Extension** — 테스트를 GUI에서 작성·실행·디버그. Codegen으로 자동 생성.

- **Trace Viewer** — 실패 분석이 30초 안에 끝난다. 다른 도구가 흉내 내기 어렵다.

- **병렬 실행** — 기본 워커 분산. CI에서 60% 시간 절감 흔함.

- **다중 페이지·도메인** — 한 테스트에서 여러 origin을 자유롭게 오갈 수 있다.

약점

- **러닝 커브** — Cypress보다 추상화가 깊다. 처음 며칠은 헤맨다.

- **컴포넌트 테스트는 베타에서 GA로** — 1.40대에 GA 됐지만 Vitest+Testing Library만큼 가볍지는 않다.

- **이미지 비교는 SaaS가 강하다** — `toHaveScreenshot`이 있지만, Chromatic·Percy의 베이스라인 관리에 비하면 약하다.

언제 고르나

- 새 프로젝트 시작 — 거의 무조건 Playwright.

- 다중 브라우저 검증이 필요 (특히 Safari/WebKit).

- 큰 monorepo에서 병렬 E2E가 필요.

- Trace 기반 디버깅이 중요한 팀.

// playwright.config.ts

export default defineConfig({

testDir: './e2e',

fullyParallel: true,

retries: process.env.CI ? 2 : 0,

reporter: [['html'], ['github']],

use: {

baseURL: 'http://localhost:3000',

trace: 'on-first-retry',

screenshot: 'only-on-failure',

},

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 7'] } },

],

})

// e2e/checkout.spec.ts

test('user can complete checkout', async ({ page }) => {

await page.goto('/products/coffee-beans')

await page.getByRole('button', { name: 'Add to cart' }).click()

await page.getByRole('link', { name: 'Cart' }).click()

await expect(page.getByText('Coffee Beans')).toBeVisible()

await page.getByRole('button', { name: 'Checkout' }).click()

await page.getByLabel('Email').fill('test@example.com')

await page.getByRole('button', { name: 'Place order' }).click()

await expect(page).toHaveURL(/thank-you/)

})

Playwright의 진짜 가치는 Trace Viewer다. CI에서 실패한 테스트의 trace.zip을 받아서 로컬에서 열면, 각 액션의 DOM 스냅샷·네트워크 호출·콘솔 로그가 GUI 타임라인으로 재생된다. "왜 실패했지?"가 캡처에서 끝난다. Cypress의 비디오 녹화보다 한 단계 위.

3장 · Cypress 14 — 여전한 강자

Cypress는 2017년경 등장해 한동안 E2E의 표준이었다. 2026년 5월 기준 14 버전이며, 점유율은 Playwright에 밀렸지만 여전히 큰 사용자 기반을 가지고 있다.

핵심 개념

- **In-browser test runner** — 테스트가 실제 브라우저 안에서 실행된다. DOM에 직접 접근.

- **Time-travel debugger** — 각 명령의 스냅샷을 좌측 패널에서 시간순으로 본다.

- **Real-time reload** — 코드 저장하면 즉시 테스트가 재실행.

- **Cypress Cloud** — 클라우드 대시보드, 평행 실행 분산, 플레이키 감지.

- **Component Testing** — React/Vue/Angular 컴포넌트를 격리 환경에서.

강점

- **DX가 압도적** — 처음 시작이 쉽다. `cy.visit` `cy.get` `cy.click`이 직관적.

- **Time-travel debugging** — 각 명령의 DOM 스냅샷이 자동 캡처. 디버깅이 즐겁다.

- **실시간 hot reload** — TDD 사이클이 빠르다.

- **풍부한 문서·커뮤니티** — Stack Overflow에 답이 거의 다 있다.

약점

- **단일 도메인 제약** — `cy.origin`이 추가됐지만 여전히 다중 도메인은 어색.

- **Safari/WebKit 지원이 약함** — 실험적 단계, 안정성 부족.

- **속도** — Playwright 대비 30~50% 느리다.

- **iframe 처리가 까다롭다** — 광고나 외부 위젯이 들어간 페이지가 아프다.

- **Cypress Cloud 가격** — 평행 실행과 결과 보관이 무료 tier에서 빠르게 제한.

언제 고르나

- 기존 Cypress 코드베이스가 큰 경우 — 마이그레이션 비용이 크다.

- 단일 도메인 SPA, 작은 팀.

- 디버깅 경험을 최우선으로 하는 경우.

// cypress/e2e/login.cy.js

describe('Login flow', () => {

beforeEach(() => {

cy.intercept('POST', '/api/login', { fixture: 'login-success.json' }).as('login')

cy.visit('/login')

})

it('logs in with valid credentials', () => {

cy.get('[data-cy=email]').type('user@example.com')

cy.get('[data-cy=password]').type('s3cret!')

cy.get('[data-cy=submit]').click()

cy.wait('@login')

cy.url().should('include', '/dashboard')

cy.contains('Welcome back').should('be.visible')

})

})

Cypress 14에서 추가된 가장 큰 기능은 **WebKit GA**와 **Component Testing UX 개선**이다. 하지만 Playwright가 이미 한 발 앞서 있어서, 신규 프로젝트가 Cypress를 고르는 비중은 2024년부터 빠르게 떨어지고 있다.

4장 · Vitest 3 — Vite와 함께 오는 최고 속도

Vitest는 2021년 Anthony Fu가 만든 유닛 테스트 러너로, Vite의 트랜스포머·HMR을 그대로 활용한다. 2026년 기준 3.x 버전이며, JS/TS 신규 프로젝트의 유닛 테스트 표준이 됐다.

핵심 개념

- **Vite-native** — Vite config을 그대로 재사용. esbuild + Rollup이 트랜스파일.

- **HMR for tests** — 변경된 모듈만 다시 평가, 밀리초 단위 사이클.

- **Jest-compatible API** — `describe`/`it`/`expect`가 Jest와 거의 동일.

- **Workspaces** — monorepo에서 여러 패키지를 한 vitest 명령으로.

- **Browser mode** — 실제 브라우저에서 컴포넌트 테스트 (Playwright/WebdriverIO 백엔드).

강점

- **속도가 압도적** — Jest 대비 2~10배 빠르다. 콜드 스타트도 빠르다.

- **Vite 생태계와 한 몸** — Vite 프로젝트라면 별도 설정 없이 즉시 동작.

- **TypeScript first-class** — esbuild가 트랜스파일하므로 ts-jest 같은 우회 불필요.

- **Worker pool 최적화** — Node worker_threads로 격리 + 빠른 실행.

- **Storybook 9와 통합** — `@storybook/addon-vitest`로 스토리가 곧 테스트.

약점

- **CRA/Next.js 레거시** — Webpack 기반 프로젝트는 마이그레이션 비용.

- **JSDOM/happy-dom 호환성** — 일부 DOM API에서 사소한 차이.

- **Jest의 거대한 플러그인 생태계** — `jest-extended` 등 일부 미러링이 부족.

언제 고르나

- Vite를 쓰는 모든 프로젝트.

- 새 프로젝트 시작 — 거의 무조건 Vitest.

- 유닛 테스트 속도가 중요한 경우 (CI 분 단위 절감).

// vitest.config.ts

export default defineConfig({

plugins: [react()],

test: {

globals: true,

environment: 'happy-dom',

setupFiles: ['./test/setup.ts'],

coverage: {

provider: 'v8',

reporter: ['text', 'json', 'html'],

exclude: ['node_modules/', 'test/'],

},

},

})

// src/utils/format.test.ts

describe('formatCurrency', () => {

it('formats KRW without decimals', () => {

expect(formatCurrency(12345, 'KRW')).toBe('₩12,345')

})

it('formats USD with two decimals', () => {

expect(formatCurrency(12.5, 'USD')).toBe('$12.50')

})

it('handles negative numbers', () => {

expect(formatCurrency(-100, 'USD')).toBe('-$100.00')

})

})

Vitest 3의 가장 큰 변화는 **Browser mode GA**다. JSDOM이 아니라 실제 Chromium에서 컴포넌트를 마운트해서 테스트한다. Playwright Component Testing과 비슷한 영역인데, Vite 기반 프로젝트에서 더 자연스럽다.

5장 · Jest 30 — 레거시 + Next 호환

Jest는 Facebook이 2014년 만든 유닛 테스트 러너로, 한동안 JS 테스트의 사실상 표준이었다. 2025년 9월에 30이 출시됐고, 2026년 5월에는 30.x 마이너 릴리스가 안정화 단계다.

핵심 개념

- **Snapshot testing** — `expect(tree).toMatchSnapshot()` — UI 트리를 직렬화해서 저장.

- **Module mocking** — `jest.mock()`으로 import 경로를 가짜로 치환.

- **Fake timers** — `jest.useFakeTimers()`로 setTimeout/setInterval 제어.

- **Coverage** — Istanbul 기반 커버리지가 내장.

강점

- **거대한 생태계** — `jest-extended`, `jest-fetch-mock` 등 수만 개 플러그인.

- **CRA/Next.js 기본 통합** — Next.js의 `next/jest`가 표준 설정을 제공.

- **안정성** — 10년의 검증. 큰 코드베이스에서 신뢰성이 높다.

- **VSCode 통합** — Jest Runner 확장이 잘 작동.

약점

- **속도** — Vitest 대비 2~5배 느리다. 큰 코드베이스에서 CI 시간이 부담.

- **ESM 지원이 어색** — 여전히 일부 ESM 패키지에서 hack이 필요.

- **TypeScript는 ts-jest 또는 babel** — Vitest의 esbuild 대비 느리다.

언제 고르나

- 기존 Jest 코드베이스가 큰 경우.

- Next.js 12 미만 또는 Webpack 기반 CRA.

- Jest 전용 플러그인에 의존하는 경우.

// jest.config.js

const nextJest = require('next/jest')

const createJestConfig = nextJest({ dir: './' })

const customConfig = {

setupFilesAfterEach: ['<rootDir>/jest.setup.js'],

testEnvironment: 'jsdom',

moduleNameMapper: {

'^@/(.*)$': '<rootDir>/src/$1',

},

collectCoverageFrom: [

'src/**/*.{ts,tsx}',

'!src/**/*.stories.tsx',

],

}

module.exports = createJestConfig(customConfig)

Jest 30의 가장 큰 변화는 **첫번째 native ESM 지원 안정화**와 **메모리 사용량 30% 감소**다. 마이그레이션 비용 때문에 여전히 큰 조직에서는 Jest를 쓰지만, 신규 프로젝트가 Jest를 고르는 일은 점점 줄어든다.

6장 · Testing Library 철학 — Implementation detail 피하기

Testing Library는 2018년 Kent C. Dodds가 만든 라이브러리 가족이다. DOM, React, Vue, Svelte, Solid 각각의 어댑터가 있다. 2026년 기준 모든 컴포넌트 테스트의 기본기다.

핵심 철학

- **"The more your tests resemble the way your software is used, the more confidence they can give you."**

- 컴포넌트의 내부 state를 보지 말고, 사용자가 보고 클릭하는 것을 본다.

- `getByRole`, `getByLabelText`, `getByText` — 접근성 기준 쿼리.

- `getByTestId`는 마지막 수단.

강점

- **리팩토링 친화적** — 컴포넌트 내부 구조가 바뀌어도 테스트는 그대로.

- **접근성과 함께 간다** — 쿼리가 ARIA role 기반이라 자연스럽게 a11y를 검증.

- **프레임워크 독립** — React/Vue/Svelte 어디서나 같은 철학.

- **TanStack/Mantine/Radix 같은 라이브러리도 Testing Library 기준으로 빌드**.

약점

- **순수 단위 테스트보다 느리다** — DOM 렌더링이 필요.

- **userEvent vs fireEvent** — 두 API의 차이가 초보자에게 혼란.

- **비동기 처리** — `findBy*`, `waitFor`의 사용을 헷갈리는 사람이 많다.

예시 — React Testing Library + Vitest

describe('LoginForm', () => {

it('shows error when password is too short', async () => {

const user = userEvent.setup()

render(<LoginForm onSubmit={() => {}} />)

await user.type(screen.getByLabelText(/email/i), 'user@example.com')

await user.type(screen.getByLabelText(/password/i), 'abc')

await user.click(screen.getByRole('button', { name: /sign in/i }))

expect(

await screen.findByText(/password must be at least 8 characters/i)

).toBeInTheDocument()

})

it('calls onSubmit with valid input', async () => {

const onSubmit = vi.fn()

const user = userEvent.setup()

render(<LoginForm onSubmit={onSubmit} />)

await user.type(screen.getByLabelText(/email/i), 'user@example.com')

await user.type(screen.getByLabelText(/password/i), 'longerpassword')

await user.click(screen.getByRole('button', { name: /sign in/i }))

expect(onSubmit).toHaveBeenCalledWith({

email: 'user@example.com',

password: 'longerpassword',

})

})

})

흔히 빠지는 함정 — `screen.getByText("Loading...")` 같은 텍스트 정확 매칭은 i18n 시 깨진다. `getByRole("status")` 또는 정규식이 안전. 그리고 `data-testid="submit-button"`은 정말 최후의 수단으로만. 사용자는 testid를 보지 않는다.

7장 · Storybook 9 (2025.6) — 가벼워지고 Vitest와 통합

Storybook은 2016년 등장한 컴포넌트 워크숍이다. 2025년 6월에 출시된 9 버전은 큰 전환점이었다. 무게가 가벼워지고(번들 사이즈 50% 감소), Vitest와 깊게 통합됐다.

핵심 변화 (Storybook 9)

- **무게 감소** — 9.0 발표에서 "최대 75% 적은 의존성, 48% 가벼운 설치"라는 수치.

- **Vitest 기반 테스트** — `@storybook/addon-vitest`가 스토리를 곧 테스트로.

- **Component testing** — Play function이 사실상 상호작용 테스트 표준.

- **Visual testing 내장** — Chromatic 연동이 더 매끄러워짐.

- **A11y 검증 내장** — `@storybook/addon-a11y`가 기본 옵션화.

강점

- **단일 작성, 다중 활용** — 한 스토리가 카탈로그·상호작용 테스트·시각 회귀·a11y 검증 모두 커버.

- **디자이너와의 협업** — Figma 통합. 디자인 토큰을 실시간 확인.

- **Vitest 통합** — 스토리 실행이 곧 단위 테스트 실행과 동일한 인프라.

- **Plugins/Addons 생태계** — `addon-controls`, `addon-actions`, `addon-docs`.

약점

- **빌드 시간** — 큰 디자인 시스템에서 Storybook 빌드가 분 단위.

- **CSF (Component Story Format) 3** — 학습 필요. 처음 작성하는 팀은 어색.

- **번들 충돌** — Vite 기반인지 Webpack 기반인지에 따라 설정이 갈린다.

예시 — CSF 3 + Play function

// Button.stories.tsx

const meta: Meta<typeof Button> = {

title: 'UI/Button',

component: Button,

tags: ['autodocs'],

}

export default meta

type Story = StoryObj<typeof Button>

export const Primary: Story = {

args: {

variant: 'primary',

children: 'Click me',

},

}

export const Clicked: Story = {

args: { variant: 'primary', children: 'Click me' },

play: async ({ canvasElement }) => {

const canvas = within(canvasElement)

const btn = canvas.getByRole('button', { name: /click me/i })

await userEvent.click(btn)

await expect(btn).toHaveAttribute('aria-pressed', 'true')

},

}

// vitest.workspace.ts — Storybook 9 + Vitest 통합

export default defineWorkspace([

'./vitest.config.ts',

{

extends: './vitest.config.ts',

plugins: [storybookTest({ configDir: '.storybook' })],

test: {

name: 'storybook',

browser: {

enabled: true,

headless: true,

name: 'chromium',

provider: 'playwright',

},

},

},

])

Storybook 9의 진짜 가치는 "스토리를 한 번 작성하면 카탈로그·테스트·시각 회귀·접근성이 다 따라온다"는 점이다. 디자인 시스템 팀이라면 사실상 필수.

8장 · Chromatic / Percy / Applitools — 시각적 회귀

시각적 회귀(Visual Regression)는 UI 변경이 의도된 것인지 아닌지 픽셀 단위로 검사한다. SaaS 3강은 Chromatic, Percy(BrowserStack), Applitools다.

Chromatic

- Storybook을 만든 회사가 직접 운영. Storybook과 한 몸.

- 스토리 단위 시각 회귀가 강점.

- Cross-browser 베이스라인을 클라우드에 저장.

- 검토 워크플로(diff → approve → merge)가 깔끔.

- 가격은 snapshot 기준 — 작은 팀은 무료 tier로 충분.

Percy (BrowserStack)

- 2017년 BrowserStack이 인수. Percy CLI로 Playwright/Cypress/WebdriverIO 통합.

- 다중 viewport, 다중 브라우저 베이스라인.

- BrowserStack의 실 디바이스 클라우드와 연동.

Applitools

- AI 기반 시각 비교가 강점 — "의미 있는 변화만" 잡는다.

- Visual AI 알고리즘이 dynamic content(타임스탬프, 광고)를 자동 무시.

- Ultrafast Grid — 한 번 캡처해서 여러 브라우저·디바이스 조합으로 검증.

- 엔터프라이즈 가격. 큰 조직에서 압도적.

셋의 차이

| 항목 | Chromatic | Percy | Applitools |

| --- | --- | --- | --- |

| 모태 | Storybook | BrowserStack | 독립 SaaS |

| 강점 | Storybook 통합 | 다중 viewport, BS 디바이스 | AI Visual diff |

| 가격 모델 | snapshot 기준 | snapshot + DOM 기준 | enterprise seat |

| Free tier | 후함 (월 5,000 snapshot) | 작음 | 평가판만 |

| AI 처리 | 부분적 | 부분적 | 핵심 기능 |

// Playwright + Percy

test('homepage looks correct', async ({ page }) => {

await page.goto('/')

await percySnapshot(page, 'Homepage')

})

// Playwright + Applitools Eyes

test('checkout flow visual', async ({ page }) => {

const eyes = new Eyes()

const cfg = new Configuration()

cfg.setBatch(new BatchInfo('Smoke 2026-05-16'))

eyes.setConfiguration(cfg)

await eyes.open(page, 'Shop', 'Checkout')

await page.goto('/checkout')

await eyes.check('Checkout page', undefined)

await eyes.close()

})

시각 회귀의 가장 큰 함정은 **flaky snapshot**이다. 폰트 로딩, 애니메이션, 캐러셀, 광고 — 이런 동적 요소를 마스킹하지 않으면 95%의 diff가 false positive다. Applitools가 강한 이유가 이걸 자동으로 처리하기 때문.

9장 · Loki / BackstopJS / Reg-Suit — 오픈소스 시각 회귀

SaaS가 부담스럽거나, 베이스라인을 자기 저장소에 두고 싶다면 OSS 옵션이 있다.

Loki

- Storybook 전용. `loki test`로 모든 스토리를 캡처·비교.

- Chromium/Firefox/WebKit 지원. Docker 기반 일관 렌더링.

- 베이스라인은 git에 같이 커밋 — review가 PR에서.

BackstopJS

- 가장 오래된 (2014년) 오픈소스 시각 회귀 도구.

- Puppeteer 기반. URL 리스트와 셀렉터로 정의.

- HTML 리포트가 깔끔. 작은 팀에서 여전히 인기.

Reg-Suit

- 일본 발 OSS. 메루카리 등이 채택.

- S3 또는 GCS에 스냅샷 저장. PR diff를 GitHub 코멘트로.

- Playwright/Cypress/Storybook 어디서나 캡처를 던질 수 있다.

셋의 차이

| 항목 | Loki | BackstopJS | Reg-Suit |

| --- | --- | --- | --- |

| 모태 | Storybook 생태계 | 독립 | 일본 OSS |

| 베이스라인 저장 | git | 로컬 | S3/GCS |

| 캡처 엔진 | Chromium | Puppeteer | 외부 (Playwright 등) |

| PR 통합 | 직접 | 약함 | 강함 (GitHub bot) |

// backstop.json — BackstopJS 기본 설정

{

"id": "my-project",

"viewports": [

{ "label": "mobile", "width": 375, "height": 667 },

{ "label": "desktop", "width": 1920, "height": 1080 }

],

"scenarios": [

{

"label": "Homepage",

"url": "http://localhost:3000/",

"delay": 500,

"misMatchThreshold": 0.1

}

],

"engine": "puppeteer",

"report": ["browser"]

}

OSS의 강점은 베이스라인을 자기 인프라에 두는 것. 보안이 엄격한 금융권·헬스케어에서는 SaaS를 못 쓰는 경우가 많아 Reg-Suit 또는 자체 호스팅이 선호된다.

10장 · Browser MCP + Playwright MCP — AI 에이전트가 브라우저 운전

2024년 후반부터 큰 변화가 있었다. MCP(Model Context Protocol)가 표준화되면서, AI 에이전트가 직접 브라우저를 운전하는 패턴이 일반화됐다. 2026년 5월 기준 Playwright MCP와 Browser MCP 두 진영이 있다.

Playwright MCP (Microsoft)

- Microsoft가 직접 만든 공식 MCP 서버. Playwright의 모든 API를 MCP 도구로 노출.

- Claude·Cursor·VSCode Copilot이 이걸 통해 브라우저 액션을 호출.

- Accessibility tree 기반 — 스크린샷이 아니라 의미적 구조로 페이지를 본다.

- Trace 캡처와 함께 작동. 에이전트가 만든 테스트도 Trace Viewer로 재생.

Browser MCP

- 오픈소스 진영의 MCP 서버. 다양한 백엔드(Playwright, Puppeteer, Selenium).

- Local Chrome extension을 통해 현재 사용자의 세션에서 작동.

- 로그인된 상태로 작업해야 하는 시나리오에 강하다.

사용 패턴

// .cursor/mcp.json — Playwright MCP 등록

{

"mcpServers": {

"playwright": {

"command": "npx",

"args": ["@playwright/mcp@latest"]

}

}

}

이 설정 후 AI 에이전트에게 "체크아웃 플로우 테스트를 작성하고 실행해줘"라고 시키면, 에이전트가 직접 브라우저를 열고 클릭·입력하면서 `*.spec.ts`를 생성한다. Codegen의 다음 세대.

한계

- **flaky** — 에이전트가 비결정적이라 테스트 자체가 안정적이지 않을 수 있다.

- **비용** — LLM 토큰 비용이 매 실행마다.

- **보안** — 프로덕션 자격증명을 에이전트에 넘기는 건 위험.

그래서 2026년의 패턴은 **"에이전트가 초안을 작성 → 사람이 리뷰 + 안정화 → CI에 등록"**이다. 에이전트가 매 CI에서 도는 건 아직 아니다.

11장 · MSW (Mock Service Worker) + 네트워크 모킹 전략

MSW는 2019년 Artem Zakharchenko가 만든 네트워크 모킹 라이브러리다. 2026년 기준 2.x이며, 프론트엔드 테스트의 사실상 표준 네트워크 모킹 도구가 됐다.

핵심 개념

- **Service Worker 기반** — 브라우저의 네트워크 계층에서 가로챈다. `fetch`, `axios`, `XHR` 무관.

- **Node 환경에서도 동작** — `setupServer`로 Vitest/Jest에서 사용.

- **REST + GraphQL** — 두 프로토콜 모두 지원.

- **타입 안전** — TypeScript와 잘 어울린다.

강점

- **앱 코드 무수정** — `axios`를 `jest.mock()` 하는 게 아니라, 실제 네트워크 호출을 가로챈다.

- **개발·테스트·스토리북 공통** — 같은 핸들러를 세 환경에서 재사용.

- **GraphQL 지원** — Apollo Client/urql 통합이 매끄럽다.

- **Devtools 통합** — 브라우저 devtools의 Network 탭에 그대로 보인다.

예시 — MSW 핸들러

// mocks/handlers.ts

export const handlers = [

http.get('/api/products', () => {

return HttpResponse.json([

{ id: 1, name: 'Coffee Beans', price: 25000 },

{ id: 2, name: 'Tea Set', price: 35000 },

])

}),

http.post('/api/cart', async ({ request }) => {

const body = await request.json()

return HttpResponse.json({ ok: true, cartId: 'abc-123' }, { status: 201 })

}),

http.get('/api/user/me', () => {

return new HttpResponse(null, { status: 401 })

}),

]

// test/setup.ts — Vitest에서

const server = setupServer(...handlers)

beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))

afterEach(() => server.resetHandlers())

afterAll(() => server.close())

// browser entrypoint (개발 환경)

if (process.env.NODE_ENV === 'development') {

const worker = setupWorker(...handlers)

worker.start()

}

MSW의 진짜 가치는 **"테스트·개발·스토리북에서 같은 모킹 코드를 쓴다"**는 점. 백엔드가 아직 없을 때도 프론트엔드가 진행 가능, 테스트와 실 개발이 같은 fixture를 공유.

대안으로 Playwright의 `page.route()`, Cypress의 `cy.intercept()`도 있지만 — 각 도구 전용이라 재사용성이 떨어진다. 그래서 MSW를 한 층 두고, E2E에서는 그 위에 Playwright route를 얹는 하이브리드가 흔하다.

12장 · Page Object / Component Testing 패턴

E2E 테스트가 늘어나면 코드 중복이 문제다. 그래서 2026년의 표준 패턴은 둘이다.

Page Object Model (POM)

- 한 페이지 = 한 클래스. 셀렉터와 액션을 클래스에 캡슐화.

- Selenium 시대부터 내려온 패턴. 2026년에도 Playwright·Cypress에서 유효.

// e2e/pages/CheckoutPage.ts

export class CheckoutPage {

readonly page: Page

readonly emailInput: Locator

readonly submitButton: Locator

constructor(page: Page) {

this.page = page

this.emailInput = page.getByLabel('Email')

this.submitButton = page.getByRole('button', { name: 'Place order' })

}

async goto() {

await this.page.goto('/checkout')

}

async fillEmail(email: string) {

await this.emailInput.fill(email)

}

async submit() {

await this.submitButton.click()

}

async expectSuccess() {

await expect(this.page).toHaveURL(/thank-you/)

}

}

// e2e/checkout.spec.ts

test('user completes checkout', async ({ page }) => {

const checkout = new CheckoutPage(page)

await checkout.goto()

await checkout.fillEmail('user@example.com')

await checkout.submit()

await checkout.expectSuccess()

})

Component Testing

- 컴포넌트를 격리 환경에서 마운트해서 검증.

- Playwright CT, Cypress CT, Vitest browser mode, Storybook play function.

- "유닛 테스트만큼 빠르고 E2E만큼 진짜 같다"는 위치.

어떤 패턴을 언제

- **유닛/순수 함수** — Vitest, JSDOM.

- **컴포넌트 단독** — Storybook + Vitest 또는 Playwright CT.

- **2~3개 컴포넌트 조합** — Testing Library + Vitest.

- **전체 페이지** — Page Object + Playwright/Cypress.

- **사용자 여정** — Page Object + Playwright, 데이터 격리.

POM의 함정 — 너무 추상화하면 테스트가 뭘 하는지 안 보인다. "Login → Cart → Checkout"이 한 줄로 끝나면 read하기는 좋지만, 실패 분석이 어렵다. 적당한 추상화 + Playwright Trace Viewer의 조합이 최적.

13장 · 한국 / 일본 사례 — 토스, 카카오, Mercari

한국 — 토스의 UI 테스트

토스는 100명 이상의 프론트엔드 팀을 가진 큰 조직이고, 자체 디자인 시스템(Toss DS)을 운영한다. 공개된 블로그·발표 자료에서 드러나는 패턴은 다음과 같다.

- **Storybook + Chromatic** — 디자인 시스템의 모든 컴포넌트가 스토리북에 등록.

- **Playwright** — E2E의 표준. 멀티 브라우저 검증.

- **Vitest + React Testing Library** — 컴포넌트 단위 테스트.

- **자체 MSW 핸들러 라이브러리** — 토스 API 패턴에 맞춘 공통 fixture.

- **CI에서 시각 회귀가 차단** — Chromatic 승인 없이는 머지 불가.

토스 블로그의 "프론트엔드에서 테스트가 정말 필요한가요?" 같은 글에서 보이는 철학은 — "테스트는 디자인 시스템과 한 몸". 컴포넌트 단위가 강하면 페이지 단위는 적게.

한국 — 카카오의 frontend

카카오 진영(카카오, 카카오뱅크, 카카오엔터프라이즈)도 비슷한 스택이다.

- **Jest 또는 Vitest** — 레거시는 Jest, 신규는 Vitest.

- **Cypress가 많이 남아 있음** — 2020~2023 사이에 채택한 코드베이스가 많다.

- **Playwright로 이전 중** — 신규 프로젝트와 큰 마이그레이션.

- **카카오뱅크는 더 엄격** — 금융 규제로 자체 인프라 검증, OSS 시각 회귀(Reg-Suit 또는 자체).

일본 — Mercari의 컴포넌트 테스팅

Mercari는 Storybook + Vitest + Reg-Suit의 조합을 공개적으로 발표한 적이 있다. 패턴은 다음과 같다.

- **Storybook** — 디자인 시스템과 모든 컴포넌트.

- **Reg-Suit** — 시각 회귀, S3에 베이스라인, GitHub PR에 자동 코멘트.

- **Vitest 또는 Jest** — 유닛.

- **Playwright** — E2E.

- **MSW** — 네트워크 모킹.

Mercari Engineering Blog의 시각 회귀 글들이 Reg-Suit의 실 사용 사례로 자주 인용된다. 일본에서 Reg-Suit가 강한 이유 중 하나가 메르카리 채택.

결론 — 지역별 권장

| 시나리오 | 한국 권장 | 일본 권장 |

| --- | --- | --- |

| 스타트업 (10~50명) | Vitest + Playwright + Chromatic | Vitest + Playwright + Reg-Suit |

| 중견 (50~500명) | Storybook 9 + Chromatic + Playwright | Storybook 9 + Reg-Suit + Playwright |

| 대기업 (500+) | 자체 디자인 시스템 + Chromatic + Playwright | 자체 + Reg-Suit + Playwright |

| 금융권 | 자체 호스팅 Reg-Suit + Playwright | 자체 호스팅 + Selenium 5 잔존 |

| 글로벌 SaaS | Applitools + Playwright | Applitools + Playwright |

14장 · 어떤 스택을 골라야 하나 — 시나리오별 가이드

시나리오 A — 큰 SaaS (수십 개 페이지, 다국어, 다중 브라우저)

- **Unit**: Vitest 3 + React Testing Library

- **Component**: Storybook 9 + Vitest browser mode

- **E2E**: Playwright 1.50+ (Chromium, Firefox, WebKit, Mobile Safari)

- **Visual**: Chromatic 또는 Applitools

- **Network**: MSW 2.x

- **CI**: GitHub Actions + Playwright trace + Chromatic publish + 실패 시 Slack

- **AI**: Playwright MCP로 신규 테스트 초안 생성

시나리오 B — 디자인 시스템 / 컴포넌트 라이브러리

- **Unit**: Vitest 3

- **Component**: Storybook 9 (CSF 3 + play function)

- **Visual**: Chromatic (Storybook과 한 몸)

- **A11y**: `@storybook/addon-a11y` + axe-core

- **Docs**: Storybook autodocs

- **E2E는 최소화** — 라이브러리는 컴포넌트 단위가 핵심

시나리오 C — E-commerce (장바구니, 결제, 다중 페이지)

- **Unit**: Vitest 3

- **Component**: Storybook 9 또는 Testing Library

- **E2E**: Playwright (Page Object 패턴)

- **Visual**: Percy 또는 Chromatic (모바일 viewport 핵심)

- **Network**: MSW + Playwright route 하이브리드

- **결제 플로우는 격리된 테스트 계정 + Stripe test mode**

시나리오 D — 미디어 / 콘텐츠 사이트

- **Unit**: Vitest 3 (SEO 메타 검증 위주)

- **E2E**: Playwright (Lighthouse CI 함께)

- **Visual**: Chromatic 또는 BackstopJS

- **Network**: MSW로 CMS 응답 모킹

- **성능 회귀가 중요** — Playwright + Lighthouse 통합

시나리오 E — 레거시 마이그레이션 (Jest + Cypress → Vitest + Playwright)

- 한 번에 다 옮기지 말고 새 코드는 새 도구로.

- Jest와 Vitest 공존 — `vitest run --project new`로 점진.

- Cypress E2E는 그대로 두고, 신규 E2E만 Playwright.

- 12~18개월 마이그레이션이 현실적.

비용 추산 (2026년 5월 기준, 50명 프론트엔드 팀)

| 도구 | 무료 tier | 유료 (월간) |

| --- | --- | --- |

| Playwright | 무료 | — |

| Vitest | 무료 | — |

| Storybook | 무료 | — |

| Chromatic | 월 5,000 snapshot 무료 | ~$149 ~ $649 |

| Percy | 월 5,000 snapshot 무료 | ~$199+ |

| Applitools | 평가판 | enterprise quote |

| Cypress Cloud | 월 500 결과 무료 | ~$75 ~ $300+ |

| MSW | 무료 | — |

| Loki/BackstopJS/Reg-Suit | 무료 | — |

작은 팀의 시작점은 단순하다 — Vitest + Playwright + Chromatic 무료 tier. 여기서 시작해 팀이 커지면 Storybook 9를 디자인 시스템 중심으로, 시각 회귀를 유료 tier로, 그리고 Playwright MCP를 도입해서 신규 테스트 작성 속도를 높이는 게 표준 경로.

마치며 — "도구를 사는 게 아니라, 신뢰를 사는 거다"

2026년의 프론트엔드 테스팅 시장은 단일 도구의 토너먼트가 아니라 4축의 합주다. 그리고 다음 5가지 흐름이 시장을 흔들고 있다.

1. **Playwright의 표준화** — 신규 E2E의 70%+ 점유율. 시간이 갈수록 격차 확대.

2. **Vitest의 부상** — Vite 생태계와 함께 사실상 표준 유닛 러너.

3. **Storybook 9의 가벼워짐** — 디자인 시스템 + 컴포넌트 테스트 + 시각 회귀의 허브.

4. **AI 에이전트가 직접 테스트 작성** — Playwright MCP, Browser MCP가 일상화.

5. **MSW의 표준화** — 네트워크 모킹 = MSW. 도구 독립적 fixture.

작은 팀의 첫 줄 — `npm i -D vitest @testing-library/react @playwright/test msw`. 이 네 개로 95%의 케이스가 커버된다. 그 다음 단계가 Storybook 9 + Chromatic, 그 다음이 Playwright MCP 통합.

하나의 진리 — **"도구를 사는 게 아니라, 신뢰(테스트가 깨졌을 때 진짜로 버그를 잡는다는 신뢰)를 사는 거다"**. 어떤 도구를 고르더라도 그 신뢰가 90% 미만이면, 그 테스트는 PR을 차단하는 잡음에 불과하다. 도구 평가의 첫 질문은 항상 "이 테스트가 빨간 줄을 띄울 때, 실제로 버그를 잡았던 비율은?"이다.

참고 / References

- Playwright — [https://playwright.dev/](https://playwright.dev/)

- Playwright VS Code Extension — [https://playwright.dev/docs/getting-started-vscode](https://playwright.dev/docs/getting-started-vscode)

- Playwright Trace Viewer — [https://playwright.dev/docs/trace-viewer](https://playwright.dev/docs/trace-viewer)

- Playwright Component Testing — [https://playwright.dev/docs/test-components](https://playwright.dev/docs/test-components)

- Playwright MCP — [https://github.com/microsoft/playwright-mcp](https://github.com/microsoft/playwright-mcp)

- Cypress — [https://www.cypress.io/](https://www.cypress.io/)

- Cypress 14 release notes — [https://docs.cypress.io/guides/references/changelog](https://docs.cypress.io/guides/references/changelog)

- Cypress Cloud — [https://www.cypress.io/cloud](https://www.cypress.io/cloud)

- Vitest — [https://vitest.dev/](https://vitest.dev/)

- Vitest Browser Mode — [https://vitest.dev/guide/browser/](https://vitest.dev/guide/browser/)

- Jest — [https://jestjs.io/](https://jestjs.io/)

- Jest 30 announcement — [https://jestjs.io/blog/2025/06/04/jest-30](https://jestjs.io/blog/2025/06/04/jest-30)

- Testing Library — [https://testing-library.com/](https://testing-library.com/)

- React Testing Library — [https://testing-library.com/docs/react-testing-library/intro/](https://testing-library.com/docs/react-testing-library/intro/)

- Storybook — [https://storybook.js.org/](https://storybook.js.org/)

- Storybook 9 release — [https://storybook.js.org/blog/storybook-9/](https://storybook.js.org/blog/storybook-9/)

- Storybook Vitest addon — [https://storybook.js.org/docs/writing-tests/test-addon](https://storybook.js.org/docs/writing-tests/test-addon)

- Chromatic — [https://www.chromatic.com/](https://www.chromatic.com/)

- Percy — [https://percy.io/](https://percy.io/)

- Applitools — [https://applitools.com/](https://applitools.com/)

- Applitools Visual AI — [https://applitools.com/platform/visual-ai/](https://applitools.com/platform/visual-ai/)

- Loki (Storybook visual regression) — [https://loki.js.org/](https://loki.js.org/)

- BackstopJS — [https://github.com/garris/BackstopJS](https://github.com/garris/BackstopJS)

- Reg-Suit — [https://github.com/reg-viz/reg-suit](https://github.com/reg-viz/reg-suit)

- Selenium — [https://www.selenium.dev/](https://www.selenium.dev/)

- WebdriverIO — [https://webdriver.io/](https://webdriver.io/)

- MSW (Mock Service Worker) — [https://mswjs.io/](https://mswjs.io/)

- Model Context Protocol — [https://modelcontextprotocol.io/](https://modelcontextprotocol.io/)

- State of JS 2024 — [https://stateofjs.com/](https://stateofjs.com/)

- Kent C. Dodds — Testing Trophy — [https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications](https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications)

- Mercari Engineering Blog — [https://engineering.mercari.com/en/blog/](https://engineering.mercari.com/en/blog/)

- 토스 기술 블로그 — [https://toss.tech/](https://toss.tech/)

- 카카오 기술 블로그 — [https://tech.kakao.com/](https://tech.kakao.com/)

현재 단락 (1/551)

2018년쯤에 "프론트엔드 테스팅 뭐 써?"라고 물으면 답은 간단했다. 유닛은 Jest, E2E는 Selenium 또는 Cypress, 시각 회귀는 한다는 사람만 BackstopJ...

작성 글자: 0원문 글자: 23,135작성 단락: 0/551