/** * @jest-environment jsdom */ import invariant from "invariant"; import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain"; import { getCurrentCosmosPreloadData } from "@ledgerhq/coin-cosmos/preloadedData"; import preloadedMockData from "@ledgerhq/coin-cosmos/preloadedData.mock"; import { LiveConfig } from "@ledgerhq/live-config/LiveConfig"; import { setEnv } from "@ledgerhq/live-env"; import { CurrencyBridge } from "@ledgerhq/types-live"; import { act, renderHook } from "@testing-library/react"; import "../../__tests__/test-helpers/dom-polyfill"; import { getAccountCurrency } from "../../account"; import { getAccountBridge, getCurrencyBridge } from "../../bridge"; import { makeBridgeCacheSystem } from "../../bridge/cache"; import { liveConfig } from "../../config/sharedConfig"; import { getCryptoCurrencyById } from "../../currencies"; import { genAccount, genAddingOperationsInAccount } from "../../mock/account"; import * as hooks from "./react"; import type { CosmosAccount, CosmosDelegation, CosmosMappedDelegation, CosmosResources, CosmosValidatorItem, Transaction, } from "./types"; const localCache = {}; const cache = makeBridgeCacheSystem({ saveData(c, d) { localCache[c.id] = d; return Promise.resolve(); }, getData(c) { return Promise.resolve(localCache[c.id]); }, }); describe("cosmos/react", () => { beforeAll(() => { LiveConfig.setConfig(liveConfig); const cosmos = cryptoFactory("cosmos"); cosmos.lcd = LiveConfig.getValueByKey("config_currency_cosmos").lcd; cosmos.minGasPrice = LiveConfig.getValueByKey("config_currency_cosmos").minGasPrice; cosmos.ledgerValidator = LiveConfig.getValueByKey("config_currency_cosmos").ledgerValidator; }); describe("useCosmosFamilyPreloadData", () => { it("should return Cosmos preload data and updates", async () => { const { prepare } = setup(); await act(() => prepare()); const { result } = renderHook(() => hooks.useCosmosFamilyPreloadData("cosmos")); const data = getCurrentCosmosPreloadData()["cosmos"]; expect(result.current).toStrictEqual(data); expect(result.current).toStrictEqual(preloadedMockData); }); }); describe("useCosmosFormattedDelegations", () => { it("should return formatted delegations", async () => { const { account, prepare } = setup(); await prepare(); const { result } = renderHook(() => hooks.useCosmosFamilyMappedDelegations(account)); const delegations = account.cosmosResources?.delegations; invariant(delegations, "cosmos: delegations is required"); expect(account.cosmosResources?.delegations?.some(d => d.amount[0] === 0)).toBe(false); expect(Array.isArray(result.current)).toBe(true); expect(result.current.length).toBe((delegations as CosmosDelegation[]).length); const { code } = getAccountCurrency(account).units[0]; expect(result.current[0].formattedAmount.split(" ")[1]).toBe(code); expect(result.current[0].formattedPendingRewards.split(" ")[1]).toBe(code); expect(typeof result.current[0].rank).toBe("number"); expect((result.current[0].validator as CosmosValidatorItem).validatorAddress).toBe( (delegations as CosmosDelegation[])[0].validatorAddress, ); }); describe("mode: claimReward", () => { it("should only return delegations which have some pending rewards", async () => { const { account, prepare } = setup(); await prepare(); const { result } = renderHook(() => hooks.useCosmosFamilyMappedDelegations(account, "claimReward"), ); expect(result.current.length).toBe(3); }); }); }); describe("useCosmosFamilyDelegationsQuerySelector", () => { it("should return delegations filtered by query as options", async () => { const { account, transaction, prepare } = setup(); await prepare(); invariant(account.cosmosResources, "cosmos: account and cosmos resources required"); if (!account.cosmosResources) throw new Error("cosmos: account and cosmos resources required"); const delegations = account.cosmosResources.delegations || []; const newTx = { ...transaction, mode: "delegate", validators: delegations.map(({ validatorAddress, amount }) => ({ address: validatorAddress, amount, })), }; const { result } = renderHook(() => hooks.useCosmosFamilyDelegationsQuerySelector(account, newTx as Transaction), ); expect(result.current.options.length).toBe(delegations.length); act(() => { result.current.setQuery("FRESHATOMS"); }); expect(result.current.options.length).toBe(0); }); it("should return the first delegation as value", async () => { const { account, transaction, prepare } = setup(); await prepare(); invariant(account.cosmosResources, "cosmos: account and cosmos resources required"); const delegations = (account.cosmosResources as CosmosResources).delegations || []; const newTx = { ...transaction, mode: "delegate", validators: delegations.map(({ validatorAddress, amount }) => ({ address: validatorAddress, amount, })), }; const { result } = renderHook(() => hooks.useCosmosFamilyDelegationsQuerySelector(account, newTx as Transaction), ); expect( ((result.current.value as CosmosMappedDelegation).validator as CosmosValidatorItem) .validatorAddress, ).toBe(delegations[0].validatorAddress); }); it("should find delegation by sourceValidator field and return as value for redelegate", async () => { const { account, transaction, prepare } = setup(); await prepare(); invariant(account.cosmosResources, "cosmos: account and cosmos resources required"); const delegations = (account.cosmosResources as CosmosResources).delegations || []; const sourceValidator = delegations[delegations.length - 1].validatorAddress; const newTx = { ...transaction, mode: "redelegate", validators: delegations.map(({ validatorAddress, amount }) => ({ address: validatorAddress, amount, })), sourceValidator, }; const { result } = renderHook(() => hooks.useCosmosFamilyDelegationsQuerySelector(account, newTx as Transaction), ); expect( ((result.current.value as CosmosMappedDelegation).validator as CosmosValidatorItem) .validatorAddress, ).toBe(sourceValidator); }); }); describe("useSortedValidators", () => { it("should reutrn sorted validators", async () => { const { account, prepare } = setup(); await prepare(); const { result: preloadDataResult } = renderHook(() => hooks.useCosmosFamilyPreloadData("cosmos"), ); const { validators } = preloadDataResult.current; const delegations = (account.cosmosResources?.delegations || []).map( ({ validatorAddress, amount }) => ({ address: validatorAddress, amount, }), ); const { result } = renderHook(() => hooks.useSortedValidators("", validators, delegations)); expect(result.current.length).toBe(validators.length); const { result: searchResult } = renderHook(() => hooks.useSortedValidators("Nodeasy.com", validators, delegations), ); expect(searchResult.current.length).toBe(1); }); }); describe("reorderValidators", () => { it("should return a list of Validators with Ledger first", () => { const { result } = renderHook(() => hooks.useLedgerFirstShuffledValidatorsCosmosFamily("cosmos"), ); const LEDGER_VALIDATOR_ADDRESS = cryptoFactory("cosmos").ledgerValidator; expect(result.current[0].validatorAddress).toBe(LEDGER_VALIDATOR_ADDRESS); }); }); }); function setup(): { account: CosmosAccount; currencyBridge: CurrencyBridge; transaction: Transaction; prepare: () => Promise; } { setEnv("MOCK", "1"); setEnv("EXPERIMENTAL_CURRENCIES", "cosmos"); const seed = "cosmos-2"; const currency = getCryptoCurrencyById("cosmos"); const a = genAccount(seed, { currency, }); const account = genAddingOperationsInAccount(a, 3, seed) as CosmosAccount; const currencyBridge = getCurrencyBridge(currency); const bridge = getAccountBridge(account); const transaction = bridge.createTransaction(account); return { account, currencyBridge, transaction, prepare: async () => cache.prepareCurrency(currency), }; }