From c4fcb4a55c351a48b157c917ee2f245155cbf449 Mon Sep 17 00:00:00 2001 From: Ogunmodede Joel Taiwo Date: Fri, 28 Aug 2026 15:46:34 +0100 Subject: [PATCH] fix: #536 unify mock client adapter and support pagination in getHistory --- src/lib/mock-client.test.ts | 42 +++++++++++++++++++++++++++++++++++-- src/lib/mock-client.ts | 18 ++++++++++++---- src/main.tsx | 4 +++- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/lib/mock-client.test.ts b/src/lib/mock-client.test.ts index e1aec9b..808256e 100644 --- a/src/lib/mock-client.test.ts +++ b/src/lib/mock-client.test.ts @@ -44,11 +44,49 @@ describe("mock-client", () => { it("verifies getHistory respects the limit parameter", async () => { const { createMockClient } = await import("./mock-client"); const client = createMockClient(); - + const limit = 3; const res = await client.transaction.getHistory("address", 1, limit); - + expect(res.data).toBeDefined(); expect(res.data?.length).toBe(limit); + expect(res.total).toBe(25); + }); + + it("verifies getHistory correctly paginates across multiple pages with page and limit", async () => { + const { createMockClient } = await import("./mock-client"); + const client = createMockClient(); + + const pageSize = 10; + const page1 = await client.transaction.getHistory("address", 1, pageSize); + const page2 = await client.transaction.getHistory("address", 2, pageSize); + const page3 = await client.transaction.getHistory("address", 3, pageSize); + const page4 = await client.transaction.getHistory("address", 4, pageSize); + + expect(page1.data).toHaveLength(10); + expect(page2.data).toHaveLength(10); + expect(page3.data).toHaveLength(5); + expect(page4.data).toHaveLength(0); + + expect(page1.total).toBe(25); + expect(page2.total).toBe(25); + expect(page3.total).toBe(25); + + // Verify page slices do not overlap + const page1Hashes = page1.data?.map((tx) => tx.hash); + const page2Hashes = page2.data?.map((tx) => tx.hash); + const page3Hashes = page3.data?.map((tx) => tx.hash); + + expect(page1Hashes?.some((h) => page2Hashes?.includes(h))).toBe(false); + expect(page2Hashes?.some((h) => page3Hashes?.includes(h))).toBe(false); + }); + + it("verifies getHistory defaults to page 1 and all items when page/limit not provided", async () => { + const { createMockClient, MOCK_HISTORY } = await import("./mock-client"); + const client = createMockClient(); + + const res = await client.transaction.getHistory("address"); + expect(res.data).toHaveLength(MOCK_HISTORY.length); + expect(res.total).toBe(MOCK_HISTORY.length); }); }); diff --git a/src/lib/mock-client.ts b/src/lib/mock-client.ts index 0ca6ce5..73f901b 100644 --- a/src/lib/mock-client.ts +++ b/src/lib/mock-client.ts @@ -21,7 +21,7 @@ export const MOCK_ADDRESS = "GBRPYHIL2CI3WHGSUJGY6O7SROQOMJG7QBCACN4QPKUOQNXJDGONXHPA"; // Generate deterministic mock data (consistent across test runs) -export const MOCK_HISTORY = deterministicMock.generateMockHistory(5); +export const MOCK_HISTORY = deterministicMock.generateMockHistory(25); export const MOCK_EVENTS = deterministicMock.generateMockEvents(3); export const NETWORKS = { @@ -283,9 +283,19 @@ export function createMockClient( status: "success", }), getStatus: async () => ({ data: "success" as TxStatus, error: null }), - getHistory: async (_address: string, _page?: number, limit?: number) => { - const history = MOCK_HISTORY.slice(0, limit ?? MOCK_HISTORY.length); - return { data: history, error: null, total: history.length }; + getHistory: async ( + _address: string, + page: number = 1, + limit?: number, + ) => { + const safePage = Math.max(1, page || 1); + const pageSize = + limit !== undefined && limit > 0 ? limit : MOCK_HISTORY.length; + const total = MOCK_HISTORY.length; + const start = (safePage - 1) * pageSize; + const end = start + pageSize; + const history = MOCK_HISTORY.slice(start, end); + return { data: history, error: null, total }; }, estimateFee: async () => ({ data: { baseFee: "100", recommended: "1000" }, diff --git a/src/main.tsx b/src/main.tsx index 9c9445a..9e3d60a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -8,7 +8,9 @@ import { ErrorBoundary } from './components/ErrorBoundary' import type { SorokitClient } from './lib/client.ts' import { createMockClient } from './lib/mock-client' -// Initialize mock client for development +// Client Strategy: Using createMockClient() from mock-client.ts for local development and demo mode. +// This single authoritative mock provides realistic delays, pagination, deterministic state, and balances. +// To connect to a live Soroban/Stellar network adapter in production, replace this factory with a real ClientAdapter. const createClient = (): SorokitClient => createMockClient() as SorokitClient function Root() {