Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions components/escrow/__tests__/EscrowInsuranceCheckout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<typeof useCreateDelivery>;

function renderForm() {
const queryClient = new QueryClient();
return render(
<QueryClientProvider client={queryClient}>
<CreateDeliveryForm />
</QueryClientProvider>
);
}

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);
});
});
82 changes: 71 additions & 11 deletions features/escrow/components/__tests__/EscrowLock.test.tsx
Original file line number Diff line number Diff line change
@@ -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');

Expand All @@ -19,6 +24,7 @@ describe('EscrowLock', () => {
mockEscrowLock.mockReturnValue({
isLoading: false,
error: null,
isSuccess: false,
escrowId: null,
transactionHash: null,
lockEscrow: jest.fn().mockResolvedValue({
Expand Down Expand Up @@ -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);
});
});

Expand Down Expand Up @@ -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(
<EscrowLock
deliveryId="delivery-usdc"
amount={42.75}
currency="USDC"
walletAddress="GUSDCWALLET"
/>
);

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',
Expand Down Expand Up @@ -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',
Expand All @@ -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);
Expand All @@ -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);

Expand All @@ -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',
Expand Down Expand Up @@ -360,6 +420,6 @@ describe('EscrowLock', () => {
/>
);

expect(screen.getByText('Wallet status: connected')).toBeInTheDocument();
expect(screen.getByText('Wallet connected')).toBeInTheDocument();
});
});