Skip to content

chore: Playwright E2E 테스트 환경 구축 - #319

Merged
iOdiO89 merged 18 commits into
devfrom
chore/318-playwright-e2e-setup
Jul 19, 2026
Merged

chore: Playwright E2E 테스트 환경 구축#319
iOdiO89 merged 18 commits into
devfrom
chore/318-playwright-e2e-setup

Conversation

@kanghaeun

@kanghaeun kanghaeun commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

작업 요약

  • PR CI에서 주요 사용자 플로우를 자동 검증하는 E2E 테스트 환경 구축

작업 세부 내용

PR CI에서 주요 사용자 플로우를 자동 검증하는 E2E 테스트 환경을 구축했습니다

같은 코드면 항상 같은 결과가 나오도록 실서버 대신 모든 API를 목킹합니다.
추가 라이브러리는 @playwright/test 하나만 (MSW 도입 없음, 목킹은 Playwright 내장 기능 + node 내장 http 사용).

만약 실서버 기반으로 PR CI를 돌리면

  • 데이터 상태 불일치 — 예: 준비 페이지 테스트는 "PENDING 상태의 토너먼트"가 필요한데, 누가 QA 중에 그 토너먼트를 시작하면 코드와 무관하게 테스트가 깨짐.
  • 백엔드 가용성에 종속 — dev 서버 배포/장애 동안 모든 프론트 PR이 막힘
  • 데이터 오염 — CI가 돌 때마다 게스트 계정·테스트 토너먼트가 dev DB에 쌓임
  • 에러 케이스 테스트 불가 — 500/403 같은 응답을 실서버에서 마음대로 발생시킬 수 없음 (목킹은 api.error(...) 한 줄)

목킹 구조

요청 경로 목킹 방법 파일
① 인증 (미들웨어의 서버사이드 게스트 로그인) 가짜 JWT를 쿠키로 심어 로그인 자체를 우회 e2e/setup/auth.setup.ts
② 브라우저 발 API 요청 (clientApi) page.route() 인터셉트 e2e/fixtures/mockApiFixture.ts
③ 서버 발 API 요청 (SSR — serverApi, RSC 레이아웃) 로컬 목 스텁 서버 (127.0.0.1:4010) e2e/setup/mockApiServer.ts

① 인증: proxy.ts(미들웨어)는 access_token 쿠키가 없으면 서버사이드에서 게스트 로그인 API를 호출하는데, 이건 브라우저 밖에서 일어나 page.route()로 못 잡습니다. 대신 토큰 검증(isTokenValid)이 서명 없이 JWT의 exp만 확인하는 점을 이용해, global setup에서 만료가 미래인 가짜 JWT를 조립해 storageState(쿠키)로 저장합니다. 네트워크 0회로 인증 상태가 만들어지고 모든 테스트가 재사용합니다.

