Conversation
Walkthrough이번 변경은 Prisma ORM 설정 명령어 수정, 서버 측 HTML 요청에 대한 인증 미들웨어 도입 및 개선, 리프레시 토큰 로직을 비동기로 전환하고 기존의 마운트 차단 로직을 제거하는 내용을 포함합니다. 또한, 레이아웃 컴포넌트와 라우팅 구조가 재구성되고, 관련 import 경로와 내보내기 방식, 테스트 파일 및 스토어 메서드가 업데이트되어 코드베이스의 구조와 일관성이 개선되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant S as Server
participant AM as AuthMiddleware
participant TS as TokenService
C->>S: HTML 요청 전송
S->>AM: preHandler Hook 호출
alt 요청이 보호된 경로인 경우
AM->>AM: refreshToken 쿠키 확인
alt 쿠키 없음
AM-->>C: 로그인 페이지로 리디렉션
else 쿠키 있음
AM->>AM: 쿠키 서명 검증
alt 서명 오류
AM-->>C: 로그인 페이지로 리디렉션
else 서명 유효
AM->>TS: refreshToken 검증 요청
alt 토큰 검증 실패
AM-->>C: 쿠키 삭제 후 로그인 페이지로 리디렉션
else 토큰 검증 성공
AM->>S: 사용자 정보 첨부 후 요청 전달
end
end
end
else
AM-->>S: 요청 그대로 진행
end
sequenceDiagram
participant App as Application
participant AF as API Client
participant RT as refreshToken()
participant LS as Logout Service
App->>AF: API 요청 전송
AF->>AF: 응답 실패 (401)
AF->>RT: refreshTokenPromise 없음? → 호출
RT-->>AF: 새 액세스 토큰 반환
alt 토큰 갱신 성공
AF->>App: 재요청 성공 응답 전달
else
AF->>LS: 로그아웃 처리 (await)
AF->>App: 실패 응답 전달
end
Assessment against linked issues
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (4)
🧰 Additional context used🧬 Code Definitions (1)src/components/layout/UserLayout.test.tsx (2)
🔇 Additional comments (4)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🔭 Outside diff range comments (4)
src/hooks/__test__/useInitToken.test.ts (3)
17-25:⚠️ Potential issue테스트 케이스 업데이트 필요
useInitToken훅이 더 이상isPending속성을 반환하지 않는 것으로 보입니다. 이 테스트 케이스를 업데이트하여 변경된 훅의 동작과 인터페이스에 맞게 조정해야 합니다.test('refresh 요청이 성공하면 accessToken을 초기화하고 isPending을 false로 설정한다', async () => { const { result } = renderHook(() => useInitToken()) - expect(result.current.isPending).toBe(true) - await waitFor(() => expect(result.current.isPending).toBe(false)) + // 변경된 useInitToken 훅 인터페이스에 맞게 테스트 케이스 수정 필요 + // 예: useInitToken이 이제 객체가 아닌 경우 + await waitFor(() => {/* 적절한 완료 조건 */}) expect(useAuthStore.getState().setAccessToken).toHaveBeenCalledWith( 'new-mock-access-token', ) })🧰 Tools
🪛 GitHub Check: test
[failure] 20-20: src/hooks/test/useInitToken.test.ts > useInitToken 훅 테스트 > refresh 요청이 성공하면 accessToken을 초기화하고 isPending을 false로 설정한다
TypeError: Cannot read properties of undefined (reading 'isPending')
❯ src/hooks/test/useInitToken.test.ts:20:27🪛 GitHub Actions: Test
[error] 20-20: Cannot read properties of undefined (reading 'isPending')
27-42:⚠️ Potential issue두 번째 테스트 케이스도 업데이트 필요
마찬가지로 refresh 실패 테스트 케이스도
isPending속성이 더 이상 존재하지 않는 것으로 보이기 때문에 수정이 필요합니다.test('refresh 요청이 실해하면 accessToken을 초기화하지 않고 isPending을 false로 설정한다', async () => { mswServer.use( http.post(`${BASE_URL}/${END_POINTS.AUTH}/refresh`, () => { return mswResponse({ status: 400, error: getErrorResponse('INVALID_REQUEST'), }) }), ) const { result } = renderHook(() => useInitToken()) - expect(result.current.isPending).toBe(true) - await waitFor(() => expect(result.current.isPending).toBe(false)) + // 변경된 useInitToken 훅 인터페이스에 맞게 테스트 케이스 수정 필요 + // 예: 비동기 요청 완료를 확인하는 다른 방법 사용 + await waitFor(() => {/* 적절한 완료 조건 */}) expect(useAuthStore.getState().setAccessToken).not.toHaveBeenCalled() })🧰 Tools
🪛 GitHub Check: test
[failure] 39-39: src/hooks/test/useInitToken.test.ts > useInitToken 훅 테스트 > refresh 요청이 실해하면 accessToken을 초기화하지 않고 isPending을 false로 설정한다
TypeError: Cannot read properties of undefined (reading 'isPending')
❯ src/hooks/test/useInitToken.test.ts:39:27🪛 GitHub Actions: Test
[error] 39-39: Cannot read properties of undefined (reading 'isPending')
10-43: 🛠️ Refactor suggestion테스트 설명 및 이름 업데이트 필요
테스트 함수 이름과 설명에
isPending에 대한 언급이 있습니다. 하지만useInitToken훅의 인터페이스가 변경되어 더 이상isPending을 반환하지 않는 것으로 보입니다. 테스트 이름과 설명을 현재 훅의 기능에 맞게 업데이트해야 합니다.-test('refresh 요청이 성공하면 accessToken을 초기화하고 isPending을 false로 설정한다', async () => { +test('refresh 요청이 성공하면 accessToken을 초기화한다', async () => { // 테스트 구현... }) -test('refresh 요청이 실해하면 accessToken을 초기화하지 않고 isPending을 false로 설정한다', async () => { +test('refresh 요청이 실패하면 accessToken을 초기화하지 않는다', async () => { // 테스트 구현... })또한 "실해하면"은 "실패하면"의 오타로 보입니다. 수정이 필요합니다.
🧰 Tools
🪛 GitHub Check: test
[failure] 20-20: src/hooks/test/useInitToken.test.ts > useInitToken 훅 테스트 > refresh 요청이 성공하면 accessToken을 초기화하고 isPending을 false로 설정한다
TypeError: Cannot read properties of undefined (reading 'isPending')
❯ src/hooks/test/useInitToken.test.ts:20:27
[failure] 39-39: src/hooks/test/useInitToken.test.ts > useInitToken 훅 테스트 > refresh 요청이 실해하면 accessToken을 초기화하지 않고 isPending을 false로 설정한다
TypeError: Cannot read properties of undefined (reading 'isPending')
❯ src/hooks/test/useInitToken.test.ts:39:27🪛 GitHub Actions: Test
[error] 20-20: Cannot read properties of undefined (reading 'isPending')
[error] 39-39: Cannot read properties of undefined (reading 'isPending')
src/components/layout/UserLayout.test.tsx (1)
31-37: 💡 Verification agent❓ Verification inconclusive
파이프라인 오류를 조사해 보세요.
screen.getByTestId('test-login-page')를 찾지 못하는 문제로 보아, 인증 정보 변경 이후에 라우팅이나 컴포넌트가 적절히 다시 렌더링되지 않았을 수 있습니다.다음 스크립트를 통해 테스트가 실패하는 정확한 이유를 확인한 뒤, 라우팅 변경이나 상태 업데이트 시점 등을 점검해 보세요:
🏁 Script executed:
#!/bin/bash # 테스트 실패에 대한 원인 파악을 위해 대상 테스트만 단독 실행 # Vitest 또는 Jest를 사용하신다면, 특정 테스트 파일만 실행할 수 있습니다. # 예: npx vitest run src/components/layout/UserLayout.test.tsx npx vitest run src/components/layout/UserLayout.test.tsxLength of output: 933
파이프라인 및 환경 구성 문제 확인 필요
- 실행한 스크립트 결과, 테스트 환경에서
vitest패키지를 찾지 못하는 설정 오류가 발생했습니다. 이는 라우팅이나 컴포넌트 재렌더링 문제와 별개로, 테스트 실행 환경 자체가 올바르게 구성되지 않았음을 의미합니다.- 우선
vite.config.ts와 테스트 실행에 필요한 의존성(특히vitest)이 제대로 설치되어 있는지 확인 및 수정해 주세요.- 환경 설정이 정상화된 이후, 인증 상태 변경 후 컴포넌트가 올바르게 렌더링되는지 재검증해 보시기 바랍니다.
🧰 Tools
🪛 GitHub Check: test
[failure] 36-36: src/components/layout/UserLayout.test.tsx > UserLayout 컴포넌트 테스트 > 인증되지 않은 상태에서 로그인 페이지로 리다이렉트 된다
TestingLibraryElementError: Unable to find an element by: [data-testid="test-login-page"]Ignored nodes: comments, script, style
- footer.friend
- footer.chat
-import UserCard from 'src/components/domain/UserCard' -import UserCardSkeleton from '#components/domain/UserCard/UserCard.skeleton.tsx' +import UserCard from '#components/domain/UserCard' +import UserCardSkeleton from '#components/domain/UserCard/UserCard.skeleton.tsx'또는:
-import UserCard from 'src/components/domain/UserCard' -import UserCardSkeleton from '#components/domain/UserCard/UserCard.skeleton.tsx' +import UserCard from 'src/components/domain/UserCard' +import UserCardSkeleton from 'src/components/domain/UserCard/UserCard.skeleton.tsx'src/components/layout/VisitorLayout.test.tsx (1)
39-41: 테스트 설명 업데이트 필요39줄의 테스트 설명에서 여전히 'Outlet'을 언급하고 있지만, 이제는 VisitorLayout 컴포넌트를 테스트하고 있습니다.
-it('인증되지 않은 상태에서는 Outlet이 올바르게 렌더링된다', () => { +it('인증되지 않은 상태에서는 VisitorLayout 내부의 Outlet이 올바르게 렌더링된다', () => {server/main.ts (1)
45-58: HTML 요청에 대한 인증 로직 추가가 적절합니다.
HTML 요청(text/html)이면서/api/주소가 아닌 경우에만authMiddleware를 적용하여 일반 페이지에 대한 접근 제어가 가능해졌습니다. 다만, 향후 SSR 라우팅에 미들웨어가 예상치 못한 영향을 주지 않도록 주기적인 테스트가 필요합니다.src/App.tsx (1)
13-13: useInitToken 훅 호출 위치 확인
App컴포넌트 내에서 바로 호출함으로써, 마운트 시 토큰 초기화가 처리됩니다. 렌더링 차질이 없는지 확인해 주세요.server/middlewares/authMiddleware.ts (1)
5-10:isProtectedRoute함수의 단순화 가능성
현재some메서드를 통해 특정 URL을 보호 대상으로 판단하고 있습니다. 추후 라우트 패턴이 복잡해지면 정규식이나 별도 매핑 로직을 고려해 보셔도 좋겠습니다.src/routes/routes.tsx (1)
5-5: 전역 Error 객체 이름 충돌 주의
Error컴포넌트 이름이 JavaScript 전역Error객체와 충돌할 가능성이 있습니다. 정적 분석 도구에서도 이 문제를 지적하고 있습니다. 컴포넌트 이름을ErrorPage,ErrorView또는ErrorComponent와 같이 변경하는 것이 좋습니다.🧰 Tools
🪛 Biome (1.9.4)
[error] 5-5: Do not shadow the global "Error" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (33)
README.md(1 hunks)server/entry.tsx(1 hunks)server/main.ts(4 hunks)server/middlewares/authMiddleware.ts(1 hunks)server/routes/auth/route.ts(1 hunks)src/App.tsx(1 hunks)src/apis/apiClient.ts(2 hunks)src/components/Layout/index.tsx(0 hunks)src/components/VisitorOutlet/index.tsx(0 hunks)src/components/layout/Footer.test.tsx(1 hunks)src/components/layout/Footer.tsx(1 hunks)src/components/layout/UserLayout.test.tsx(1 hunks)src/components/layout/UserLayout.tsx(1 hunks)src/components/layout/VisitorLayout.test.tsx(1 hunks)src/components/layout/VisitorLayout.tsx(1 hunks)src/contexts/QueryProvider/index.tsx(1 hunks)src/hooks/__test__/useInitToken.test.ts(1 hunks)src/hooks/useInitToken.ts(2 hunks)src/main.tsx(1 hunks)src/pages/Chat/index.tsx(1 hunks)src/pages/Friend/index.tsx(1 hunks)src/pages/FriendFind/index.tsx(1 hunks)src/pages/Home/Home.test.tsx(1 hunks)src/pages/Home/index.tsx(1 hunks)src/pages/Login/Login.test.tsx(1 hunks)src/pages/Login/index.tsx(1 hunks)src/pages/Register/Register.test.tsx(1 hunks)src/pages/Register/index.tsx(1 hunks)src/queries/auth/useLoginMutation.ts(1 hunks)src/queries/auth/useRegisterMutation.ts(1 hunks)src/routes/path.ts(1 hunks)src/routes/routes.tsx(4 hunks)src/stores/authStore.ts(1 hunks)
💤 Files with no reviewable changes (2)
- src/components/Layout/index.tsx
- src/components/VisitorOutlet/index.tsx
🧰 Additional context used
🧬 Code Definitions (5)
src/components/layout/VisitorLayout.tsx (2)
src/stores/authStore.ts (1)
useAuthStore(12-28)src/routes/path.ts (1)
PATH(1-14)
src/apis/apiClient.ts (2)
src/stores/authStore.ts (1)
useAuthStore(12-28)server/routes/path.ts (2)
API_URL(2-3)END_POINTS(5-10)
src/App.tsx (1)
src/hooks/useInitToken.ts (1)
useInitToken(5-22)
server/main.ts (1)
server/middlewares/authMiddleware.ts (1)
authMiddleware(13-52)
src/routes/routes.tsx (2)
src/components/layout/VisitorLayout.tsx (1)
VisitorLayout(6-21)src/components/layout/UserLayout.tsx (1)
UserLayout(6-18)
🪛 GitHub Actions: Test
src/pages/Register/Register.test.tsx
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
src/pages/Login/Login.test.tsx
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
src/pages/Home/Home.test.tsx
[error] 51-51: expected "spy" to be called with arguments: [ '/chat', { replace: true } ]
src/hooks/__test__/useInitToken.test.ts
[error] 20-20: Cannot read properties of undefined (reading 'isPending')
[error] 39-39: Cannot read properties of undefined (reading 'isPending')
src/components/layout/UserLayout.test.tsx
[error] 36-36: Unable to find an element by: [data-testid="test-login-page"]
🪛 Biome (1.9.4)
src/routes/routes.tsx
[error] 5-5: Do not shadow the global "Error" property.
Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.
(lint/suspicious/noShadowRestrictedNames)
🔇 Additional comments (49)
server/entry.tsx (1)
10-10: 절대 경로 사용 검토
기존 상대 경로('../src/routes')에서 절대 경로('#routes/routes.tsx')로 임포트 경로가 변경되었습니다. 다른 모듈들과 일관성이 유지되는지, 그리고 해당 경로가 올바르게 해석되는지 재확인 부탁드립니다.src/queries/auth/useLoginMutation.ts (1)
9-10: 라우트 경로 업데이트 확인
PATH변수의 임포트 경로가#routes/path.ts로 변경되었습니다. 이 변경으로 인해navigate(PATH.CHAT, { replace: true })가 의도한 대로 작동하는지 추가 테스트해주시기 바랍니다.src/queries/auth/useRegisterMutation.ts (1)
8-9: 라우트 경로 변경 점검
PATH모듈의 경로가#routes/path.ts로 업데이트되었습니다. 이 변경이 어플리케이션 전반의 라우팅 로직과 일관되게 통합되어 있는지 확인해주세요.src/components/layout/Footer.test.tsx (1)
6-6: 테스트 파일 내 경로 업데이트 검증
테스트 파일에서도PATH의 임포트 경로가#routes/path.ts로 변경되었습니다. 변경된 경로가 테스트 케이스에 문제없이 반영되는지 확인 부탁드립니다.src/components/layout/Footer.tsx (1)
6-6: PATH 임포트 경로 구조 개선경로 상수를 별도의
path.ts파일로 분리한 것은 코드 구조를 개선하는 좋은 리팩토링입니다. 이렇게 하면 경로 정의를 중앙화하여 유지보수성을 높이고 일관성을 보장할 수 있습니다.src/stores/authStore.ts (1)
9-9: logout 메서드 타입 시그니처 수정
logout메서드의 반환 타입을void에서Promise<void>로 변경한 것은 비동기 구현과 일치시키는 올바른 접근입니다. 이제 이 메서드를 사용하는 쪽에서await를 통해 적절히 처리할 수 있게 되었습니다.src/pages/Login/Login.test.tsx (1)
9-9:Details
❓ Verification inconclusive
PATH 임포트 경로 업데이트 및 파이프라인 오류
경로 상수를
#routes/path.ts로 분리한 리팩토링은 좋은 변화입니다. 그러나 파이프라인 실패 로그에 따르면 컴포넌트 임포트와 관련된 오류가 발생하고 있습니다.오류 메시지: "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined."
이는 다음과 같은 원인이 있을 수 있습니다:
- 컴포넌트가 소스 파일에서 올바르게 내보내지지 않음
- 기본 내보내기와 명명된 내보내기/임포트 간의 불일치
- 임포트 경로가 잘못됨
이 문제를 해결하기 위해 관련 컴포넌트 파일들을 확인해 보세요:
🏁 Script executed:
#!/bin/bash # 임포트 문제가 있는 컴포넌트 파일 확인 echo "1. 경로 관련 파일 확인:" cat src/routes/path.ts || echo "path.ts 파일이 없습니다" echo "\n2. 이전 경로 파일 확인:" cat src/routes.tsx || echo "routes.tsx 파일이 없습니다" echo "\n3. 경로 사용 패턴 확인:" grep -r "import { PATH }" src/ --include="*.tsx" --include="*.ts" | head -n 10Length of output: 1425
경로 상수 업데이트 검증 및 추가 확인 필요
src/routes/path.ts파일이 존재하며, 올바르게export const PATH = { ... }방식으로 상수를 내보내고 있음을 확인했습니다.- 이전 경로 파일인
src/routes.tsx는 더 이상 존재하지 않아, 경로 리팩토링이 올바르게 반영된 것으로 보입니다.- 전체 코드베이스에서
import { PATH } from '#routes/path.ts'구문이 일관되게 사용되고 있어 임포트 경로 관련 문제는 해결된 것으로 확인됩니다.- 파이프라인 오류 메시지 "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined."는 PATH 상수 자체와는 직접적인 연관이 없어 보입니다. 해당 오류는 컴포넌트의 내보내기 방식(명명된 내보내기/기본 내보내기) 문제일 가능성이 있으므로, 관련 컴포넌트의 export 방식이 올바른지 함께 검토해 주시기 바랍니다.
src/pages/Chat/index.tsx (1)
9-16: 비동기 로그아웃 처리 개선을 잘 구현하셨습니다!로그아웃 함수를 비동기적으로 처리하고
await를 사용하여 완료된 후에만 페이지를 새로고침하도록 수정한 것은 매우 좋은 변경사항입니다. 이렇게 하면 로그아웃 프로세스가 완전히 완료되기 전에 페이지가 새로고침되는 잠재적인 문제를 방지할 수 있습니다.src/pages/Register/index.tsx (1)
13-13: 라우팅 구조 개선이 잘 적용되었습니다.
PATH상수의 import 경로를#routes.tsx에서#routes/path.ts로 변경한 것은 코드 구조를 개선하는 좋은 변화입니다. 이렇게 함으로써 라우트 경로 정의와 라우트 구성을 분리하고, 경로 상수를 한 곳에 집중시켜 유지보수성을 높였습니다.src/main.tsx (1)
6-6: 라우팅 모듈의 구조 개선이 일관되게 적용되었습니다.라우트 import 경로를
./routes.tsx에서./routes/routes.tsx로 변경한 것은 전체적인 라우팅 시스템 재구성의 일부로 잘 적용되었습니다. 이러한 구조 변경은 코드의 조직화를 개선하고, 관심사의 분리를 명확히 하며, 애플리케이션이 성장함에 따라 유지보수성을 향상시킵니다.src/pages/Login/index.tsx (1)
13-13: 라우팅 구조 변경이 일관성 있게 적용되었습니다.
PATH상수의 import 경로를#routes.tsx에서#routes/path.ts로 변경한 점은 Register 컴포넌트와 동일하게 적용되었습니다. 이는 전체 코드베이스에서 일관된 방식으로 경로 상수를 가져오도록 하여 코드의 일관성과 가독성을 향상시켰습니다.src/pages/Home/Home.test.tsx (2)
9-9: import 경로 변경이 적절하게 이루어졌습니다.routes 모듈에서 PATH를 별도 파일로 분리하여 조직화한 것은 좋은 변경입니다. 이렇게 하면 라우팅 관련 상수를 더 명확하게 관리할 수 있습니다.
51-51:Details
❓ Verification inconclusive
테스트 실패 해결 필요: PATH.CHAT 값 검증이 필요합니다.
파이프라인 실패 로그에 따르면 이 테스트에서
mockNavigate가[ '/chat', { replace: true } ]인수로 호출될 것으로 예상했으나 실제로는 다른 값이 전달되고 있습니다. PATH.CHAT의 값이 변경되었거나 다른 경로로 리다이렉트되고 있을 수 있습니다.경로 값을 확인하기 위해 아래 스크립트를 실행해 보시기 바랍니다:
🏁 Script executed:
#!/bin/bash # src/routes/path.ts 파일에서 PATH.CHAT 값 확인 cat src/routes/path.tsLength of output: 370
검증 결과: PATH.CHAT 값은 예상대로
/chat으로 정의되어 있습니다.
파이프라인 실패 로그에서 지적한 문제는 PATH 정의의 문제가 아니라, 테스트 대상 코드에서mockNavigate가 올바른 인수를 전달하고 있지 않음을 의미하는 것으로 보입니다. 즉, 현재 코드에서는mockNavigate호출 시 예상과 다른 인수가 전달되고 있어, 리다이렉트 경로가 변경되었거나 다른 로직 문제일 가능성이 높습니다.
- 확인 사항:
src/routes/path.ts파일 내 PATH 정의가 올바릅니다.- 실제
mockNavigate호출부가 PATH.CHAT를 사용하지 않거나, 다른 인수를 전달하는지 코드 검토가 필요합니다.테스트 실패 원인이 PATH 정의 자체가 아니라 호출부 로직에 있을 가능성이 있으므로, 해당 테스트 케이스와 실제 리다이렉트 로직을 다시 점검해 주시기 바랍니다.
🧰 Tools
🪛 GitHub Check: test
[failure] 51-51: src/pages/Home/Home.test.tsx > Home 페이지 기능 테스트 > 인증 상태가 true일 때 채팅 페이지로 리다이렉트한다
AssertionError: expected "spy" to be called with arguments: [ '/chat', { replace: true } ]Received:
Number of calls: 0
❯ src/pages/Home/Home.test.tsx:51:26
🪛 GitHub Actions: Test
[error] 51-51: expected "spy" to be called with arguments: [ '/chat', { replace: true } ]
src/components/layout/UserLayout.tsx (2)
1-18: 사용자 레이아웃 구조가 잘 설계되었습니다.UserLayout 컴포넌트가 Header, main content 영역, Footer를 포함하는 명확한 구조로 잘 구현되었습니다. Outlet을 사용하여 중첩된 라우트의 내용을 표시하는 방식도 적절합니다. useLocation을 통해 가져온 pathname을 Footer에 전달하여 현재 경로에 따른 동적 표시를 가능하게 한 점도 좋은 설계입니다.
12-12: 현대적인 CSS 사용이 적절합니다.
h-[calc(100dvh-7.5rem)]에서dvh단위를 사용하여 모바일 기기의 동적 뷰포트 높이를 정확하게 계산한 것은 좋은 접근입니다. 또한overflow-y: auto를 적용하여 내용이 넘칠 경우 스크롤이 생기도록 한 점도 사용자 경험을 향상시킵니다.src/components/layout/VisitorLayout.tsx (3)
1-21: 방문자 레이아웃 컴포넌트의 구조와 인증 처리가 잘 구현되었습니다.VisitorLayout 컴포넌트가 인증되지 않은 사용자를 위한 레이아웃을 적절하게 처리하고 있습니다. 인증 상태를 확인하여 인증된 사용자를 리다이렉트하는 로직이 잘 구현되었습니다. Outlet을 사용하여 중첩된 라우트의 내용을 표시하는 방식도 적절합니다.
11-12: URL 검색 매개변수를 활용한 리다이렉트 처리가 좋습니다.URL 검색 매개변수에서 리다이렉트 URL을 추출하고, 없을 경우 기본값으로 PATH.CHAT을 사용하는 방식은 유연한 네비게이션 처리를 가능하게 합니다. 이는 사용자 경험을 향상시키는 좋은 패턴입니다.
14-18: useEffect의 의존성 배열이 정확합니다.useEffect에 isAuthenticated, navigate, redirectUrl을 의존성 배열에 포함시켜 이 값들이 변경될 때만 효과가 실행되도록 한 것은 좋은 구현입니다. 이는 불필요한 리다이렉트를 방지하고 성능을 최적화합니다.
src/pages/Register/Register.test.tsx (3)
10-10: import 경로 변경이 적절하게 이루어졌습니다.routes 모듈에서 PATH를 별도 파일로 분리하여 조직화한 것은 좋은 변경입니다. 이는 다른 파일에서의 변경과 일관성을 유지합니다.
62-62: PATH.CHAT 값 검증이 필요합니다.성공적인 회원가입 후 사용자가 PATH.CHAT으로 리다이렉트되는 테스트에서, PATH.CHAT의 실제 값이 테스트 기대값과 일치하는지 확인해야 합니다. Home.test.tsx에서도 유사한 이슈가 발견되었습니다.
1-86:Details
❓ Verification inconclusive
컴포넌트 import/export 오류를 해결해야 합니다.
파이프라인 실패 로그에 따르면 "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined" 오류가 발생하고 있습니다. 이는 컴포넌트가 undefined로 평가되어 렌더링할 수 없다는 의미입니다.
다음 사항을 확인해 보세요:
- Register 컴포넌트가 제대로 export되었는지 확인
- 관련 컴포넌트들의 import/export 구문이 올바른지 확인
- default export와 named export가 혼합되어 사용되지 않았는지 확인
컴포넌트 구조를 확인하기 위해 아래 스크립트를 실행해 보세요:
🏁 Script executed:
#!/bin/bash # Register 컴포넌트 파일 확인 cat src/pages/Register/index.tsxLength of output: 3524
컴포넌트 Export 검증 결과 및 추가 확인 요청
Register 페이지의 컴포넌트 파일(
src/pages/Register/index.tsx)을 확인한 결과, 기본(default) export가 올바르게 처리되어 있음을 확인했습니다. 테스트 파일(src/pages/Register/Register.test.tsx)에서의 import도 정상적으로 이루어지고 있음을 확인하였습니다.다만, 파이프라인에서 발생한 “Element type is invalid … got: undefined” 오류는 해당 컴포넌트 외 다른 의존 컴포넌트(예:
#components/_common/Button,#components/_common/Input,#components/_common/Label,#components/_common/ErrorMessage)나 경로 alias 설정, 혹은react-router관련 import 설정 문제에서 기인할 수 있습니다. 아래 사항들을 추가로 확인해 보시기 바랍니다:
의존 컴포넌트 export 확인:
#components/_common/Button,Input,Label,ErrorMessage등 해당 컴포넌트들이 올바르게 export 되었는지 확인- 각 컴포넌트의 import 구문과 사용법이 일치하는지 검토
경로 alias 설정 점검:
#components/_common/와 같이 사용하는 alias가 올바르게 설정되어 있는지 확인React Router 관련 확인:
- 현재
useNavigate를react-router에서 import하고 있는데, 필요시react-router-dom사용 여부도 점검위 사항들을 확인 후, 문제의 원인에 따른 수정이 필요하다면 적절한 조치를 취해주시기 바랍니다.
🧰 Tools
🪛 GitHub Actions: Test
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
[error] 1-1: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
src/routes/path.ts (2)
1-14: 라우트 경로 상수화 구현이 잘 되었습니다.경로를 상수로 관리하는 방식이 잘 구현되었습니다. 경로를 하드코딩하는 대신 이런 방식으로 관리하면 경로 변경 시 한 곳만 수정하면 되어 유지보수성이 크게 향상됩니다. 또한
chatRoom함수를 통해 동적 세그먼트가 있는 경로를 생성하는 방식도 좋습니다.
as const를 사용하여 객체를 불변으로 만든 것도 타입 안전성을 높이는 좋은 방법입니다.
16-17: 보호된 라우트 분리가 효과적입니다.인증이 필요한 라우트를 별도의 배열로 분리한 접근 방식이 좋습니다. 이를 통해 인증 미들웨어에서 쉽게 참조할 수 있으며, 보호된 라우트 목록을 한 곳에서 관리할 수 있습니다.
src/pages/Friend/index.tsx (1)
5-8: 임포트 경로 업데이트가 적절합니다.임포트 경로가 업데이트되어 이제 상대 경로와 새로운 경로 모듈을 사용하고 있습니다. 이는 코드베이스의 구조 변경을 반영하는 좋은 변화입니다.
특히
UserCard컴포넌트를src/components/domain/UserCard에서 가져오고PATH를#routes/path.ts에서 가져오는 것은 컴포넌트와 라우트의 조직적인 구조화를 보여줍니다.src/hooks/useInitToken.ts (3)
2-2: 임포트 간소화가 적절합니다.useState 훅이 더 이상 사용되지 않아 임포트에서 제거된 것이 적절합니다. 사용하지 않는 임포트를 제거하는 것은 코드 정리에 도움이 됩니다.
5-5: export 방식 변경이 적절합니다.기본 내보내기(default export)에서 명명된 내보내기(named export)로 변경된 것은 일관된 모듈 패턴을 따르는 좋은 접근입니다. 이는 다른 파일들에서도 동일하게 적용된 패턴으로 보입니다.
18-20: 비동기 처리가 간소화되었습니다.이전 코드에서는 isPending 상태를 사용하여 초기화 진행 상태를 추적했지만, 이제는 간소화되었습니다. 이는 컴포넌트 렌더링 차단 없이 토큰을 초기화하는 좋은 접근법입니다.
다만
// noinspection JSIgnoredPromiseFromCall주석은 무시된 프로미스 경고를 방지하기 위한 것으로 보입니다. 이상적으로는 프로미스를 적절히 처리하는 것이 좋지만, 이 경우에는 초기화 프로세스가 UI에 영향을 주지 않도록 하는 의도가 분명해 보입니다.src/contexts/QueryProvider/index.tsx (1)
26-26: export 방식 변경이 일관성 있습니다.기본 내보내기(default export)에서 명명된 내보내기(named export)로 변경된 것은 프로젝트 전체의 일관된 패턴을 따르는 좋은 변화입니다. 이는 다른 파일들(예: useInitToken.ts)에서도 동일하게 적용된 패턴으로 보입니다.
명명된 내보내기를 사용하면 IDE의 자동 완성 기능이 더 효과적으로 작동하고, 임포트 시 오타의 가능성을 줄일 수 있습니다. 또한 한 파일에서 여러 항목을 내보낼 때도 일관된 방식을 유지할 수 있어 좋습니다.
src/pages/Home/index.tsx (2)
6-6: import 경로 변경PATH의 import 경로가 '#routes.tsx'에서 '#routes/path.ts'로 변경되었습니다. 이는 라우팅 구조의 재구성을 반영하며, 프로젝트 전체적으로 일관성 있게 적용되어야 합니다.
8-61: 인증 관련 리다이렉션 로직 제거이전에 있던 useEffect와 useAuthStore를 사용한 인증 확인 및 리다이렉션 로직이 제거되었습니다. 이는 아마도 라우팅 구조의 변경으로 인해 인증 확인 로직이 다른 곳으로 이동되었기 때문일 것입니다.
인증 로직이 제거되었으니, 이제 이 컴포넌트는 인증 여부와 상관없이 항상 같은 내용을 렌더링합니다. 다른 곳(예: 라우터 구성, 레이아웃 컴포넌트 등)에서 인증 관련 리다이렉션을 처리하고 있는지 확인하는 것이 좋습니다.
src/components/layout/VisitorLayout.test.tsx (2)
5-8: 임포트 경로 및 컴포넌트 업데이트임포트 경로와 컴포넌트 이름이 업데이트되었습니다:
- useAuthStore 임포트에 .ts 확장자 추가
- VisitorOutlet 대신 VisitorLayout 컴포넌트 사용
- PATH 임포트 경로 변경됨
이 변경은 프로젝트 구조의 전반적인 재구성과 일치합니다.
16-16: 컴포넌트 변경VisitorOutlet에서 VisitorLayout으로 컴포넌트가 변경되었습니다. 이는 프로젝트 내 레이아웃 구조 변경의 일부로 보입니다.
src/components/layout/UserLayout.test.tsx (3)
7-8: import문 경로가 잘 변경되었습니다.
사용하려는 컴포넌트와 상수(PATH)를 정상적으로 가리키고 있는지 다시 한번 확인해 주시면 좋겠습니다.
10-10: 테스트 설명을 명확하게 바꾸셨네요.
UserLayout컴포넌트에 맞춰 테스트 설명을 잘 변경하셨습니다. 명확한 테스트 목적을 드러내고 있어 좋습니다.
16-16: 라우트 요소 설정이 합리적으로 보입니다.
새로 import한UserLayout을<Route element={…}>로 설정하여, 자식 라우트에 대해 일관된 레이아웃이 적용될 것으로 보입니다.server/main.ts (2)
13-13: 신규 인증 미들웨어 import 확인
authMiddleware를 올바르게 import하고 있으므로, 충돌이나 오타가 없는지 최종적으로 점검해 주세요.
116-116: 에러 로깅을 추가하셨습니다.
console에 에러를 출력할 때, 민감한 정보를 로깅하지 않도록 주의해 주세요. 필요하다면 에러 내용을 일부 마스킹하거나 상세 내용은 디버그 모드에서만 노출하도록 설계하는 것이 좋습니다.src/App.tsx (2)
5-5: useInitToken 훅 import를 명시적으로 바꾸셨네요.
named export로 변경되어 import도 맞춰서 수정하신 점이 좋습니다.
7-7: QueryProvider import도 명시적 변경이 잘 되었습니다.
Context provider 사용 시, named export 방식을 통해 가독성을 높일 수 있습니다.server/middlewares/authMiddleware.ts (2)
1-3: 주요 의존성 import가 적절해 보입니다.
FastifyRequest,FastifyReply, 그리고TokenService를 사용한 미들웨어 구성이 자연스럽습니다.
12-52: SSR 환경에서의 토큰 검증 흐름이 타당합니다.
isProtectedRoute를 통해 보호된 라우트인지 판별- 쿠키의
refreshToken서명 검증- 토큰 검증 실패 시 쿠키 제거 후 로그인 페이지로 리다이렉트
SSR 렌더링을 고려하는 환경에서도 상당히 자연스러운 흐름이며, 명시적 리다이렉트 코드를 통해 즉시 응답을 종료하므로 안정적입니다. 향후 쿠키 이름이나 경로 등이 변경될 경우 충돌 방지 차원에서 상수를 한 군데서 관리해도 좋겠습니다.
src/apis/apiClient.ts (4)
6-7: 토큰 리프레시 요청 중복 방지를 위한 효과적인 패턴 구현!
refreshTokenPromise변수를 통해 동시에 여러 토큰 리프레시 요청이 발생하는 것을 효과적으로 방지하고 있습니다. 이는 동시성 문제를 해결하고 불필요한 네트워크 요청을 줄이는 좋은 패턴입니다.
8-23: 토큰 리프레시 로직 분리 및 에러 처리가 잘 구현되었습니다!토큰 리프레시 로직을 별도의 함수로 분리하여 관심사 분리가 잘 되었습니다. 특히:
- Zustand 스토어를 컴포넌트 외부에서 접근할 때
getState()를 올바르게 사용- API 요청 후 적절하게 상태 업데이트
finally블록을 통해 성공/실패 여부와 관계없이refreshTokenPromise변수를 초기화하여 다음 리프레시 요청이 가능하도록 처리이러한 구현은 인증 토큰 관리의 안정성과 신뢰성을 높여줍니다.
34-37: 동시 토큰 리프레시 요청 방지 로직이 효과적으로 개선되었습니다!기존의 인라인 토큰 리프레시 로직을 개선하여:
- 이미 진행 중인 리프레시 요청이 있는지 확인
- 없으면 새로운 리프레시 요청 시작
- 있으면 기존 요청의 프로미스를 재사용
- 항상 토큰 리프레시가 완료될 때까지 대기
이 접근 방식은 동시성 문제를 효과적으로 해결하고 코드 유지보수성을 높입니다.
45-45: 로그아웃 프로세스 완료 보장을 위한 비동기 처리 적용!
logout함수를await로 처리하여 로그아웃 프로세스가 완전히 완료될 때까지 기다리도록 수정했습니다. 이는 로그아웃 과정에서 API 요청이나 상태 변경과 같은 비동기 작업이 모두 완료된 후에 다음 코드가 실행되도록 보장하여 상태 불일치 문제를 방지합니다.src/routes/routes.tsx (4)
3-3: App 컴포넌트 import 경로 업데이트App 컴포넌트의 import 경로가 상대 경로로 변경되었습니다. 이는 프로젝트 구조 개선의 일환으로 보입니다. 파일 확장자(.tsx)를 명시적으로 포함하는 것은 일부 번들러 설정이나 ESM 호환성에 도움이 될 수 있습니다.
7-8: 레이아웃 컴포넌트 구조 개선 및 의미있는 이름 변경레이아웃 관련 컴포넌트의 import가 개선되었습니다:
VisitorOutlet에서VisitorLayout으로,Layout에서UserLayout으로 이름이 변경되어 더 명확한 의미 전달- 전용
#components/layout/경로를 사용하여 컴포넌트 조직 구조 개선- 경로 별칭(
#)을 사용하여 import 일관성 향상이러한 변경은 코드베이스의 구조와 가독성을 크게 향상시킵니다.
20-20: 라우트 경로 정의의 중앙화로 유지보수성 향상
PATH상수를 별도의 모듈(#routes/path.ts)로 분리한 것은 다음과 같은 이점이 있습니다:
- 경로 정의 중앙화로 유지보수 용이성 증가
- 코드 중복 없이 여러 파일에서 경로 재사용 가능
- 경로 일관성 보장
- routes.tsx 파일의 복잡도 감소
이는 라우팅 코드의 구조적 개선으로 볼 수 있습니다.
41-41: 라우팅 구조에서 레이아웃 컴포넌트 업데이트라우팅 구조에서 레이아웃 컴포넌트 사용이 업데이트되었습니다. 새 컴포넌트 이름(
VisitorLayout,UserLayout)은 이전 이름보다 더 의미적으로 명확하여 이 컴포넌트들이 단순한 outlet이 아닌 레이아웃 역할을 한다는 것을 분명히 나타냅니다.Also applies to: 54-54
Summary by CodeRabbit
Documentation
New Features
Refactor
Tests