UNPKG

@ledgerhq/coin-tezos

Version:
124 lines (105 loc) 3.71 kB
// SPDX-FileCopyrightText: © 2026 LEDGER SAS // SPDX-License-Identifier: Apache-2.0 import type { TezosCoinConfig, TezosContext } from '../config' import { getBlockInfo } from './getBlockInfo' const mockGetBlockByLevel = jest.fn() jest.mock('../network', () => ({ createTzktApi: () => ({ getBlockByLevel: (...args: unknown[]) => mockGetBlockByLevel(...args), }), })) const context: TezosContext = { config: async () => ({}) as unknown as TezosCoinConfig, logger: () => undefined, } describe('getBlockInfo', () => { beforeEach(() => { jest.clearAllMocks() }) it('maps level, hash, timestamp, and parent from the TzKT block response', async () => { // Given const level = 7_000_000 mockGetBlockByLevel.mockResolvedValueOnce({ level, hash: 'BLockHashABC123', timestamp: '2024-06-15T10:30:00Z', } as any) mockGetBlockByLevel.mockResolvedValueOnce({ level: level - 1, hash: 'BLockHashParent', timestamp: '2024-06-15T10:29:52Z', } as any) // When const result = await getBlockInfo(context, level) // Then expect(mockGetBlockByLevel).toHaveBeenCalledTimes(2) expect(mockGetBlockByLevel).toHaveBeenCalledWith(level) expect(mockGetBlockByLevel).toHaveBeenCalledWith(level - 1) expect(result).toEqual({ height: level, hash: 'BLockHashABC123', time: new Date('2024-06-15T10:30:00Z'), parent: { height: level - 1, hash: 'BLockHashParent' }, }) }) it('parses the timestamp string into a proper Date instance', async () => { // Given const isoDate = '2025-01-01T00:00:00.000Z' mockGetBlockByLevel.mockResolvedValue({ level: 8_000_000, hash: 'BLockHashXYZ', timestamp: isoDate, } as any) // When const result = await getBlockInfo(context, 8_000_000) // Then expect(result.time).toBeInstanceOf(Date) expect(result.time.toISOString()).toBe(isoDate) }) it('throws for height = 0 without calling the API', async () => { // When / Then await expect(getBlockInfo(context, 0)).rejects.toThrow( 'getBlockInfo: height must be a positive integer, got 0' ) expect(mockGetBlockByLevel).not.toHaveBeenCalled() }) it('throws for negative height without calling the API', async () => { // When / Then await expect(getBlockInfo(context, -5)).rejects.toThrow( 'getBlockInfo: height must be a positive integer, got -5' ) expect(mockGetBlockByLevel).not.toHaveBeenCalled() }) it.each([NaN, 1.5, Infinity, -Infinity])( 'throws for non-safe-integer height (%s) without calling the API', async (height) => { await expect(getBlockInfo(context, height)).rejects.toThrow( 'getBlockInfo: height must be a positive integer' ) expect(mockGetBlockByLevel).not.toHaveBeenCalled() } ) it('includes parent from the predecessor block fetched in parallel', async () => { // Given – genesis-adjacent block: level 1 with level 0 as parent mockGetBlockByLevel.mockResolvedValueOnce({ level: 1, hash: 'BLBlock1', timestamp: '2018-06-30T16:07:40Z', } as any) mockGetBlockByLevel.mockResolvedValueOnce({ level: 0, hash: 'BLGenesis', timestamp: '2018-06-30T16:07:32Z', } as any) // When const result = await getBlockInfo(context, 1) // Then expect(result.parent).toEqual({ height: 0, hash: 'BLGenesis' }) }) it('propagates errors thrown by the network layer', async () => { // Given mockGetBlockByLevel.mockRejectedValue(new Error('TzKT unreachable')) // When / Then await expect(getBlockInfo(context, 999_999)).rejects.toThrow('TzKT unreachable') }) })