Files
xo-stack/packages/stack/tests/blockchain/blockchain-e2e.spec.ts
T

148 lines
5.5 KiB
TypeScript

// TODO: We want to create a uniform set of tests for our BaseBlockchain interface.
// We should repeat the tests for each provider that we have.
// The below is a **VERY ROUGH** example of how we might be able to do this.
// However, Chaingraph backend is currently broken for many queries, so let's not do this yet.
import { beforeAll, describe, it, expect } from 'vitest';
import { BaseBlockchain, BlockchainElectrum } from '../../src/index.js';
const adapters: Record<
string,
() => Promise<BaseBlockchain<unknown, unknown>>
> = {
// Commenting out since the chaingraph endopoints we are hitting are currently broken.
// demo won't allow non-browser clients
// Pat's server isn't responding to block height requests correctly (or we are using an old version, which the demo server is also running).
// chaingraph: async () => {
// return await BlockchainChaingraph.from();
// },
electrum: async () => {
return await BlockchainElectrum.from();
},
};
const testAddress = 'bitcoincash:qq974d8zzqxmkzk0xxlm6ryx3nqyq53u25w6mwm0rm';
const testLockscript = '76a91454eaf78abae543d9d8c1cf87109cb261101714ea88ac';
const testTxId =
'7b63d5923f76be4e49820c41ed3557a55d5ce33e429519c6b9773b3214be5cb6';
const testBlockHeight = 800000;
describe.each(Object.entries(adapters))('%s Adapter', (name, createAdapter) => {
let blockchain: BaseBlockchain<unknown, unknown>;
beforeAll(async () => {
blockchain = await createAdapter();
});
it(`${name}.fetchUnspents()`, async () => {
const result = await blockchain.fetchUnspents(testAddress);
expect(Array.isArray(result.toArray())).toBeTruthy();
if (result.size > 0) {
const firstUTXO = result.toArray()[0];
expect(firstUTXO.utxo.outpoint).toHaveProperty('outpointTransactionHash');
expect(firstUTXO.utxo.outpoint).toHaveProperty('outpointIndex');
expect(firstUTXO.utxo.output).toHaveProperty('valueSatoshis');
}
});
it(`${name}.fetchTransaction() `, async () => {
const result = await blockchain.fetchTransaction(testTxId);
expect(result).toBeDefined();
expect(Array.isArray(result.getInputs())).toBeTruthy();
expect(result.getInputs()[0]).toHaveProperty('outpointTransactionHash');
expect(Array.isArray(result.getOutputs())).toBeTruthy();
expect(result.getOutputs()[0]).toHaveProperty('valueSatoshis');
});
it(`${name}.fetchBlockHeader() `, async () => {
const result = await blockchain.fetchBlockHeader(1);
expect(result).toBeDefined();
expect(result.toHex()).toBeTypeOf('string');
expect(result.getTimestamp()).toBeTypeOf('number');
});
it(`${name}.fetchChainTip() `, async () => {
const result = await blockchain.fetchChainTip();
expect(result).toBeDefined();
expect(result.height).toBeTypeOf('number');
expect(result.blockHeader.getHashHex()).toBeTypeOf('string');
});
it(`${name}.subscribeLockscript()`, async () => {
const subscriptionPromise = new Promise((resolve, reject) => {
blockchain
.subscribeLockscript(testLockscript, () => {})
.then((unsubscribeCallback) => resolve(unsubscribeCallback))
.catch((error) => reject(error));
});
// Should return and unsuscription callback after a successful suscription.
await expect(subscriptionPromise).resolves.toBeTypeOf('function');
});
it(`${name}.subscribeAddress(), `, async () => {
const subscriptionPromise = new Promise((resolve, reject) => {
blockchain
.subscribeAddress(testAddress, () => {})
.then((unsubscribeCallback) => resolve(unsubscribeCallback))
.catch((error) => reject(error));
});
// Should return and unsuscription callback after a successful suscription.
await expect(subscriptionPromise).resolves.toBeTypeOf('function');
});
it.sequential(`${name}.subscribeTransaction()`, async () => {
const subscriptionPromise = new Promise((resolve, reject) => {
blockchain
.subscribeTransaction(testTxId, () => {})
.then((unsubscribeCallback) => resolve(unsubscribeCallback))
.catch((error) => reject(error));
});
// Should return and unsuscription callback after a successful suscription.
await expect(subscriptionPromise).resolves.toBeTypeOf('function');
});
it(`${name}.unsubscribeLockscript()`, async () => {
const unsubscriptionPromise = new Promise((resolve, reject) => {
blockchain
.unsubscribeLockscript(testLockscript, () => {})
.then((result) => resolve(result))
.catch((error) => reject(error));
});
// Should return true after a successful unsubscription.
await expect(unsubscriptionPromise).resolves.toBeTypeOf('boolean');
});
it(`${name}.unsubscribeAddress()`, async () => {
const unsubscriptionPromise = new Promise((resolve, reject) => {
blockchain
.unsubscribeAddress(testAddress, () => {})
.then((result) => resolve(result))
.catch((error) => reject(error));
});
// Should return true after a successful unsubscription.
await expect(unsubscriptionPromise).resolves.toBeTypeOf('boolean');
});
it.sequential(`${name}.unsubscribeTransaction()`, async () => {
const unsubscriptionPromise = new Promise((resolve, reject) => {
blockchain
.unsubscribeTransaction(testTxId, () => {})
.then((result) => resolve(result))
.catch((error) => reject(error));
});
// Should return true after a successful unsubscription.
await expect(unsubscriptionPromise).resolves.toBeTypeOf('boolean');
});
});