Skip to content

Commit 1d9a396

Browse files
committed
test: TransactionTimeline comprehensive tests (Haroldwonder#179)
10 cases: deposit/withdrawal render, all statuses icons/colors/labels, txHash display, onRetry failed click, onClose Close/Done, timestamps/details, no Retry non-failed
1 parent ee05628 commit 1d9a396

1 file changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import React from 'react';
2+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
4+
import { TransactionTimeline, TxStatus, TxType, TxEvent } from './TransactionTimeline';
5+
import '@testing-library/jest-dom';
6+
7+
const user = userEvent.setup();
8+
9+
const baseProps = {
10+
type: 'deposit' as TxType,
11+
amount: '250.00',
12+
asset: 'USDC',
13+
events: [] as TxEvent[],
14+
currentStatus: 'initiated' as TxStatus,
15+
onRetry: jest.fn(),
16+
onClose: jest.fn(),
17+
};
18+
19+
describe('TransactionTimeline', () => {
20+
test('renders deposit header correctly', () => {
21+
render(<TransactionTimeline {...baseProps} />);
22+
expect(screen.getByText('↓ Deposit')).toBeInTheDocument();
23+
expect(screen.getByText('250.00')).toHaveTextContent('250.00');
24+
expect(screen.getByText('USDC')).toBeInTheDocument();
25+
expect(screen.getByText('Initiated')).toBeInTheDocument();
26+
});
27+
28+
test('renders withdrawal header correctly', () => {
29+
render(<TransactionTimeline {...baseProps} type="withdrawal" />);
30+
expect(screen.getByText('↑ Withdrawal')).toBeInTheDocument();
31+
});
32+
33+
test('renders status badge with correct color class', () => {
34+
render(<TransactionTimeline {...baseProps} currentStatus="processing" />);
35+
const badge = screen.getByText('Processing');
36+
expect(badge).toBeInTheDocument();
37+
expect(badge).toHaveStyle({ color: '#0284c7' });
38+
});
39+
40+
test('renders all TxStatus icons and labels', () => {
41+
const statuses: TxStatus[] = ['initiated', 'pending', 'processing', 'completed', 'failed'];
42+
statuses.forEach(status => {
43+
render(<TransactionTimeline {...baseProps} currentStatus={status} />);
44+
const label = screen.getByText(expect.stringMatching(new RegExp(status.charAt(0).toUpperCase() + status.slice(1), 'i')));
45+
expect(label).toBeInTheDocument();
46+
});
47+
});
48+
49+
test('shows txHash link when completed with txHash', () => {
50+
const events: TxEvent[] = [{
51+
status: 'completed' as TxStatus,
52+
txHash: 'abc123def456',
53+
}];
54+
render(<TransactionTimeline {...baseProps} currentStatus="completed" events={events} />);
55+
expect(screen.getByText('abc123def…f456')).toBeInTheDocument();
56+
const link = screen.getByRole('link');
57+
expect(link).toHaveAttribute('href', expect.stringContaining('abc123def456'));
58+
});
59+
60+
test('shows Retry button on failed status and calls onRetry on click', async () => {
61+
render(<TransactionTimeline {...baseProps} currentStatus="failed" />);
62+
const retryButton = screen.getByRole('button', { name: /retry/i });
63+
expect(retryButton).toBeInTheDocument();
64+
await user.click(retryButton);
65+
expect(baseProps.onRetry).toHaveBeenCalledTimes(1);
66+
});
67+
68+
test('shows Close button and calls onClose on click', async () => {
69+
render(<TransactionTimeline {...baseProps} currentStatus="pending" />);
70+
const closeButton = screen.getByRole('button', { name: /close/i });
71+
expect(closeButton).toBeInTheDocument();
72+
await user.click(closeButton);
73+
expect(baseProps.onClose).toHaveBeenCalledTimes(1);
74+
});
75+
76+
test('shows Done button on completed and calls onClose', async () => {
77+
render(<TransactionTimeline {...baseProps} currentStatus="completed" />);
78+
const doneButton = screen.getByRole('button', { name: /done/i });
79+
expect(doneButton).toBeInTheDocument();
80+
await user.click(doneButton);
81+
expect(baseProps.onClose).toHaveBeenCalledTimes(1);
82+
});
83+
84+
test('renders event timestamps and details', () => {
85+
const events: TxEvent[] = [{
86+
status: 'pending' as TxStatus,
87+
timestamp: '2024-01-15T10:30:00Z',
88+
detail: 'via ACH',
89+
}];
90+
render(<TransactionTimeline {...baseProps} events={events} currentStatus="pending" />);
91+
expect(screen.getByText(expect.stringMatching(/Jan 15.*10:30/))).toBeInTheDocument();
92+
expect(screen.getByText('via ACH')).toBeInTheDocument();
93+
});
94+
95+
test('renders failed state with custom label and description', () => {
96+
const events: TxEvent[] = [{
97+
status: 'failed' as TxStatus,
98+
label: 'Bank Error',
99+
description: 'Account details mismatch',
100+
}];
101+
render(<TransactionTimeline {...baseProps} events={events} currentStatus="failed" />);
102+
expect(screen.getByText('Bank Error')).toBeInTheDocument();
103+
expect(screen.getByText('Account details mismatch')).toBeInTheDocument();
104+
expect(screen.getByText('✕')).toBeInTheDocument();
105+
});
106+
107+
test('does not show Retry button when not failed', () => {
108+
render(<TransactionTimeline {...baseProps} currentStatus="completed" />);
109+
expect(screen.queryByRole('button', { name: /retry/i })).not.toBeInTheDocument();
110+
});
111+
});

0 commit comments

Comments
 (0)