Files
Charon/frontend/src/pages/__tests__/Setup.test.tsx
2026-01-02 01:01:54 +00:00

167 lines
4.8 KiB
TypeScript

import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter } from 'react-router-dom';
import { vi, describe, it, expect, beforeEach } from 'vitest';
import Setup from '../Setup';
import * as setupApi from '../../api/setup';
// Mock AuthContext so useAuth works in tests
vi.mock('../../hooks/useAuth', () => ({
useAuth: () => ({
login: vi.fn(),
logout: vi.fn(),
isAuthenticated: false,
isLoading: false,
user: null,
}),
}));
// Mock API client
vi.mock('../../api/client', () => ({
default: {
post: vi.fn().mockResolvedValue({ data: {} }),
get: vi.fn().mockResolvedValue({ data: {} }),
},
}));
// Mock react-router-dom
const mockNavigate = vi.fn();
vi.mock('react-router-dom', async () => {
const actual = await vi.importActual('react-router-dom');
return {
...actual,
useNavigate: () => mockNavigate,
};
});
// Mock the API module
vi.mock('../../api/setup', () => ({
getSetupStatus: vi.fn(),
performSetup: vi.fn(),
}));
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const renderWithProviders = (ui: React.ReactNode) => {
return render(
<QueryClientProvider client={queryClient}>
<MemoryRouter>
{ui}
</MemoryRouter>
</QueryClientProvider>
);
};
describe('Setup Page', () => {
beforeEach(() => {
vi.clearAllMocks();
queryClient.clear();
});
it('renders setup form when setup is required', async () => {
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
renderWithProviders(<Setup />);
await waitFor(() => {
expect(screen.getByText('Welcome to Charon')).toBeTruthy();
});
// Verify logo is present
expect(screen.getAllByAltText('Charon').length).toBeGreaterThan(0);
expect(screen.getByLabelText('Name')).toBeTruthy();
expect(screen.getByLabelText('Email Address')).toBeTruthy();
expect(screen.getByLabelText('Password')).toBeTruthy();
});
it('does not render form when setup is not required', async () => {
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: false });
renderWithProviders(<Setup />);
await waitFor(() => {
expect(screen.queryByText('Welcome to Charon')).toBeNull();
});
await waitFor(() => {
expect(mockNavigate).toHaveBeenCalledWith('/login');
});
});
it('submits form successfully', async () => {
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
vi.mocked(setupApi.performSetup).mockResolvedValue();
renderWithProviders(<Setup />);
await waitFor(() => {
expect(screen.getByText('Welcome to Charon')).toBeTruthy();
});
const user = userEvent.setup()
await user.type(screen.getByLabelText('Name'), 'Admin')
await user.type(screen.getByLabelText('Email Address'), 'admin@example.com')
await user.type(screen.getByLabelText('Password'), 'password123')
await user.click(screen.getByRole('button', { name: 'Create Admin Account' }))
await waitFor(() => {
expect(setupApi.performSetup).toHaveBeenCalledWith({
name: 'Admin',
email: 'admin@example.com',
password: 'password123',
});
});
await waitFor(() => {
expect(mockNavigate).toHaveBeenCalledWith('/');
});
});
it('displays error on submission failure', async () => {
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
vi.mocked(setupApi.performSetup).mockRejectedValue({
response: { data: { error: 'Setup failed' } }
});
renderWithProviders(<Setup />);
await waitFor(() => {
expect(screen.getByText('Welcome to Charon')).toBeTruthy();
});
const user = userEvent.setup()
await user.type(screen.getByLabelText('Name'), 'Admin')
await user.type(screen.getByLabelText('Email Address'), 'admin@example.com')
await user.type(screen.getByLabelText('Password'), 'password123')
await user.click(screen.getByRole('button', { name: 'Create Admin Account' }))
await waitFor(() => {
expect(screen.getByText('Setup failed')).toBeTruthy();
});
});
it('has proper autocomplete attributes for password managers', async () => {
vi.mocked(setupApi.getSetupStatus).mockResolvedValue({ setupRequired: true });
renderWithProviders(<Setup />);
await waitFor(() => {
expect(screen.getByText('Welcome to Charon')).toBeTruthy();
});
const emailInput = screen.getByLabelText('Email Address')
const passwordInput = screen.getByLabelText('Password')
expect(emailInput).toHaveAttribute('autocomplete', 'email')
expect(passwordInput).toHaveAttribute('autocomplete', 'new-password')
});
});