② 브라우저 요청: api fixture가 **/api/v1/** 라우트를 선점하고 pathname+method로 매칭합니다. 팀 응답 규약 { status, data, detail, code }를 그대로 따르고, 목킹 안 된 요청은 500으로 실패시키고 테스트 끝에 단언이 터지게 해서 목 누락을 즉시 잡습니다.

③ SSR 요청: tournament/[id]/layout.tsx가 접근 권한 확인을 위해 RSC에서 getTournament를 직접 await하므로(실패 시 rethrow), 서버 발 요청은 반드시 성공해야 토너먼트 페이지에 진입할 수 있습니다. 그래서 NEXT_PUBLIC_API_URL127.0.0.1:4010으로 강제하고, globalSetup에서 node 내장 http로 목 스텁 서버를 띄워 응답합니다. 목 데이터 상수는 e2e/mocks/를 ②와 공유합니다(단일 소스)

파일 구조

apps/web/
├── playwright.config.ts        # 중심 설정 (모바일 뷰포트, webServer 로컬/CI 분리)
└── e2e/
    ├── home.spec.ts            # 샘플: 홈 진입 → 토너먼트 목록 렌더링
    ├── tournamentCreate.spec.ts # 샘플: 홈 → 카드 클릭 → 준비 페이지 진입 플로우
    ├── consts.ts               # 목 스텁 주소/포트
    ├── fixtures/mockApiFixture.ts  # page.route 목킹 fixture (api.get/post/error)
    ├── helpers/
    │   ├── apiResponse.ts      # 팀 응답 규약 래핑 (createApiSuccess/Error)
    │   └── fakeJwt.ts          # 가짜 JWT 조립
    ├── mocks/                  # 목 데이터 (실제 도메인 타입 기준)
    └── setup/
        ├── auth.setup.ts       # storageState 생성 (setup 프로젝트)
        ├── globalSetup.ts      # SSR 목 스텁 서버 기동/종료
        └── mockApiServer.ts    # node:http 목 스텁

실행 방법

# 기본 — dev 서버 있으면 재사용, 없으면 알아서 띄웠다 내림
pnpm test:e2e

# 디버깅 — GUI에서 단계별 화면/네트워크 타임라인 확인
pnpm --filter piki-web test:e2e:ui

# CI 완전 재현 — 프로덕션 빌드 기준 (CI에서만 깨질 때)
NEXT_PUBLIC_API_URL=http://127.0.0.1:4010 pnpm build:web && CI=1 pnpm test:e2e
  • 결과는 터미널에 3 passed처럼 출력되고, 실패 시 스크린샷 경로 + HTML 리포트가 자동으로 열립니다
  • 최초 실행은 수 분 걸릴 수 있습니다
  • UI 모드에서 테스트가 안 보이면 좌측 필터의 Projects에서 mobile-chromium을 체크해주세요

CI

  • 기존 ci 잡(lint/type/build)과 병렬로 도는 e2e 잡 추가 — 기존 필수 체크에 영향 없음
  • Playwright 브라우저 바이너리 캐싱 (~/.cache/ms-playwright, 버전 기반 키)
  • 실패 시 playwright-report + test-results(trace/스크린샷) 아티팩트 업로드

스크린샷

  • pnpm test:e2e 입력
image
  • pnpm --filter piki-web test:e2e:ui 입력
image

연관 이슈

closes #318

Summary by CodeRabbit

  • 새 기능

    • Playwright 기반 E2E 테스트 환경과 테스트 실행 명령을 추가했습니다.
    • 홈 화면과 토너먼트 생성 이동 흐름을 자동으로 검증합니다.
    • 실제 서버 대신 안정적인 테스트용 데이터와 이미지가 제공됩니다.
  • CI 개선

    • Node.js 22 환경에서 E2E 테스트를 자동 실행합니다.
    • 실패 시 테스트 리포트와 결과를 확인할 수 있습니다.
  • 문서

    • E2E 테스트 실행 방법, 작성 규칙 및 데이터 모킹 절차를 문서화했습니다.

@kanghaeun
kanghaeun requested a review from iOdiO89 July 9, 2026 09:05
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
depromeet Ready Ready Preview, Comment Jul 19, 2026 5:07am
piki Ready Ready Preview, Comment Jul 19, 2026 5:07am

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 125a51a5-164b-419f-b185-808a14cd04b8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Playwright 기반 E2E 실행 환경이 추가되었습니다. API·SSR 목킹, 게스트 인증 상태, 홈 및 토너먼트 시나리오, 로컬 실행 설정과 CI 자동 실행 구성이 포함됩니다.

Changes

Playwright E2E 환경 구축

Layer / File(s) Summary
Playwright 설정과 실행 기반
.gitignore, package.json, apps/web/package.json, apps/web/playwright.config.ts, apps/web/tsconfig.json, prettier.config.mjs, CLAUDE.md, apps/web/e2e/README.md
Playwright 실행 스크립트·의존성·프로젝트 설정·경로 별칭·산출물 제외 규칙과 사용 문서가 추가되었습니다.
응답 헬퍼와 테스트 목 데이터
apps/web/e2e/helpers/*, apps/web/e2e/mocks/*
표준 API 응답, 가짜 JWT, 이미지 SVG, 게스트 사용자와 토너먼트 목 데이터가 정의되었습니다.
SSR 목 서버와 게스트 인증
apps/web/e2e/setup/*
SSR API 목 서버, 전역 서버 수명주기, 게스트 쿠키 기반 storage state 생성이 추가되었습니다.
브라우저 API 및 외부 리소스 목킹
apps/web/e2e/fixtures/mockApiFixture.ts
API·SSE·이미지 요청을 목킹하고, 외부 스크립트를 차단하며, 미목킹 API 요청을 테스트 종료 시 검증합니다.
홈과 토너먼트 E2E 시나리오
apps/web/e2e/specs/*
홈의 토너먼트 렌더링과 토너먼트 생성 페이지 이동 및 렌더링을 검증합니다.
CI E2E 실행 통합
.github/workflows/ci.yml
Node 22, Playwright 브라우저 캐시·설치, 웹 빌드, E2E 실행 및 실패 리포트 업로드가 추가되었습니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant E2ETest
  participant PlaywrightFixture
  participant NextApp
  participant MockApiServer
  E2ETest->>PlaywrightFixture: API 목 응답 등록
  E2ETest->>NextApp: /home 요청
  NextApp->>PlaywrightFixture: 브라우저 API 요청
  NextApp->>MockApiServer: SSR API 요청
  PlaywrightFixture-->>NextApp: 목 응답 반환
  MockApiServer-->>NextApp: SSR 목 응답 반환
  NextApp-->>E2ETest: 렌더링된 화면
Loading

Possibly related issues

  • 이슈 318: Playwright E2E 설정, 목킹, 인증, 샘플 테스트 및 CI 통합이라는 목표를 구현합니다.

Suggested reviewers: soyeong0115

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 Playwright E2E 테스트 환경 구축이라는 핵심 변경을 정확히 요약합니다.
Linked Issues check ✅ Passed Playwright 설치, 결정적 목킹, 게스트 storageState, 샘플 E2E, CI 잡/캐시/아티팩트까지 요구사항이 구현되었습니다.
Out of Scope Changes check ✅ Passed 추가된 문서, alias, 헬퍼, 목 데이터, CI 조정은 모두 E2E 환경 구축과 직접 연관되어 보입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/318-playwright-e2e-setup

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
.github/workflows/ci.yml (2)

53-121: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

e2e 잡에 timeout-minutes 설정 권장

Playwright 브라우저 자동화는 네트워크/타이밍 이슈로 예기치 않게 멎을 수 있어, 다른 유사 워크플로 예시들도 대부분 잡 레벨에 timeout-minutes(보통 30~60분)를 명시해 러너가 기본 6시간까지 점유되는 것을 방지합니다. 현재 e2e 잡에는 이 설정이 없어, 테스트가 행(hang)될 경우 러너 자원이 오래 낭비될 수 있습니다.

⏱️ 제안
   e2e:
     name: E2E (Playwright)
     runs-on: ubuntu-latest
+    timeout-minutes: 30
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 53 - 121, The e2e job is missing an
explicit timeout, so add a job-level timeout-minutes to the e2e workflow block
to prevent a hung Playwright run from occupying the runner too long. Update the
e2e job definition in the CI workflow (the job that runs Build web, Run E2E
tests, and Upload Playwright report) and choose a reasonable limit consistent
with other workflow jobs, such as 30–60 minutes.

53-55: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

ci 잡과의 의존 관계 부재로 인한 불필요한 실행 가능성

e2e 잡이 needs: ci를 지정하지 않아 lint/타입체크/빌드가 실패해도 e2e 잡은 독립적으로 실행됩니다. 브라우저 캐시 복원, pnpm build:web, 전체 테스트 스위트가 매번 도는 구조라, 기존 ci 잡이 먼저 실패할 게 뻔한 PR에서도 러너 시간이 소모됩니다. 의도적으로 병렬 실행해 피드백 속도를 우선한 것이라면 넘어가도 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 53 - 55, The e2e job is currently
independent from the main ci job, so it can still run and consume runner time
even when lint/typecheck/build already failed. Update the workflow by adding a
dependency from the e2e job to the ci job in the GitHub Actions YAML, using the
e2e job definition as the place to reference needs: ci, unless parallel
execution is intentionally desired.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/e2e/setup/mockApiServer.ts`:
- Around line 29-54: `startMockApiServer`의 `server.listen()`에 에러 처리 경로가 없어 포트 충돌
시 프로세스가 종료될 수 있습니다. `http.Server`의 `'error'` 이벤트를 `startMockApiServer` 안에서 처리하고,
Promise를 성공 시 `resolve(server)`만 하지 말고 실패 시 `reject`하도록 바꿔 `EADDRINUSE` 같은
listen 오류가 `globalSetup`에서 명확히 전파되게 하세요. `startMockApiServer`, `server.listen`,
그리고 생성된 `server` 객체를 기준으로 수정하면 됩니다.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 53-121: The e2e job is missing an explicit timeout, so add a
job-level timeout-minutes to the e2e workflow block to prevent a hung Playwright
run from occupying the runner too long. Update the e2e job definition in the CI
workflow (the job that runs Build web, Run E2E tests, and Upload Playwright
report) and choose a reasonable limit consistent with other workflow jobs, such
as 30–60 minutes.
- Around line 53-55: The e2e job is currently independent from the main ci job,
so it can still run and consume runner time even when lint/typecheck/build
already failed. Update the workflow by adding a dependency from the e2e job to
the ci job in the GitHub Actions YAML, using the e2e job definition as the place
to reference needs: ci, unless parallel execution is intentionally desired.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 47e78ea4-01a3-45b7-ba74-85af8cf61e48

📥 Commits

Reviewing files that changed from the base of the PR and between ef66bef and bec89ed.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (16)
  • .github/workflows/ci.yml
  • .gitignore
  • apps/web/e2e/consts.ts
  • apps/web/e2e/fixtures/mockApiFixture.ts
  • apps/web/e2e/helpers/apiResponse.ts
  • apps/web/e2e/helpers/fakeJwt.ts
  • apps/web/e2e/home.spec.ts
  • apps/web/e2e/mocks/me.ts
  • apps/web/e2e/mocks/tournament.ts
  • apps/web/e2e/setup/auth.setup.ts
  • apps/web/e2e/setup/globalSetup.ts
  • apps/web/e2e/setup/mockApiServer.ts
  • apps/web/e2e/tournamentCreate.spec.ts
  • apps/web/package.json
  • apps/web/playwright.config.ts
  • package.json

Comment on lines +29 to +54
export const startMockApiServer = (port: number) =>
new Promise<http.Server>(resolve => {
const server = http.createServer((req, res) => {
const pathname = new URL(req.url ?? '/', `http://127.0.0.1:${port}`).pathname;
const body = SSR_MOCK_ROUTES[`${req.method} ${pathname}`];

if (!body) {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(
JSON.stringify(
createApiError({
status: 404,
code: 'E2E_SSR_UNMOCKED',
detail: `SSR 목 스텁에 등록되지 않은 요청: ${req.method} ${pathname}`,
})
)
);
return;
}

res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(body));
});

server.listen(port, '127.0.0.1', () => resolve(server));
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

server.listen()에 에러 핸들러가 없어 포트 충돌 시 프로세스가 크래시할 수 있습니다.

http.ServerEventEmitter이므로 listen()EADDRINUSE 등으로 'error' 이벤트가 발생하면, 리스너가 없을 경우 처리되지 않은 예외로 Node 프로세스가 종료됩니다. 현재 Promise는 성공 콜백에서만 resolve되고 reject 경로가 없어, 이전 실행이 정상 종료되지 않아 포트가 남아있는 경우(예: CI 재시도, 로컬에서 강제 종료 후 재실행) globalSetup 단계에서 명확한 에러 메시지 없이 전체 E2E 실행이 죽어버릴 수 있습니다.

🔧 제안하는 수정
 export const startMockApiServer = (port: number) =>
-  new Promise<http.Server>(resolve => {
+  new Promise<http.Server>((resolve, reject) => {
     const server = http.createServer((req, res) => {
       ...
     });
 
+    server.on('error', reject);
     server.listen(port, '127.0.0.1', () => resolve(server));
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const startMockApiServer = (port: number) =>
new Promise<http.Server>(resolve => {
const server = http.createServer((req, res) => {
const pathname = new URL(req.url ?? '/', `http://127.0.0.1:${port}`).pathname;
const body = SSR_MOCK_ROUTES[`${req.method} ${pathname}`];
if (!body) {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(
JSON.stringify(
createApiError({
status: 404,
code: 'E2E_SSR_UNMOCKED',
detail: `SSR 목 스텁에 등록되지 않은 요청: ${req.method} ${pathname}`,
})
)
);
return;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(body));
});
server.listen(port, '127.0.0.1', () => resolve(server));
});
export const startMockApiServer = (port: number) =>
new Promise<http.Server>((resolve, reject) => {
const server = http.createServer((req, res) => {
const pathname = new URL(req.url ?? '/', `http://127.0.0.1:${port}`).pathname;
const body = SSR_MOCK_ROUTES[`${req.method} ${pathname}`];
if (!body) {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(
JSON.stringify(
createApiError({
status: 404,
code: 'E2E_SSR_UNMOCKED',
detail: `SSR 목 스텁에 등록되지 않은 요청: ${req.method} ${pathname}`,
})
)
);
return;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(body));
});
server.on('error', reject);
server.listen(port, '127.0.0.1', () => resolve(server));
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/e2e/setup/mockApiServer.ts` around lines 29 - 54,
`startMockApiServer`의 `server.listen()`에 에러 처리 경로가 없어 포트 충돌 시 프로세스가 종료될 수 있습니다.
`http.Server`의 `'error'` 이벤트를 `startMockApiServer` 안에서 처리하고, Promise를 성공 시
`resolve(server)`만 하지 말고 실패 시 `reject`하도록 바꿔 `EADDRINUSE` 같은 listen 오류가
`globalSetup`에서 명확히 전파되게 하세요. `startMockApiServer`, `server.listen`, 그리고 생성된
`server` 객체를 기준으로 수정하면 됩니다.

@m-a-king

m-a-king commented Jul 9, 2026

Copy link
Copy Markdown

완전 최고다

kanghaeun and others added 2 commits July 12, 2026 23:37
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/e2e/setup/globalSetup.ts`:
- Around line 6-7: Update the server reuse logic around startMockApiServer so an
EADDRINUSE/null result is accepted only after a health check or identifying
response confirms the process is the expected mock API server; otherwise fail
setup instead of reusing the process. Preserve reuse for valid existing mock
servers and keep the normal newly-started server path unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b95d009-1ddc-497a-80a7-4339fcd89b77

📥 Commits

Reviewing files that changed from the base of the PR and between bec89ed and baa9f4a.

📒 Files selected for processing (3)
  • apps/web/e2e/fixtures/mockApiFixture.ts
  • apps/web/e2e/setup/globalSetup.ts
  • apps/web/e2e/setup/mockApiServer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/e2e/setup/mockApiServer.ts

Comment on lines +6 to +7
/** null 이면 다른 세션(UI 모드 등)이 띄운 기존 스텁을 재사용 — 내리지 않는다 */
const server = await startMockApiServer(MOCK_API_PORT);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files ==\n'
git ls-files 'apps/web/e2e/setup/*' 'apps/web/e2e/**/*mock*' 'apps/web/e2e/**/*setup*' | sort

