good forst commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
|
||||
import LoginPage from './page';
|
||||
import { AuthProvider } from '../_lib/auth-context';
|
||||
import { SuperAdminProvider } from '../_lib/super-admin-context';
|
||||
|
||||
const pushMock = jest.fn();
|
||||
const refreshMock = jest.fn();
|
||||
|
||||
jest.mock('next/navigation', () => ({
|
||||
useRouter: () => ({ push: pushMock, refresh: refreshMock, replace: jest.fn() }),
|
||||
useSearchParams: () => new URLSearchParams(),
|
||||
}));
|
||||
|
||||
function authResponse(body: unknown, status = 200) {
|
||||
return new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' } });
|
||||
}
|
||||
|
||||
const UNAUTHORIZED = () => Promise.resolve(new Response('Unauthorized', { status: 401 }));
|
||||
|
||||
function mockFetch(responses: Record<string, (url: string, init?: RequestInit) => Response | Promise<Response>>) {
|
||||
fetchSpy.mockImplementation((url: string, init?: RequestInit) => {
|
||||
const handler = responses[url];
|
||||
if (handler) return handler(url, init);
|
||||
return responses['default']?.(url, init) ?? UNAUTHORIZED();
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
fetchSpy = jest.spyOn(global, 'fetch');
|
||||
mockFetch({ default: UNAUTHORIZED });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
function renderWithProvider(ui: React.ReactElement) {
|
||||
return render(
|
||||
<AuthProvider>
|
||||
<SuperAdminProvider>{ui}</SuperAdminProvider>
|
||||
</AuthProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
describe('LoginPage', () => {
|
||||
it('renders email and password fields and a submit button', async () => {
|
||||
renderWithProvider(<LoginPage />);
|
||||
expect(await screen.findByLabelText(/email/i)).toBeInTheDocument();
|
||||
expect(await screen.findByLabelText(/password/i)).toBeInTheDocument();
|
||||
expect(await screen.findByRole('button', { name: /sign in/i })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('posts credentials to /api/auth/login and redirects on success', async () => {
|
||||
mockFetch({
|
||||
'/api/auth/login': () => authResponse({ admin: { id: 'a-1', email: 'me@x.com' } }),
|
||||
'/api/auth/me': () => authResponse({ admin: { id: 'a-1', email: 'me@x.com', role: 'OWNER', tenantId: 't1', tenantSlug: 'default', tenantName: 'Default' } }),
|
||||
});
|
||||
renderWithProvider(<LoginPage />);
|
||||
await screen.findByLabelText(/email/i);
|
||||
fireEvent.change(screen.getByLabelText(/email/i), { target: { value: 'me@x.com' } });
|
||||
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: 'secret' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /sign in/i }));
|
||||
await waitFor(() =>
|
||||
expect(fetchSpy).toHaveBeenCalledWith(
|
||||
'/api/auth/login',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email: 'me@x.com', password: 'secret' }),
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(pushMock).toHaveBeenCalledWith('/');
|
||||
});
|
||||
|
||||
it('shows an error message on 401', async () => {
|
||||
mockFetch({
|
||||
'/api/auth/login': () => authResponse({ message: 'Invalid email or password' }, 401),
|
||||
});
|
||||
renderWithProvider(<LoginPage />);
|
||||
await screen.findByLabelText(/email/i);
|
||||
fireEvent.change(screen.getByLabelText(/email/i), { target: { value: 'me@x.com' } });
|
||||
fireEvent.change(screen.getByLabelText(/password/i), { target: { value: 'wrong' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /sign in/i }));
|
||||
expect(await screen.findByRole('alert')).toHaveTextContent(/invalid email or password/i);
|
||||
expect(pushMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user