UNPKG

@ledgerhq/coin-filecoin

Version:
102 lines (85 loc) 3.74 kB
import { fetchBalances, fetchERC20TokenBalance } from "../../network/api"; import { getBalance } from "./getBalance"; jest.mock("../../network/api"); jest.mock("@ledgerhq/logs"); // Mock convertAddressFilToEth so synthetic addresses can drive both code paths: // when the address starts with "f410f" -> returns a fake ETH equivalent, // otherwise -> throws (forcing the native-only fallback branch). jest.mock("../../network/addresses", () => ({ convertAddressFilToEth: (addr: string) => { if (addr.startsWith("f410f")) return "0x" + addr.slice(5); throw new Error("not convertible"); }, })); const mockedFetchBalances = fetchBalances as jest.MockedFunction<typeof fetchBalances>; const mockedFetchERC20Balance = fetchERC20TokenBalance as jest.MockedFunction< typeof fetchERC20TokenBalance >; describe("getBalance", () => { beforeEach(() => jest.clearAllMocks()); it("returns native balance entry from API response", async () => { mockedFetchBalances.mockResolvedValueOnce({ total_balance: "5000000000000000000", spendable_balance: "4000000000000000000", locked_balance: "1000000000000000000", }); const result = await getBalance("f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za"); expect(result).toHaveLength(1); expect(result[0].asset).toEqual({ type: "native" }); expect(result[0].value).toBe(5_000_000_000_000_000_000n); expect(result[0].locked).toBe(1_000_000_000_000_000_000n); }); it("uses 0n as locked_balance fallback when field is absent", async () => { mockedFetchBalances.mockResolvedValueOnce({ total_balance: "1000", spendable_balance: "1000", locked_balance: undefined as unknown as string, }); const result = await getBalance("f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za"); expect(result[0].locked).toBe(0n); }); it("does not call fetchERC20TokenBalance when no tokens registered", async () => { mockedFetchBalances.mockResolvedValueOnce({ total_balance: "0", spendable_balance: "0", locked_balance: "0", }); await getBalance("f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za"); expect(mockedFetchERC20Balance).not.toHaveBeenCalled(); }); it("returns token balance entries (lowercase assetReference) when tokenContracts provided", async () => { mockedFetchBalances.mockResolvedValueOnce({ total_balance: "100", spendable_balance: "100", locked_balance: "0", }); mockedFetchERC20Balance.mockResolvedValueOnce("0"); mockedFetchERC20Balance.mockResolvedValueOnce("42"); const result = await getBalance("f410fkkld55ioe7qg24wvt7fu6pbknb56ht7ptloy", [ "0xABCDEF", "0xDEADBEEF", ]); expect(result).toHaveLength(3); const tokens = result.filter(b => b.asset.type === "erc20"); expect(tokens).toHaveLength(2); // zero-balance entries must be included (specialized task constraint) expect(tokens[0].value).toBe(0n); expect(tokens[1].value).toBe(42n); // assetReference normalized to lowercase tokens.forEach(t => { expect((t.asset as { assetReference: string }).assetReference).toMatch(/^0x[a-f0-9]+$/); }); }); it("falls back to native-only when address cannot be converted to ETH form", async () => { mockedFetchBalances.mockResolvedValueOnce({ total_balance: "100", spendable_balance: "100", locked_balance: "0", }); // f1 SECP256K1 addresses are not convertAddressFilToEth-compatible — should fall back const result = await getBalance("f1abjxfbp274xpdqcpuaykwkfb43omjotacm2p3za", ["0xabcdef"]); expect(result).toHaveLength(1); expect(result[0].asset.type).toBe("native"); expect(mockedFetchERC20Balance).not.toHaveBeenCalled(); }); });