테스트
vitest 유닛 · API 통합 · Playwright e2e · Appium 네이티브, 그리고 회귀 테스트 정책
Neul 은 버그 성격에 맞는 레벨에서 테스트를 작성합니다. 핵심 원칙은 "고친 버그는 영구 회귀 테스트로 남긴다" 입니다.
회귀 테스트 정책 (항상)
버그/이슈를 고치면 그 케이스에 대한 영구 회귀 테스트를 반드시 커밋합니다. 일회성 검증 스크립트로 끝내지 않습니다. "그 버그를 잡았을 테스트"를 작성 → 실행 → 수정과 함께 커밋하세요.
외부 의존(실제 Google OAuth, AI 키 없는 경로 등)은 목킹/스텁으로 결정적으로
만듭니다. 이 정책은 저장소의 AGENTS.md 에 명시되어 있고, Stop 훅(작업 종료 시점)
에서 테스트 보강을 환기시키는 방식으로 강제됩니다.
레벨별 가이드
유닛 — packages/shared
순수 로직·수식 검증. vitest 로 실행합니다.
pnpm test # turbo run test (= vitest, packages/shared)통합 — apps/api
라우트·서버 데이터 흐름 검증. handler.fetch + 로컬 Postgres 를 사용합니다.
시간 의존을 결정적으로 만들기 위해 TZ=UTC 로 실행합니다.
pnpm test:integration # = TZ=UTC vitest run (apps/api)스펙 위치: apps/api/src/__tests__/*.integration.test.ts
(api.integration.test.ts = 라우트/데이터 흐름, google-oauth.integration.test.ts = 로그인 검증 크립토)
통합 테스트는 로컬 Postgres 가 떠 있어야 합니다(pnpm db:up). 날짜 경계 로직은
런타임(Workers=UTC)과 동일하게 UTC 로 비교되므로, 테스트도 TZ=UTC 로 맞춥니다.
Google 로그인 모킹 — 목 OIDC 발행자
실제 Google 없이 구글 로그인 전 경로(코드 교환 → 서명 검증 → aud/iss 체크) 를
결정적으로 테스트합니다. jose 로 RS256 키쌍을 만들어 자체 서명 id_token + JWKS 를
발급하는 목 OIDC 발행자를 in-process 로 세웁니다(외부 프로세스 불필요).
- 라우트는
APP_ENV가 prod 가 아닐 때만 테스트용 env 오버라이드를 적용합니다:GOOGLE_TOKEN_URL— 토큰 교환 엔드포인트(우리 코드의fetch라 스텁 가능).GOOGLE_JWKS_JSON— 로컬 JWKS(JSON).createLocalJWKSet로 원격 fetch 없이 서명 검증.GOOGLE_ISSUER— 허용 issuer.
- 운영(
APP_ENV=prod)에서는 이 오버라이드를 무시하고 항상 실제 Google 로 검증합니다 — 목 키로 우회 불가(테스트가 이 가드도 함께 검증).
jose 의 createRemoteJWKSet 은 Node 에서 global fetch 를 거치지 않아 스텁이 안 먹습니다.
그래서 키 검증은 로컬 JWKS(createLocalJWKSet)로, 토큰 교환만 fetch 스텁으로 가로챕니다.
이는 dotfive 의 oauth2-mock-server(별도 프로세스) 와 같은 목 발행자 원리를 우리 in-process
하네스에 맞춘 것입니다.
e2e (웹) — e2e-web
UI·데이터 바인딩 플로우 검증. Playwright 로 실행합니다.
pnpm e2e:web # = playwright test (e2e-web/*.spec.ts)동일 스펙으로 배포본 원격 검증도 가능합니다. 환경변수로 대상만 바꿉니다:
E2E_BASE_URL=https://<web> E2E_API_URL=https://<api> pnpm e2e:webe2e (네이티브) — e2e-native
iOS/Android 네이티브 셸 검증. Appium + WebdriverIO 로 실행합니다.
pnpm appium # Appium 서버 (chromedriver autodownload)
pnpm e2e:ios # APPIUM_PLATFORM=ios wdio (e2e-native/wdio.ios.conf.ts)
pnpm e2e:android # APPIUM_PLATFORM=android wdio (e2e-native/wdio.android.conf.ts)모바일 dev 네트워킹(CORS/PNA, 클리어텍스트)은 iOS 시뮬레이터 + Android 에뮬레이터 양쪽에서 검증되었습니다 — 아키텍처 › CORS와 모바일 네트워킹 참고.
한눈에 보기
| 레벨 | 위치 | 러너 | 명령 |
|---|---|---|---|
| 유닛 | packages/shared | vitest | pnpm test |
| 통합 | apps/api/src/__tests__ | vitest (TZ=UTC) + 로컬 PG | pnpm test:integration |
| e2e(웹) | e2e-web/*.spec.ts | Playwright | pnpm e2e:web |
| e2e(네이티브) | e2e-native/* | Appium + WDIO | pnpm e2e:ios / pnpm e2e:android |