216 lines
6.4 KiB
TypeScript
216 lines
6.4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { renderHook, waitFor, act } from '@testing-library/react';
|
|
import { createTestQueryClient } from '@/lib/test-utils';
|
|
import {
|
|
useRFAs,
|
|
useRFA,
|
|
useCreateRFA,
|
|
useUpdateRFA,
|
|
useProcessRFA,
|
|
rfaKeys,
|
|
} from '../use-rfa';
|
|
import { rfaService } from '@/lib/services/rfa.service';
|
|
import { toast } from 'sonner';
|
|
|
|
// Mock service
|
|
vi.mock('@/lib/services/rfa.service', () => ({
|
|
rfaService: {
|
|
getAll: vi.fn(),
|
|
getById: vi.fn(),
|
|
create: vi.fn(),
|
|
update: vi.fn(),
|
|
processWorkflow: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
describe('use-rfa hooks', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('rfaKeys', () => {
|
|
it('should generate correct cache keys', () => {
|
|
expect(rfaKeys.all).toEqual(['rfas']);
|
|
expect(rfaKeys.lists()).toEqual(['rfas', 'list']);
|
|
expect(rfaKeys.list({ projectId: 1 })).toEqual(['rfas', 'list', { projectId: 1 }]);
|
|
expect(rfaKeys.details()).toEqual(['rfas', 'detail']);
|
|
expect(rfaKeys.detail(1)).toEqual(['rfas', 'detail', 1]);
|
|
});
|
|
});
|
|
|
|
describe('useRFAs', () => {
|
|
it('should fetch RFAs successfully', async () => {
|
|
const mockData = {
|
|
data: [
|
|
{ id: 1, rfaNumber: 'RFA-001' },
|
|
{ id: 2, rfaNumber: 'RFA-002' },
|
|
],
|
|
meta: { total: 2, page: 1, limit: 10 },
|
|
};
|
|
|
|
vi.mocked(rfaService.getAll).mockResolvedValue(mockData);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useRFAs({ projectId: 1 }), { wrapper });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
expect(rfaService.getAll).toHaveBeenCalledWith({ projectId: 1 });
|
|
});
|
|
|
|
it('should handle error state', async () => {
|
|
vi.mocked(rfaService.getAll).mockRejectedValue(new Error('API Error'));
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useRFAs({ projectId: 1 }), { wrapper });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isError).toBe(true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('useRFA', () => {
|
|
it('should fetch single RFA by id', async () => {
|
|
const mockData = { id: 1, rfaNumber: 'RFA-001', status: 'pending' };
|
|
vi.mocked(rfaService.getById).mockResolvedValue(mockData);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useRFA(1), { wrapper });
|
|
|
|
await waitFor(() => {
|
|
expect(result.current.isSuccess).toBe(true);
|
|
});
|
|
|
|
expect(result.current.data).toEqual(mockData);
|
|
expect(rfaService.getById).toHaveBeenCalledWith(1);
|
|
});
|
|
|
|
it('should not fetch when id is falsy', () => {
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useRFA(0), { wrapper });
|
|
|
|
expect(result.current.isFetching).toBe(false);
|
|
expect(rfaService.getById).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('useCreateRFA', () => {
|
|
it('should create RFA and show success toast', async () => {
|
|
const mockResponse = { id: 1, rfaNumber: 'RFA-001' };
|
|
vi.mocked(rfaService.create).mockResolvedValue(mockResponse);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useCreateRFA(), { wrapper });
|
|
|
|
await act(async () => {
|
|
await result.current.mutateAsync({
|
|
projectId: 1,
|
|
subject: 'Test RFA',
|
|
});
|
|
});
|
|
|
|
expect(rfaService.create).toHaveBeenCalled();
|
|
expect(toast.success).toHaveBeenCalledWith('RFA created successfully');
|
|
});
|
|
|
|
it('should show error toast on failure', async () => {
|
|
const mockError = {
|
|
message: 'Error',
|
|
response: { data: { message: 'Validation failed' } },
|
|
};
|
|
vi.mocked(rfaService.create).mockRejectedValue(mockError);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useCreateRFA(), { wrapper });
|
|
|
|
await act(async () => {
|
|
try {
|
|
await result.current.mutateAsync({
|
|
projectId: 1,
|
|
subject: '',
|
|
});
|
|
} catch {
|
|
// Expected
|
|
}
|
|
});
|
|
|
|
expect(toast.error).toHaveBeenCalledWith('Failed to create RFA', {
|
|
description: 'Validation failed',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('useUpdateRFA', () => {
|
|
it('should update RFA and invalidate cache', async () => {
|
|
const mockResponse = { id: 1, subject: 'Updated RFA' };
|
|
vi.mocked(rfaService.update).mockResolvedValue(mockResponse);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useUpdateRFA(), { wrapper });
|
|
|
|
await act(async () => {
|
|
await result.current.mutateAsync({
|
|
id: 1,
|
|
data: { subject: 'Updated RFA' },
|
|
});
|
|
});
|
|
|
|
expect(rfaService.update).toHaveBeenCalledWith(1, { subject: 'Updated RFA' });
|
|
expect(toast.success).toHaveBeenCalledWith('RFA updated successfully');
|
|
});
|
|
});
|
|
|
|
describe('useProcessRFA', () => {
|
|
it('should process workflow action and show toast', async () => {
|
|
const mockResponse = { id: 1, status: 'approved' };
|
|
vi.mocked(rfaService.processWorkflow).mockResolvedValue(mockResponse);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useProcessRFA(), { wrapper });
|
|
|
|
await act(async () => {
|
|
await result.current.mutateAsync({
|
|
id: 1,
|
|
data: { action: 'approve', comment: 'Approved' },
|
|
});
|
|
});
|
|
|
|
expect(rfaService.processWorkflow).toHaveBeenCalledWith(1, {
|
|
action: 'approve',
|
|
comment: 'Approved',
|
|
});
|
|
expect(toast.success).toHaveBeenCalledWith('Workflow status updated successfully');
|
|
});
|
|
|
|
it('should handle workflow error', async () => {
|
|
const mockError = {
|
|
message: 'Error',
|
|
response: { data: { message: 'Permission denied' } },
|
|
};
|
|
vi.mocked(rfaService.processWorkflow).mockRejectedValue(mockError);
|
|
|
|
const { wrapper } = createTestQueryClient();
|
|
const { result } = renderHook(() => useProcessRFA(), { wrapper });
|
|
|
|
await act(async () => {
|
|
try {
|
|
await result.current.mutateAsync({
|
|
id: 1,
|
|
data: { action: 'reject' },
|
|
});
|
|
} catch {
|
|
// Expected
|
|
}
|
|
});
|
|
|
|
expect(toast.error).toHaveBeenCalledWith('Failed to process workflow', {
|
|
description: 'Permission denied',
|
|
});
|
|
});
|
|
});
|
|
});
|