Files
frontend/apps/cs/tests/unit/walkthrough.md
T

192 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# cs 앱 단위(Unit) 및 통합(Integration) 테스트 구축 결과 보고서
cs 애플리케이션 내의 컴포넌트 로직 검증 및 렌더링 검사 기능을 수행할 수 있도록 **Vitest**와 **React Testing Library (RTL)** 설정을 완료하고 샘플 코드를 생성했습니다.
## 변경 및 추가 사항 요약
### 1. 의존성 설치 및 스크립트 추가
* `apps/cs/package.json`의 개발용 라이브러리로 다음 패키지들을 설치했습니다:
* `vitest`, `@testing-library/react`, `@testing-library/jest-dom`, `jsdom`, `@vitejs/plugin-react`, `vite-tsconfig-paths`
* `scripts` 항목에 단위 테스트 실행 스크립트를 정의했습니다:
* `"test:unit": "vitest run"` (1회 실행)
* `"test:unit:watch": "vitest"` (실시간 Watch 모드)
### 2. 설정 파일 정의
* **[vitest.config.ts](file:///Users/changwng/workspace.ona/frontend/apps/cs/vitest.config.ts)**:
* React 플러그인 및 tsconfig alias 경로 파싱을 연결했습니다.
* 테스트 환경으로 가상 브라우저 돔(jsdom)을 연결했습니다.
* Playwright E2E 테스트 스펙(`*.spec.ts`)과 충돌이 나지 않도록, 단위 테스트 범위를 **`tests/unit/**/*.{test,spec}.{ts,tsx}`** 경로로 제한했습니다.
* **[setup-tests.ts](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/setup-tests.ts)**:
* DOM 전역 단언식인 `@testing-library/jest-dom`을 확장했습니다.
### 3. 샘플 및 페이지 테스트 코드 생성
* **[sample-counter.tsx](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/unit/sample-counter.tsx)**:
* 상태값 관리(useState) 및 이벤트 처리, 5 초과 시의 경고문 조건부 렌더링 등이 구현된 React 컴포넌트입니다.
* **[sample-counter.test.tsx](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/unit/sample-counter.test.tsx)**:
* **기본 렌더링 검사** (초기 값 및 제목 텍스트 검증)
* **상태 변경 검사** (증가/감소 버튼 동작에 따른 값 업데이트 검증)
* **통합 조건부 검사** (5 초과 시의 경고 노출 여부 검증)
* **[login-page.test.tsx](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/unit/login-page.test.tsx)**:
* 실제 로그인 컴포넌트(`LoginPage`)를 대상으로 한 단위/통합 테스트 스위트입니다.
* **UI 요소 검증**: 타이틀 렌더링, ID/PW 입력 필드 및 로그인 버튼 존재 확인.
* **로그인 실패 케이스**: `authService.login` API가 에러를 발생시킬 때 화면에 한글 에러 문구(`아이디와 비밀번호가 일치하지 않습니다.`)가 정상 표출되는지 검증.
* **로그인 성공 케이스**: 정상적으로 로그인이 완료되었을 때 `window.location.href` 가 `"/dashboard"` 로 셋업되어 이동되는지 검증.
* *Next.js `next/image` 컴포넌트 및 글로벌 `window.location`을 가상 돔 환경에 맞추어 적절하게 모킹 처리하였습니다.*
* **[use-session-extend-confirm.test.ts](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/unit/use-session-extend-confirm.test.ts)**:
* 세션 연장 팝업 제어용 공통 훅(`useSessionExtendConfirm`)에 대한 단위 테스트 스위트입니다.
* **기본 타이머 대기 검증**: 토큰 만료 버퍼 도달 전까지는 컨펌창이 나타나지 않고, 해당 시점(예: 10초) 경과 후에 `confirm`이 정상 호출되는지 검증.
* **연장 승인 시나리오**: 팝업에서 승인 시 `silentRefresh()`가 호출되고 갱신된 신규 토큰으로 재스케줄링되는지 검증.
* **연장 거절 시나리오**: 팝업에서 거절 시 `declineSessionExtend()`가 호출되고, 해당 토큰에 대해서는 더 이상 팝업을 띄우지 않도록 무한 루프가 방지되는지 검증.
* **즉시 노출 시나리오**: 이미 만료 버퍼 내인 경우 타이머 대기 없이 즉각적으로 컨펌창이 실행되는지 검증.
* **미동작 예외 시나리오**: 비활성화 상태(`enabled: false`)이거나 이미 토큰이 완전히 만료된 경우 어떠한 스케줄도 잡지 않는지 검증.
* *가상 타이머(`vi.useFakeTimers()`) 및 마이크로태스크 큐 제어를 결합하여 비동기 훅의 작동 방식을 정밀하고 빠르게 시뮬레이션하였습니다.*
### 4. Playwright E2E 테스트 코드 및 격리 스텁 뷰 추가
* **[session-extend-confirm.spec.ts](file:///Users/changwng/workspace.ona/frontend/apps/cs/tests/session-extend-confirm.spec.ts)**:
* 세션 연장 팝업의 만료 전 타이머 동작과 실제 화면 조작 및 훅 상호작용을 검증하는 브라우저 E2E 테스트 스펙입니다.
* **승인 E2E 시나리오**: 만료 5분(버퍼 시간) 전 진입 시 리액트 HTML 모달 팝업이 노출되며, "확인" 버튼 클릭 시 리액트의 `silentRefresh()`가 트리거되고 모달이 닫히는 동작을 실 브라우저 상에서 검증.
* **거절 E2E 시나리오**: 모달 팝업 노출 상태에서 "취소" 버튼 클릭 시 세션 연장 요청이 거절되고 모달이 닫히며, 이후 시간이 더 지나도 모달이 중복 재노출되지 않는 동작을 검증.
* **[page.tsx](file:///Users/changwng/workspace.ona/frontend/apps/cs/app/(main)/(with-base-layout)/test-session/page.tsx)**:
* 실시간 API와 계정/시간 몽키패칭 부작용으로 인한 브라우저 락(Lock) 및 로그인 튕김 현상을 완벽하게 예방하기 위해 구축한 **격리된 E2E 스텁 라우트**입니다.
* `/test-session` 경로는 `ConfirmProvider`와 `ConfirmDialog` 래퍼가 마운트되는 기본 레이아웃 하위에서 작동하므로, 실 브라우저가 직접 마운트된 모달 HTML 요소를 안정적으로 감지하고 클릭할 수 있는 신뢰성 높은 환경을 제공합니다.
---
## 5. Playwright E2E 테스트 개념 및 실전 사용법 가이드
### 5.1 Playwright 핵심 개념 (What is Playwright?)
Playwright는 Microsoft에서 개발한 차세대 **End-to-End(E2E) 브라우저 자동화 및 테스트 프레임워크**입니다. 사용자 관점에서 브라우저를 실제로 조작하며 전체 애플리케이션 플로우(인증, 페이지 이동, 폼 입력, 서버 연동)를 검증합니다.
#### Vitest(단위 테스트) vs Playwright(E2E 테스트) 비교
| 비교 항목 | Vitest + React Testing Library | Playwright (E2E) |
|---|---|---|
| **실행 환경** | Node.js + 가상 DOM (jsdom) | **실제 브라우저** (Chromium, Firefox, WebKit) |
| **속도** | 초고속 (밀리초 단위) | 상대적으로 무거움 (수 초 ~ 수십 초) |
| **검증 대상** | 개별 함수, 훅, 단일 컴포넌트 렌더링 로직 | 브라우저 렌더링, 실제 네트워크, 전체 사용자 시나리오 |
| **주요 역할** | 회귀 방지, 비즈니스 계산/매퍼 검증 | 최종 배포 전 시스템 통합 동작 보증 |
#### Playwright의 핵심 메커니즘
1. **브라우저 컨텍스트 격리 (Browser Context Isolation)**:
- 새 브라우저 프로세스를 매번 띄우는 대신, 가벼운 브라우저 컨텍스트를 생성하여 테스트 간 쿠키/스토리지 오염 없이 100% 독립된 환경을 제공합니다.
2. **자동 대기 (Auto-waiting)**:
- 요소를 클릭하거나 타이핑하기 전, 요소가 DOM에 부착(Attached), 표시(Visible), 활성화(Enabled), 애니메이션 정지 상태인지 자동으로 기다려 Flaky(불안정한) 테스트를 원천 차단합니다.
3. **Web-first Assertions**:
- `expect(locator).toBeVisible()`과 같은 단언문은 조건이 충족될 때까지 지정된 시간(기본 5초) 동안 자동으로 재시도합니다.
---
### 5.2 Playwright 실행 명령어 치트시트
`apps/cs` 폴더 또는 루트 디렉터리에서 실행합니다:
```bash
# 1. 헤드리스 모드로 전체 E2E 테스트 실행 (CLI 모드)
pnpm --filter cs test:playwright
# 2. 대화형 UI 모드 실행 (테스트 단계별 타임라인 탐색, 실시간 렌더링 시각화)
pnpm --filter cs test:playwright:ui
# 3. 브라우저 화면을 직접 보면서 실행 (--headed)
pnpm --filter cs exec playwright test --headed
# 4. 특정 테스트 파일만 지정 실행
pnpm --filter cs exec playwright test tests/session-extend-confirm.spec.ts
pnpm --filter cs exec playwright test tests/login.spec.ts
# 5. 특정 브라우저(엔진)만 지정 실행
pnpm --filter cs exec playwright test --project=chromium
# 6. 코드젠 (Codegen): 브라우저 조작 시 테스트 코드를 자동 생성해주는 도구
pnpm --filter cs exec playwright codegen http://localhost:3000
# 7. 마지막 테스트 실행 결과 HTML 리포트 열기
pnpm --filter cs exec playwright show-report
```
---
### 5.3 테스트 작성 표준 패턴 및 베스트 프랙티스
#### ① 권장 로케이터(Locator) 사용 순서
Playwright는 사용자가 인지하는 방식을 반영하는 시맨틱 로케이터를 권장합니다:
1. `page.getByRole('button', { name: '확인' })` (접근성 및 의미 기반 - 최우선 권장)
2. `page.getByLabel('아이디')` (폼 레이블 기반)
3. `page.getByPlaceholder('비밀번호를 입력하세요')`
4. `page.getByText('저장되었습니다')`
5. `page.locator('button.login_btn')` (CSS 선택자 - 최후의 수단)
#### ② 표준 테스트 구조 예시
```typescript
import { test, expect } from "@playwright/test";
test.describe("로그인 및 대시보드 플로우", () => {
test.beforeEach(async ({ page }) => {
// 1. 사전 진입
await page.goto("/auth/login");
});
test("아이디/비밀번호 입력 후 정상 대시보드로 이동해야 한다", async ({ page }) => {
// 2. 사용자 조작 (자동 대기 내장)
await page.getByPlaceholder("아이디").fill("admin");
await page.getByPlaceholder("비밀번호").fill("secret123!");
await page.getByRole("button", { name: "로그인" }).click();
// 3. Web-first 단언문
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByText("관리자님 환영합니다")).toBeVisible();
});
});
```
---
### 5.4 프로젝트 설정 해설 (`playwright.config.ts`)
`apps/cs/playwright.config.ts`의 주요 설정 포인트:
- `testIgnore: "**/unit/**"`: Vitest로 실행되어야 할 jsdom 단위 테스트 파일이 중복 실행되지 않도록 격리.
- `workers: 1` & `fullyParallel: false`: 공유 세션(Redis, DB)을 사용하는 통합 인증 테스트 간의 충돌 방지.
- `webServer`: 테스트 실행 전 개발 서버(`http://localhost:3000`)가 구동되어 있지 않으면 자동으로 구동하여 테스트 완료 후 종료.
- `trace: "retain-on-failure"`: 테스트가 실패한 경우에만 DOM 스냅샷, 콘솔 로그, 네트워크 요청이 담긴 Trace 파일을 저장하여 디버깅을 지원.
---
## 6. 검증 결과
### 1. Vitest 단위 테스트 결과
터미널에서 `pnpm --filter cs run test:unit` 명령을 실행하여 모든 단위 테스트(총 13개)가 정상 통과함을 검증하였습니다:
```bash
RUN v4.1.10 /Users/changwng/workspace.ona/frontend/apps/cs
✓ tests/unit/use-session-extend-confirm.test.ts (6 tests) 16ms
✓ tests/unit/sample-counter.test.tsx (4 tests) 94ms
✓ tests/unit/login-page.test.tsx (3 tests) 152ms
Test Files 3 passed (3)
Tests 13 passed (13)
Start at 14:21:52
Duration 819ms (transform 217ms, setup 109ms, import 367ms, tests 257ms, environment 1.04s)
```
속도 면에서 아주 빠르고 안정적으로 가상 돔 유닛 테스트 환경이 준비되었습니다.
### 2. Playwright E2E 테스트 결과
터미널에서 `pnpm --filter cs exec playwright test tests/session-extend-confirm.spec.ts` 명령을 실행하여, `chromium`, `firefox`, `webkit` 3대 주요 실 브라우저 환경에서 연장 성공 시 다음 팝업 억제 검증을 포함한 세션 연장 E2E 테스트(총 6개 스위트)가 100% 정상 통과함을 확인하였습니다:
```bash
Running 6 tests using 1 worker
✓ 1 [chromium] › tests/session-extend-confirm.spec.ts:8:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 1. 세션 만료 5분(버퍼 시간) 전 도달 시 컨펌 다이얼로그가 자동 노출되고, 승인 시 연장 처리가 수행되어야 함 (11.6s)
✓ 2 [chromium] › tests/session-extend-confirm.spec.ts:42:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 2. 컨펌 다이얼로그를 거절(Dismiss)한 경우 세션 연장 처리가 취소되고 재차 팝업이 노출되지 않아야 함 (9.8s)
✓ 3 [firefox] › tests/session-extend-confirm.spec.ts:8:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 1. 세션 만료 5분(버퍼 시간) 전 도달 시 컨펌 다이얼로그가 자동 노출되고, 승인 시 연장 처리가 수행되어야 함 (16.4s)
✓ 4 [firefox] › tests/session-extend-confirm.spec.ts:42:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 2. 컨펌 다이얼로그를 거절(Dismiss)한 경우 세션 연장 처리가 취소되고 재차 팝업이 노출되지 않아야 함 (15.3s)
✓ 5 [webkit] › tests/session-extend-confirm.spec.ts:8:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 1. 세션 만료 5분(버퍼 시간) 전 도달 시 컨펌 다이얼로그가 자동 노출되고, 승인 시 연장 처리가 수행되어야 함 (11.1s)
✓ 6 [webkit] › tests/session-extend-confirm.spec.ts:42:7 › 세션 연장 확인 팝업 (useSessionExtendConfirm) E2E 테스트 › 2. 컨펌 다이얼로그를 거절(Dismiss)한 경우 세션 연장 처리가 취소되고 재차 팝업이 노출되지 않아야 함 (9.9s)
6 passed (1.3m)
```
이로써 단위/통합 테스트 환경과 연장 처리 성공 후 중복 팝업 억제 시나리오가 포함된 E2E 테스트 환경 구축 임무가 성공적으로 완결되었습니다.