Skip to content

Conversation

@seongwon030
Copy link
Member

@seongwon030 seongwon030 commented Feb 1, 2026

#️⃣연관된 이슈

ex) #이슈번호, #이슈번호

📝작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지/동영상 첨부 가능)

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

릴리스 노트

  • Tests

    • 클럽 지원 흐름을 검증하는 Playwright E2E 테스트 및 관련 실행/디버그 스크립트 추가
  • Chores

    • 프론트엔드 CI 파이프라인 추가(린트·유닛테스트·E2E·프로덕션 빌드)
    • MSW 비활성화 옵션과 Mixpanel 모킹 옵션 도입으로 E2E/개발 환경 안정성 개선
  • Ignore

    • E2E 산출물 및 테스트 결과 파일에 대한 무시 규칙 추가

✏️ Tip: You can customize this high-level summary in your review settings.

- 커스텀 DOM 접근 오류 제거
- 기본 브라우저/모바일 디바이스, webServer 구동, 스크린샷·트레이스 옵션 포함
- 실제 네트워크 요청으로 테스트 실행
- DEV + VITE_DISABLE_MSW=true에서 기존 SW unregister로 e2e 오염 방지
- msw 버전 업데이트에 맞춰 mockServiceWorker.js 갱신
- 메인 → 상세 → 지원서 작성/제출 시나리오 검증
- playwright-report/, test-results/
- Node 타입 추가 및 Playwright 설정 파일 포함
@seongwon030 seongwon030 self-assigned this Feb 1, 2026
@seongwon030 seongwon030 added ✅ Test test 관련(storybook, jest...) 💻 FE Frontend labels Feb 1, 2026
@vercel
Copy link

vercel bot commented Feb 1, 2026

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

Project Deployment Actions Updated (UTC)
moadong Ready Ready Preview, Comment Feb 1, 2026 0:53am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 1, 2026

Warning

Rate limit exceeded

@seongwon030 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

프론트엔드에 Playwright 기반 E2E 인프라와 "지원하기" 플로우 테스트를 추가하고, Mock Service Worker의 요청/응답 직렬화·타이밍 로직을 변경했으며, 다수의 styled-components에서 비-DOM props를 트랜지언트($ 접두사)로 리네이밍하고 CI 워크플로우·스크립트를 추가했습니다.

Changes

