Skip to content

[FIX] 테스트 기능 수정 - #340

Merged
maylh merged 8 commits into
developfrom
fix/#338/test-func
Jan 22, 2026
Merged

[FIX] 테스트 기능 수정#340
maylh merged 8 commits into
developfrom
fix/#338/test-func

Conversation

@maylh

@maylh maylh commented Jan 21, 2026

Copy link
Copy Markdown
Collaborator

🛰️ 관련 이슈

해결한 이슈 번호를 작성해주세요
close #338

🧑‍💻 작업 내용

작업한 내용을 간략히 작성해주세요

  • 테스트 기능 미완료 부분 & 수정된 내용들 반영했습니다
    • onCloseClick 분기처리 (홈에서 왔으면 홈으로, 마이에서 왔으면 마이로)
    • 테스트 exceptLayout
    • 추천 받기 버튼 클릭 시 홈의 추천 섹션으로 이동

🗯️ PR 포인트

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

테스트 결과를 setQueryData로 캐시에만 저장하던 구조라 새로고침 시 결과 데이터가 유실되는 문제가 있어서

  1. 타입만 저장해두고 캐시가 비었을 때 해당 타입으로 다시 요청하는 방식
  2. 결과 response 자체를 세션에 저장하는 방식

결국 어떠한 값이든 저장해둬야 하는 구조라면 불필요한 요청을 줄일 수 있는 2번 방식이 나은 것 같아서 세션에 저장해두고 React Query 캐시가 없을 경우 세션에 저장된 데이터를 사용하도록 했습니다 해당 data는 /test 재진입 시 지워집니다

페이지 이동 후 특정 컴포넌트의 위치로 스크롤을 이동 시키는 useScrollToTarget 훅을 만들었습니다 라우터 넘길 때 scrollTo=targetId 쿼리 붙여서 넘겨주면 됩니다 ! 해시도 동작 안하고 앱라우터라 Route Masking도 안돼서 이렇게 함 ..

🚀 알게된 점

기록하며 개발하기!

📖 참고 자료 (선택)

참고했던 문서들 공유하기!

📸 스크린샷 (선택)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 테스트 완료 후 추천 섹션으로 자동 스크롤 이동
    • 테스트 결과 페이지에서 모바일 공유 기능 추가
    • 이전 페이지로 돌아가는 네비게이션 개선
  • 개선 사항

    • 테스트 재시작 시 이전 위치 유지
    • 에러 상태에서 추가 작업 옵션 제공
    • 테스트 페이지 흐름 및 상태 관리 개선

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

@maylh maylh self-assigned this Jan 21, 2026
@coderabbitai

coderabbitai Bot commented Jan 21, 2026

Copy link
Copy Markdown

📋 Walkthrough

테스트 기능 완성을 위해 페이지 네비게이션 흐름을 개선하고, 테스트 결과를 sessionStorage에 저장하여 관리하며, 이전 페이지 경로를 localStorage에 저장하여 동적 리다이렉션을 구현합니다. 또한 추천 섹션으로 스크롤하는 기능을 추가하고, 결과 페이지의 모바일 공유 기능을 확대합니다.

🗂️ Changes

Cohort / File(s) 변경 요약
테스트 흐름 네비게이션
src/apis/test/index.ts, src/app/test/page.tsx, src/app/myPage/page.tsx
테스트 시작 시 현재 페이지를 localStorage('prevPage')에 저장하고, 테스트 결과를 sessionStorage('test-result')에 저장. 테스트 페이지 닫기 시 저장된 prevPath로 되돌아가기 구현. myPage의 재테스트 버튼이 handleGoToTest 통일
인증 흐름 리다이렉션
src/apis/auth/index.ts
로그인 성공 후 sessionStorage의 'type'이 존재하면 테스트 결과를 저장하고 '/?scrollTo=recommend'로 리다이렉트, 아니면 '/'로 이동
결과 페이지 확장
src/app/test/result/page.tsx, src/app/test/result/resultPage.css.ts
동적 로딩(SSR 비활성화)으로 변경, sessionStorage의 폴백 데이터 지원, 모바일 공유 기능 추가, prevPath 기반 네비게이션, exceptButtonWrapper CSS 추가
UI 컴포넌트 수정
src/app/RecommendTempleClient.tsx, src/app/page.tsx, src/components/except/exceptLayout/ExceptLayout.tsx
RecommendTempleClient에서 TestType 동적 이미지 렌더링 및 useScrollToTarget 훅 추가. page.tsx에 id="recommend" 섹션 래퍼 추가. ExceptLayout에 children prop 지원
유틸리티 & 상수
src/hooks/useScrollToTarget.ts, src/constants/exceptInfos.ts
새로운 useScrollToTarget 훅으로 scrollTo 쿼리 파라미터 기반 부드러운 스크롤 구현. EXCEPT_INFOS의 testError.subtitle을 빈 문자열로 변경

