149 lines
4.8 KiB
TypeScript
149 lines
4.8 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import LoginPage from '../app/(auth)/login/page';
|
|
import { useAuthStore } from '../stores/auth-store';
|
|
|
|
// Mock next/navigation
|
|
vi.mock('next/navigation', () => ({
|
|
useRouter: () => ({
|
|
push: vi.fn(),
|
|
}),
|
|
}));
|
|
|
|
// Mock useTranslation
|
|
vi.mock('../shared/hooks/use-translation', () => ({
|
|
useTranslation: () => ({
|
|
t: (key: string) => key,
|
|
}),
|
|
}));
|
|
|
|
// Mock auth store
|
|
vi.mock('../stores/auth-store', () => ({
|
|
useAuthStore: vi.fn(),
|
|
}));
|
|
|
|
describe('Auth Flow Integration', () => {
|
|
let queryClient: QueryClient;
|
|
let mockAuthStore: any;
|
|
|
|
beforeEach(() => {
|
|
queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: { retry: false },
|
|
mutations: { retry: false },
|
|
},
|
|
});
|
|
|
|
mockAuthStore = {
|
|
login: vi.fn(),
|
|
isLoading: false,
|
|
user: null,
|
|
isAuthenticated: false,
|
|
};
|
|
|
|
(useAuthStore as any).mockReturnValue(mockAuthStore);
|
|
});
|
|
|
|
const renderLoginPage = () => {
|
|
return render(
|
|
<QueryClientProvider client={queryClient}>
|
|
<LoginPage />
|
|
</QueryClientProvider>
|
|
);
|
|
};
|
|
|
|
describe('Login Page', () => {
|
|
it('renders login form with required fields', () => {
|
|
renderLoginPage();
|
|
|
|
expect(screen.getByLabelText(/email/i)).toBeInTheDocument();
|
|
expect(screen.getByLabelText(/password/i)).toBeInTheDocument();
|
|
expect(screen.getByRole('button', { name: /login/i })).toBeInTheDocument();
|
|
expect(screen.getByText(/remember me/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows validation errors for empty fields', async () => {
|
|
renderLoginPage();
|
|
|
|
const submitButton = screen.getByRole('button', { name: /login/i });
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText(/validation\.emailRequired/i)).toBeInTheDocument();
|
|
expect(screen.getByText(/validation\.password/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it('shows validation error for invalid email', async () => {
|
|
renderLoginPage();
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
const passwordInput = screen.getByLabelText(/password/i);
|
|
const submitButton = screen.getByRole('button', { name: /login/i });
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'invalid-email' } });
|
|
fireEvent.change(passwordInput, { target: { value: 'password123' } });
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText(/validation\.email/i)).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
it('calls login function on valid form submission', async () => {
|
|
mockAuthStore.login.mockResolvedValue(undefined);
|
|
|
|
renderLoginPage();
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
const passwordInput = screen.getByLabelText(/password/i);
|
|
const submitButton = screen.getByRole('button', { name: /login/i });
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
fireEvent.change(passwordInput, { target: { value: 'password123' } });
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(mockAuthStore.login).toHaveBeenCalledWith('test@example.com', 'password123');
|
|
});
|
|
});
|
|
|
|
it('shows loading state during login', async () => {
|
|
mockAuthStore.isLoading = true;
|
|
mockAuthStore.login.mockImplementation(() => new Promise(() => {})); // Never resolves
|
|
|
|
renderLoginPage();
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
const passwordInput = screen.getByLabelText(/password/i);
|
|
const submitButton = screen.getByRole('button', { name: /login/i });
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
fireEvent.change(passwordInput, { target: { value: 'password123' } });
|
|
fireEvent.click(submitButton);
|
|
|
|
expect(screen.getByText(/auth\.login\.loginButtonLoading/i)).toBeInTheDocument();
|
|
expect(submitButton).toBeDisabled();
|
|
});
|
|
|
|
it('shows error message on login failure', async () => {
|
|
const errorMessage = 'Invalid credentials';
|
|
mockAuthStore.login.mockRejectedValue(new Error(errorMessage));
|
|
|
|
renderLoginPage();
|
|
|
|
const emailInput = screen.getByLabelText(/email/i);
|
|
const passwordInput = screen.getByLabelText(/password/i);
|
|
const submitButton = screen.getByRole('button', { name: /login/i });
|
|
|
|
fireEvent.change(emailInput, { target: { value: 'test@example.com' } });
|
|
fireEvent.change(passwordInput, { target: { value: 'password123' } });
|
|
fireEvent.click(submitButton);
|
|
|
|
await waitFor(() => {
|
|
expect(screen.getByText(errorMessage)).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|
|
}); |