GitHub ↗
CHAPTER 03 OF 10
🎭

Testing & QA Skills — Automation at Scale

Testing & QA 스킬 — 테스트를 무기로 만드는 법

2026년 가장 많이 설치된 Claude Code 스킬은 Playwright E2E다. 테스팅 스킬 스택을 올바르게 구성하면 QA 시간의 80%를 Claude에게 위임할 수 있다.

Testing & QA Skills — Automation at Scale cheatsheet
🍌 NANO BANANA CHEATSHEET · CH 03

Overview

개관

테스팅은 Claude Code가 가장 극적인 ROI를 보여주는 영역이다. 이유는 단순하다 — 테스트 작성은 반복 구조가 명확하고 검증 가능한 작업이기 때문이다.

Playwright E2E 스킬이 2026년 설치 수 1위를 차지한 것은 우연이 아니다. E2E 테스트는 작성하기 어렵고, flaky하기 쉽고, CI 설정이 복잡하다 — 정확히 Claude 스킬이 전문성을 발휘하는 지점이다.

테스팅 스킬 스택: Playwright(E2E) + Vitest/Jest(유닛) + RTL(컴포넌트) + MSW(API 모킹) — 이 4개를 갖추면 테스트 코드의 80%를 Claude에게 위임할 수 있다.

🎯 Learning Goals
  • Playwright 스킬로 견고한(flaky하지 않은) E2E 테스트를 작성하는 원칙을 이해한다
  • RTL의 올바른 쿼리 우선순위(getByRole > getByText > getByTestId)를 적용할 수 있다
  • MSW로 API 모킹을 설정하고 네트워크 계층을 격리하는 방법을 안다
  • 테스트 피라미드(유닛:통합:E2E = 70:20:10)를 기준으로 커버리지 전략을 설계한다

Sections

본문

Playwright — 견고한 E2E의 원칙

Playwright 스킬이 가르치는 핵심 원칙:

견고한 로케이터 우선순위: getByRole > getByLabel > getByPlaceholder > getByText > getByTestId. CSS selector나 XPath는 UI 변경에 취약하다.

인증 상태 관리: storageState를 사용해 로그인 상태를 저장하고 재사용. 매 테스트마다 로그인 플로우를 반복하지 않는다.

병렬 실행: worker 수 설정과 test.describe.parallel()로 전체 수트 실행 시간을 극적으로 단축.

React Testing Library — 올바른 테스트 철학

RTL의 핵심 철학: '구현 세부사항이 아니라 사용자 행동을 테스트하라.'

fireEvent보다 userEvent를 쓰는 이유, waitFor의 올바른 사용, findBy 쿼리로 비동기 요소 처리 — RTL 스킬은 이런 미묘한 차이를 Claude가 항상 올바르게 적용하도록 보장한다.

MSW — 네트워크 계층 격리

Mock Service Worker는 서비스 워커 레이어에서 HTTP 요청을 가로채기 때문에 실제 fetch/axios 코드를 수정하지 않아도 된다.

MSW 스킬은 핸들러 설정, setupServer 초기화, 에러 시나리오 모킹, 응답 지연 시뮬레이션 패턴을 Claude가 일관되게 적용하게 한다.

💡 Analogy · 비유
테스트는 안전망이다

서커스 공중 곡예사가 안전망 없이 연습하지 않는다. 안전망이 있을 때 더 과감한 기술을 시도할 수 있다. 테스트 스위트는 코드베이스의 안전망이다. 스킬로 이 안전망을 빠르게 구축하면, Claude가 더 과감한 리팩토링을 제안하고 실행할 수 있다.

Playwright 스킬이 생성하는 견고한 E2E 테스트 패턴

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

// Playwright 스킬 원칙: 인증 상태 재사용
test.use({ storageState: 'playwright/.auth/user.json' });

test.describe('결제 플로우', () => {
  test('장바구니에서 결제 완료까지', async ({ page }) => {
    // ✅ getByRole — 가장 견고한 로케이터
    await page.goto('/cart');
    await page.getByRole('button', { name: '결제하기' }).click();
    
    // ✅ 라벨 기반 — 접근성과 일치
    await page.getByLabel('카드 번호').fill('4111111111111111');
    await page.getByLabel('유효기간').fill('12/28');
    
    // ✅ 비동기 처리 — waitFor 패턴
    await page.getByRole('button', { name: '결제 완료' }).click();
    await expect(page.getByRole('heading', { 
      name: '주문이 완료되었습니다' 
    })).toBeVisible({ timeout: 10000 });
    
    // ✅ URL 검증
    await expect(page).toHaveURL(/\/order\/[a-z0-9-]+/);
  });
  
  // ❌ Playwright 스킬이 피하도록 가르치는 패턴:
  // await page.click('.checkout-btn');  // CSS selector — 취약
  // await page.waitForTimeout(2000);    // 하드코딩된 sleep — flaky
});

getByRole로 접근성 기반 로케이터를 사용하고, storageState로 인증을 재사용한다. waitForTimeout 대신 expect().toBeVisible()의 timeout 옵션으로 안정적인 대기를 구현한다.

🏭 현업에서의 평가
테스트 코드 리뷰에서 가장 먼저 보는 것: 로케이터 전략. CSS selector 투성이라면 이 사람은 테스트 유지보수의 고통을 아직 경험하지 못한 것이다. getByRole 기반 코드는 리팩토링에 강하다.

✅ 시니어가 보는 것

  • 접근성 기반 로케이터(getByRole, getByLabel) 사용률
  • 인증 상태 재사용으로 테스트 속도 최적화
  • flaky 테스트 방지 패턴(waitForTimeout 미사용)
  • 테스트 피라미드 비율이 적절한가

Key Takeaways

핵심 정리

로케이터 우선순위: Role > Label > Text > TestId

이 순서를 지키는 테스트는 UI가 바뀌어도 살아남는다.

MSW로 네트워크 계층 격리

실제 API에 의존하지 않는 빠르고 신뢰할 수 있는 테스트를 작성한다.

storageState로 인증 재사용

매 테스트 로그인 플로우는 시간 낭비이자 flakiness의 원인이다.