Cohort / File(s) Summary
CI 및 E2E 인프라
​.github/workflows/front-test.yml, frontend/playwright.config.ts, frontend/package.json, frontend/tsconfig.json, frontend/jest.config.js
Frontend CI 워크플로우(프론트 lint/test/e2e/build) 추가, Playwright 설정·스크립트·의존성 추가, TS/Jest에 e2e 관련 제외·타입 추가
E2E 테스트 구현
frontend/e2e/apply-flow.spec.ts, frontend/e2e/fixture/mock-data.ts
클럽 지원 플로우 Playwright E2E 테스트 추가(검색→상세→지원서 조회·작성·제출) 및 목 데이터 제공, 팝업 닫기 헬퍼·콘솔 로그 수집 포함
Mock Service Worker 변경
frontend/public/mockServiceWorker.js, frontend/src/index.tsx
요청 직렬화(serializeRequest)·requestInterceptedAt 타임스탬프 도입, 응답 페이로드 확장 및 메시지 포맷 변경, VITE_DISABLE_MSW 처리(서비스워커 언등록) 및 MSW 초기화 보호 로직 추가
프로젝트 설정·무시 파일
frontend/.gitignore
playwright-report/test-results/ 무시 패턴 추가
styled-components: 공통 컴포넌트 변경
frontend/src/components/.../Header/*, frontend/src/components/ClubTag/ClubTag.tsx, frontend/src/components/common/InputField/*, frontend/src/components/common/CustomTextArea/*
여러 공통 컴포넌트에서 스타일용 props를 $ 접두사 트랜지언트로 일괄 변경(예: isScrolled$isScrolled, width$width, hasError$hasError) 및 사용처 업데이트
styled-components: 페이지별 변경
frontend/src/pages/MainPage/components/*, frontend/src/pages/ClubDetailPage/components/PhotoModal/*, frontend/src/pages/ApplicationFormPage/components/QuestionContainer/*
Banner, Popup, PhotoModal, QuestionContainer 등 페이지 컴포넌트의 스타일용 props를 $ 접두사로 변경하고 호출부 업데이트
styled-components: Admin 페이지 변경
frontend/src/pages/AdminPage/components/QuestionBuilder/*, frontend/src/pages/AdminPage/tabs/ApplicantsTab/*
관리자 페이지 관련 styled-components의 props를 $ 접두사로 일괄 변경(예: active$active, disabled$disabled, status$status) 및 사용처 업데이트
Mixpanel 초기화 변경
frontend/src/utils/initSDK.ts
VITE_DISABLE_MIXPANEL 플래그에 따른 mockMixpanel 도입 및 해당 플래그일 때 실제 초기화 회피 로직 추가

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant PW as Playwright 브라우저
    participant App as Vite 앱
    participant MSW as Mock Service Worker
    participant API as Mock 핸들러

    User->>PW: 메인 페이지 접근
    PW->>App: 정적 리소스 / 라우트 요청
    PW->>MSW: /api/club/search 요청 (intercept, serialized request)
    MSW->>API: 목 응답 반환 (클럽 목록)
    PW->>PW: 클럽 카드 클릭 (클라이언트 라우팅)
    PW->>MSW: /api/club/{id} 요청 (intercept)
    MSW->>API: 목 응답 반환 (클럽 상세)
    PW->>MSW: /api/club/{id}/apply GET 요청 (intercept)
    MSW->>API: 목 응답 반환 (폼 목록/폼 데이터)
    User->>PW: 폼 입력 및 제출
    PW->>MSW: /api/club/{id}/apply POST 요청 (serializeRequest 포함)
    MSW->>API: 목 제출 응답 반환
    PW->>PW: 제출 완료 후 상세로 복귀
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • [feature] MOA-591 지원하기 e2e 테스트 추가 #1131: Main changes add a Playwright E2E "apply" test — PR의 E2E 테스트 및 목 데이터 추가 목표와 직접 일치합니다.
  • MOA-591: 지원하기 E2E 테스트 추가 요청 — 본 PR이 해당 이슈의 구현(지원하기 플로우 E2E 테스트)을 충족합니다.

Possibly related PRs

Suggested reviewers

  • lepitaaar
  • oesnuj
  • suhyun113
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning PR의 일부 변경사항(ClubTag, CustomTextArea, Header, InputField, QuestionBuilder, ApplicantsTab, PhotoModal, Banner, Popup의 styled-components 프로퍼티 이름 변경 등)이 E2E 테스트 추가 범위를 벗어나 있습니다. 스타일 컴포넌트 프로퍼티 이름 변경(non-DOM props 접두사 추가)과 관련된 변경사항을 별도의 리팩토링 PR로 분리하세요. E2E 테스트 구현에만 집중하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목 '[test] 지원하기 e2e 테스트'는 주요 변경사항인 지원하기(apply) 플로우에 대한 E2E 테스트 추가를 명확하게 요약합니다.
Linked Issues check ✅ Passed MOA-591 이슈의 목표인 '지원하기 e2e 테스트 추가'가 PR의 모든 변경사항으로 충족됩니다: Playwright 설정, 테스트 구성, mock 데이터, apply-flow 테스트 스펙이 구현되었습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/#1131-apply-e2e-test-MOA-591

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@frontend/e2e/apply-flow.spec.ts`:
- Around line 96-104: Replace the flaky text-regex assertion by explicitly
waiting for the /api/club/search response and then asserting the presence of a
known club card from the mock data (e.g., "테스트 동아리"); specifically, after
calling page.goto('/') and closePopupIfExists(page), call Playwright's
response-waiting (e.g., page.waitForResponse that matches '/api/club/search') to
ensure the search API completed, then replace expect(page.getByText(/전체 \d+개의
동아리/)) with an assertion that the club card element for "테스트 동아리" (using
page.getByText("테스트 동아리") or the card selector used in the test suite) is
visible.
- Around line 52-58: The URL matching in the request handler is too brittle
because it uses string includes and a negative includes check; update the logic
in the handler that currently checks
url.includes(`/api/club/${MOCK_CLUB_ID}/apply`) && !url.includes(`/apply/`) to
instead parse the request URL (e.g., const pathname = new URL(url).pathname) and
compare pathname === `/api/club/${MOCK_CLUB_ID}/apply`; when matched, continue
to call route.fulfill with mockApplicationOptionsResponse as before. This change
should be applied where MOCK_CLUB_ID, mockApplicationOptionsResponse, and
route.fulfill are used so the GET /api/club/{clubId}/apply matching is based on
pathname not raw URL string.

In `@frontend/src/index.tsx`:
- Around line 15-24: Currently the code blindly unregisters all service workers
via navigator.serviceWorker.getRegistrations() and
registrations.map(...unregister()), which can remove non-MSW workers; instead,
filter registrations to only target MSW's worker by checking each registration's
scriptURL or active?.scriptURL for the MSW filename (e.g., "mockServiceWorker"
or the configured MSW script name) and only call unregister() on those matches;
update the logic around navigator.serviceWorker.getRegistrations(), the
registrations.map/unregister call, and any surrounding DEV + disableMsw guard to
perform this filtered-unregister behavior.
🧹 Nitpick comments (5)
frontend/src/pages/ClubDetailPage/components/PhotoModal/PhotoModal.styles.ts (1)

203-218: LGTM! $isActive 트랜지언트 prop 변경이 적절합니다.

하드코딩된 #ddd 색상이 있습니다. 일관성을 위해 테마 색상 사용을 고려해 보세요.

🎨 테마 색상 사용 제안
   &:hover {
     border-color: ${({ $isActive }) =>
-      $isActive ? colors.primary[900] : '#ddd'};
+      $isActive ? colors.primary[900] : colors.gray[400]};
   }
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantsTab.styles.ts (1)

341-357: 상태 문자열 하드코딩에 대한 유지보수 고려사항.

$status 트랜지언트 prop 변경은 올바르지만, 스타일 로직에 한글 상태 문자열('서류검토', '면접예정', '합격', '불합')이 직접 하드코딩되어 있습니다. 상태 값이 변경되면 여러 곳을 수정해야 할 수 있습니다.

향후 유지보수를 위해 상수나 매핑 객체 사용을 고려해 보세요.

♻️ 상수 사용 제안 예시
// 상태별 스타일 매핑 상수 정의
const STATUS_STYLES = {
  서류검토: { background: '#E6F4FB', color: '#222' },
  면접예정: { background: '#E6FBF0', color: '#222' },
  합격: { background: '#F5F5F5', color: '#888' },
  불합: { background: '#FFE8E8', color: '#222' },
  default: { background: '#eee', color: '#222' },
} as const;

// 사용 예시
export const ApplicantStatusBadge = styled.span<{ $status: string }>`
  ...
  background: ${({ $status }) => STATUS_STYLES[$status]?.background ?? STATUS_STYLES.default.background};
  color: ${({ $status }) => STATUS_STYLES[$status]?.color ?? STATUS_STYLES.default.color};
`;
.github/workflows/front-test.yml (1)

90-96: Playwright report 업로드 경로 생성 보장 필요

CI에서 reporter가 github만이면 playwright-report/가 생성되지 않아 업로드 단계가 경고/실패할 수 있습니다. HTML reporter 추가 또는 업로드 단계의 if-no-files-found 처리 중 하나를 권장합니다.

🧩 업로드 단계에서 누락 허용
       - name: Upload Playwright report
         uses: actions/upload-artifact@v4
         if: always()
         with:
           name: playwright-report
           path: frontend/playwright-report/
           retention-days: 7
+          if-no-files-found: ignore
frontend/e2e/apply-flow.spec.ts (2)

11-28: 중복 헬퍼는 공통 유틸로 추출 권장

main-page.spec.ts와 동일한 closePopupIfExists가 중복되어 유지보수 비용이 커집니다. 공통 유틸로 분리해 import하는 쪽이 안정적입니다.


108-110: toHaveURL은 정규식 대신 문자열 매칭으로 단순화 권장

MOCK 상수 기반이라 위험도는 낮지만, 정규식 생성 경고가 계속 남습니다. toHaveURL에 문자열을 넘기면 경고 제거 + 가독성 향상 효과가 있습니다.

🔧 제안 수정안
-    await expect(page).toHaveURL(new RegExp(`/clubDetail/${MOCK_CLUB_ID}`), {
+    await expect(page).toHaveURL(`/clubDetail/${MOCK_CLUB_ID}`, {
       timeout: 10000,
     });

-    await expect(page).toHaveURL(
-      new RegExp(`/application/${MOCK_CLUB_ID}/${MOCK_FORM_ID}`),
-      { timeout: 10000 },
-    );
+    await expect(page).toHaveURL(
+      `/application/${MOCK_CLUB_ID}/${MOCK_FORM_ID}`,
+      { timeout: 10000 },
+    );

-    await expect(page).toHaveURL(new RegExp(`/clubDetail/${MOCK_CLUB_ID}`), {
+    await expect(page).toHaveURL(`/clubDetail/${MOCK_CLUB_ID}`, {
       timeout: 10000,
     });

Also applies to: 123-125, 153-155

Comment on lines +15 to +24
} else if (
import.meta.env.DEV &&
disableMsw &&
'serviceWorker' in navigator
) {
// 남아 있는 MSW 서비스워커가 e2e 실행에 영향을 주지 않도록 정리
const registrations = await navigator.serviceWorker.getRegistrations();
await Promise.all(
registrations.map((registration) => registration.unregister()),
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

MSW 비활성화 시 모든 서비스워커 제거는 과도합니다

VITE_DISABLE_MSW=true일 때 전체 등록을 해제하면 MSW 외 다른 서비스워커까지 제거될 수 있어 dev 동작이 깨질 수 있습니다. MSW 워커만 필터링해서 해제하는 쪽이 안전합니다.

🔧 MSW 워커만 해제하도록 필터링
-    const registrations = await navigator.serviceWorker.getRegistrations();
-    await Promise.all(
-      registrations.map((registration) => registration.unregister()),
-    );
+    const registrations = await navigator.serviceWorker.getRegistrations();
+    const mswRegistrations = registrations.filter((registration) =>
+      [registration.active, registration.waiting, registration.installing].some(
+        (sw) => sw?.scriptURL.includes('mockServiceWorker.js'),
+      ),
+    );
+    await Promise.all(mswRegistrations.map((r) => r.unregister()));
🤖 Prompt for AI Agents
In `@frontend/src/index.tsx` around lines 15 - 24, Currently the code blindly
unregisters all service workers via navigator.serviceWorker.getRegistrations()
and registrations.map(...unregister()), which can remove non-MSW workers;
instead, filter registrations to only target MSW's worker by checking each
registration's scriptURL or active?.scriptURL for the MSW filename (e.g.,
"mockServiceWorker" or the configured MSW script name) and only call
unregister() on those matches; update the logic around
navigator.serviceWorker.getRegistrations(), the registrations.map/unregister
call, and any surrounding DEV + disableMsw guard to perform this
filtered-unregister behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend ✅ Test test 관련(storybook, jest...)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants