diff --git a/src/lib/__tests__/mock-client.test.ts b/src/lib/__tests__/mock-client.test.ts index 6accc86..137f345 100644 --- a/src/lib/__tests__/mock-client.test.ts +++ b/src/lib/__tests__/mock-client.test.ts @@ -124,4 +124,28 @@ describe('Mock Client - Issue #30 Fixes', () => { expect(snapshot1).toEqual(snapshot2); }); }); + + describe('Fix 4: Pagination support in getHistory (Issue #588)', () => { + it('should paginate results by page and limit with accurate total', async () => { + const client = createMockClient() as SorokitClient; + + const page1 = await client.transaction.getHistory('GADDR', 1, 10); + const page2 = await client.transaction.getHistory('GADDR', 2, 10); + const page3 = await client.transaction.getHistory('GADDR', 3, 10); + + expect(page1.data).toHaveLength(10); + expect(page2.data).toHaveLength(10); + expect(page3.data).toHaveLength(5); + + expect(page1.total).toBe(25); + expect(page2.total).toBe(25); + expect(page3.total).toBe(25); + + // Verify that page 1 and page 2 return completely different transactions + const page1Ids = page1.data?.map(t => t.id); + const page2Ids = page2.data?.map(t => t.id); + expect(page1Ids).not.toEqual(page2Ids); + }); + }); }); + diff --git a/src/lib/mock-client.test.ts b/src/lib/mock-client.test.ts index 673c769..8376a2e 100644 --- a/src/lib/mock-client.test.ts +++ b/src/lib/mock-client.test.ts @@ -52,9 +52,8 @@ describe("mock-client", () => { expect(res.data?.length).toBe(limit); }); - it("verifies getHistory returns distinct pages via the page parameter", async () => { - const { createMockClient } = await import("./mock-client"); - const { MOCK_HISTORY } = await import("./mock-client"); + it("verifies getHistory paginates correctly across multiple pages", async () => { + const { createMockClient, MOCK_HISTORY } = await import("./mock-client"); const client = createMockClient(); const limit = 2; @@ -70,4 +69,18 @@ describe("mock-client", () => { expect(page2.data?.[0].hash).toBe(MOCK_HISTORY[limit].hash); expect(page1.total).toBe(MOCK_HISTORY.length); }); + + it("verifies instance isolation between multiple createMockClient invocations", async () => { + const { createMockClient } = await import("./mock-client"); + const clientA = createMockClient("testnet"); + const clientB = createMockClient("public"); + + if ("network" in clientA && "network" in clientB) { + const netA = await clientA.network.getNetwork(); + const netB = await clientB.network.getNetwork(); + expect(netA.data?.name).toBe("testnet"); + expect(netB.data?.name).toBe("mainnet"); + } + }); }); + diff --git a/src/lib/mock-client.ts b/src/lib/mock-client.ts index 40bb179..894a963 100644 --- a/src/lib/mock-client.ts +++ b/src/lib/mock-client.ts @@ -20,8 +20,8 @@ import { deterministicMock } from "./deterministic-mock"; export const MOCK_ADDRESS = "GBRPYHIL2CI3WHGSUJGY6O7SROQOMJG7QBCACN4QPKUOQNXJDGONXHPA"; -// Generate deterministic mock data (consistent across test runs) -export const MOCK_HISTORY = deterministicMock.generateMockHistory(5); +// Generate deterministic mock data (consistent across test runs, 25 items to support multi-page pagination) +export const MOCK_HISTORY = deterministicMock.generateMockHistory(25); export const MOCK_EVENTS = deterministicMock.generateMockEvents(3); export const NETWORKS = { @@ -230,9 +230,17 @@ const MOCK_ALLOWANCES: AllowanceEntry[] = [ ]; /** - * Create a mock client that satisfies the SorokitClient interface. - * If called with an invalid network name, returns the error object - * (backward compatible with simple-error tests). + * Mock Strategy: + * + * Provides a canonical, standalone implementation of SorokitClient for development, + * demo mode (in main.tsx), and component/screen unit testing. + * + * Design: + * - Single source of truth for mock blockchain data across the entire repository. + * - Instance-scoped state: Each invocation of createMockClient() creates an independent + * instance with its own network and connection state, preventing test cross-contamination. + * - Proper pagination support: getHistory slices deterministic transaction records by + * page and limit, providing distinct pages and accurate total count for TransactionHistory. */ export function createMockClient(): SorokitClient; export function createMockClient( @@ -241,8 +249,9 @@ export function createMockClient( export function createMockClient( networkName?: string, ): SorokitClient | { data: null; error: string } { - const activeNetwork = + let activeNetwork = networkName && networkName in NETWORKS ? networkName : "testnet"; + let connectedAddress = MOCK_ADDRESS; if (networkName && !(networkName in NETWORKS)) { const validNetworks = Object.keys(NETWORKS).join(", "); @@ -255,12 +264,12 @@ export function createMockClient( return { wallet: { connect: async () => ({ - data: { address: MOCK_ADDRESS }, + data: { address: connectedAddress }, error: null, status: "success" as const, }), disconnect: async () => {}, - getAddress: async () => ({ data: MOCK_ADDRESS, error: null }), + getAddress: async () => ({ data: connectedAddress, error: null }), }, account: { getAccount: async () => ({