🔄 Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TestPage as Test Page
    participant API as Test API
    participant SessionStor as sessionStorage
    participant ResultPage as Result Page
    participant AuthAPI as Auth API
    participant MainPage as Main Page

    User->>TestPage: 테스트 시작 (prevPage 저장)
    TestPage->>SessionStor: localStorage('prevPage') 저장
    User->>API: 테스트 제출
    API->>SessionStor: test-result 저장
    API->>ResultPage: 결과 페이지로 이동
    
    alt 로그인되지 않음
        ResultPage->>AuthAPI: 로그인
        AuthAPI->>SessionStor: type 확인
        AuthAPI->>MainPage: scrollTo=recommend 파라미터로 리다이렉트
        MainPage->>User: 추천 섹션으로 스크롤
    else 로그인된 상태
        ResultPage->>SessionStor: prevPath에서 복구
        ResultPage->>User: 이전 페이지로 이동
    end
Loading

🎯 Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🔗 Possibly related PRs

👥 Suggested reviewers

  • seong-hui
  • bykbyk0401
  • Taew00k

🐰 Poem

🐇 테스트의 길을 다시 걷고,
세션 어딘가 결과를 묻고,
추천으로 부드럽게 흘러,
이전 길도 기억하며,
완성된 기능, 환영합니다! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목 '[FIX] 테스트 기능 수정'은 풀 리퀘스트의 주요 변경사항을 포괄적으로 반영하며, 테스트 기능 개선이라는 핵심 의도를 명확히 전달합니다.
Description check ✅ Passed PR 설명은 템플릿 구조를 따르며 관련 이슈, 작업 내용, PR 포인트 등 필수 항목을 포함하고 있습니다. 기술 결정사항도 상세히 설명되어 있습니다.
Linked Issues check ✅ Passed PR 변경사항이 #338의 주요 목표들을 충족합니다: onCloseClick 분기처리 구현, 테스트 exceptLayout 수정, 결과 페이지에서 추천 섹션으로의 스크롤 이동을 모두 구현했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #338의 범위 내에 있습니다. 테스트 결과 캐싱, useScrollToTarget 훅, 페이지 네비게이션 로직 등 모두 명시된 목표 달성을 위한 필수 변경입니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

@github-actions

github-actions Bot commented Jan 21, 2026

Copy link
Copy Markdown

🪷 Storybook 확인 🪷
🔗 https://677fa9af1269762b7858c29f-aqtexigixk.chromatic.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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/test/page.tsx (1)

6-18: ESLint import/order 규칙 위반 정정 필요

