Skip to content

Commit

Permalink
Add public-samples/mint-mobile-app-fq9nqt/src/web/tests/hooks/transac…
Browse files Browse the repository at this point in the history
…tions.test.ts
  • Loading branch information
siddhantpp committed Nov 10, 2024
1 parent 1ba0b1d commit 6c620a8
Showing 1 changed file with 354 additions and 0 deletions.
354 changes: 354 additions & 0 deletions src/web/tests/hooks/transactions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
// @version jest ^29.0.0
// @version @testing-library/react-hooks ^8.0.0
// @version @testing-library/react ^14.0.0

import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor } from '@testing-library/react';
import { useTransactions } from '../../src/hooks/useTransactions';
import {
getTransactions,
updateTransaction,
categorizeTransaction,
searchTransactions
} from '../../src/services/api/transactions.api';
import { Transaction } from '../../src/types/models.types';

// Mock the WebSocket
class MockWebSocket {
onmessage: ((event: any) => void) | null = null;
close = jest.fn();
send = jest.fn();

constructor() {
setTimeout(() => {
if (this.onmessage) {
this.onmessage({ data: JSON.stringify({
type: 'TRANSACTION_UPDATE',
data: mockTransactions[0]
})});
}
}, 100);
}
}

// Mock the API modules
jest.mock('../../src/services/api/transactions.api');
jest.mock('ws', () => MockWebSocket);

// Mock transaction data
const mockTransactions: Transaction[] = [
{
id: '1',
accountId: 'acc1',
categoryId: 'cat1',
amount: 100,
date: new Date('2023-01-01'),
description: 'Test Transaction 1',
pending: false,
metadata: {}
},
{
id: '2',
accountId: 'acc1',
categoryId: 'cat2',
amount: 200,
date: new Date('2023-01-02'),
description: 'Test Transaction 2',
pending: false,
metadata: {}
}
];

describe('useTransactions', () => {
// Reset all mocks before each test
beforeEach(() => {
jest.clearAllMocks();
(global as any).WebSocket = MockWebSocket;
});

/**
* Tests successful transaction fetching with pagination
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should fetch transactions successfully', async () => {
// Mock successful API response
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: mockTransactions,
total: 2,
page: 1,
limit: 20
});

// Render hook with test filters
const { result } = renderHook(() => useTransactions({
accountId: 'acc1',
startDate: new Date('2023-01-01'),
endDate: new Date('2023-01-31')
}));

// Verify initial loading state
expect(result.current.loading).toBe(true);
expect(result.current.transactions).toEqual([]);

// Wait for data to be loaded
await waitFor(() => {
expect(result.current.loading).toBe(false);
});

// Verify fetched data
expect(result.current.transactions).toEqual(mockTransactions);
expect(result.current.totalCount).toBe(2);
expect(result.current.hasMore).toBe(false);
expect(getTransactions).toHaveBeenCalledWith({
page: 1,
limit: 20,
accountId: 'acc1',
startDate: expect.any(Date),
endDate: expect.any(Date)
});
});

/**
* Tests error handling in transaction fetching
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should handle API errors', async () => {
// Mock API error
const errorMessage = 'Failed to fetch transactions';
(getTransactions as jest.Mock).mockRejectedValueOnce(new Error(errorMessage));

// Render hook
const { result } = renderHook(() => useTransactions());

// Wait for error state
await waitFor(() => {
expect(result.current.loading).toBe(false);
});

// Verify error handling
expect(result.current.error).toBe(errorMessage);
expect(result.current.transactions).toEqual([]);
});

/**
* Tests transaction categorization functionality
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should update transaction category', async () => {
// Mock initial transactions fetch
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: mockTransactions,
total: 2,
page: 1,
limit: 20
});

// Mock category update
const updatedTransaction = {
...mockTransactions[0],
categoryId: 'newCategory'
};
(categorizeTransaction as jest.Mock).mockResolvedValueOnce({
data: updatedTransaction
});

// Render hook
const { result } = renderHook(() => useTransactions());

// Wait for initial data load
await waitFor(() => {
expect(result.current.loading).toBe(false);
});

// Perform category update
await act(async () => {
await result.current.categorizeTransaction('1', 'newCategory');
});

// Verify optimistic update
expect(result.current.transactions[0].categoryId).toBe('newCategory');
expect(categorizeTransaction).toHaveBeenCalledWith('1', 'newCategory');
});

/**
* Tests transaction pagination functionality
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should handle pagination', async () => {
// Mock first page response
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: [mockTransactions[0]],
total: 2,
page: 1,
limit: 1
});

// Render hook
const { result } = renderHook(() => useTransactions());

// Wait for initial data load
await waitFor(() => {
expect(result.current.loading).toBe(false);
});

// Verify first page
expect(result.current.transactions).toHaveLength(1);
expect(result.current.hasMore).toBe(true);

// Mock second page response
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: [mockTransactions[1]],
total: 2,
page: 2,
limit: 1
});

// Load next page
await act(async () => {
await result.current.fetchMoreTransactions();
});

// Verify pagination results
expect(result.current.transactions).toHaveLength(2);
expect(result.current.hasMore).toBe(false);
expect(result.current.currentPage).toBe(2);
});

/**
* Tests real-time update functionality
* Requirement: Real-time Data Synchronization (Technical Specification/5.1 High-Level Architecture Overview)
*/
it('should handle real-time updates', async () => {
// Mock initial fetch
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: mockTransactions,
total: 2,
page: 1,
limit: 20
});

// Render hook
const { result } = renderHook(() => useTransactions());

// Wait for initial data and WebSocket update
await waitFor(() => {
expect(result.current.transactions[0]).toEqual(mockTransactions[0]);
});

// Verify WebSocket connection cleanup
const { unmount } = renderHook(() => useTransactions());
unmount();
expect(MockWebSocket.prototype.close).toHaveBeenCalled();
});

