/** * Unit tests for the dbis_core HTTP client adapter. * * Covers both provider-switch legs: * - `createDbisCoreClient()` with DBIS_CORE_URL unset → mock mode. * - `createDbisCoreClient({ baseUrl, fetchImpl })` → live mode, with * a stub `fetch` so tests never hit the network. */ import { createDbisCoreClient, type DbisCoreClient, } from "../../src/services/dbisCore"; describe("dbisCore.createDbisCoreClient() — mock mode", () => { let client: DbisCoreClient; beforeAll(() => { delete process.env.DBIS_CORE_URL; delete process.env.DBIS_CORE_API_KEY; client = createDbisCoreClient(); }); it("reports mock mode", () => { expect(client.mode).toBe("mock"); }); it("returns a balance shaped like upstream", async () => { const b = await client.getAccountBalance("acct-1"); expect(b.accountId).toBe("acct-1"); expect(typeof b.available).toBe("string"); expect(typeof b.held).toBe("string"); expect(b.currency).toBeDefined(); }); it("returns a plausible route", async () => { const r = await client.findSettlementRoute({ sourceBankId: "src", destinationBankId: "dst", amount: "100", currencyCode: "USD", }); expect(r.routeId).toContain("src"); expect(r.hops.length).toBeGreaterThan(0); expect(r.estimatedFeeBps).toBeGreaterThanOrEqual(0); }); it("settles atomically with a deterministic id", async () => { const s = await client.atomicSettle({ routeId: "r1", sourceAccountId: "a", destinationAccountId: "b", amount: "1", currencyCode: "USD", reference: "ref-1", }); expect(s.status).toBe("settled"); expect(s.settlementId).toContain("ref-1"); expect(s.completedAt).toBeDefined(); }); it("returns an allow decision by default from ARI", async () => { const d = await client.requestAriDecision({ txId: "tx-1", amount: "1", currencyCode: "USD", creator: "0xdead", }); expect(d.outcome).toBe("allow"); expect(d.txId).toBe("tx-1"); expect(d.riskScore).toBeLessThan(1); }); it("accepts a pacs008 dispatch and echoes the messageId", async () => { const r = await client.dispatchPacs008({ messageId: "msg-1", creationDateTime: "2026-01-01T00:00:00Z", debtor: { name: "Acme", bic: "ACMEUS33", account: "1" }, creditor: { name: "Widget", bic: "WDGTGB22", account: "2" }, amount: "100", currencyCode: "USD", }); expect(r.status).toBe("accepted"); expect(r.messageId).toBe("msg-1"); }); it("returns a settled status from a synthetic settlementId", async () => { const s = await client.getSettlementStatus("stlm-99"); expect(s.status).toBe("settled"); expect(s.legs.length).toBeGreaterThan(0); }); }); describe("dbisCore.createDbisCoreClient() — live mode (stubbed fetch)", () => { function makeFetch( record: (url: string, init: RequestInit) => void, responseBody: unknown, status = 200, ): typeof fetch { return (async (input: string | URL | Request, init?: RequestInit) => { record(String(input), init ?? {}); return new Response(JSON.stringify(responseBody), { status, headers: { "Content-Type": "application/json" }, }); }) as typeof fetch; } it("reports live mode when baseUrl is set", () => { const client = createDbisCoreClient({ baseUrl: "http://dbis.example.test", fetchImpl: makeFetch( () => undefined, { accountId: "a", currency: "USD", available: "0", held: "0", asOf: "" }, ), }); expect(client.mode).toBe("live"); }); it("hits GET /api/accounts/:id/balance with the API key header", async () => { const calls: { url: string; headers: Record; method?: string }[] = []; const client = createDbisCoreClient({ baseUrl: "http://dbis.example.test", apiKey: "k-secret", fetchImpl: makeFetch( (url, init) => { calls.push({ url, method: init.method, headers: (init.headers ?? {}) as Record, }); }, { accountId: "a42", currency: "USD", available: "500", held: "10", asOf: "2026-01-01T00:00:00Z", }, ), }); const b = await client.getAccountBalance("a42"); expect(b.available).toBe("500"); expect(calls).toHaveLength(1); expect(calls[0].url).toBe("http://dbis.example.test/api/accounts/a42/balance"); expect(calls[0].method).toBe("GET"); expect(calls[0].headers["X-API-Key"]).toBe("k-secret"); }); it("posts a route request and parses the structured response", async () => { const client = createDbisCoreClient({ baseUrl: "http://dbis.example.test/", fetchImpl: makeFetch( () => undefined, { routeId: "R1", hops: [{ bankId: "A", latencyMs: 1, feeBps: 2 }], estimatedLatencyMs: 10, estimatedFeeBps: 2, }, ), }); const r = await client.findSettlementRoute({ sourceBankId: "A", destinationBankId: "B", amount: "1", currencyCode: "USD", }); expect(r.routeId).toBe("R1"); expect(r.estimatedFeeBps).toBe(2); }); it("throws a descriptive error on non-2xx", async () => { const client = createDbisCoreClient({ baseUrl: "http://dbis.example.test", fetchImpl: makeFetch(() => undefined, { error: "denied" }, 403), }); await expect(client.getAccountBalance("a1")).rejects.toThrow(/HTTP 403/); }); it("encodes path parameters safely", async () => { const calls: string[] = []; const client = createDbisCoreClient({ baseUrl: "http://dbis.example.test", fetchImpl: makeFetch( (url) => { calls.push(url); }, { settlementId: "x", status: "settled", legs: [], lastUpdated: "" }, ), }); await client.getSettlementStatus("weird/id with space"); expect(calls[0]).toBe( "http://dbis.example.test/api/isn/settlements/weird%2Fid%20with%20space", ); }); });