printf '\n== Outline: globalSetup ==\n'
ast-grep outline apps/web/e2e/setup/globalSetup.ts --view expanded

printf '\n== Outline: mockApiServer ==\n'
ast-grep outline apps/web/e2e/setup/mockApiServer.ts --view expanded

printf '\n== Relevant excerpts ==\n'
sed -n '1,220p' apps/web/e2e/setup/globalSetup.ts | cat -n
printf '\n--- mockApiServer.ts ---\n'
sed -n '1,260p' apps/web/e2e/setup/mockApiServer.ts | cat -n

Repository: TeamPiKi/PiKi-Client

Length of output: 3846


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== MOCK_API_PORT references ==\n'
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/.next/**' 'MOCK_API_PORT|startMockApiServer\(' apps/web

printf '\n== consts file ==\n'
sed -n '1,220p' apps/web/e2e/consts.ts | cat -n

printf '\n== e2e setup files ==\n'
sed -n '1,220p' apps/web/e2e/setup/auth.setup.ts | cat -n
printf '\n--- fixture ---\n'
sed -n '1,240p' apps/web/e2e/fixtures/mockApiFixture.ts | cat -n

printf '\n== package scripts mentioning e2e or ui mode ==\n'
sed -n '1,240p' package.json | cat -n

Repository: TeamPiKi/PiKi-Client

Length of output: 8127


기존 서버 재사용 전에 신원을 확인하세요
EADDRINUSE를 그대로 null로 처리하면 4010을 점유한 stale/unrelated 프로세스도 목 서버로 간주됩니다. 헬스체크나 식별 응답이 맞을 때만 재사용하고, 그렇지 않으면 실패시키는 편이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/e2e/setup/globalSetup.ts` around lines 6 - 7, Update the server
reuse logic around startMockApiServer so an EADDRINUSE/null result is accepted
only after a health check or identifying response confirms the process is the
expected mock API server; otherwise fail setup instead of reusing the process.
Preserve reuse for valid existing mock servers and keep the normal newly-started
server path unchanged.

@iOdiO89 iOdiO89 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어렵당 나도 playwright는 제대로 써본적이 없어서 가볍게 리뷰남겼어!

이거 관련 md 파일을 하나 추가하면 어떨까 폴더 구조나 어떻게 사용해야한다는 지침서가 있으면 좋을 것 같아

Comment thread .github/workflows/ci.yml
Comment on lines +112 to +120
- name: Upload Playwright report
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: |
apps/web/playwright-report/
apps/web/test-results/
retention-days: 7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failure 발생하면 디스코드로 알림 보내주면 어떨까??
이거는 근데 discord-pr-bot 쪽 워크플로우를 건드려야하는 거긴 해

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR에서도 테스트 통과 못하면 실패 표시가 뜨긴해서 디스코드까지 추가하면 조금 과할 수도 있을 것 같은데
다 같이 테스트 실패를 공유하고 싶은거지?

Comment on lines +99 to +103
await provide({
get: (path, data) =>
entries.push({ method: 'GET', path, status: 200, body: createApiSuccess(data) }),
post: (path, data) =>
entries.push({ method: 'POST', path, status: 200, body: createApiSuccess(data) }),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

patch, delete가 없는데 이건 e2e 테스트 생성하면서 추가하면 될까? error는 get, post, delete, patch까지 다 대응되어 있는 것 같아서!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일단 자주 쓰는 메서드만 추가해놨는데 patch랑 delete도 미리 추가해놓는게 좋겠다 수정완!

Comment thread apps/web/e2e/mocks/me.ts Outdated
Comment on lines +6 to +7
/** 외부 이미지 URL 금지 — next/image 가 서버사이드에서 fetch 해 목킹이 불가능하다 */
profileImage: '',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 좀 고민이 된다 ~.. 빈 문자열로 처리한 이유는 합당한 거 같은데, Next/Image에서는 src가 빈 문자열이면 에러가 발생해서 테스트하다가 ui 상에 오류가 날 수도 있겠다는 생각!

