UNPKG

mock-chronik-client

Version:

Testing utility to mock the Chronik indexer client and support unit tests that need to mock chronik related API calls.

382 lines 17.7 kB
"use strict"; // Copyright (c) 2023 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const chai = __importStar(require("chai")); const chai_as_promised_1 = __importDefault(require("chai-as-promised")); const index_1 = require("./index"); const mocks_1 = __importDefault(require("./mocks")); const ecashaddrjs_1 = require("ecashaddrjs"); const expect = chai.expect; chai.use(chai_as_promised_1.default); describe('MockAgora', () => { let mockAgora; const agoraError = new Error('some agora error'); beforeEach(() => { mockAgora = new index_1.MockAgora(); }); it('We can set and get offeredGroupTokenIds', async () => { const tokenIds = ['a', 'b', 'c']; mockAgora.setOfferedGroupTokenIds(tokenIds); expect(await mockAgora.offeredGroupTokenIds()).to.deep.equal(tokenIds); // And force a thrown error mockAgora.setOfferedGroupTokenIds(agoraError); await expect(mockAgora.offeredGroupTokenIds()).to.be.rejectedWith(agoraError); }); it('We can set and get offeredFungibleTokenIds', async () => { const tokenIds = ['a', 'b', 'c']; mockAgora.setOfferedFungibleTokenIds(tokenIds); expect(await mockAgora.offeredFungibleTokenIds()).to.deep.equal(tokenIds); // And force a thrown error mockAgora.setOfferedFungibleTokenIds(agoraError); await expect(mockAgora.offeredFungibleTokenIds()).to.be.rejectedWith(agoraError); }); it('We can set and get activeOffersByPubKey', async () => { const pk = 'pk'; const mockOffers = [{ test: 'a' }]; mockAgora.setActiveOffersByPubKey(pk, mockOffers); expect(await mockAgora.activeOffersByPubKey(pk)).to.deep.equal(mockOffers); // And force a thrown error mockAgora.setActiveOffersByPubKey(pk, agoraError); await expect(mockAgora.activeOffersByPubKey(pk)).to.be.rejectedWith(agoraError); }); it('We can set and get activeOffersByGroupTokenId', async () => { const groupTokenId = '00'.repeat(32); const mockOffers = [{ test: 'a' }]; mockAgora.setActiveOffersByGroupTokenId(groupTokenId, mockOffers); expect(await mockAgora.activeOffersByGroupTokenId(groupTokenId)).to.deep.equal(mockOffers); // And force a thrown error mockAgora.setActiveOffersByGroupTokenId(groupTokenId, agoraError); await expect(mockAgora.activeOffersByGroupTokenId(groupTokenId)).to.be.rejectedWith(agoraError); }); it('We can set and get activeOffersByTokenId', async () => { const tokenId = '00'.repeat(32); const mockOffers = [{ test: 'a' }]; mockAgora.setActiveOffersByTokenId(tokenId, mockOffers); expect(await mockAgora.activeOffersByTokenId(tokenId)).to.deep.equal(mockOffers); // And force a thrown error mockAgora.setActiveOffersByTokenId(tokenId, agoraError); await expect(mockAgora.activeOffersByTokenId(tokenId)).to.be.rejectedWith(agoraError); }); }); describe('MockChronikClient', () => { let mockChronik; const chronikError = new Error('some chronik error'); beforeEach(() => { mockChronik = new index_1.MockChronikClient(); }); it('We can set and get a Block by height', async () => { const { tipHeight, block } = mocks_1.default; mockChronik.setBlock(tipHeight, block); expect(await mockChronik.block(tipHeight)).to.deep.equal(block); // And force a thrown error mockChronik.setBlock(tipHeight, chronikError); await expect(mockChronik.block(tipHeight)).to.be.rejectedWith(chronikError); }); it('We can set and get a Block by hash', async () => { const { tipHash, block } = mocks_1.default; mockChronik.setBlock(tipHash, block); expect(await mockChronik.block(tipHash)).to.deep.equal(block); // And force a thrown error mockChronik.setBlock(tipHash, chronikError); await expect(mockChronik.block(tipHash)).to.be.rejectedWith(chronikError); }); it('We can set and get BlockchainInfo', async () => { mockChronik.setBlockchainInfo(mocks_1.default.blockchainInfo); expect(await mockChronik.blockchainInfo()).to.deep.equal(mocks_1.default.blockchainInfo); // And force a thrown error mockChronik.setBlockchainInfo(chronikError); await expect(mockChronik.blockchainInfo()).to.be.rejectedWith(chronikError); }); it('We can set and get chronikInfo', async () => { const versionInfo = { version: '1.0.0' }; mockChronik.setChronikInfo(versionInfo); expect(await mockChronik.chronikInfo()).to.deep.equal(versionInfo); // And force a thrown error mockChronik.setChronikInfo(chronikError); await expect(mockChronik.chronikInfo()).to.be.rejectedWith(chronikError); }); it('We can set and get a Tx by txid', async () => { const { txid, tx } = mocks_1.default; mockChronik.setTx(txid, tx); expect(await mockChronik.tx(txid)).to.deep.equal(tx); // And force a thrown error mockChronik.setTx(txid, chronikError); await expect(mockChronik.tx(txid)).to.be.rejectedWith(chronikError); }); it('We can set and get a Token by tokenId', async () => { const { tokenId, token } = mocks_1.default; mockChronik.setToken(tokenId, token); expect(await mockChronik.token(tokenId)).to.deep.equal(token); // And force a thrown error mockChronik.setToken(tokenId, chronikError); await expect(mockChronik.token(tokenId)).to.be.rejectedWith(chronikError); }); it('We can mock broadcasting a rawTx and getting its txid', async () => { const { txid, rawTx } = mocks_1.default; mockChronik.setBroadcastTx(rawTx, txid); expect(await mockChronik.broadcastTx(rawTx)).to.deep.equal({ txid }); // And force a thrown error mockChronik.setBroadcastTx(rawTx, chronikError); await expect(mockChronik.broadcastTx(rawTx)).to.be.rejectedWith(chronikError); }); it('We can mock broadcasting an array of rawTxs and getting txids', async () => { const { txid, rawTx } = mocks_1.default; // We still set them one at a time mockChronik.setBroadcastTx(rawTx, txid); expect(await mockChronik.broadcastTxs([rawTx, rawTx, rawTx])).to.deep.equal([{ txid }, { txid }, { txid }]); // And force a thrown error mockChronik.setBroadcastTx(rawTx, chronikError); await expect(mockChronik.broadcastTxs([rawTx])).to.be.rejectedWith(chronikError); }); it('We can test websocket methods', async () => { // Create websocket subscription to listen to confirmations on txid const ws = mockChronik.ws({ onMessage: msg => { console.log(`msg`, msg); }, }); // Wait for WS to be connected: await ws.waitForOpen(); expect(ws.waitForOpenCalled).to.equal(true); // We can test if a websocket was closed by calling wsClose() (aka "manually closed") ws.close(); expect(ws.manuallyClosed).to.equal(true); // We can subscribe to blocks ws.subscribeToBlocks(); expect(ws.subs.blocks).to.equal(true); // We can unsubscribe from blocks ws.unsubscribeFromBlocks(); expect(ws.subs.blocks).to.equal(false); // We can subscribe to a script const scriptType = 'p2pkh'; const payload = '00'.repeat(20); ws.subscribeToScript(scriptType, payload); expect(ws.subs.scripts).to.deep.equal([{ scriptType, payload }]); // We can unsubscribe from a script ws.unsubscribeFromScript(scriptType, payload); expect(ws.subs.scripts).to.deep.equal([]); // We can subscribe to an address const addr = (0, ecashaddrjs_1.encodeCashAddress)('ecash', scriptType, payload); ws.subscribeToAddress(addr); expect(ws.subs.scripts).to.deep.equal([{ scriptType, payload }]); // We can unsubscribe from an address ws.unsubscribeFromAddress(addr); expect(ws.subs.scripts).to.deep.equal([]); const tokenId = '00'.repeat(32); // We can subscribe to a token by tokenId ws.subscribeToTokenId(tokenId); expect(ws.subs.tokens).to.deep.equal([tokenId]); // We can unsubscribe from a tokenid ws.unsubscribeFromTokenId(tokenId); expect(ws.subs.tokens).to.deep.equal([]); const lokadId = '00'.repeat(2); // We can subscribe to a token by lokadId ws.subscribeToLokadId(lokadId); expect(ws.subs.lokadIds).to.deep.equal([lokadId]); // We can unsubscribe from a lokadId ws.unsubscribeFromLokadId(lokadId); expect(ws.subs.lokadIds).to.deep.equal([]); // We can subscribe to a plugin ws.subscribeToPlugin('name', 'group'); expect(ws.subs.plugins).to.deep.equal([ { group: 'group', pluginName: 'name' }, ]); // We can unsubscribe from a plugin ws.unsubscribeFromPlugin('name', 'group'); expect(ws.subs.plugins).to.deep.equal([]); // We can use available Agora method to subscribe to Agora plugin by token id const mockAgora = new index_1.MockAgora(); const tokenIdSub = { type: 'TOKEN_ID', tokenId, }; mockAgora.subscribeWs(ws, tokenIdSub); expect(ws.subs.plugins).to.deep.equal([ { group: `${index_1.TOKEN_ID_PREFIX}${tokenId}`, pluginName: index_1.PLUGIN_NAME }, ]); mockAgora.unsubscribeWs(ws, tokenIdSub); expect(ws.subs.plugins).to.deep.equal([]); // We can sub/unsub by group tokenId const groupTokenIdSub = { type: 'GROUP_TOKEN_ID', groupTokenId: tokenId, }; mockAgora.subscribeWs(ws, groupTokenIdSub); expect(ws.subs.plugins).to.deep.equal([ { group: `${index_1.GROUP_TOKEN_ID_PREFIX}${tokenId}`, pluginName: index_1.PLUGIN_NAME, }, ]); mockAgora.unsubscribeWs(ws, groupTokenIdSub); expect(ws.subs.plugins).to.deep.equal([]); // We can sub/unsub by pubkey const mockPubKey = '12'.repeat(32); const pubkeySub = { type: 'PUBKEY', pubkeyHex: mockPubKey, }; mockAgora.subscribeWs(ws, pubkeySub); expect(ws.subs.plugins).to.deep.equal([ { group: `${index_1.PUBKEY_PREFIX}${mockPubKey}`, pluginName: index_1.PLUGIN_NAME, }, ]); mockAgora.unsubscribeWs(ws, pubkeySub); expect(ws.subs.plugins).to.deep.equal([]); }); it('We can set and get tx history by script', async () => { const { tx } = mocks_1.default; const type = 'p2pkh'; const hash = '00'.repeat(20); mockChronik.setTxHistoryByScript(type, hash, [tx]); expect(await mockChronik.script(type, hash).history()).to.deep.equal({ txs: [tx], numPages: 1, numTxs: 1, }); mockChronik.setTxHistoryByScript(type, hash, chronikError); await expect(mockChronik.script(type, hash).history()).to.be.rejectedWith(chronikError); }); it('We can set and get utxos by script', async () => { const { utxo } = mocks_1.default; const type = 'p2pkh'; const hash = '00'.repeat(20); mockChronik.setUtxosByScript(type, hash, [utxo]); expect(await mockChronik.script(type, hash).utxos()).to.deep.equal({ outputScript: `76a914${hash}88ac`, utxos: [utxo], }); mockChronik.setUtxosByScript(type, hash, chronikError); await expect(mockChronik.script(type, hash).utxos()).to.be.rejectedWith(chronikError); }); it('We can set and get tx history by address', async () => { const { tx } = mocks_1.default; const type = 'p2pkh'; const hash = '00'.repeat(20); const address = (0, ecashaddrjs_1.encodeCashAddress)('ecash', type, hash); mockChronik.setTxHistoryByAddress(address, [tx]); expect(await mockChronik.address(address).history()).to.deep.equal({ txs: [tx], numPages: 1, numTxs: 1, }); mockChronik.setTxHistoryByAddress(address, chronikError); await expect(mockChronik.address(address).history()).to.be.rejectedWith(chronikError); }); it('We can set and get utxos by address', async () => { const { utxo, scriptUtxo } = mocks_1.default; const type = 'p2pkh'; const hash = '00'.repeat(20); const address = (0, ecashaddrjs_1.encodeCashAddress)('ecash', type, hash); mockChronik.setUtxosByAddress(address, [utxo]); expect(await mockChronik.address(address).utxos()).to.deep.equal({ outputScript: `76a914${hash}88ac`, utxos: [utxo], }); mockChronik.setUtxosByAddress(address, chronikError); await expect(mockChronik.address(address).utxos()).to.be.rejectedWith(chronikError); }); it('We can set and get tx history by tokenId', async () => { const { tx } = mocks_1.default; const tokenId = '00'.repeat(32); mockChronik.setTxHistoryByTokenId(tokenId, [tx]); expect(await mockChronik.tokenId(tokenId).history()).to.deep.equal({ txs: [tx], numPages: 1, numTxs: 1, }); mockChronik.setTxHistoryByTokenId(tokenId, chronikError); await expect(mockChronik.tokenId(tokenId).history()).to.be.rejectedWith(chronikError); }); it('We can set and get utxos by tokenId', async () => { const { utxo } = mocks_1.default; const tokenId = '00'.repeat(32); mockChronik.setUtxosByTokenId(tokenId, [utxo]); expect(await mockChronik.tokenId(tokenId).utxos()).to.deep.equal({ tokenId, utxos: [utxo], }); mockChronik.setUtxosByTokenId(tokenId, chronikError); await expect(mockChronik.tokenId(tokenId).utxos()).to.be.rejectedWith(chronikError); }); it('We can set and get tx history by lokadId', async () => { // NB we cannot set and get utxos by lokadId, this is not available in chronik-client const { tx } = mocks_1.default; const lokadId = '00'.repeat(2); mockChronik.setTxHistoryByLokadId(lokadId, [tx]); expect(await mockChronik.lokadId(lokadId).history()).to.deep.equal({ txs: [tx], numPages: 1, numTxs: 1, }); mockChronik.setTxHistoryByLokadId(lokadId, chronikError); await expect(mockChronik.lokadId(lokadId).history()).to.be.rejectedWith(chronikError); }); context('Integration tests', () => { it('We can set utxos and then tx history at the same address without overwriting the utxos', async () => { const { utxo, scriptUtxo } = mocks_1.default; const type = 'p2pkh'; const hash = '00'.repeat(20); const address = (0, ecashaddrjs_1.encodeCashAddress)('ecash', type, hash); mockChronik.setUtxosByAddress(address, [utxo]); expect(await mockChronik.address(address).utxos()).to.deep.equal({ outputScript: `76a914${hash}88ac`, utxos: [utxo], }); const { tx } = mocks_1.default; const tokenId = '00'.repeat(32); mockChronik.setTxHistoryByTokenId(tokenId, [tx]); expect(await mockChronik.tokenId(tokenId).history()).to.deep.equal({ txs: [tx], numPages: 1, numTxs: 1, }); // Setting the tx history did not overwrite the utxos expect(await mockChronik.address(address).utxos()).to.deep.equal({ outputScript: `76a914${hash}88ac`, utxos: [utxo], }); }); }); }); //# sourceMappingURL=index.test.js.map