Skip to content

Commit

Permalink
test: LoginForm 테스트 및 쿠키 처리 로직 개선
Browse files Browse the repository at this point in the history
- LoginForm.test.tsx에 테스트 추가
- accessToken 추출 로직을 정규식 대신 getCookieValue 함수로 리팩토링
- getCookieValue 함수를 통해 쿠키 값 가져오는 방식 개선
  • Loading branch information
deipanema committed Oct 30, 2024
1 parent 5a49a56 commit de54a98
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 12 deletions.
80 changes: 80 additions & 0 deletions src/app/(auth)/components/LoginForm.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { vi, Mock } from "vitest";

import { useAuth } from "@/hooks/useAuth";

import LoginForm from "./LoginForm";

// Mock the useAuth hook
vi.mock("@/hooks/useAuth");

describe("LoginForm", () => {
const mockLoginMutation = {
mutate: vi.fn(),
isLoading: false,
};

beforeEach(() => {
(useAuth as Mock).mockReturnValue({
loginMutation: mockLoginMutation,
});
});

it("모든 입력 필드와 로그인 버튼이 렌더링되어야 한다.", () => {
render(<LoginForm />);

expect(screen.getByPlaceholderText("이메일")).toBeInTheDocument();
expect(screen.getByPlaceholderText("비밀번호")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "로그인" })).toBeInTheDocument();
});

describe("유효성 검사", () => {
it("이메일 및 비밀번호 필드 유효성 검사", async () => {
render(<LoginForm />);
fireEvent.blur(screen.getByPlaceholderText("이메일"));
fireEvent.blur(screen.getByPlaceholderText("비밀번호"));

await waitFor(() => {
expect(screen.getByText("유효한 이메일 주소를 입력해주세요.")).toBeInTheDocument();
expect(screen.getByText("비밀번호는 최소 8자 이상이어야 합니다.")).toBeInTheDocument();
});
});

it("이메일과 비밀번호로 로그인합니다.", async () => {
render(<LoginForm />);

fireEvent.change(screen.getByPlaceholderText("이메일"), {
target: { value: "[email protected]" },
});
fireEvent.change(screen.getByPlaceholderText("비밀번호"), {
target: { value: "password123" },
});
fireEvent.click(screen.getByRole("button", { name: "로그인" }));

await waitFor(() => {
expect(mockLoginMutation.mutate).toHaveBeenCalledWith({
email: "[email protected]",
password: "password123",
});
});
});

it("제출 시 로딩 중인 스피너를 표시합니다.", async () => {
mockLoginMutation.isLoading = true;
render(<LoginForm />);

fireEvent.change(screen.getByPlaceholderText("이메일"), {
target: { value: "[email protected]" },
});
fireEvent.change(screen.getByPlaceholderText("비밀번호"), {
target: { value: "password123" },
});

fireEvent.click(screen.getByRole("button", { name: "로그인" }));

await waitFor(() => {
expect(screen.getByTestId("spinner")).toBeInTheDocument();
});
});
});
});
19 changes: 11 additions & 8 deletions src/app/(auth)/components/SignupForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { render, screen, waitFor } from "@testing-library/react";
import { vi, Mock } from "vitest";
import userEvent from "@testing-library/user-event";

import { useSignup } from "@/hook/useSignup";
import { useAuth } from "@/hooks/useAuth";

import SignupForm from "./SignupForm";

// Mock modules

vi.mock("@/hooks/useAuth");

vi.mock("next/navigation", () => ({
useRouter: () => ({
push: vi.fn(),
Expand All @@ -25,17 +28,17 @@ vi.mock("react-toastify", () => ({
}));

describe("SignupForm", () => {
const mockMutate = vi.fn();
const mockSignupMutation = { mutate: vi.fn() };

beforeEach(() => {
vi.clearAllMocks();
(useSignup as Mock).mockReturnValue({
mutate: mockMutate,
(useAuth as Mock).mockReturnValue({
signupMutation: mockSignupMutation,
isLoading: false,
});
});
describe("렌더링 테스트", () => {

describe("SignupForm 렌더링 테스트", () => {
it("모든 입력 필드와 제출 버튼이 렌더링되어야 한다", () => {
render(<SignupForm />);

Expand Down Expand Up @@ -117,7 +120,7 @@ describe("SignupForm", () => {
await userEvent.click(submitButton);

await waitFor(() => {
expect(mockMutate).toHaveBeenCalledWith(
expect(mockSignupMutation.mutate).toHaveBeenCalledWith(
expect.objectContaining({
nickname: validFormData.nickname,
email: validFormData.email,
Expand All @@ -137,7 +140,7 @@ describe("SignupForm", () => {
},
};

mockMutate.mockImplementation((_, options) => {
mockSignupMutation.mutate.mockImplementation((_, options) => {
options.onError(mockError);
});

Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/goal/[goalId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AxiosError } from "axios";

import { deleteGoal, ErrorType, getGoal } from "@/api/goalAPI";
import { getTodos } from "@/api/todoAPI";
import useModal from "@/hook/useModal";
import useModal from "@/hooks/useModal";
import { useTodoStore } from "@/store/todoStore";
import CreateNewTodo from "@/components/CreateNewTodo";
import EditGoalTitleModal from "@/components/EditGoalTitleModal";
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/note/[noteId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Image from "next/image";
import { ChangeEvent, useEffect, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";

import useModal from "@/hook/useModal";
import useModal from "@/hooks/useModal";
import { getNote, patchNotes, postNotes } from "@/api/noteAPI";
import { getTodos } from "@/api/todoAPI";
import UploadLinkModal from "@/components/UploadLinkModal";
Expand Down
2 changes: 1 addition & 1 deletion src/app/dashboard/todoboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useEffect, useState } from "react";

import { useTodoStore } from "@/store/todoStore";
import CreateNewTodo from "@/components/CreateNewTodo";
import useModal from "@/hook/useModal";
import useModal from "@/hooks/useModal";
import { getAllTodos } from "@/api/todoAPI";
import { TodoType } from "@/type";

Expand Down
10 changes: 9 additions & 1 deletion src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});

// 쿠키에서 특정 키의 값을 가져오는 함수
const getCookieValue = (key: string) => {
const cookies = document.cookie.split("; ");
const cookie = cookies.find((cookie) => cookie.startsWith(`${key}=`));
return cookie ? cookie.split("=")[1] : null;
};

api.interceptors.request.use(
(config) => {
const token = document.cookie.replace(/(?:(?:^|.*;\s*)accessToken\s*=\s*([^;]*).*$)|^.*$/, "$1");
const token = getCookieValue("accessToken"); // getCookieValue 함수를 사용하여 accessToken을 가져옴
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
Expand All @@ -26,6 +33,7 @@ api.interceptors.response.use(
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const refreshToken = localStorage.getItem("refreshToken");

if (refreshToken) {
try {
const { data } = await axios.post("/auth/tokens", { refreshToken });
Expand Down

0 comments on commit de54a98

Please sign in to comment.