mock-chronik-client
Version:
Testing utility to mock the Chronik indexer client and support unit tests that need to mock chronik related API calls.
386 lines • 15.2 kB
TypeScript
import { BatchSummaryRow, BatchUtxosRow, Block, TxHistoryPage, Tx, TokenInfo, BlockchainInfo, Utxo, TokenIdUtxos, ScriptRef, ScriptUtxo, ScriptUtxos, WsConfig, WsMsgClient, WsSubScriptClient, WsSubPluginClient } from 'chronik-client';
import * as ws from 'ws';
type MockAgoraOffer = Record<string, any>;
/**
* MockAgora stores set responses in this object
*/
interface MockAgoraMockResponses {
/** Supported Agora methods in MockAgora */
offeredGroupTokenIds: string[] | Error;
offeredFungibleTokenIds: string[] | Error;
activeOffersByPubKey: {
[key: string]: MockAgoraOffer[] | Error;
};
activeOffersByGroupTokenId: {
[key: string]: MockAgoraOffer[] | Error;
};
activeOffersByTokenId: {
[key: string]: MockAgoraOffer[] | Error;
};
}
export type AgoraQueryParamVariants = {
type: 'TOKEN_ID';
tokenId: string;
} | {
type: 'GROUP_TOKEN_ID';
groupTokenId: string;
} | {
type: 'PUBKEY';
pubkeyHex: string;
};
interface MockAgoraInterface {
mockedResponses: MockAgoraMockResponses;
/** Methods used to set expected responses */
setOfferedGroupTokenIds: (expectedResponse: string[] | Error) => void;
setOfferedFungibleTokenIds: (expectedResponse: string[] | Error) => void;
setActiveOffersByPubKey: (pubKey: string, expectedResponse: MockAgoraOffer[] | Error) => void;
setActiveOffersByGroupTokenId: (groupTokenId: string, expectedResponse: MockAgoraOffer[] | Error) => void;
setActiveOffersByTokenId: (tokenId: string, expectedResponse: MockAgoraOffer[] | Error) => void;
/** Supported Agora methods */
offeredGroupTokenIds: () => void;
offeredFungibleTokenIds: () => void;
activeOffersByPubKey: (pubKey: string) => void;
activeOffersByGroupTokenId: (groupTokenId: string) => void;
activeOffersByTokenId: (tokenId: string) => void;
subscribeWs: (ws: MockWsEndpoint, params: AgoraQueryParamVariants) => void;
unsubscribeWs: (ws: MockWsEndpoint, params: AgoraQueryParamVariants) => void;
}
export declare const TOKEN_ID_PREFIX = "54";
export declare const PUBKEY_PREFIX = "50";
export declare const GROUP_TOKEN_ID_PREFIX = "47";
export declare const PLUGIN_NAME = "agora";
/**
* MockAgora
* Useful test mock for writing unit tests for functions that use the Agora
* class from the ecash-agora library. Drop-in replacement for Agora object
* to unit test functions that accept an intialized Agora object as a param.
* In this way, can write unit tests without hitting an actual chronik API.
*
* Mock calls to chronik nodes indexed with the ecash-agora plugin
*
* See Cashtab and ecash-herald for implementation examples.
*
* Note: not all Agora methods are mocked, can be extended as needed
*/
export declare class MockAgora implements MockAgoraInterface {
mockedResponses: MockAgoraMockResponses;
constructor();
setOfferedGroupTokenIds: (expectedResponse: string[] | Error) => void;
setOfferedFungibleTokenIds: (expectedResponse: string[] | Error) => void;
setActiveOffersByPubKey: (pubKey: string, expectedResponse: MockAgoraOffer[] | Error) => void;
setActiveOffersByGroupTokenId: (groupTokenId: string, expectedResponse: MockAgoraOffer[] | Error) => void;
setActiveOffersByTokenId: (tokenId: string, expectedResponse: MockAgoraOffer[] | Error) => void;
offeredGroupTokenIds: () => Promise<Error | string[]>;
offeredFungibleTokenIds: () => Promise<Error | string[]>;
activeOffersByPubKey: (pubKey: string) => Promise<Error | MockAgoraOffer[]>;
activeOffersByGroupTokenId: (groupTokenId: string) => Promise<Error | MockAgoraOffer[]>;
activeOffersByTokenId: (tokenId: string) => Promise<Error | MockAgoraOffer[]>;
/** Subscribe to updates from the websocket for some params */
subscribeWs: (ws: MockWsEndpoint, params: AgoraQueryParamVariants) => void;
/** Unsubscribe from updates from the websocket for some params */
unsubscribeWs: (ws: MockWsEndpoint, params: AgoraQueryParamVariants) => void;
private _groupHex;
private _throwOrReturnValue;
}
type AddressType = 'p2sh' | 'p2pkh';
/**
* Object where we store expected the values we want to get when
* we make ChronikClient calls
*/
interface MockChronikClientMockedResponses {
block: {
[key: string | number]: Block | Error;
};
blockTxs: {
[key: string | number]: {
history: Tx[] | Error;
};
};
tx: {
[key: string | number]: Tx | Error;
};
token: {
[key: string | number]: TokenInfo | Error;
};
broadcastTx: {
[key: string | number]: {
txid: string;
} | Error;
};
blockchainInfo: BlockchainInfo | Error | object;
chronikInfo: {
version: string;
} | Error;
script: {
p2pkh: {
[key: string | number]: {
history: Tx[] | Error;
utxos: ScriptUtxo[] | Error;
};
};
p2sh: {
[key: string | number]: {
history: Tx[] | Error;
utxos: ScriptUtxo[] | Error;
};
};
};
address: {
[key: string | number]: {
history: Tx[] | Error;
utxos: ScriptUtxo[] | Error;
};
};
tokenId: {
[key: string | number]: {
history: Tx[] | Error;
utxos: Utxo[] | Error;
};
};
lokadId: {
[key: string | number]: {
history: Tx[] | Error;
utxos: ScriptUtxo[] | Error;
};
};
}
/**
* Object where we store "deeper" methods
* ChronikClient API supports methods that take params
* So, when we call chronik.address(address).utxos, we
* want the utxos for that address
* And we want to also be able to set and get utxos for
* another address in the mock
*/
interface MockChronikClientMockedMethods {
script: {
p2pkh: {
[key: string]: {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
};
};
p2sh: {
[key: string]: {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
};
};
};
address: {
[key: string]: {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
};
};
tokenId: {
[key: string]: {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<TokenIdUtxos | Error>;
};
};
lokadId: {
[key: string]: {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
};
};
}
/**
* MockChronikClient
* Drop-in replacement for ChronikClient in unit tests
*
* See Cashtab, token-server, ecash-herald for implementation
*
* Can set expected return values to test ChronikClient functions
* without hitting an API
*/
export declare class MockChronikClient {
mockedResponses: MockChronikClientMockedResponses;
mockedMethods: MockChronikClientMockedMethods;
constructor();
block: (blockHashOrHeight: string | number) => Promise<Error | Block>;
tx: (txid: string) => Promise<Error | Tx>;
token: (tokenId: string) => Promise<Error | TokenInfo>;
blockTxs: (hashOrHeight: number | string, pageNumber?: number, pageSize?: number) => Promise<TxHistoryPage>;
broadcastTx: (txHex: string, _skipTokenChecks?: boolean) => Promise<Error | {
txid: string;
}>;
broadcastTxs: (txsHex: string[], _skipTokenChecks?: boolean) => Promise<{
txids: string[];
}>;
/**
* Same mocked responses as broadcastTx; optional separate timeout/error behavior later.
*/
broadcastAndFinalizeTx: (txHex: string, _finalizationTimeoutSecs?: number, _skipTokenChecks?: boolean) => Promise<Error | {
txid: string;
}>;
broadcastAndFinalizeTxs: (txsHex: string[], _finalizationTimeoutSecs?: number, _skipTokenChecks?: boolean) => Promise<{
txids: string[];
}>;
blockchainInfo: () => Promise<object | Error | BlockchainInfo>;
script: (type: AddressType, hash: string) => {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
} | {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
};
address: (address: string) => {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<ScriptUtxos | Error>;
};
tokenId: (tokenId: string) => {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
utxos: () => Promise<TokenIdUtxos | Error>;
};
lokadId: (lokadId: string) => {
history: (pageNumer?: number, pageSize?: number) => Promise<TxHistoryPage | Error>;
};
ws: (wsConfig: WsConfig) => MockWsEndpoint;
setBlock: (hashOrHeight: string | number, block: Block | Error) => void;
setTx: (txid: string, tx: Tx | Error) => void;
setToken: (tokenId: string, token: TokenInfo | Error) => void;
setBlockchainInfo: (blockchainInfo: BlockchainInfo | Error) => void;
setChronikInfo: (versionInfo: {
version: string;
} | Error) => void;
chronikInfo: () => Promise<Error | {
version: string;
}>;
/**
* Batch UTXOs: resolves each script from data set by {@link setUtxosByScript}
* or {@link setUtxosByAddress} (p2pkh / p2sh only). Unknown scripts get empty
* `utxos`. Row order matches the request.
*/
batchUtxos: (scripts: ScriptRef[]) => Promise<BatchUtxosRow[]>;
/**
* Batch history summary: uses the same mocked `history` arrays as
* `setTxHistoryByScript` / `setTxHistoryByAddress` (p2pkh / p2sh only).
* The head tx is `history[0]`, matching page 0 of {@link MockChronikClientMockedMethods.script.*.history}.
*/
batchSummary: (scripts: ScriptRef[]) => Promise<BatchSummaryRow[]>;
setBroadcastTx: (rawTx: string, txidOrError: string | Error) => void;
setTxHistoryByScript: (type: AddressType, hash: string, history: Tx[] | Error) => void;
setTxHistoryByAddress: (address: string, history: Tx[] | Error) => void;
setTxHistoryByTokenId: (tokenId: string, history: Tx[] | Error) => void;
setTxHistoryByLokadId: (lokadId: string, history: Tx[] | Error) => void;
setTxHistoryByBlock: (hashOrHeight: string | number, history: Tx[] | Error) => void;
setUtxosByScript: (type: AddressType, hash: string, utxos: ScriptUtxo[] | Error) => void;
setUtxosByAddress: (address: string, utxos: ScriptUtxo[] | Error) => void;
setUtxosByTokenId: (tokenId: string, utxos: Utxo[] | Error) => void;
plugin: () => string;
private _proxyInterface;
proxyInterface: {};
blocks: () => void;
rawTx: () => void;
private _setAddress;
private _setTokenId;
private _setLokadId;
private _setScript;
private _getScriptUtxos;
private _getAddressUtxos;
private _getTokenIdUtxos;
private _batchUtxosRowForScript;
/** Resolved tx-history array for p2pkh/p2sh batch helpers. */
private _txHistoryArrayForScript;
private _getTxHistory;
private _throwOrReturnValue;
}
interface WsSubscriptions {
/** Subscriptions to scripts */
scripts: WsSubScriptClient[];
/** Subscriptions to tokens by tokenId */
tokens: string[];
/** Subscriptions to txids */
txids: string[];
/** Subscriptions to lokadIds */
lokadIds: string[];
/** Subscriptions to plugins */
plugins: WsSubPluginClient[];
/** Subscription to blocks */
blocks: boolean;
}
/**
* Mock WsEndpoint for MockChronikClient.
* Based on WsEndpoint in chronik-client.
* We do not test network functionality
* Useful for testing that methods are called as expected,
* ws is opened and closed as expected, subscriptions are added
* and removed as expected
*
* See Cashtab and token-server tests for implemented examples
*/
export declare class MockWsEndpoint {
/** Fired when a message is sent from the WebSocket. */
onMessage?: (msg: WsMsgClient) => void;
/** Fired when a connection has been (re)established. */
onConnect?: (e: ws.Event) => void;
/**
* Fired after a connection has been unexpectedly closed, and before a
* reconnection attempt is made. Only fired if `autoReconnect` is true.
*/
onReconnect?: (e: ws.Event) => void;
/** Fired when an error with the WebSocket occurs. */
onError?: (e: ws.ErrorEvent) => void;
/**
* Fired after a connection has been manually closed, or if `autoReconnect`
* is false, if the WebSocket disconnects for any reason.
*/
onEnd?: (e: ws.Event) => void;
/** Whether to automatically reconnect on disconnect, default true. */
autoReconnect: boolean;
ws: ws.WebSocket | undefined;
connected: Promise<ws.Event> | undefined;
manuallyClosed: boolean;
waitForOpenCalled: boolean;
subs: WsSubscriptions;
constructor(config: WsConfig);
/** Wait for the WebSocket to be connected. */
waitForOpen(): Promise<void>;
/**
* Subscribe to block messages
*/
subscribeToBlocks(): void;
/**
* Unsubscribe from block messages
*/
unsubscribeFromBlocks(): void;
/**
* Subscribe to the given script type and payload.
* For "p2pkh", `scriptPayload` is the 20 byte public key hash.
*/
subscribeToScript(type: AddressType, payload: string): void;
/** Unsubscribe from the given script type and payload. */
unsubscribeFromScript(type: AddressType, payload: string): void;
/**
* Subscribe to an address
* Method can be used for p2pkh or p2sh addresses
*/
subscribeToAddress(address: string): void;
/** Unsubscribe from the given address */
unsubscribeFromAddress(address: string): void;
/** Subscribe to a lokadId */
subscribeToLokadId(lokadId: string): void;
/** Unsubscribe from the given lokadId */
unsubscribeFromLokadId(lokadId: string): void;
/** Subscribe to a tokenId */
subscribeToTokenId(tokenId: string): void;
/** Unsubscribe from the given tokenId */
unsubscribeFromTokenId(tokenId: string): void;
/** Subscribe to a txid */
subscribeToTxid(txid: string): void;
/** Unsubscribe from the given txid */
unsubscribeFromTxid(txid: string): void;
/** Subscribe to a plugin */
subscribeToPlugin(pluginName: string, group: string): void;
/** Unsubscribe from the given plugin */
unsubscribeFromPlugin(pluginName: string, group: string): void;
/**
* Close the WebSocket connection and prevent any future reconnection
* attempts.
*/
close(): void;
private _subUnsubBlocks;
}
export {};
//# sourceMappingURL=index.d.ts.map