Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6a51faa
[myPage] fix : chore(api): v6 마이페이지 전용 axiosInstanceV6 추가
HA-SEUNG-JEONG May 23, 2026
b0c151a
[fix-myPage-to-main] cherry : [myPage] fix : feat(my-inquiry): 1:1 문의…
HA-SEUNG-JEONG May 23, 2026
175e9d3
[fix-myPage-to-main] cherry : [myPage] fix : feat(my-page): 마이페이지 내가 …
HA-SEUNG-JEONG May 23, 2026
b0daa2b
[fix-myPage-to-main] cherry : [myPage] fix : 마이 클래스 토글 비활성화 기능 추가 — l…
HA-SEUNG-JEONG May 24, 2026
0fadee5
[myPage] fix : 마이클래스 버튼 토큰 수정 및 코드 정리
HA-SEUNG-JEONG May 24, 2026
e88f9d3
[fix-myPage-to-main] cherry : [myPage] feat : 마이페이지 배너 UI 업데이트 및 토큰 수정
HA-SEUNG-JEONG May 24, 2026
520657d
[fix-myPage-to-main] cherry : [myPage] fix : 마이페이지 전역 primary-500 미존재…
HA-SEUNG-JEONG May 24, 2026
e4f1ca7
[fix-myPage-to-main] cherry : [myPage] chore : 마이페이지 에셋 추가
HA-SEUNG-JEONG May 24, 2026
7a31e08
[fix-myPage-to-main] cherry : [myPage] fix : 탈퇴 확인 모달 Figma 디자인 반영
HA-SEUNG-JEONG May 24, 2026
be28f9f
[fix-myPage-to-main] cherry : [myPage] fix : chore(types): 클래스 결제 환불/…
HA-SEUNG-JEONG May 24, 2026
488def8
[fix-myPage-to-main] cherry : [myPage] fix : chore(api): 클래스 결제 상세 조회…
HA-SEUNG-JEONG May 24, 2026
5ee9234
[fix-myPage-to-main] cherry : [myPage] fix : feat(결제관리): 클래스 결제 취소·환불…
HA-SEUNG-JEONG May 24, 2026
644d0ab
[fix-myPage-to-main] cherry : [myPage] fix : feat(마이피드): 임시 저장 피드 목록 …
HA-SEUNG-JEONG May 24, 2026
bd5e002
[fix-myPage-to-main] cherry : [myPage] fix : chore(types): 빌더 피드 관리 응…
HA-SEUNG-JEONG May 24, 2026
5292c9e
[fix-myPage-to-main] cherry : [myPage] fix : 문의 첨부 미연동 숨김, 알림 토글 hydr…
HA-SEUNG-JEONG May 24, 2026
aa7f111
[fix-myPage-to-main] cherry : [myPage] fix : chore(types): MyDraftBui…
HA-SEUNG-JEONG May 24, 2026
63d24de
[fix-myPage-to-main] cherry : [myPage] fix : refactor(api): useGetMyD…
HA-SEUNG-JEONG May 24, 2026
6cde47d
[myPage] fix : fix(임시저장): draft 중복 생성 방지 및 DRAFT→PUBLISHED 전환 처리
HA-SEUNG-JEONG May 24, 2026
d46321d
[fix-myPage-to-main] cherry : [myPage] fix : fix(피드 등록): 임시저장 발행 후 피드…
HA-SEUNG-JEONG May 24, 2026
9ec998f
[myPage] fix : 테스트 코드 수정
HA-SEUNG-JEONG May 24, 2026
dd6bbb4
[fix-myPage-to-main] cherry : [myPage] fix : fix(ci): 스테이징 서버 다운 시 E2…
HA-SEUNG-JEONG May 25, 2026
fd261af
[fix-myPage-to-main] cherry : [myPage] fix : fix(ci): non-@auth E2E를 …
HA-SEUNG-JEONG May 25, 2026
e0108e9
[fix-myPage-to-main] chore : CI 서버 기동 실패 시 명시적 exit 1 추가, stripHtml 유…
HA-SEUNG-JEONG May 25, 2026
d440b0e
[fix-myPage-to-main] fix : QnA 임시저장 disabled, 환불 모달 step 경합, feedCont…
HA-SEUNG-JEONG May 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 39 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ jobs:
- name: Build Storybook
run: yarn build-storybook