BaseImage 컴포넌트 썼으면 미리 에러 핸들링 해두어서 문제 없을텐데, 내 기억에는 Next/Image 자체를 쓴 경우도 많았어서 문제가 될까봐 마음에 좀 걸리넹

Image

이런 느낌으로 실제 image url을 사용해보면 어때?!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아님 이런건 e2e 테스트 실제로 생성하면서 작업하는 게 나을까!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋다 수정해놨어~! 4e705eb

@kanghaeun

kanghaeun commented Jul 18, 2026

Copy link
Copy Markdown
Contributor Author

추가 작업 내용

  • E2E 테스트 사용 가이드 추가
  • E2E 테스트 이미지 모킹 추가: 태그 등에서 직접 외부 CDN URL을 사용하는 경우를 대비해, 가짜 CDN 주소(https://cdn.example/**) 요청을 가로채 미리 준비된 목 이미지로 응답하도록 설정
image

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/e2e/fixtures/mockApiFixture.ts (1)

6-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

@e2e/ 절대 경로 별칭 사용을 권장합니다.

apps/web 코딩 가이드라인에 따르면 동일 디렉토리가 아닌 파일은 상대 경로 대신 절대 별칭을 사용해야 합니다. fixtures/helpers/, fixtures/mocks/는 서로 다른 디렉토리이므로 @e2e/ 별칭을 사용하는 것이 가이드라인에 부합합니다.

As per coding guidelines: apps/web/**/*.{ts,tsx} — "Use the @/* absolute alias for imports when possible, and relative imports only for files in the same directory."

♻️ 제안 수정
-import { createApiError, createApiSuccess } from '../helpers/apiResponse';
-import { DEFAULT_MOCK_IMAGE, MOCK_IMAGE_MAP } from '../mocks/images';
+import { createApiError, createApiSuccess } from '`@e2e/helpers/apiResponse`';
+import { DEFAULT_MOCK_IMAGE, MOCK_IMAGE_MAP } from '`@e2e/mocks/images`';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/e2e/fixtures/mockApiFixture.ts` around lines 6 - 7, Update the
imports in mockApiFixture.ts to use the `@e2e/` absolute alias for
createApiError/createApiSuccess from helpers/apiResponse and
DEFAULT_MOCK_IMAGE/MOCK_IMAGE_MAP from mocks/images, replacing the
cross-directory relative paths while preserving the imported symbols.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/e2e/README.md`:
- Line 18: Update the folder-structure code block in the README to specify the
text language, changing its opening fence from an untyped fence to a text-tagged
fence while leaving the displayed structure unchanged.

---

Nitpick comments:
In `@apps/web/e2e/fixtures/mockApiFixture.ts`:
- Around line 6-7: Update the imports in mockApiFixture.ts to use the `@e2e/`
absolute alias for createApiError/createApiSuccess from helpers/apiResponse and
DEFAULT_MOCK_IMAGE/MOCK_IMAGE_MAP from mocks/images, replacing the
cross-directory relative paths while preserving the imported symbols.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 82368bfb-b7ee-420a-b71f-0e2af61dac8b

📥 Commits

Reviewing files that changed from the base of the PR and between a2c90d9 and 173eff0.

📒 Files selected for processing (10)
  • CLAUDE.md
  • apps/web/e2e/README.md
  • apps/web/e2e/fixtures/mockApiFixture.ts
  • apps/web/e2e/mocks/images.ts
  • apps/web/e2e/mocks/me.ts
  • apps/web/e2e/mocks/tournament.ts
  • apps/web/e2e/specs/home/home.spec.ts
  • apps/web/e2e/specs/tournament/tournamentCreate.spec.ts
  • apps/web/tsconfig.json
  • prettier.config.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/e2e/mocks/me.ts
  • apps/web/e2e/mocks/tournament.ts

Comment thread apps/web/e2e/README.md
@iOdiO89
iOdiO89 merged commit baee552 into dev Jul 19, 2026
7 checks passed
@iOdiO89
iOdiO89 deleted the chore/318-playwright-e2e-setup branch July 19, 2026 05:18
iOdiO89 added a commit that referenced this pull request Jul 19, 2026
* chore: playwright 설치

* chore: Playwright 설정 및 테스트 스크립트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: 게스트 storageState 생성 setup 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: page.route 기반 API 목킹 fixture 및 목 데이터 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: 홈 및 토너먼트 준비 페이지 E2E 테스트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: SSR 접근 권한 조회용 목 스텁 서버 추가 및 준비 페이지 테스트를 진입 플로우로 변경

* chore: playwright/.auth gitignore 패턴 수정

* chore: E2E 테스트 CI 잡 추가

* fix: UI 모드와 CLI 동시 실행 시 목 스텁 포트 충돌 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: dev 전용 react-grab 스크립트 차단으로 trace 스냅샷 빈 화면 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: CI Node 버전 22 LTS로 변경

* refactor: E2E 테스트를 도메인 폴더 구조로 변경

* refactor: @e2e alias 도입

* feat: E2E 이미지 목킹 추가 (가짜 CDN URL + /_next/image 인터셉트)

* feat: api 목킹 fixture에 patch, delete 메서드 추가

* docs: E2E 테스트 사용 가이드 추가

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jung Sun A <amber0809@naver.com>
iOdiO89 added a commit that referenced this pull request Jul 19, 2026
* fix: svgo removeViewBox 비활성화로 아이콘 축소 렌더링 시 잘림 방지

* feat: 바텀탭 디자인 변경 및 탭 4개로 분리

* refactor: 바텀탭 button > link 태그로 교체

* feat: 마이페이지에 바텀탭 추가

* refactor: 바텀탭 z-index를 Z_INDEX 상수로 관리

* refactor: 마이 탭 신설에 따라 헤더 프로필 아이콘 제거

* feat: 바텀탭 포인터 다운 시 스케일업 인터랙션 추가

* feat: 바텀탭 인디케이터 드래그로 탭 전환하는 인터랙션 추가

* feat: 바텀탭 liquid glass 효과 추가

* feat: 바텀탭 포커스되지 않은 탭 클릭해도 드래그 가능하도록 변경

* feat: 바텀탭 렌즈 변신 조건 정리 및 배경 틴트 상태 분리

* refactor: 바텀탭 wrapper 컴포넌트 내부로 이동

* style: 바텀탭 blur 완화

* fix: 탭바 새 제스처 시작 시 예약된 라우팅 취소

* fix: 탭바 착지 애니메이션 완료 후 라우팅되도록 지연 정렬

* fix: 탭바 새 제스처 시작 시 예약된 라우팅 취소

* refactor: 로그인 진입 시 세션 조회 왕복 제거 및 스플래시 전환 개선 (#348)

* refactor: access token JWT에서 role 추출하는 유틸 추가

* refactor: 로그인 세션 검사(getMe) 제거하고 JWT role 기반으로 전환

* refactor: 게스트 세션 재활용 판정을 클릭 시점 refresh로 일원화

* fix: 루트 스플래시 배경 FOUC 제거

* feat: 로그인 진입 시 문구·버튼 fade-in 애니메이션 추가

* refactor: /archive 탭을 위시리스트·내 토너먼트 페이지로 분리 (#347)

* refactor: /archive 탭 쿼리 파라미터를 /archive/wish, /archive/tournament 경로로 분리

* refactor: 구버전 /archive(?tab=) 경로를 신규 경로로 리다이렉트

* refactor: 옛 /wish 페이지 잔재 정리 및 archive 콜로케이션 재배치

* fix: 위시 페이지 체류 중 후속 공유 인텐트가 무시되던 문제 수정

* fix: 보관 탭 활성 판정 경로 경계 추가 및 위시 추가 후 중복 라우팅 제거

* fix: 공유 인텐트 실패 URL 잠금 해제 및 링크 담기 실패 시 다이얼로그 유지

* refactor: JWT role을 명시적 검증으로 좁혀 타입 단언 제거

* fix: share intent 처리 후 URL 잠금 해제하여 재공유 허용

* refactor: font preload 삭제

* refactor: Pretendard 폰트 CDN Dynamic Subset Variable로 교체

* chore: TanstackQuery devtool Dynamic Import로 변경

* chore: Tanstack Query Devtools ssr false 설정

* fix: Android 12+ 스플래시 로고 저해상도 문제 해결 (RN 오버레이로 전환)

* fix: Android 시스템 스플래시 저품질 로고 미노출 처리 (배경색만 표시)

* Revert "fix: Android 시스템 스플래시 저품질 로고 미노출 처리 (배경색만 표시)"

This reverts commit adede7e.

* Revert "fix: Android 12+ 스플래시 로고 저해상도 문제 해결 (RN 오버레이로 전환)"

This reverts commit 74d09aa.

* fix: 안드로이드 카카오 로그인 무한 로딩 수정 (리다이렉트 수신 액티비티 등록) (#350)

* fix: 카카오 로그인 안드로이드 리다이렉트 수신 액티비티 등록

* chore: 서명 자격증명 및 빌드 산출물 gitignore 추가

* fix: 안드로이드 스플래시 로고 저해상도 노출 수정 (RN 오버레이 전환) (#352)

* fix: Android 12+ 스플래시 로고 저해상도 문제 해결 (RN 오버레이로 전환)

* fix: Android 시스템 스플래시 저품질 로고 미노출 처리 (배경색만 표시)

* fix: SplashScreen.hideAsync rejection 처리 추가

* refactor: BottomCta 공통 컴포넌트 개선 및 페이지별 개별 구현 통합 (#345)

* feat: 바텀 CTA 상단 그라데이션 옵션 추가 및 패딩 스펙 반영

* refactor: 페이지별 바텀 CTA를 BottomCta 공통 컴포넌트로 교체

* chore: iOS ShareBottomSheet 에셋 파일명 교체 (#353)

* chore: iOS 앱 공유 바텀 시트 에셋 추가

* feat: iOS 앱 공유 바텀시트 성공/에러 UI 추가

* chore: app sentry cli 추가

* chore: patch app version

* chore: Playwright E2E 테스트 환경 구축 (#319)

* chore: playwright 설치

* chore: Playwright 설정 및 테스트 스크립트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: 게스트 storageState 생성 setup 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: page.route 기반 API 목킹 fixture 및 목 데이터 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: 홈 및 토너먼트 준비 페이지 E2E 테스트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: SSR 접근 권한 조회용 목 스텁 서버 추가 및 준비 페이지 테스트를 진입 플로우로 변경

* chore: playwright/.auth gitignore 패턴 수정

* chore: E2E 테스트 CI 잡 추가

* fix: UI 모드와 CLI 동시 실행 시 목 스텁 포트 충돌 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: dev 전용 react-grab 스크립트 차단으로 trace 스냅샷 빈 화면 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: CI Node 버전 22 LTS로 변경

* refactor: E2E 테스트를 도메인 폴더 구조로 변경

* refactor: @e2e alias 도입

* feat: E2E 이미지 목킹 추가 (가짜 CDN URL + /_next/image 인터셉트)

* feat: api 목킹 fixture에 patch, delete 메서드 추가

* docs: E2E 테스트 사용 가이드 추가

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jung Sun A <amber0809@naver.com>

---------

Co-authored-by: joyeongchan <tigerbone@naver.com>
Co-authored-by: kanghaeun <145974230+kanghaeun@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
iOdiO89 added a commit that referenced this pull request Jul 19, 2026
* chore: playwright 설치

* chore: Playwright 설정 및 테스트 스크립트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: 게스트 storageState 생성 setup 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat: page.route 기반 API 목킹 fixture 및 목 데이터 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: 홈 및 토너먼트 준비 페이지 E2E 테스트 추가

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: SSR 접근 권한 조회용 목 스텁 서버 추가 및 준비 페이지 테스트를 진입 플로우로 변경

* chore: playwright/.auth gitignore 패턴 수정

* chore: E2E 테스트 CI 잡 추가

* fix: UI 모드와 CLI 동시 실행 시 목 스텁 포트 충돌 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: dev 전용 react-grab 스크립트 차단으로 trace 스냅샷 빈 화면 해결

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: CI Node 버전 22 LTS로 변경

* refactor: E2E 테스트를 도메인 폴더 구조로 변경

* refactor: @e2e alias 도입

* feat: E2E 이미지 목킹 추가 (가짜 CDN URL + /_next/image 인터셉트)

* feat: api 목킹 fixture에 patch, delete 메서드 추가

* docs: E2E 테스트 사용 가이드 추가

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Jung Sun A <amber0809@naver.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore: Playwright E2E 테스트 환경 구축

3 participants