You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

130 lines
3.3 KiB
TypeScript

import { describe, it, expect, vi, afterEach } from 'vitest';
import { render, waitFor, screen } from '@solidjs/testing-library';
import { Router, Route } from '@solidjs/router';
import { AuthProvider, useAuth } from '~/contexts/AuthContext';
import { I18nProvider } from '~/i18n';
import { ToastProvider } from '~/components/ui/Toast';
import { authApi } from '~/api/auth';
import type { User } from '~/types';
vi.mock('~/api/auth', () => ({
authApi: {
me: vi.fn(),
logout: vi.fn(),
},
}));
const mockedMe = vi.mocked(authApi.me);
afterEach(() => {
vi.clearAllMocks();
});
const adminUser: User = {
id: '1',
email: 'admin@example.com',
display_name: 'Admin',
role: 'admin',
created_at: '2026-01-01T00:00:00Z',
};
const regularUser: User = {
id: '2',
email: 'user@example.com',
display_name: 'User',
role: 'user',
created_at: '2026-01-01T00:00:00Z',
};
describe('Admin Route Guard', () => {
it('should expose isAdmin as true for admin users', async () => {
mockedMe.mockResolvedValue(adminUser);
const TestComponent = () => {
const { isAdmin, loading } = useAuth();
return (
<div>
<span data-testid="loading">{loading() ? 'true' : 'false'}</span>
<span data-testid="isAdmin">{isAdmin() ? 'true' : 'false'}</span>
</div>
);
};
render(() => (
<I18nProvider locale="fr">
<ToastProvider>
<AuthProvider>
<TestComponent />
</AuthProvider>
</ToastProvider>
</I18nProvider>
));
await waitFor(() => {
expect(screen.getByTestId('loading').textContent).toBe('false');
});
expect(screen.getByTestId('isAdmin').textContent).toBe('true');
});
it('should expose isAdmin as false for non-admin users', async () => {
mockedMe.mockResolvedValue(regularUser);
const TestComponent = () => {
const { isAdmin, loading } = useAuth();
return (
<div>
<span data-testid="loading">{loading() ? 'true' : 'false'}</span>
<span data-testid="isAdmin">{isAdmin() ? 'true' : 'false'}</span>
</div>
);
};
render(() => (
<I18nProvider locale="fr">
<ToastProvider>
<AuthProvider>
<TestComponent />
</AuthProvider>
</ToastProvider>
</I18nProvider>
));
await waitFor(() => {
expect(screen.getByTestId('loading').textContent).toBe('false');
});
expect(screen.getByTestId('isAdmin').textContent).toBe('false');
});
it('should expose isAdmin as false when user is null', async () => {
mockedMe.mockRejectedValue(new Error('Unauthorized'));
const TestComponent = () => {
const { isAdmin, loading } = useAuth();
return (
<div>
<span data-testid="loading">{loading() ? 'true' : 'false'}</span>
<span data-testid="isAdmin">{isAdmin() ? 'true' : 'false'}</span>
</div>
);
};
render(() => (
<I18nProvider locale="fr">
<ToastProvider>
<AuthProvider>
<TestComponent />
</AuthProvider>
</ToastProvider>
</I18nProvider>
));
await waitFor(() => {
expect(screen.getByTestId('loading').textContent).toBe('false');
});
expect(screen.getByTestId('isAdmin').textContent).toBe('false');
});
});