Files
pos-system/apps/web-client/src/__tests__/auth-flow.integration.test.tsx

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();
});
});
});
});