현재 imports가 ESLint import/order 규칙을 위반합니다. 설정된 규칙에 따라 다음 순서로 정렬되어야 합니다: builtin (React, next/navigation) → external (cookies-next) → sibling/parent (./testPage.css) → internal (@/*) 각 그룹 사이에는 빈 줄이 필요합니다. eslint --fix로 자동 정렬하거나 수동으로 재정렬해주세요.

🤖 Fix all issues with AI agents
In `@src/apis/auth/index.ts`:
- Around line 34-47: The current flow always removes the session key from
sessionStorage in the finally block which prevents retry on
saveTestResultMutation.mutateAsync failure; change the logic so
sessionStorage.removeItem('type') is only called after a successful await of
saveTestResultMutation.mutateAsync (move it into the try after the await), add a
catch block to handle errors from saveTestResultMutation.mutateAsync (log or
surface an error/toast and leave the 'type' in sessionStorage for retry), and
ensure router.push(url) still runs with the correct url determined on success or
failure; refer to sessionStorage.getItem('type'),
saveTestResultMutation.mutateAsync, sessionStorage.removeItem('type'), and
router.push when making the change.

In `@src/app/test/page.tsx`:
- Line 26: The default for prevPath returned from getStorageValue('prevPage') is
an empty string which causes router.push('') to be called (invalid in Next.js);
change the default from '' to '/' so prevPath = getStorageValue('prevPage') ||
'/' and ensure any subsequent router.push(prevPath) receives a valid path; apply
the same change to other places using getStorageValue('prevPage') (e.g., in
SearchResultPageClient and the test result page) and verify router.push calls
rely on the sanitized prevPath variable.

In `@src/app/test/result/page.tsx`:
- Line 33: Change the default prevPath from an empty string to '/' so
router.push won't be called with an empty path: update the assignment where
prevPath is set (const prevPath = getStorageValue('prevPage') || '') to use '/'
as the fallback; ensure any subsequent usage such as router.push(prevPath) in
the same file (page.tsx) will correctly navigate to the home page when
getStorageValue('prevPage') returns null/undefined.
- Around line 5-26: Reorder the import statements to satisfy import/order: group
and sort imports, remove blank lines inside each group and keep a single blank
line between groups; specifically alphabetize external libs (e.g., move
`@tanstack/react-query`, cookies-next, html-to-image into correct alphabetical
order), then alphabetize component imports (PageBottomBtn, PopupBtn, KakaoBtn,
Bubble, ResultCard, TestHeader, ExceptLayout) and utility/hooks/constants
imports (getStorageValue, getTestType, TestType) within their groups, keep
next/dynamic, next/image, next/navigation in the framework group, and leave the
styles import in the local group; you can run npx eslint --fix to apply
auto-fixes or reorder manually ensuring no extra blank lines inside groups and
only one blank line between groups.

In `@src/hooks/useScrollToTarget.ts`:
- Around line 12-37: The useScrollToTarget effect (useScrollToTarget) currently
only relies on a MutationObserver so if the target element already exists at
effect run time the scroll is never triggered; fix by first checking
document.getElementById(targetId) immediately and calling performScroll(element)
if found, before instantiating the MutationObserver, otherwise keep the observer
logic as-is; reference performScroll, MutationObserver instance (observer) and
observer.observe to locate where to add the immediate existence check and early
performScroll call.
🧹 Nitpick comments (2)
src/constants/exceptInfos.ts (1)

12-16: 빈 subtitle 렌더링으로 여백이 남을 수 있습니다.
의도적으로 숨기는 거라면 null/undefined로 두고, 레이아웃에서 falsy면 렌더링하지 않도록 처리하는 편이 깔끔합니다.

src/apis/test/index.ts (1)

20-31: sessionStorage 예외 대비가 있으면 더 안전합니다.
차단된 환경(예: 일부 프라이빗 모드)에서 setItem이 예외를 던지면 이후 캐시/라우팅이 중단될 수 있어요. try/catch로 보호하는 쪽을 권장합니다.

🔒️ 방어 코드 예시
-      sessionStorage.setItem('test-result', JSON.stringify(data));
+      try {
+        sessionStorage.setItem('test-result', JSON.stringify(data));
+      } catch (e) {
+        console.error(e);
+      }

Comment thread src/apis/auth/index.ts
Comment on lines 34 to +47
// 비회원 상태에서 테스트 완료 후 로그인한 경우 테스트 결과 저장
const type = sessionStorage.getItem('type') as TestType;

let url = '/';

if (type) {
try {
await saveTestResultMutation.mutateAsync(type);
url = '/?scrollTo=recommend';
} finally {
sessionStorage.removeItem('type');
}
}
router.push('/');
router.push(url);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and view the exact code at lines 34-47
if [ -f "src/apis/auth/index.ts" ]; then
  echo "=== File content at lines 34-47 ==="
  sed -n '34,47p' src/apis/auth/index.ts | cat -n
  echo ""
  echo "=== Full context (lines 1-60) ==="
  head -60 src/apis/auth/index.ts | cat -n
else
  echo "File not found: src/apis/auth/index.ts"
  find . -name "index.ts" -path "*/auth/*" 2>/dev/null
fi

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 2724


🏁 Script executed:

# Search for saveTestResultMutation definition
rg "saveTestResultMutation" --max-count 20 -B 2 -A 2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 598


🏁 Script executed:

# Search for how sessionStorage 'type' is used elsewhere - check for retry patterns
rg "sessionStorage.*type|type.*sessionStorage" -B 2 -A 2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 928


저장 실패 시 type 삭제로 재시도 불가합니다.

mutateAsync 실패 시 finally에서 type을 지워서 결과 유실이 발생할 수 있습니다. 성공 시에만 삭제하거나 실패 시 별도 처리/재시도 방안을 추가해주세요.

🛠️ 수정 제안
      if (type) {
        try {
          await saveTestResultMutation.mutateAsync(type);
          url = '/?scrollTo=recommend';
+         sessionStorage.removeItem('type');
        } catch (e) {
+         console.error(e);
+         // 실패 시 type을 유지해 재시도 여지를 남기는 방안 고려
        }
-       } finally {
-         sessionStorage.removeItem('type');
-       }
      }
📝 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
// 비회원 상태에서 테스트 완료 후 로그인한 경우 테스트 결과 저장
const type = sessionStorage.getItem('type') as TestType;
let url = '/';
if (type) {
try {
await saveTestResultMutation.mutateAsync(type);
url = '/?scrollTo=recommend';
} finally {
sessionStorage.removeItem('type');
}
}
router.push('/');
router.push(url);
if (type) {
try {
await saveTestResultMutation.mutateAsync(type);
url = '/?scrollTo=recommend';
sessionStorage.removeItem('type');
} catch (e) {
console.error(e);
// 실패 시 type을 유지해 재시도 여지를 남기는 방안 고려
}
}
router.push(url);
🤖 Prompt for AI Agents
In `@src/apis/auth/index.ts` around lines 34 - 47, The current flow always removes
the session key from sessionStorage in the finally block which prevents retry on
saveTestResultMutation.mutateAsync failure; change the logic so
sessionStorage.removeItem('type') is only called after a successful await of
saveTestResultMutation.mutateAsync (move it into the try after the await), add a
catch block to handle errors from saveTestResultMutation.mutateAsync (log or
surface an error/toast and leave the 'type' in sessionStorage for retry), and
ensure router.push(url) still runs with the correct url determined on success or
failure; refer to sessionStorage.getItem('type'),
saveTestResultMutation.mutateAsync, sessionStorage.removeItem('type'), and
router.push when making the change.

Comment thread src/app/test/page.tsx
const [isModalOpen, setIsModalOpen] = useState(false);
const steps = ['START', ...TEST_STEPS.map((step) => step.id)];
const hasType = getCookie('hasType');
const prevPath = getStorageValue('prevPage') || '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the file exists and read the relevant sections
if [ -f "src/app/test/page.tsx" ]; then
  echo "=== File exists, reading content ==="
  wc -l src/app/test/page.tsx
  echo ""
  echo "=== Lines 20-80 context ==="
  sed -n '20,80p' src/app/test/page.tsx | cat -n
else
  echo "File not found. Checking directory structure..."
  find . -name "page.tsx" -type f 2>/dev/null | head -20
fi

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 192


🏁 Script executed:

# Search for getStorageValue and router.push to understand the pattern
rg "getStorageValue|router\.push" --no-heading -B2 -A2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 10638


🏁 Script executed:

# Read lines 60-80 to see the exact context of line 73
sed -n '60,80p' src/app/test/page.tsx | cat -n

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 753


🏁 Script executed:

# Check all files with the prevPage pattern to see if they all have the same issue
rg "prevPath = getStorageValue\('prevPage'\)" -A 20 --no-heading

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 3883


🌐 Web query:

Next.js router.push empty string behavior navigation

💡 Result:

Short answer: Next.js doesn't document a special meaning for router.push('') — passing an empty string is effectively undefined/unsupported and in practice behaves like a no-op (or a relative navigation to the current URL) depending on router/version. Use an explicit path (e.g. '/' or the current pathname) or call router.refresh() instead. [1][2]

Why / what to do:

  • The official API only documents router.push(href: string | UrlObject, ...); it expects a real URL/href, so '' is not a supported explicit value. Use explicit hrefs. [1][2]
  • There are multiple GitHub/Forum reports about surprising behaviour when pushing the same URL or updating only query params — same-URL pushes sometimes do nothing or trigger server fetches depending on App/Pages router and Next.js version. For reliable results use an explicit path, router.replace, or router.refresh() as appropriate. [3][4]

Sources:

  • Next.js router.push docs (pages/app-router API). [1][2]
  • Community issues / discussion describing same-URL / query-update quirks and router.push behavior. [3][4]

References:
[1] Next.js docs — useRouter / router.push (API).
[2] Next.js docs — Linking and Navigating (Routing).
[3] vercel/next.js GitHub issues discussing navigation behavior.
[4] Next.js forum / community threads about router.push and same-URL/query updates.


prevPath가 비어 있으면 라우팅이 작동하지 않을 수 있어요.

Line 26의 기본값이 ''일 때 Line 73에서 router.push('')가 호출되는데, Next.js에서 빈 문자열은 지원되지 않는 값이며 예상치 못한 동작(무시되거나 오류 발생)을 유발할 수 있습니다. 기본값을 '/'로 변경하세요. 이 패턴은 src/app/searchResult/SearchResultPageClient.tsx와 src/app/test/result/page.tsx에도 동일하게 적용됩니다.

🔧 제안 수정
-  const prevPath = getStorageValue('prevPage') || '';
+  const prevPath = getStorageValue('prevPage') || '/';

Also applies to: 73-73

🤖 Prompt for AI Agents
In `@src/app/test/page.tsx` at line 26, The default for prevPath returned from
getStorageValue('prevPage') is an empty string which causes router.push('') to
be called (invalid in Next.js); change the default from '' to '/' so prevPath =
getStorageValue('prevPage') || '/' and ensure any subsequent
router.push(prevPath) receives a valid path; apply the same change to other
places using getStorageValue('prevPage') (e.g., in SearchResultPageClient and
the test result page) and verify router.push calls rely on the sanitized
prevPath variable.

Comment on lines +5 to +26
import dynamic from 'next/dynamic';
import Image from 'next/image';
import { useRouter } from 'next/navigation';

import { toPng } from 'html-to-image';
import { getCookie } from 'cookies-next';
import { useQueryClient } from '@tanstack/react-query';

import { TestResponse } from '@apis/test/type';
import PageBottomBtn from '@components/common/button/pageBottomBtn/PageBottomBtn';
import KakaoBtn from '@components/common/button/kakaoBtn/KakaoBtn';
import Bubble from '@components/common/bubble/Bubble';
import PopupBtn from '@components/common/button/popupBtn/PopupBtn';
import ResultCard from '@components/test/resultCard/ResultCard';
import { useQueryClient } from '@tanstack/react-query';
import { TestResponse } from '@apis/test/type';
import getTestType from '@utils/getTestType';
import { TestType } from '@constants/test';
import { toPng } from 'html-to-image';
import TestHeader from '@components/test/testHeader/TestHeader';
import { useRouter } from 'next/navigation';
import ExceptLayout from '@components/except/exceptLayout/ExceptLayout';
import { getCookie } from 'cookies-next';

import { getStorageValue } from '@hooks/useLocalStorage';
import getTestType from '@utils/getTestType';
import { TestType } from '@constants/test';

import * as styles from './resultPage.css';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for ESLint configuration files
fd -e '.eslintrc*' -o -e 'eslint.config.*' -o -e 'package.json'

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 192


🏁 Script executed:

#!/bin/bash
# List files in the repository root to understand structure
git ls-files | head -20

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 594


🏁 Script executed:

#!/bin/bash
# Check the actual content of the file
cat -n src/app/test/result/page.tsx | head -30

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 1425


🏁 Script executed:

cat -n eslint.config.js

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 3776


🏁 Script executed:

npx eslint src/app/test/result/page.tsx --format=json 2>&1 | head -100

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 18895


import/order ESLint 규칙 위반 정리 필요

17개의 import/order 오류가 감지되었습니다. 다음을 수정하세요:

  • 각 그룹 내 빈 줄 제거
  • 외부 라이브러리 알파벳순 정렬: @tanstack/react-querycookies-nexthtml-to-image
  • 컴포넌트 경로 알파벳순 정렬
  • 각 그룹 간에만 빈 줄 유지

npx eslint --fix로 자동 정렬하거나 수동으로 재정렬해주세요.

🧰 Tools
🪛 ESLint

[error] 5-5: next/dynamic import should occur after import of @constants/test

(import/order)


[error] 6-6: next/image import should occur after import of @constants/test

(import/order)


[error] 7-7: There should be no empty line within import group

(import/order)


[error] 7-7: next/navigation import should occur after import of @constants/test

(import/order)


[error] 9-9: html-to-image import should occur after import of @constants/test

(import/order)


[error] 10-10: cookies-next import should occur after import of @constants/test

(import/order)


[error] 11-11: There should be no empty line within import group

(import/order)


[error] 11-11: @tanstack/react-query import should occur after import of @constants/test

(import/order)


[error] 14-14: @components/common/button/pageBottomBtn/PageBottomBtn import should occur after import of @components/common/bubble/Bubble

(import/order)


[error] 15-15: @components/common/button/kakaoBtn/KakaoBtn import should occur after import of @components/common/bubble/Bubble

(import/order)


[error] 18-18: @components/test/resultCard/ResultCard import should occur after import of @components/except/exceptLayout/ExceptLayout

(import/order)


[error] 19-19: @components/test/testHeader/TestHeader import should occur after import of @components/except/exceptLayout/ExceptLayout

(import/order)


[error] 20-20: There should be no empty line within import group

(import/order)


[error] 22-22: @hooks/useLocalStorage import should occur after import of @constants/test

(import/order)


[error] 23-23: @utils/getTestType import should occur after import of @constants/test

(import/order)

🤖 Prompt for AI Agents
In `@src/app/test/result/page.tsx` around lines 5 - 26, Reorder the import
statements to satisfy import/order: group and sort imports, remove blank lines
inside each group and keep a single blank line between groups; specifically
alphabetize external libs (e.g., move `@tanstack/react-query`, cookies-next,
html-to-image into correct alphabetical order), then alphabetize component
imports (PageBottomBtn, PopupBtn, KakaoBtn, Bubble, ResultCard, TestHeader,
ExceptLayout) and utility/hooks/constants imports (getStorageValue, getTestType,
TestType) within their groups, keep next/dynamic, next/image, next/navigation in
the framework group, and leave the styles import in the local group; you can run
npx eslint --fix to apply auto-fixes or reorder manually ensuring no extra blank
lines inside groups and only one blank line between groups.

const router = useRouter();
const queryClient = useQueryClient();
const userNickname = getCookie('userNickname');
const prevPath = getStorageValue('prevPage') || '';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/app/test/result/page.tsx | sed -n '30,50p'

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 940


🏁 Script executed:

cat -n src/app/test/result/page.tsx | sed -n '90,105p'

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 693


🏁 Script executed:

wc -l src/app/test/result/page.tsx

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 100


🏁 Script executed:

rg "getStorageValue" src/ --type ts --type tsx -B 2 -A 2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 95


🏁 Script executed:

rg "prevPage" src/ --type ts --type tsx

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 95


🏁 Script executed:

fd -e ts -e tsx src/ -x grep -l "getStorageValue"

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 389


🏁 Script executed:

rg "getStorageValue" src/ -B 2 -A 2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 4828


🏁 Script executed:

rg "prevPage" src/

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 564


🏁 Script executed:

fd . src/ -e ts -x grep -l "getStorageValue" {} \;

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 96


🏁 Script executed:

rg "prevPage" src/app/test/page.tsx -B 5 -A 5

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 453


🏁 Script executed:

cat -n src/app/test/page.tsx | head -50

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 2074


🏁 Script executed:

rg "router.push" src/app/test/result/page.tsx -B 3 -A 3

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 884


🏁 Script executed:

cat -n src/app/test/page.tsx | tail -100

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 3469


🏁 Script executed:

rg "localStorage.setItem\('prevPage'" src/

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 303


🏁 Script executed:

rg "prevPath" src/app/searchResult/SearchResultPageClient.tsx -B 2 -A 2

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 343


🏁 Script executed:

grep -n "router.push(prevPath)" src/app/searchResult/SearchResultPageClient.tsx

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 50


prevPath 기본값을 '/'로 변경하세요

Line 33에서 getStorageValue('prevPage')가 null을 반환하면 기본값 ''이 설정되어 Line 97에서 router.push('')가 호출됩니다. test 페이지로 직접 접근하거나 localStorage가 클리어된 경우 prevPage가 없으므로 기본값을 홈으로 설정해야 합니다.

수정
-  const prevPath = getStorageValue('prevPage') || '';
+  const prevPath = getStorageValue('prevPage') || '/';
📝 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
const prevPath = getStorageValue('prevPage') || '';
const prevPath = getStorageValue('prevPage') || '/';
🤖 Prompt for AI Agents
In `@src/app/test/result/page.tsx` at line 33, Change the default prevPath from an
empty string to '/' so router.push won't be called with an empty path: update
the assignment where prevPath is set (const prevPath =
getStorageValue('prevPage') || '') to use '/' as the fallback; ensure any
subsequent usage such as router.push(prevPath) in the same file (page.tsx) will
correctly navigate to the home page when getStorageValue('prevPage') returns
null/undefined.

Comment on lines +12 to +37
useEffect(() => {
if (!targetId) return;

const performScroll = (element: HTMLElement) => {
element.scrollIntoView({
block: 'start',
behavior: 'smooth',
});

// url에서 파라미터 제거
router.replace(pathname, { scroll: false });
};

// height 생길 때까지 체크
const observer = new MutationObserver((_, obs) => {
const element = document.getElementById(targetId);
if (element && element.offsetHeight > 0) {
performScroll(element);
obs.disconnect();
}
});

observer.observe(document.body, {
childList: true,
subtree: true,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "useScrollToTarget.ts" | head -20

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 192


🏁 Script executed:

cat -n src/hooks/useScrollToTarget.ts | head -50

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 192


🏁 Script executed:

wc -l src/hooks/useScrollToTarget.ts

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 101


🏁 Script executed:

cat src/hooks/useScrollToTarget.ts

Repository: JEOLLOGA/JEOLLOGA-CLIENT

Length of output: 1127


이미 렌더된 타겟 요소는 스크롤이 발생하지 않습니다.

MutationObserver는 관찰자가 설정된 이후의 DOM 변경만 감지합니다. 만약 targetId 요소가 useEffect 실행 시점에 이미 DOM에 존재하면 콜백이 실행되지 않아 스크롤이 누락됩니다. 특히 ?scrollTo=id 파라미터를 포함한 URL로 이동할 때 대상 요소가 초기 렌더링 시 이미 있으므로 이 버그가 자주 발생합니다.

🔧 제안 수정
  useEffect(() => {
    if (!targetId) return;

    const performScroll = (element: HTMLElement) => {
      element.scrollIntoView({
        block: 'start',
        behavior: 'smooth',
      });

      // url에서 파라미터 제거
      router.replace(pathname, { scroll: false });
    };

+    // 이미 존재하는 요소 먼저 확인
+    const existing = document.getElementById(targetId);
+    if (existing && existing.offsetHeight > 0) {
+      performScroll(existing);
+      return;
+    }
+
     // height 생길 때까지 체크
     const observer = new MutationObserver((_, obs) => {
       const element = document.getElementById(targetId);
       if (element && element.offsetHeight > 0) {
         performScroll(element);
         obs.disconnect();
       }
     });

     observer.observe(document.body, {
       childList: true,
       subtree: true,
     });

     return () => observer.disconnect();
   }, [targetId, router, pathname]);
🤖 Prompt for AI Agents
In `@src/hooks/useScrollToTarget.ts` around lines 12 - 37, The useScrollToTarget
effect (useScrollToTarget) currently only relies on a MutationObserver so if the
target element already exists at effect run time the scroll is never triggered;
fix by first checking document.getElementById(targetId) immediately and calling
performScroll(element) if found, before instantiating the MutationObserver,
otherwise keep the observer logic as-is; reference performScroll,
MutationObserver instance (observer) and observer.observe to locate where to add
the immediate existence check and early performScroll call.

@bykbyk0401 bykbyk0401 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

사용자 경험이 잘 고려된 것 같네요우~~
고생하셨습니당

@maylh
maylh merged commit d0f3765 into develop Jan 22, 2026
7 checks passed
@maylh
maylh deleted the fix/#338/test-func branch January 22, 2026 13:56
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.

[FIX] 테스트 기능 수정

2 participants