diff --git a/components/escrow/__tests__/EscrowInsuranceCheckout.test.tsx b/components/escrow/__tests__/EscrowInsuranceCheckout.test.tsx index f1d1a02..47cc0f3 100644 --- a/components/escrow/__tests__/EscrowInsuranceCheckout.test.tsx +++ b/components/escrow/__tests__/EscrowInsuranceCheckout.test.tsx @@ -248,6 +248,19 @@ describe('EscrowInsuranceCheckout — escrow and cargo insurance flow', () => { ); }); + it('updates the estimated total when cargo coverage is selected', async () => { + const user = userEvent.setup(); + renderCheckout(); + await awaitPlansLoaded(); + + expect(screen.getByRole('radio', { name: /Continue without coverage/ })).toBeChecked(); + await user.click(screen.getByRole('radio', { name: /Premium Cover/ })); + await user.click(screen.getByRole('button', { name: 'Continue to payment' })); + + expect(screen.getByTestId('summary-premium')).toHaveTextContent('40.25 XLM'); + expect(screen.getByTestId('summary-total')).toHaveTextContent('290.25 XLM'); + }); + it('rounds the escrow total to stroop precision', async () => { const user = userEvent.setup(); mockGetPlans.mockResolvedValue([ diff --git a/features/deliveries/components/__tests__/BulkShipmentImport.test.tsx b/features/deliveries/components/__tests__/BulkShipmentImport.test.tsx index 6d8a76c..edc94c2 100644 --- a/features/deliveries/components/__tests__/BulkShipmentImport.test.tsx +++ b/features/deliveries/components/__tests__/BulkShipmentImport.test.tsx @@ -290,6 +290,16 @@ describe('BulkShipmentImport', () => { await waitFor(() => { expect(mockDeliveriesService.createDelivery).toHaveBeenCalledTimes(1); }); + + expect(mockDeliveriesService.createDelivery).toHaveBeenCalledWith({ + pickupAddress: '123 Main St', + destination: 'Lagos', + packageSize: 'small', + description: 'Electronics package', + recipientName: 'John Doe', + recipientPhone: '+2348012345678', + recipientEmail: 'john@example.com', + }); }); it('calls onComplete callback with results', async () => { diff --git a/features/deliveries/components/__tests__/CreateDeliveryForm.test.tsx b/features/deliveries/components/__tests__/CreateDeliveryForm.test.tsx new file mode 100644 index 0000000..3809fcf --- /dev/null +++ b/features/deliveries/components/__tests__/CreateDeliveryForm.test.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { CreateDeliveryForm } from '@/features/deliveries/components/CreateDeliveryForm'; +import { useCreateDelivery } from '@/hooks/useCreateDelivery'; + +jest.mock('@/hooks/useCreateDelivery'); + +const mockUseCreateDelivery = useCreateDelivery as jest.MockedFunction; + +function renderForm() { + const queryClient = new QueryClient(); + return render( + + + + ); +} + +describe('CreateDeliveryForm package tier mapping', () => { + it.each([ + ['small', 'Small'], + ['medium', 'Medium'], + ['large', 'Large'], + ])('keeps the %s shipping tier selectable as %s', async (value, label) => { + const user = userEvent.setup(); + const onSubmit = jest.fn(); + const register = jest.fn((name: string) => ({ name, onChange: jest.fn(), onBlur: jest.fn(), ref: jest.fn() })); + + mockUseCreateDelivery.mockReturnValue({ + form: { + register, + handleSubmit: (submit: (_values: unknown) => unknown) => (event: React.FormEvent) => { + event.preventDefault(); + return submit({ packageSize: value }); + }, + formState: { errors: {}, isValid: true }, + } as any, + isSubmitting: false, + isSuccess: false, + onSubmit, + }); + + renderForm(); + + const packageSize = screen.getByRole('combobox', { name: 'Package Size' }); + await user.selectOptions(packageSize, value); + + expect(packageSize).toHaveValue(value); + expect(screen.getByRole('option', { name: label })).toHaveValue(value); + }); +}); \ No newline at end of file diff --git a/features/escrow/components/__tests__/EscrowLock.test.tsx b/features/escrow/components/__tests__/EscrowLock.test.tsx index ab312e2..68bc0d5 100644 --- a/features/escrow/components/__tests__/EscrowLock.test.tsx +++ b/features/escrow/components/__tests__/EscrowLock.test.tsx @@ -1,10 +1,15 @@ import React from 'react'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { EscrowLock } from '@/features/escrow/components'; import { useEscrowLock } from '@/hooks/useEscrowLock'; import { useToast } from '@/hooks/useToast'; +jest.mock('@/services/escrowService', () => ({ + escrowService: { + lockEscrow: jest.fn(), + }, +})); jest.mock('@/hooks/useEscrowLock'); jest.mock('@/hooks/useToast'); @@ -19,6 +24,7 @@ describe('EscrowLock', () => { mockEscrowLock.mockReturnValue({ isLoading: false, error: null, + isSuccess: false, escrowId: null, transactionHash: null, lockEscrow: jest.fn().mockResolvedValue({ @@ -127,7 +133,7 @@ describe('EscrowLock', () => { await user.click(button); await waitFor(() => { - expect(screen.getByText('100.50 USDC')).toBeInTheDocument(); + expect(screen.getAllByText('100.50 USDC')).toHaveLength(2); }); }); @@ -194,9 +200,49 @@ describe('EscrowLock', () => { }); }); + it('passes the USDC payment mapping through the confirmation flow', async () => { + const user = userEvent.setup(); + const mockLockEscrow = jest.fn().mockResolvedValue({ + escrowId: 'escrow-usdc-1', + transactionHash: '0xusdc123', + }); + + mockEscrowLock.mockReturnValue({ + isLoading: false, + isSuccess: false, + error: null, + escrowId: null, + transactionHash: null, + lockEscrow: mockLockEscrow, + reset: jest.fn(), + } as any); + + render( + + ); + + await user.click(screen.getByRole('button', { name: /Lock Payment in Escrow/i })); + await user.click(screen.getByRole('button', { name: /Confirm Lock/i })); + + await waitFor(() => { + expect(mockLockEscrow).toHaveBeenCalledWith({ + deliveryId: 'delivery-usdc', + amount: 42.75, + currency: 'USDC', + walletAddress: 'GUSDCWALLET', + }); + }); + }); + it('displays success state with transaction hash', () => { mockEscrowLock.mockReturnValue({ isLoading: false, + isSuccess: true, error: null, escrowId: 'escrow-123', transactionHash: '0xabc123def456789', @@ -240,7 +286,8 @@ describe('EscrowLock', () => { expect(screen.getByText('Insufficient funds in wallet')).toBeInTheDocument(); }); - it('calls onSuccess callback with escrowId and transactionHash', async () => { + it('calls onSuccess callback after a successful confirmation', async () => { + const user = userEvent.setup(); const mockOnSuccess = jest.fn(); const mockLockEscrow = jest.fn().mockResolvedValue({ escrowId: 'escrow-123', @@ -250,8 +297,8 @@ describe('EscrowLock', () => { mockEscrowLock.mockReturnValue({ isLoading: false, error: null, - escrowId: 'escrow-123', - transactionHash: '0xabc123', + escrowId: null, + transactionHash: null, lockEscrow: mockLockEscrow, reset: jest.fn(), } as any); @@ -266,17 +313,24 @@ describe('EscrowLock', () => { /> ); - expect(mockOnSuccess).toHaveBeenCalledWith('escrow-123', '0xabc123'); + await user.click(screen.getByRole('button', { name: /Lock Payment in Escrow/i })); + await user.click(screen.getByRole('button', { name: /Confirm Lock/i })); + + await waitFor(() => { + expect(mockOnSuccess).toHaveBeenCalledWith('escrow-123', '0xabc123'); + }); }); - it('calls onError callback with error message', () => { + it('calls onError callback when confirmation fails', async () => { + const user = userEvent.setup(); const mockOnError = jest.fn(); + const mockLockEscrow = jest.fn().mockRejectedValue(new Error('Failed to lock escrow')); mockEscrowLock.mockReturnValue({ isLoading: false, - error: 'Failed to lock escrow', + error: null, escrowId: null, transactionHash: null, - lockEscrow: jest.fn(), + lockEscrow: mockLockEscrow, reset: jest.fn(), } as any); @@ -290,12 +344,18 @@ describe('EscrowLock', () => { /> ); - expect(mockOnError).toHaveBeenCalledWith('Failed to lock escrow'); + await user.click(screen.getByRole('button', { name: /Lock Payment in Escrow/i })); + await user.click(screen.getByRole('button', { name: /Confirm Lock/i })); + + await waitFor(() => { + expect(mockOnError).toHaveBeenCalledWith('Failed to lock escrow'); + }); }); it('shows reset button in success state', () => { mockEscrowLock.mockReturnValue({ isLoading: false, + isSuccess: true, error: null, escrowId: 'escrow-123', transactionHash: '0xabc123', @@ -360,6 +420,6 @@ describe('EscrowLock', () => { /> ); - expect(screen.getByText('Wallet status: connected')).toBeInTheDocument(); + expect(screen.getByText('Wallet connected')).toBeInTheDocument(); }); });