From fde7a33dd7444bb00807b64b1b32a046990cd28f Mon Sep 17 00:00:00 2001 From: ahmadmustafaanis Date: Tue, 12 May 2026 23:34:30 +0500 Subject: [PATCH] Add BalanceCard component tests --- .eslintrc.json | 3 + package-lock.json | 47 ++++++++++++ package.json | 1 + src/components/BalanceCard.test.tsx | 86 ++++++++++++++++++++++ src/components/TransactionHistory.test.tsx | 4 +- src/components/TransactionHistory.tsx | 3 +- tsconfig.json | 3 +- 7 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 .eslintrc.json create mode 100644 src/components/BalanceCard.test.tsx diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/package-lock.json b/package-lock.json index 57f6e65..f2ce8c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "devDependencies": { "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^15.0.5", + "@types/jest": "^29.5.14", "@types/node": "^20.12.7", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", @@ -1795,6 +1796,52 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/jsdom": { "version": "20.0.1", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", diff --git a/package.json b/package.json index ee9fd1a..5ff9e17 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@types/node": "^20.12.7", + "@types/jest": "^29.5.14", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", "autoprefixer": "^10.4.19", diff --git a/src/components/BalanceCard.test.tsx b/src/components/BalanceCard.test.tsx new file mode 100644 index 0000000..42f93a4 --- /dev/null +++ b/src/components/BalanceCard.test.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { BalanceCard } from './BalanceCard'; +import { useVault } from '@/hooks/useVault'; + +jest.mock('@/hooks/useVault', () => ({ + useVault: jest.fn(), +})); + +const mockUseVault = useVault as jest.Mock; + +const defaultVaultState = { + balance: 15000000000n, + totalShares: 100000n, + isLoading: false, + isRefreshing: false, + error: null, + deposit: jest.fn(), + withdraw: jest.fn(), + claimRewards: jest.fn(), + refresh: jest.fn(), +}; + +const renderBalanceCard = (overrides = {}) => { + const state = { + ...defaultVaultState, + refresh: jest.fn(), + claimRewards: jest.fn(), + ...overrides, + }; + + mockUseVault.mockReturnValue(state); + render(); + + return state; +}; + +describe('BalanceCard', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders the current balance and pending rewards', () => { + renderBalanceCard(); + + expect(screen.getByText('Vault Balance')).toBeInTheDocument(); + expect(screen.getByRole('heading', { name: '1500 XLM' })).toBeInTheDocument(); + expect(screen.getByText('Pending Rewards: 12.5 XLM')).toBeInTheDocument(); + }); + + it('shows a loading placeholder and disables actions while loading', () => { + renderBalanceCard({ isLoading: true }); + + expect(screen.getByRole('heading', { name: '...' })).toBeInTheDocument(); + + const [refreshButton, claimButton] = screen.getAllByRole('button'); + expect(refreshButton).toBeDisabled(); + expect(claimButton).toBeDisabled(); + }); + + it('renders zero balance clearly', () => { + renderBalanceCard({ balance: 0n }); + + expect(screen.getByRole('heading', { name: '0 XLM' })).toBeInTheDocument(); + }); + + it('formats atomic Stellar units as XLM', () => { + renderBalanceCard({ balance: 123456789n }); + + expect(screen.getByRole('heading', { name: '12.3456789 XLM' })).toBeInTheDocument(); + }); + + it('calls vault actions from the refresh and claim buttons', () => { + const refresh = jest.fn(); + const claimRewards = jest.fn(); + + renderBalanceCard({ refresh, claimRewards }); + + const [refreshButton, claimButton] = screen.getAllByRole('button'); + fireEvent.click(refreshButton); + fireEvent.click(claimButton); + + expect(refresh).toHaveBeenCalledTimes(1); + expect(claimRewards).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/components/TransactionHistory.test.tsx b/src/components/TransactionHistory.test.tsx index a0ff4a1..5f41ebc 100644 --- a/src/components/TransactionHistory.test.tsx +++ b/src/components/TransactionHistory.test.tsx @@ -21,7 +21,9 @@ describe('TransactionHistory', () => { // So it should show 1 successful deposit. const transactions = screen.getAllByRole('link'); expect(transactions.length).toBe(1); - expect(screen.getByText('500.00 XLM')).toBeInTheDocument(); + expect( + screen.getByText((_, element) => element?.textContent === '+500.00 XLM') + ).toBeInTheDocument(); }); it('filters by failed transactions', () => { diff --git a/src/components/TransactionHistory.tsx b/src/components/TransactionHistory.tsx index f12f06d..21f8f22 100644 --- a/src/components/TransactionHistory.tsx +++ b/src/components/TransactionHistory.tsx @@ -159,7 +159,7 @@ export const TransactionHistory: React.FC = () => {

No transactions found

- We couldn't find any activities matching your current filters. + We couldn't find any activities matching your current filters.

)} @@ -172,4 +172,3 @@ export const TransactionHistory: React.FC = () => { ); }; - diff --git a/tsconfig.json b/tsconfig.json index 49c5504..b91ea2b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es5", + "target": "es2020", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, @@ -18,6 +18,7 @@ "paths": { "@/*": ["src/*"] }, + "types": ["jest", "@testing-library/jest-dom"], "plugins": [ { "name": "next"