/**
* Tests transaction search functionality
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should search transactions', async () => {
// Mock search response
const searchResults = [mockTransactions[0]];
(searchTransactions as jest.Mock).mockResolvedValueOnce({
data: searchResults,
total: 1,
page: 1,
limit: 20
});

// Render hook
const { result } = renderHook(() => useTransactions());

// Perform search
await act(async () => {
await result.current.searchTransactions('Test');
});

// Verify search results
expect(result.current.transactions).toEqual(searchResults);
expect(searchTransactions).toHaveBeenCalledWith({
query: 'Test',
page: 1,
limit: 20,
sortBy: 'date',
sortDirection: 'desc'
});
});

/**
* Tests transaction update functionality
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should update transaction details', async () => {
// Mock initial fetch
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: mockTransactions,
total: 2,
page: 1,
limit: 20
});

// Mock update response
const updatedTransaction = {
...mockTransactions[0],
amount: 150
};
(updateTransaction as jest.Mock).mockResolvedValueOnce({
data: updatedTransaction
});

// Render hook
const { result } = renderHook(() => useTransactions());

// Wait for initial data load
await waitFor(() => {
expect(result.current.loading).toBe(false);
});

// Perform update
await act(async () => {
await result.current.updateTransaction('1', { amount: 150 });
});

// Verify update
expect(result.current.transactions[0].amount).toBe(150);
expect(updateTransaction).toHaveBeenCalledWith('1', { amount: 150 });
});

/**
* Tests filter change handling
* Requirement: Transaction Management (Technical Specification/1.2 Scope/Core Features)
*/
it('should handle filter changes', async () => {
// Mock initial fetch
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: mockTransactions,
total: 2,
page: 1,
limit: 20
});

// Render hook with initial filters
const { rerender } = renderHook(
(filters) => useTransactions(filters),
{ initialProps: { accountId: 'acc1' } }
);

// Mock fetch with new filters
(getTransactions as jest.Mock).mockResolvedValueOnce({
data: [mockTransactions[1]],
total: 1,
page: 1,
limit: 20
});

// Change filters
rerender({ accountId: 'acc2' });

// Verify new fetch with updated filters
expect(getTransactions).toHaveBeenCalledWith(
expect.objectContaining({
accountId: 'acc2'
})
);
});
});

0 comments on commit 6c620a8

Please sign in to comment.