-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
7 changed files
with
370 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { cleanup, render, screen } from "@testing-library/react"; | ||
import UserProfile from "@/components/user-page/UserProfile"; | ||
import "@testing-library/jest-dom"; | ||
|
||
describe("UserProfile Component", () => { | ||
const mockUserInfo = { | ||
userId: 1, | ||
email: "[email protected]", | ||
nickname: "테스트 유저", | ||
profileImg: "https://test.com/test-profile.jpg", | ||
qualificationStatus: "QUALIFIED" as const, | ||
bio: "테스트 자기소개", | ||
userTagList: [ | ||
{ id: 1, tag: "태그1" }, | ||
{ id: 2, tag: "태그2" }, | ||
], | ||
ownId: true, | ||
}; | ||
|
||
beforeEach(() => { | ||
render(<UserProfile userInfo={mockUserInfo} />); | ||
}); | ||
|
||
describe("기본 정보 렌더링", () => { | ||
it("닉네임을 렌더링 한다.", () => { | ||
expect(screen.getByText("테스트 유저")).toBeInTheDocument(); | ||
}); | ||
|
||
it("프로필 이미지를 올바르게 렌더링한다.", () => { | ||
const image = screen.getByRole("img"); | ||
expect(image).toHaveAttribute( | ||
"src", | ||
expect.stringContaining("test-profile.jpg"), | ||
); | ||
expect(image).toHaveAttribute("alt", "테스트 유저님의 프로필 이미지"); | ||
}); | ||
}); | ||
|
||
describe("자기소개 렌더링", () => { | ||
it("자기소개를 렌더링 한다.", () => { | ||
expect(screen.getByText("테스트 자기소개")).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe("사용자 태그 목록 렌더링", () => { | ||
it("사용자 태그 목록을 모두 표시한다.", () => { | ||
expect(screen.getByText("태그1")).toBeInTheDocument(); | ||
expect(screen.getByText("태그2")).toBeInTheDocument(); | ||
|
||
const tagList = screen.getByLabelText("자기소개 키워드"); | ||
expect(tagList.children).toHaveLength(mockUserInfo.userTagList.length); | ||
}); | ||
}); | ||
|
||
describe("과외선생님 뱃지", () => { | ||
describe("자격이 있을 때", () => { | ||
it("뱃지를 표시한다.", () => { | ||
expect(screen.getByText("과외선생님")).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
describe("자격이 없을 때", () => { | ||
beforeEach(() => { | ||
cleanup(); | ||
const unqualifiedUserInfo = { | ||
...mockUserInfo, | ||
qualificationStatus: "UNQUALIFIED" as const, | ||
}; | ||
render(<UserProfile userInfo={unqualifiedUserInfo} />); | ||
}); | ||
it("뱃지를 표시하지 않는다.", () => { | ||
expect(screen.queryByText("과외선생님")).not.toBeInTheDocument(); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import userEvent from "@testing-library/user-event"; | ||
import Error, { type ErrorProps } from "@/app/user/[id]/error"; | ||
import "@testing-library/jest-dom"; | ||
|
||
const mockReplace = jest.fn(); | ||
|
||
jest.mock("next/navigation", () => ({ | ||
useRouter: () => ({ | ||
replace: mockReplace, | ||
}), | ||
})); | ||
|
||
describe("유저페이지 Error 컴포넌트", () => { | ||
const errorMessage = "해당 유저는 존재하지 않습니다."; | ||
const mockError: ErrorProps["error"] = { | ||
name: "Error", | ||
message: "해당 유저는 존재하지 않습니다.", | ||
digest: "test-digest", | ||
} as const; | ||
|
||
beforeEach(() => { | ||
jest.clearAllMocks(); | ||
render(<Error error={mockError} />); | ||
}); | ||
|
||
it("에러 메세지를 표시한다", () => { | ||
expect(screen.getByText(errorMessage)).toBeInTheDocument(); | ||
}); | ||
|
||
it("전달받은 에러 메세지가 없으면 기본 메세지를 표시한다", () => { | ||
const mockErrorWithoutMessage: ErrorProps["error"] = { | ||
name: "Error", | ||
message: "", | ||
} as const; | ||
|
||
render(<Error error={mockErrorWithoutMessage} />); | ||
expect(screen.getByText("오류가 발생했습니다.")).toBeInTheDocument(); | ||
}); | ||
|
||
it("홈으로 돌아가기 버튼 클릭시 홈으로 이동한다", async () => { | ||
const button = screen.getByText("홈으로 돌아가기"); | ||
await userEvent.click(button); | ||
|
||
expect(mockReplace).toHaveBeenCalledWith("/"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { fetcher } from "@/lib/user/fetcher"; | ||
|
||
describe("fetcher", () => { | ||
const mockData = { data: "test" }; | ||
const mockResponse = { | ||
ok: true, | ||
json: () => Promise.resolve(mockData), | ||
} as Response; | ||
|
||
beforeEach(() => { | ||
jest.resetAllMocks(); | ||
global.fetch = jest.fn(() => Promise.resolve(mockResponse)); | ||
}); | ||
|
||
describe("기본 동작", () => { | ||
it("기본 GET 요청을 성공적으로 처리한다", async () => { | ||
const res = await fetcher("/test", ""); | ||
const data = await res.json(); | ||
|
||
expect(res.ok).toBe(true); | ||
expect(data).toEqual(mockData); | ||
}); | ||
|
||
it("HTTP 메서드를 설정할 수 있다", async () => { | ||
const originalData = { title: "수정 전" }; | ||
const updateData = { title: "수정 후" }; | ||
|
||
(global.fetch as jest.Mock).mockImplementationOnce(() => | ||
Promise.resolve({ | ||
ok: true, | ||
json: () => Promise.resolve(updateData), | ||
}), | ||
); | ||
|
||
const res = await fetcher("/update", "", { | ||
method: "PATCH", | ||
body: JSON.stringify(updateData), | ||
}); | ||
|
||
expect(global.fetch).toHaveBeenCalledWith( | ||
expect.any(String), | ||
expect.objectContaining({ | ||
method: "PATCH", | ||
body: JSON.stringify(updateData), | ||
}), | ||
); | ||
|
||
const data = await res.json(); | ||
expect(data).toEqual(updateData); | ||
expect(data).not.toEqual(originalData); | ||
}); | ||
}); | ||
|
||
describe("헤더 처리", () => { | ||
it("인증 토큰이 필요한 요청을 성공적으로 처리한다", async () => { | ||
const token = "test-token"; | ||
const res = await fetcher("/auth-test", token, { auth: true }); | ||
|
||
expect(global.fetch).toHaveBeenCalledWith( | ||
expect.any(String), | ||
expect.objectContaining({ | ||
headers: expect.objectContaining({ | ||
Authorization: `Bearer ${token}`, | ||
}), | ||
}), | ||
); | ||
|
||
const data = await res.json(); | ||
expect(data).toEqual(mockData); | ||
}); | ||
|
||
it("커스텀 헤더를 설정할 수 있다", async () => { | ||
const customHeaders = { | ||
"Accept-Language": "ko-KR", | ||
}; | ||
const token = "test-token"; | ||
|
||
await fetcher("/test", token, { | ||
auth: true, | ||
headers: customHeaders, | ||
}); | ||
|
||
expect(global.fetch).toHaveBeenCalledWith( | ||
expect.any(String), | ||
expect.objectContaining({ | ||
headers: expect.objectContaining({ | ||
Authorization: `Bearer ${token}`, | ||
"Content-Type": "application/json", | ||
...customHeaders, | ||
}), | ||
}), | ||
); | ||
}); | ||
|
||
it("FormData 요청시 Content-Type: application/json이 설정되지 않는다", async () => { | ||
const formData = new FormData(); | ||
formData.append("key", "value"); | ||
|
||
await fetcher("/upload", "", { | ||
method: "POST", | ||
body: formData, | ||
}); | ||
|
||
expect(global.fetch).toHaveBeenCalledWith( | ||
expect.any(String), | ||
expect.objectContaining({ | ||
body: formData, | ||
headers: expect.not.objectContaining({ | ||
"Content-Type": "application/json", | ||
}), | ||
}), | ||
); | ||
|
||
const fetchCall = (global.fetch as jest.Mock).mock.calls[0][1]; | ||
expect(fetchCall.body).toBeInstanceOf(FormData); | ||
}); | ||
}); | ||
|
||
describe("Next.js 옵션 처리", () => { | ||
it("Next.js fetch 옵션을 처리할 수 있다", async () => { | ||
const nextOptions = { | ||
cache: "no-store" as const, | ||
next: { revalidate: 60 }, | ||
headers: { | ||
"Content-Type": "application/json", | ||
"Accept-Language": "ko-KR", | ||
}, | ||
}; | ||
|
||
await fetcher("/test", "", nextOptions); | ||
|
||
expect(global.fetch).toHaveBeenCalledWith( | ||
expect.any(String), | ||
expect.objectContaining(nextOptions), | ||
); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.