# Playwright E2E: 스테이징 환경 대상 실행
# E2E_AUTH_JSON secret 설정 시 @auth 태그 포함 전체 스위트 실행
# secret 누락/만료 시 비인증 테스트만 실행 (fallback)
# Playwright E2E:
# - non-@auth 테스트: CI 내 로컬 서버(localhost:3000) 대상 항상 실행 (스테이징 의존 없음)
# - @auth 테스트: 스테이징 접속 가능 시에만 실행, 불가 시 경고 후 스킵
# 갱신 절차: yarn e2e:save-auth → GitHub Secret E2E_AUTH_JSON 업데이트
e2e:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -170,15 +170,45 @@ jobs:
if: env.E2E_AUTH_JSON == ''
run: echo "::warning::E2E_AUTH_JSON not set — skipping @auth tests"

- name: Run E2E tests (full suite, with auth)
if: env.E2E_AUTH_JSON != '' && env.AUTH_EXPIRED != 'true'
run: yarn e2e
- name: Build Next.js app
run: yarn build
env:
E2E_BASE_URL: https://test.zeroone.it.kr
NEXT_PUBLIC_API_BASE_URL: https://test-api.zeroone.it.kr

- name: Run E2E tests (non-auth only)
if: env.E2E_AUTH_JSON == '' || env.AUTH_EXPIRED == 'true'
- name: Start local server
run: |
NEXT_PUBLIC_API_BASE_URL=https://test-api.zeroone.it.kr yarn start &
for i in $(seq 1 30); do
if curl -sf --max-time 5 http://localhost:3000/ > /dev/null 2>&1; then
echo "Local server ready"
break
fi
echo "Waiting for server... ($i/30)"
if [[ "$i" == "30" ]]; then
echo "::error::Local server failed to start after 60s"
exit 1
fi
sleep 2
done

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Run E2E tests (non-auth, local server)
run: yarn e2e --grep-invert @auth
env:
E2E_BASE_URL: http://localhost:3000

- name: Check staging connectivity
run: |
STATUS=$(curl -s --max-time 10 -o /dev/null -w "%{http_code}" https://test.zeroone.it.kr/ 2>/dev/null || true)
if [[ "$STATUS" =~ ^[2-4][0-9][0-9]$ ]]; then
echo "Staging reachable (HTTP $STATUS)"
else
echo "::warning::Staging https://test.zeroone.it.kr unreachable — skipping @auth tests"
echo "STAGING_DOWN=true" >> "$GITHUB_ENV"
fi

- name: Run E2E tests (auth suite, staging)
if: env.E2E_AUTH_JSON != '' && env.AUTH_EXPIRED != 'true' && env.STAGING_DOWN != 'true'
run: yarn e2e --grep @auth
env:
E2E_BASE_URL: https://test.zeroone.it.kr

Expand Down
52 changes: 35 additions & 17 deletions e2e/class/builder-feed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ function makeComments(): { content: BuilderFeedCommentsResponse } {
{
commentId: 1,
content: '멋진 피드네요!',
author: { memberId: 3, nickname: '댓글러', role: 'STUDENT' },
author: {
memberId: 3,
nickname: '댓글러',
role: 'STUDENT',
},
createdAt: '2025-05-01T13:00:00.000Z',
replies: [],
},
Expand Down Expand Up @@ -215,7 +219,9 @@ async function mockFeedDetailApis(page: Page) {
return;
}
await route.fulfill({
json: { content: { feedId: FEED_ID, isLiked: true, likeCount: 6 } },
json: {
content: { feedId: FEED_ID, isLiked: true, likeCount: 6 },
},
});
},
);
Expand All @@ -228,11 +234,13 @@ test.describe('빌더 피드 목록 @auth', () => {
page,
}) => {
await mockFeedListApis(page, [makeFeedItem(FEED_ID)]);
await page.goto(FEED_LIST_PATH, { waitUntil: 'load' });
await page.waitForLoadState('networkidle', { timeout: 30000 });
await Promise.all([
page.waitForResponse((r) => /\/courses\/vibe-intro$/.test(r.url())),
page.goto(FEED_LIST_PATH, { waitUntil: 'load' }),
]);

await expect(page.getByText(/테스트 피드 내용/)).toBeVisible({
timeout: 15000,
timeout: 5000,
});
await expect(page.getByText('테스터').first()).toBeVisible();
});
Expand All @@ -241,11 +249,13 @@ test.describe('빌더 피드 목록 @auth', () => {
page,
}) => {
await mockFeedListApis(page, []);
await page.goto(FEED_LIST_PATH, { waitUntil: 'load' });
await page.waitForLoadState('networkidle', { timeout: 30000 });
await Promise.all([
page.waitForResponse((r) => /\/courses\/vibe-intro$/.test(r.url())),
page.goto(FEED_LIST_PATH, { waitUntil: 'load' }),
]);

await expect(page.getByText('아직 등록된 피드가 없어요.')).toBeVisible({
timeout: 15000,
timeout: 5000,
});
});
});
Expand All @@ -256,11 +266,17 @@ test.describe('빌더 피드 상세 @auth', () => {
});

