import type { ReactNode } from 'react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, renderHook, waitFor } from '@testing-library/react' import { del, get, post, put } from '@/service/base' import { useCopyAccessRule, useCreateAccessRule, useDeleteAccessRule, useInfiniteWorkspaceAppAccessRules, useInfiniteWorkspaceDatasetAccessRules, useUpdateAccessRule, } from '../use-workspace-access-rules' vi.mock('@/service/base', () => ({ del: vi.fn(), get: vi.fn(), post: vi.fn(), put: vi.fn(), })) const createWrapper = () => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false }, }, }) return ({ children }: { children: ReactNode }) => ( {children} ) } describe('use-workspace-access-rules', () => { beforeEach(() => { vi.clearAllMocks() vi.mocked(get).mockResolvedValue({ items: [], pagination: {} }) vi.mocked(post).mockResolvedValue({}) vi.mocked(put).mockResolvedValue({}) vi.mocked(del).mockResolvedValue({}) }) // Queries load workspace-level app and dataset access policies from separate endpoints. describe('Queries', () => { it('should fetch workspace app access rules', async () => { renderHook(() => useInfiniteWorkspaceAppAccessRules({ page: 1, limit: 20, language: 'zh' }), { wrapper: createWrapper() }) await waitFor(() => { expect(get).toHaveBeenCalledWith('/workspaces/current/rbac/workspace/apps/access-policy', { params: { page: 1, limit: 20, language: 'zh' }, }) }) }) it('should fetch workspace dataset access rules', async () => { renderHook(() => useInfiniteWorkspaceDatasetAccessRules({ page: 1, limit: 20, language: 'ja' }), { wrapper: createWrapper() }) await waitFor(() => { expect(get).toHaveBeenCalledWith('/workspaces/current/rbac/workspace/datasets/access-policy', { params: { page: 1, limit: 20, language: 'ja' }, }) }) }) }) // Rule mutations normalize form data to the API body expected by RBAC access policies. describe('Rule Mutations', () => { it('should create and update access rules', async () => { const createHook = renderHook(() => useCreateAccessRule(), { wrapper: createWrapper() }) const updateHook = renderHook(() => useUpdateAccessRule(), { wrapper: createWrapper() }) await act(async () => { await createHook.result.current.mutateAsync({ resourceType: 'app', name: 'App rule', description: 'App access', permission_keys: ['app.acl.edit'], }) await updateHook.result.current.mutateAsync({ id: 'policy-1', resourceType: 'dataset', name: 'Dataset rule', description: 'Dataset access', permission_keys: ['dataset.acl.edit'], }) }) expect(post).toHaveBeenCalledWith('/workspaces/current/rbac/access-policies', { body: { resource_type: 'app', name: 'App rule', description: 'App access', permission_keys: ['app.acl.edit'], }, }) expect(put).toHaveBeenCalledWith('/workspaces/current/rbac/access-policies/policy-1', { body: { id: 'policy-1', name: 'Dataset rule', description: 'Dataset access', permission_keys: ['dataset.acl.edit'], }, }) }) it('should copy and delete access rules by id', async () => { const copyHook = renderHook(() => useCopyAccessRule('app'), { wrapper: createWrapper() }) const deleteHook = renderHook(() => useDeleteAccessRule('dataset'), { wrapper: createWrapper() }) await act(async () => { await copyHook.result.current.mutateAsync('policy-1') await deleteHook.result.current.mutateAsync('policy-2') }) expect(post).toHaveBeenCalledWith('/workspaces/current/rbac/access-policies/policy-1/copy', {}) expect(del).toHaveBeenCalledWith('/workspaces/current/rbac/access-policies/policy-2', {}) }) }) })