adds unit tests to cover 80%

This commit is contained in:
2026-06-26 00:27:27 +02:00
parent b84e2f8e3e
commit 0e01ca1e1c
69 changed files with 90596 additions and 46 deletions
@@ -0,0 +1,38 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { screen } from '@testing-library/react';
import { http, HttpResponse } from 'msw';
import { renderApp } from '@/test/utils';
import { server } from '@/mocks/server';
import { API_BASE, makeAuthResponse, mockUser } from '@/mocks/auth/fixtures';
import { _resetSetupStatusCache } from '@/router';
beforeEach(() => {
_resetSetupStatusCache();
});
describe('RoleGuard', () => {
it('renders protected content when user has an allowed role (Owner on /users)', async () => {
// Default auth mock returns Owner role, /users requires Owner or Administrator
server.use(
http.post(`${API_BASE}/api/v1/auth/refresh`, () =>
HttpResponse.json(makeAuthResponse()),
),
);
renderApp('/users');
expect(await screen.findByTestId('users-title')).toBeInTheDocument();
});
it('shows access denied message when user lacks the required role', async () => {
// Authenticate with 'User' role — /users requires Owner or Administrator
server.use(
http.post(`${API_BASE}/api/v1/auth/refresh`, () =>
HttpResponse.json(makeAuthResponse({ user: { ...mockUser, role: 'User' } })),
),
);
renderApp('/users');
expect(await screen.findByTestId('access-denied-message')).toBeInTheDocument();
expect(screen.queryByTestId('users-title')).not.toBeInTheDocument();
});
});
@@ -56,3 +56,29 @@ describe('AppLayout auth guard', () => {
expect(await screen.findByTestId('login-form-submit-button')).toBeInTheDocument();
});
});
describe('UserMenu', () => {
it('shows user name in menu after opening', async () => {
mockAuthenticated();
const user = userEvent.setup();
renderApp('/dashboard');
await screen.findByTestId('user-menu-button');
await user.click(screen.getByTestId('user-menu-button'));
expect(await screen.findByTestId('user-menu-name')).toBeInTheDocument();
});
it('logs out and redirects to login when logout is clicked', async () => {
mockAuthenticated();
const user = userEvent.setup();
renderApp('/dashboard');
await screen.findByTestId('user-menu-button');
await user.click(screen.getByTestId('user-menu-button'));
await screen.findByTestId('user-menu-logout');
await user.click(screen.getByTestId('user-menu-logout'));
expect(await screen.findByTestId('login-form-submit-button')).toBeInTheDocument();
});
});
@@ -0,0 +1,36 @@
import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { FormBannerError } from '@/components/ui/FormBannerError';
describe('FormBannerError', () => {
it('renders nothing when error is null', () => {
const { container } = render(
<FormBannerError error={null} onDismiss={vi.fn()} />,
);
expect(container.firstChild).toBeNull();
});
it('renders the error message when error is provided', () => {
render(
<FormBannerError
error={{ message: 'Something went wrong' }}
onDismiss={vi.fn()}
/>,
);
expect(screen.getByTestId('form-error-banner')).toBeInTheDocument();
expect(screen.getByText('Something went wrong')).toBeInTheDocument();
});
it('calls onDismiss when the dismiss button is clicked', async () => {
const onDismiss = vi.fn();
render(
<FormBannerError
error={{ message: 'Error to dismiss' }}
onDismiss={onDismiss}
/>,
);
await userEvent.click(screen.getByRole('button', { name: /dismiss/i }));
expect(onDismiss).toHaveBeenCalledOnce();
});
});