136 lines
3.9 KiB
TypeScript
136 lines
3.9 KiB
TypeScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||
|
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||
|
|
import { ToastProvider } from '@/components/ui/Toast';
|
||
|
|
import { I18nProvider } from '@/lib/i18n';
|
||
|
|
import LoginPage from '@/app/(auth)/login/page';
|
||
|
|
|
||
|
|
// Mock the API module
|
||
|
|
vi.mock('@/lib/api', () => ({
|
||
|
|
login: vi.fn(),
|
||
|
|
setTokens: vi.fn(),
|
||
|
|
clearTokens: vi.fn(),
|
||
|
|
isAuthenticated: () => false,
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock next/navigation
|
||
|
|
vi.mock('next/navigation', () => ({
|
||
|
|
useRouter: () => ({
|
||
|
|
push: vi.fn(),
|
||
|
|
replace: vi.fn(),
|
||
|
|
back: vi.fn(),
|
||
|
|
refresh: vi.fn(),
|
||
|
|
}),
|
||
|
|
redirect: vi.fn(),
|
||
|
|
}));
|
||
|
|
|
||
|
|
import { login as mockLogin } from '@/lib/api';
|
||
|
|
|
||
|
|
describe('LoginPage', () => {
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.clearAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders the login form with email and password fields', () => {
|
||
|
|
render(
|
||
|
|
<I18nProvider initialLocale="de">
|
||
|
|
<ToastProvider>
|
||
|
|
<LoginPage />
|
||
|
|
</ToastProvider>
|
||
|
|
</I18nProvider>
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(screen.getByTestId('login-form')).toBeInTheDocument();
|
||
|
|
expect(screen.getByTestId('email-input')).toBeInTheDocument();
|
||
|
|
expect(screen.getByTestId('password-input')).toBeInTheDocument();
|
||
|
|
expect(screen.getByTestId('login-button')).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('shows validation errors for empty fields', async () => {
|
||
|
|
render(
|
||
|
|
<I18nProvider initialLocale="de">
|
||
|
|
<ToastProvider>
|
||
|
|
<LoginPage />
|
||
|
|
</ToastProvider>
|
||
|
|
</I18nProvider>
|
||
|
|
);
|
||
|
|
|
||
|
|
const submitButton = screen.getByTestId('login-button');
|
||
|
|
fireEvent.click(submitButton);
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
expect(screen.getByText('E-Mail-Adresse ist erforderlich')).toBeInTheDocument();
|
||
|
|
expect(screen.getByText('Passwort ist erforderlich')).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('calls login API on submit with valid credentials', async () => {
|
||
|
|
(mockLogin as any).mockResolvedValue({
|
||
|
|
access_token: 'fake-token',
|
||
|
|
refresh_token: 'fake-refresh',
|
||
|
|
token_type: 'bearer',
|
||
|
|
expires_in: 900,
|
||
|
|
});
|
||
|
|
|
||
|
|
render(
|
||
|
|
<I18nProvider initialLocale="de">
|
||
|
|
<ToastProvider>
|
||
|
|
<LoginPage />
|
||
|
|
</ToastProvider>
|
||
|
|
</I18nProvider>
|
||
|
|
);
|
||
|
|
|
||
|
|
const emailInput = screen.getByTestId('email-input');
|
||
|
|
const passwordInput = screen.getByTestId('password-input');
|
||
|
|
const submitButton = screen.getByTestId('login-button');
|
||
|
|
|
||
|
|
fireEvent.change(emailInput, { target: { value: 'admin@test.com' } });
|
||
|
|
fireEvent.change(passwordInput, { target: { value: 'Admin12345!' } });
|
||
|
|
fireEvent.click(submitButton);
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
expect(mockLogin).toHaveBeenCalledWith('admin@test.com', 'Admin12345!');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('shows error toast on login failure', async () => {
|
||
|
|
(mockLogin as any).mockRejectedValue({
|
||
|
|
error: { code: 'INVALID_CREDENTIALS', message: 'Invalid email or password' },
|
||
|
|
});
|
||
|
|
|
||
|
|
render(
|
||
|
|
<I18nProvider initialLocale="de">
|
||
|
|
<ToastProvider>
|
||
|
|
<LoginPage />
|
||
|
|
</ToastProvider>
|
||
|
|
</I18nProvider>
|
||
|
|
);
|
||
|
|
|
||
|
|
const emailInput = screen.getByTestId('email-input');
|
||
|
|
const passwordInput = screen.getByTestId('password-input');
|
||
|
|
const submitButton = screen.getByTestId('login-button');
|
||
|
|
|
||
|
|
fireEvent.change(emailInput, { target: { value: 'wrong@test.com' } });
|
||
|
|
fireEvent.change(passwordInput, { target: { value: 'wrongpass' } });
|
||
|
|
fireEvent.click(submitButton);
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
const toastContainer = screen.getByTestId('toast-container');
|
||
|
|
expect(toastContainer).toHaveTextContent('Invalid email or password');
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
it('renders with English locale when selected', () => {
|
||
|
|
render(
|
||
|
|
<I18nProvider initialLocale="en">
|
||
|
|
<ToastProvider>
|
||
|
|
<LoginPage />
|
||
|
|
</ToastProvider>
|
||
|
|
</I18nProvider>
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(screen.getAllByText('Sign In').length).toBeGreaterThanOrEqual(1);
|
||
|
|
expect(screen.getByText('Email Address')).toBeInTheDocument();
|
||
|
|
expect(screen.getByText('Password')).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
});
|