// File: frontend/components/numbering/__tests__/cancel-number-form.test.tsx import React from 'react'; import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { CancelNumberForm } from '../cancel-number-form'; import { documentNumberingService } from '@/lib/services/document-numbering.service'; import { toast } from 'sonner'; vi.mock('@/lib/services/document-numbering.service', () => ({ documentNumberingService: { cancelNumber: vi.fn(), }, })); vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), }, })); describe('CancelNumberForm', () => { beforeEach(() => { vi.clearAllMocks(); }); it('renders correctly', () => { render(); expect(screen.getByRole('heading', { name: 'Cancel Number' })).toBeInTheDocument(); expect(screen.getByLabelText('Document Number')).toBeInTheDocument(); expect(screen.getByLabelText('Reason')).toBeInTheDocument(); expect(screen.getByRole('button', { name: 'Cancel Number' })).toBeInTheDocument(); }); it('shows validation error for empty fields', async () => { const user = userEvent.setup(); render(); const button = screen.getByRole('button', { name: 'Cancel Number' }); await user.click(button); await waitFor(() => { expect(screen.getByText('Document Number is required')).toBeInTheDocument(); expect(screen.getByText('Reason must be at least 5 characters')).toBeInTheDocument(); }); expect(documentNumberingService.cancelNumber).not.toHaveBeenCalled(); }); it('shows validation error for short reason', async () => { const user = userEvent.setup(); render(); await user.type(screen.getByLabelText('Document Number'), 'DOC-001'); await user.type(screen.getByLabelText('Reason'), 'abc'); // too short const button = screen.getByRole('button', { name: 'Cancel Number' }); await user.click(button); await waitFor(() => { expect(screen.getByText('Reason must be at least 5 characters')).toBeInTheDocument(); }); expect(documentNumberingService.cancelNumber).not.toHaveBeenCalled(); }); it('handles successful cancellation', async () => { const user = userEvent.setup(); render(); await user.type(screen.getByLabelText('Document Number'), 'DOC-001'); await user.type(screen.getByLabelText('Reason'), 'Generated by mistake'); vi.mocked(documentNumberingService.cancelNumber).mockResolvedValue({} as any); const button = screen.getByRole('button', { name: 'Cancel Number' }); await user.click(button); expect(documentNumberingService.cancelNumber).toHaveBeenCalledWith({ documentNumber: 'DOC-001', reason: 'Generated by mistake', }); await waitFor(() => { expect(toast.success).toHaveBeenCalledWith('Number cancelled successfully.'); }); // Check if form was reset expect(screen.getByLabelText('Document Number')).toHaveValue(''); expect(screen.getByLabelText('Reason')).toHaveValue(''); }); it('handles cancellation failure', async () => { const user = userEvent.setup(); render(); await user.type(screen.getByLabelText('Document Number'), 'DOC-001'); await user.type(screen.getByLabelText('Reason'), 'Generated by mistake'); vi.mocked(documentNumberingService.cancelNumber).mockRejectedValue(new Error('Failed')); const button = screen.getByRole('button', { name: 'Cancel Number' }); await user.click(button); await waitFor(() => { expect(toast.error).toHaveBeenCalledWith('Failed to cancel number. It may not exist or is already cancelled.'); }); // Form is not reset on error expect(screen.getByLabelText('Document Number')).toHaveValue('DOC-001'); }); });