test('피드 상세 렌더링 — 내용·댓글 표시', async ({ page }) => {
await page.goto(FEED_DETAIL_PATH, { waitUntil: 'load' });
await page.waitForLoadState('networkidle', { timeout: 30000 });
await Promise.all([
page.waitForResponse(
(r) =>
/\/builder-feeds\/\d+$/.test(r.url()) &&
r.request().method() === 'GET',
),
page.goto(FEED_DETAIL_PATH, { waitUntil: 'load' }),
]);

await expect(page.getByText('피드 상세 내용입니다.')).toBeVisible({
timeout: 15000,
timeout: 5000,
});
await expect(page.getByText('멋진 피드네요!')).toBeVisible({
timeout: 10000,
Expand All @@ -270,12 +286,14 @@ test.describe('빌더 피드 상세 @auth', () => {
test('좋아요 버튼 클릭 → POST /builder-feeds/{id}/like 호출 확인', async ({
page,
}) => {
await page.goto(FEED_DETAIL_PATH, { waitUntil: 'load' });
await page.waitForLoadState('networkidle', { timeout: 30000 });

await expect(page.getByText('피드 상세 내용입니다.')).toBeVisible({
timeout: 15000,
});
await Promise.all([
page.waitForResponse(
(r) =>
/\/builder-feeds\/\d+$/.test(r.url()) &&
r.request().method() === 'GET',
),
page.goto(FEED_DETAIL_PATH, { waitUntil: 'load' }),
]);

const [likeResponse] = await Promise.all([
page.waitForResponse(
Expand Down
Binary file added public/my-page/discord-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/my-page/feed-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/api/client/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,22 @@ axiosInstanceV5.interceptors.response.use(
axiosInstanceV5(requestConfig),
),
);

// v6 MyPage API 전용 인스턴스
export const axiosInstanceV6 = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_API_BASE_URL}/api/v6/`,
timeout: 60000,
headers: {
'Content-Type': 'application/json',
},
withCredentials: true,
});

attachApiLogger(axiosInstanceV6, 'client-v6-json');
axiosInstanceV6.interceptors.request.use(attachAccessTokenToRequest);
axiosInstanceV6.interceptors.response.use(
(config) => config,
createClientAuthResponseRejectedHandler((requestConfig) =>
axiosInstanceV6(requestConfig),
),
);
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,11 @@ export function LessonQnaSubmissionModal({
</div>

{/* Footer */}
<div className="flex shrink-0 items-center justify-center gap-200 px-750 py-300">
<div className="flex shrink-0 items-center gap-200 px-750 py-300">
<button
type="button"
onClick={handleDraftSave}
className="w-full rounded-100 border border-rose-400 px-400 py-200 font-designer-18b text-rose-500 hover:opacity-80"
className="flex h-700 flex-1 items-center justify-center rounded-100 border border-rose-400 font-designer-18b text-rose-500 hover:opacity-80"
>
임시저장
</button>
Expand All @@ -299,7 +299,7 @@ export function LessonQnaSubmissionModal({
onClick={handleSubmit}
disabled={createQna.isPending}
className={cn(
'w-full rounded-100 px-400 py-200 font-designer-18b text-text-inverse transition-opacity',
'flex h-700 flex-1 items-center justify-center rounded-100 font-designer-18b text-text-inverse transition-opacity',
createQna.isPending
? 'cursor-not-allowed bg-gray-300'
: 'bg-rose-500 hover:opacity-90',
Expand Down
Loading
Loading