7e8f4859cd
- Add ADR-036 unified OCR architecture (typhoon-ocr via Ollama) - Extend AI execution profiles for OCR sandbox configuration - Add comprehensive frontend test coverage (components, hooks, services) - Add backend test coverage for document-numbering services - Update OCR sidecar with typhoon-ocr integration - Add AI policy service and execution profile management - Update AGENTS.md and architecture documentation
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
// File: frontend/components/admin/security/__tests__/rbac-matrix.test.tsx
|
|
// Change Log
|
|
// - 2026-06-13: Add coverage for RBAC matrix load, toggle, and save behavior.
|
|
|
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
import userEvent from '@testing-library/user-event';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { toast } from 'sonner';
|
|
import apiClient from '@/lib/api/client';
|
|
import { createTestQueryClient } from '@/lib/test-utils';
|
|
import { RbacMatrix } from '../rbac-matrix';
|
|
|
|
const roles = [
|
|
{
|
|
publicId: '019505a1-7c3e-7000-8000-abc123def601',
|
|
roleId: 10,
|
|
roleName: 'Admin',
|
|
permissions: [{ permissionId: 1, permissionName: 'system.view', description: 'View system' }],
|
|
},
|
|
{
|
|
publicId: '019505a1-7c3e-7000-8000-abc123def602',
|
|
roleId: 20,
|
|
roleName: 'Viewer',
|
|
permissions: [],
|
|
},
|
|
];
|
|
|
|
const permissions = [
|
|
{ permissionId: 1, permissionName: 'system.view', description: 'View system' },
|
|
{ permissionId: 2, permissionName: 'system.manage', description: 'Manage system' },
|
|
];
|
|
|
|
function renderWithQueryClient() {
|
|
const { wrapper } = createTestQueryClient();
|
|
return render(<RbacMatrix />, { wrapper });
|
|
}
|
|
|
|
describe('RbacMatrix', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
vi.mocked(apiClient.get).mockImplementation((url: string) => {
|
|
if (url === '/users/roles') return Promise.resolve({ data: { data: roles } });
|
|
if (url === '/users/permissions') return Promise.resolve({ data: { data: permissions } });
|
|
return Promise.resolve({ data: [] });
|
|
});
|
|
vi.mocked(apiClient.patch).mockResolvedValue({ data: { success: true } });
|
|
});
|
|
|
|
it('renders roles and permissions from API data', async () => {
|
|
renderWithQueryClient();
|
|
expect(await screen.findByText('Admin')).toBeInTheDocument();
|
|
expect(screen.getByText('Viewer')).toBeInTheDocument();
|
|
expect(screen.getByText('system.manage')).toBeInTheDocument();
|
|
});
|
|
|
|
it('saves pending permission changes', async () => {
|
|
const user = userEvent.setup();
|
|
renderWithQueryClient();
|
|
await screen.findByText('system.manage');
|
|
const checkboxes = screen.getAllByRole('checkbox');
|
|
await user.click(checkboxes[3]);
|
|
await user.click(screen.getByRole('button', { name: /save changes/i }));
|
|
await waitFor(() => {
|
|
expect(apiClient.patch).toHaveBeenCalledWith('/users/roles/20/permissions', { permissionIds: [2] });
|
|
});
|
|
expect(toast.success).toHaveBeenCalledWith('Permissions updated successfully');
|
|
});
|
|
|
|
it('renders empty matrix safely when API response is malformed', async () => {
|
|
vi.mocked(apiClient.get).mockResolvedValue({ data: { data: { data: null } } });
|
|
renderWithQueryClient();
|
|
await waitFor(() => {
|
|
expect(screen.getByRole('button', { name: /save changes/i })).toBeDisabled();
|
|
});
|
|
});
|
|
});
|