UNPKG

@ledgerhq/coin-casper

Version:
274 lines 12.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const logs_1 = require("@ledgerhq/logs"); const bignumber_js_1 = __importDefault(require("bignumber.js")); const live_network_1 = __importDefault(require("@ledgerhq/live-network")); const casper_js_sdk_1 = require("casper-js-sdk"); const _1 = require("."); const config_1 = require("../config"); const fixtures_1 = require("../test/fixtures"); const consts_1 = require("../consts"); // Constants const MOCK_NODE_URL = "https://mock.casper.node"; const MOCK_INDEXER_URL = "https://mock.casper.indexer"; const MOCK_PUBLIC_KEY = fixtures_1.TEST_ADDRESSES.SECP256K1; const MOCK_PURSE_UREF = "uref-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef-007"; const MOCK_ACCOUNT_HASH = "account-hash-1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"; const DEFAULT_LIMIT = 100; // Mock dependencies jest.mock("@ledgerhq/logs", () => ({ log: jest.fn(), })); jest.mock("@ledgerhq/live-network", () => ({ __esModule: true, default: jest.fn(), })); jest.mock("../config", () => ({ getCoinConfig: jest.fn(), })); // Helper functions for creating mocks const createMockRpcClient = (methodOverrides) => { const defaultMethods = { getAccountInfo: jest.fn(), getStateRootHashLatest: jest.fn(), getBalanceByStateRootHash: jest.fn(), getLatestBlock: jest.fn(), putTransaction: jest.fn(), }; // Create a combined mock with defaultMethods overridden by methodOverrides const combinedMock = { ...defaultMethods, ...methodOverrides }; // Mock the RpcClient implementation to return our mock methods jest.mocked(casper_js_sdk_1.RpcClient).mockImplementation(() => combinedMock); return combinedMock; }; const createNetworkMock = (responseData, pageCount = 1, itemCount = responseData.length) => ({ data: { data: responseData, pageCount, itemCount, pages: [], }, status: 200, }); // Mock casper-js-sdk jest.mock("casper-js-sdk", () => { const originalModule = jest.requireActual("casper-js-sdk"); return { ...originalModule, RpcClient: jest.fn(), HttpHandler: jest.fn(), AccountIdentifier: jest.fn(), PublicKey: { fromHex: jest.fn(), }, }; }); describe("Casper API Unit Tests", () => { beforeEach(() => { jest.clearAllMocks(); // Setup config mock jest.mocked(config_1.getCoinConfig).mockReturnValue({ infra: { API_CASPER_NODE_ENDPOINT: MOCK_NODE_URL, API_CASPER_INDEXER: MOCK_INDEXER_URL, }, }); }); describe("getCasperNodeRpcClient", () => { it("should create RPC client with correct URL", () => { (0, _1.getCasperNodeRpcClient)(); expect(casper_js_sdk_1.HttpHandler).toHaveBeenCalledWith(MOCK_NODE_URL); expect(casper_js_sdk_1.RpcClient).toHaveBeenCalled(); }); it("should throw error if API base URL is not available", () => { jest.mocked(config_1.getCoinConfig).mockReturnValueOnce({ infra: {}, }); expect(() => (0, _1.getCasperNodeRpcClient)()).toThrow("API base URL not available"); }); }); describe("fetchAccountStateInfo", () => { it("should fetch account state info successfully", async () => { // Mock PublicKey const mockPublicKeyInstance = { fromHex: () => ({ fromHex: true }) }; jest.mocked(casper_js_sdk_1.PublicKey.fromHex).mockReturnValue(mockPublicKeyInstance); // Mock AccountIdentifier const mockAccountIdentifier = {}; jest .mocked(casper_js_sdk_1.AccountIdentifier) .mockReturnValue(mockAccountIdentifier); // Mock RpcClient.getAccountInfo const mockGetAccountInfo = jest.fn().mockResolvedValue({ account: { accountHash: { toHex: () => MOCK_ACCOUNT_HASH }, mainPurse: { toPrefixedString: () => MOCK_PURSE_UREF }, }, }); createMockRpcClient({ getAccountInfo: mockGetAccountInfo, }); const result = await (0, _1.fetchAccountStateInfo)(MOCK_PUBLIC_KEY); expect(casper_js_sdk_1.PublicKey.fromHex).toHaveBeenCalledWith(MOCK_PUBLIC_KEY); expect(casper_js_sdk_1.AccountIdentifier).toHaveBeenCalledWith(undefined, mockPublicKeyInstance); expect(mockGetAccountInfo).toHaveBeenCalledWith(null, mockAccountIdentifier); expect(result).toEqual({ purseUref: MOCK_PURSE_UREF, accountHash: MOCK_ACCOUNT_HASH, }); }); it("should return undefined values when account not found", async () => { // Mock error with account not found status code const mockError = new Error("Account not found"); mockError.statusCode = consts_1.NodeErrorCodeAccountNotFound; createMockRpcClient({ getAccountInfo: jest.fn().mockRejectedValue(mockError), }); const result = await (0, _1.fetchAccountStateInfo)(MOCK_PUBLIC_KEY); expect(result).toEqual({ purseUref: undefined, accountHash: undefined, }); }); it("should throw error for other error cases", async () => { const mockError = new Error("General error"); createMockRpcClient({ getAccountInfo: jest.fn().mockRejectedValue(mockError), }); await expect((0, _1.fetchAccountStateInfo)(MOCK_PUBLIC_KEY)).rejects.toThrow("General error"); }); }); describe("fetchBalance", () => { it("should fetch balance successfully", async () => { const mockBalanceValue = "10000000000"; const mockRootHash = "mocked-root-hash"; // Create mock methods with implementations that return expected values const mockGetStateRootHashLatest = jest.fn().mockResolvedValue({ stateRootHash: { toHex: () => mockRootHash }, }); const mockGetBalanceByStateRootHash = jest.fn().mockResolvedValue({ balanceValue: mockBalanceValue, }); // Create the mock RPC client with our implementations const mockMethods = createMockRpcClient({ getStateRootHashLatest: mockGetStateRootHashLatest, getBalanceByStateRootHash: mockGetBalanceByStateRootHash, }); const result = await (0, _1.fetchBalance)(MOCK_PURSE_UREF); expect(mockMethods.getStateRootHashLatest).toHaveBeenCalled(); expect(mockMethods.getBalanceByStateRootHash).toHaveBeenCalledWith(MOCK_PURSE_UREF, mockRootHash); expect(result).toEqual(new bignumber_js_1.default(mockBalanceValue)); }); it("should throw error when balance fetch fails", async () => { const mockError = new Error("Failed to fetch balance"); createMockRpcClient({ getStateRootHashLatest: jest.fn().mockRejectedValue(mockError), }); await expect((0, _1.fetchBalance)(MOCK_PURSE_UREF)).rejects.toThrow("Failed to fetch balance"); expect(logs_1.log).toHaveBeenCalledWith("error", "Failed to fetch balance", mockError); }); }); describe("fetchBlockHeight", () => { it("should fetch block height successfully", async () => { const mockHeight = 12345; createMockRpcClient({ getLatestBlock: jest.fn().mockResolvedValue({ block: { height: mockHeight }, }), }); const result = await (0, _1.fetchBlockHeight)(); expect(result).toBe(mockHeight); }); it("should throw error when block height fetch fails", async () => { const mockError = new Error("Failed to fetch block height"); createMockRpcClient({ getLatestBlock: jest.fn().mockRejectedValue(mockError), }); await expect((0, _1.fetchBlockHeight)()).rejects.toThrow("Failed to fetch block height"); expect(logs_1.log).toHaveBeenCalledWith("error", "Failed to fetch block height", mockError); }); }); describe("fetchTxs", () => { const createMockTxData = (hash) => ({ deploy_hash: hash, block_hash: "block-hash-1", caller_public_key: MOCK_PUBLIC_KEY, execution_type_id: 1, cost: "10000", payment_amount: "100000000", timestamp: "2023-01-01T12:00:00Z", status: "success", args: { id: { parsed: 12345, cl_type: { Option: "U64", }, }, amount: { parsed: "500000000", cl_type: "U512", }, target: { parsed: fixtures_1.TEST_ADDRESSES.RECIPIENT_SECP256K1, cl_type: "PublicKey", }, }, amount: "500000000", }); const mockTxData = [createMockTxData("deploy-hash-1")]; const getExpectedNetworkCall = (page) => ({ method: "GET", url: `${MOCK_INDEXER_URL}/accounts/${MOCK_PUBLIC_KEY}/ledgerlive-deploys?limit=${DEFAULT_LIMIT}&page=${page}`, }); it("should fetch transactions successfully (single page)", async () => { jest.mocked(live_network_1.default).mockResolvedValueOnce(createNetworkMock(mockTxData)); const result = await (0, _1.fetchTxs)(MOCK_PUBLIC_KEY); expect(live_network_1.default).toHaveBeenCalledWith(getExpectedNetworkCall(1)); expect(result).toEqual(mockTxData); }); it("should fetch transactions successfully (multiple pages)", async () => { // Mock first page jest.mocked(live_network_1.default).mockResolvedValueOnce(createNetworkMock([mockTxData[0]], 2, 2)); // Mock second page const secondPageTx = createMockTxData("deploy-hash-2"); jest.mocked(live_network_1.default).mockResolvedValueOnce(createNetworkMock([secondPageTx], 2, 2)); const result = await (0, _1.fetchTxs)(MOCK_PUBLIC_KEY); expect(live_network_1.default).toHaveBeenCalledTimes(2); expect(live_network_1.default).toHaveBeenNthCalledWith(1, getExpectedNetworkCall(1)); expect(live_network_1.default).toHaveBeenNthCalledWith(2, getExpectedNetworkCall(2)); expect(result).toEqual([mockTxData[0], secondPageTx]); }); it("should throw error when transactions fetch fails", async () => { const mockError = new Error("Failed to fetch transactions"); jest.mocked(live_network_1.default).mockRejectedValueOnce(mockError); await expect((0, _1.fetchTxs)(MOCK_PUBLIC_KEY)).rejects.toThrow("Failed to fetch transactions"); expect(logs_1.log).toHaveBeenCalledWith("error", "Casper indexer error: ", mockError); }); }); describe("broadcastTx", () => { it("should broadcast transaction successfully", async () => { const mockTransaction = {}; const mockTxHash = "0123456789abcdef"; createMockRpcClient({ putTransaction: jest.fn().mockResolvedValue({ transactionHash: { toHex: () => mockTxHash }, }), }); const result = await (0, _1.broadcastTx)(mockTransaction); expect(result).toBe(mockTxHash); }); it("should throw error when broadcast fails", async () => { const mockTransaction = {}; const mockError = new Error("Failed to broadcast transaction"); createMockRpcClient({ putTransaction: jest.fn().mockRejectedValue(mockError), }); await expect((0, _1.broadcastTx)(mockTransaction)).rejects.toThrow("Failed to broadcast transaction"); expect(logs_1.log).toHaveBeenCalledWith("error", "Failed to broadcast transaction", mockError); }); }); }); //# sourceMappingURL=index.test.js.map