xpeditis2.0/apps/frontend/src/lib/context/auth-context.test.tsx
2026-09-14 11:19:29 +02:00

54 lines
1.8 KiB
TypeScript

import React from 'react';
import { act, renderHook } from '@testing-library/react';
import { AuthProvider, useAuth } from './auth-context';
import { getCurrentUser, login } from '../api/auth';
const mockPush = jest.fn();
jest.mock('next/navigation', () => ({ useRouter: () => ({ push: mockPush }) }));
jest.mock('../api/auth', () => ({
login: jest.fn(),
getCurrentUser: jest.fn(),
register: jest.fn(),
logout: jest.fn(),
}));
jest.mock('../api/client', () => ({ hasSession: () => false, clearAuthTokens: jest.fn() }));
describe('authenticated navigation', () => {
beforeEach(() => {
jest.clearAllMocks();
jest
.mocked(getCurrentUser)
.mockResolvedValue({ id: 'test-user' } as Awaited<ReturnType<typeof getCurrentUser>>);
});
it.each(['javascript:alert(1)', '//example.org', '/\\example.org', '/\n/example.org'])(
'does not navigate to attacker destination %j',
async destination => {
const { result } = renderHook(useAuth, { wrapper: AuthProvider });
await act(async () => {
await result.current.login('user@example.org', 'password', destination);
});
expect(login).toHaveBeenCalledWith({
email: 'user@example.org',
password: 'password',
rememberMe: false,
});
expect(mockPush).toHaveBeenCalledWith('/dashboard');
expect(result.current.isAuthenticated).toBe(true);
}
);
it('preserves localized navigation after successful login', async () => {
const { result } = renderHook(useAuth, { wrapper: AuthProvider });
await act(async () => {
await result.current.login(
'user@example.org',
'password',
'/fr/dashboard?tab=1#bookings',
true
);
});
expect(mockPush).toHaveBeenCalledWith('/fr/dashboard?tab=1#bookings');
});
});