feat(ai): add ADR-036 unified OCR architecture and frontend test coverage
- 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
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user