diff --git a/src/components/pages/auth/login/login-form/index.test.tsx b/src/components/pages/auth/login/login-form/index.test.tsx
new file mode 100644
index 00000000..731e0470
--- /dev/null
+++ b/src/components/pages/auth/login/login-form/index.test.tsx
@@ -0,0 +1,84 @@
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+import { LoginForm } from './index';
+
+const handleLoginMock = jest.fn();
+const clearLoginErrorMock = jest.fn();
+
+jest.mock('@/hooks/use-auth', () => ({
+ useLogin: () => ({
+ handleLogin: handleLoginMock,
+ loginError: null,
+ clearLoginError: clearLoginErrorMock,
+ }),
+}));
+
+type MinimalField = {
+ state: { value: string };
+ handleChange: (value: string) => void;
+};
+
+type FieldProps = { field: MinimalField };
+
+jest.mock('@/components/pages/auth/fields', () => ({
+ EmailField: ({ field }: FieldProps) => (
+ field.handleChange(e.target.value)}
+ />
+ ),
+ PasswordField: ({ field }: FieldProps) => (
+ field.handleChange(e.target.value)}
+ />
+ ),
+}));
+
+jest.mock('../../auth-button', () => ({
+ AuthSubmitButton: () => ,
+}));
+
+type LoginSnsButtonProps = React.PropsWithChildren<{ onClick: () => void }>;
+
+jest.mock('../login-sns-button', () => ({
+ LoginSnsButton: ({ onClick, children }: LoginSnsButtonProps) => (
+
+ ),
+}));
+
+describe('LoginForm', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('입력 후 submit 시 handleLogin이 payload로 호출된다', async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.type(screen.getByLabelText('이메일'), 'ok@wego.com');
+ await user.type(screen.getByLabelText('비밀번호'), 'pw');
+
+ await user.click(screen.getByRole('button', { name: '로그인하기' }));
+
+ expect(handleLoginMock).toHaveBeenCalledTimes(1);
+ expect(handleLoginMock.mock.calls[0][0]).toEqual({
+ email: 'ok@wego.com',
+ password: 'pw',
+ });
+ expect(handleLoginMock.mock.calls[0][1]).toBeTruthy();
+ });
+
+ it('email/password 변경 시 clearLoginError가 호출된다', async () => {
+ const user = userEvent.setup();
+ render();
+
+ await user.type(screen.getByLabelText('이메일'), 'a');
+ expect(clearLoginErrorMock).toHaveBeenCalled();
+ });
+});
diff --git a/src/hooks/use-auth/use-auth-login/index.ts b/src/hooks/use-auth/use-auth-login/index.ts
index 0d5f2d0f..45165489 100644
--- a/src/hooks/use-auth/use-auth-login/index.ts
+++ b/src/hooks/use-auth/use-auth-login/index.ts
@@ -1,6 +1,6 @@
'use client';
-import { useRouter, useSearchParams } from 'next/navigation';
+import { useSearchParams } from 'next/navigation';
import { useCallback, useState } from 'react';
@@ -24,22 +24,8 @@ const getLoginErrorMessage = (problem: CommonErrorResponse) => {
return '로그인에 실패했습니다.';
};
-// 📜 proxy 설정 후 삭제
-// const isCommonErrorResponse = (e: unknown): e is CommonErrorResponse => {
-// if (!e || typeof e !== 'object') return false;
-
-// const obj = e as Record;
-// return (
-// typeof obj.status === 'number' &&
-// typeof obj.detail === 'string' &&
-// typeof obj.errorCode === 'string' &&
-// typeof obj.instance === 'string'
-// );
-// };
-
export const useLogin = () => {
const searchParams = useSearchParams();
- const router = useRouter();
const [loginError, setLoginError] = useState(null);
const clearLoginError = useCallback(() => setLoginError(null), []);
@@ -56,16 +42,8 @@ export const useLogin = () => {
setIsAuthenticated(true);
const nextPath = normalizePath(searchParams.get('path'));
- // window.location.replace(nextPath);
-
- router.replace(nextPath);
+ window.location.replace(nextPath);
} catch (error) {
- // if (isCommonErrorResponse(error)) {
- // console.error('[LOGIN ERROR]', error.errorCode, error.detail);
- // setLoginError(getLoginErrorMessage(error));
- // return;
- // }
-
if (axios.isAxiosError(error)) {
const axiosError = error as AxiosError;
const problem = axiosError.response?.data;
@@ -78,7 +56,7 @@ export const useLogin = () => {
}
console.error(error);
- setLoginError('알 수 없는 오류가 발생했습니다.');
+ setLoginError('로그인에 실패했습니다. 다시 시도해주세요.');
}
};
diff --git a/src/hooks/use-auth/use-auth-logout/index.ts b/src/hooks/use-auth/use-auth-logout/index.ts
index 71d20b67..905fcd78 100644
--- a/src/hooks/use-auth/use-auth-logout/index.ts
+++ b/src/hooks/use-auth/use-auth-logout/index.ts
@@ -1,7 +1,5 @@
'use client';
-import { useRouter } from 'next/navigation';
-
import { useQueryClient } from '@tanstack/react-query';
import { API } from '@/api';
@@ -9,7 +7,6 @@ import { userKeys } from '@/lib/query-key/query-key-user';
import { useAuth } from '@/providers';
export const useLogout = () => {
- const router = useRouter();
const queryClient = useQueryClient();
const { setIsAuthenticated } = useAuth();
@@ -24,8 +21,7 @@ export const useLogout = () => {
queryClient.removeQueries({ queryKey: userKeys.all });
setIsAuthenticated(false);
-
- router.push('/');
+ window.location.replace('/');
}
};
diff --git a/src/hooks/use-auth/use-auth-signup/index.ts b/src/hooks/use-auth/use-auth-signup/index.ts
index 859f3445..6afbf42c 100644
--- a/src/hooks/use-auth/use-auth-signup/index.ts
+++ b/src/hooks/use-auth/use-auth-signup/index.ts
@@ -11,9 +11,7 @@ export const useSignup = () => {
const handleSignup = async (payload: SignupRequest, formApi: { reset: () => void }) => {
try {
- const result = await API.authService.signup(payload);
- // 📜 추후 삭제
- console.log('signup success:', result);
+ await API.authService.signup(payload);
formApi.reset();
router.push('/login');
@@ -27,7 +25,7 @@ export const useSignup = () => {
alert(problem.detail || '회원가입에 실패했습니다.');
} else {
console.error(error);
- alert('알 수 없는 오류가 발생했습니다.');
+ alert('회원가입에 실패했습니다. 잠시 후에 다시 시도해주세요.');
}
}
};
diff --git a/src/hooks/use-auth/use-auth-withdraw/index.ts b/src/hooks/use-auth/use-auth-withdraw/index.ts
index 78f3a689..a0891d31 100644
--- a/src/hooks/use-auth/use-auth-withdraw/index.ts
+++ b/src/hooks/use-auth/use-auth-withdraw/index.ts
@@ -12,7 +12,7 @@ export const useWithdraw = () => {
} catch (error) {
// 📜 에러 UI 결정나면 변경
console.error('[WITHDRAW ERROR]', error);
- alert('회원탈퇴에 실패했습니다.');
+ alert('회원탈퇴에 실패했습니다. 잠시 후에 다시 시도해주세요.');
}
};