stellar-plus
Version:
beta version of stellar-plus, an all-in-one sdk for the Stellar blockchain
224 lines (223 loc) • 13.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const stellar_sdk_1 = require("@stellar/stellar-sdk");
const soroban_get_transaction_1 = require("../../../../stellar-plus/core/pipelines/soroban-get-transaction");
const errors_1 = require("../../../../stellar-plus/core/pipelines/soroban-get-transaction/errors");
const types_1 = require("../../../../stellar-plus/core/pipelines/soroban-get-transaction/types");
const network_1 = require("../../../../stellar-plus/network");
const default_handler_1 = require("../../../../stellar-plus/rpc/default-handler");
jest.mock('stellar-plus/rpc/default-handler', () => ({
DefaultRpcHandler: jest.fn().mockImplementation(() => ({
getTransaction: jest.fn(),
})),
}));
const MOCKED_RPC_HANDLER = default_handler_1.DefaultRpcHandler;
const TESTNET_CONFIG = (0, network_1.TestNet)();
const MOCKED_PK_A = 'GACF23GKVFTU77K6W6PWSVN7YBM63UHDULILIEXJO6FR4YKMJ7FW3DTI';
const MOCKED_ACCOUNT_A = new stellar_sdk_1.Account(MOCKED_PK_A, '100');
const MOCKED_TX_OPTIONS = {
fee: '100',
networkPassphrase: TESTNET_CONFIG.networkPassphrase,
timebounds: {
minTime: 0,
maxTime: 0,
},
};
const MOCKED_SOROBAN_SUBMISSION = {
status: 'PENDING',
hash: 'mocked-hash',
latestLedger: 0,
latestLedgerCloseTime: 0,
};
const MOCKED_SUCCESSFUL_RESPONSE = {
status: stellar_sdk_1.rpc.Api.GetTransactionStatus.SUCCESS,
};
const MOCKED_FAILED_RESPONSE = {
status: stellar_sdk_1.rpc.Api.GetTransactionStatus.FAILED,
resultXdr: stellar_sdk_1.xdr.TransactionResult.fromXDR('AAAAAAAAAGT////4AAAAAA==', 'base64'),
resultMetaXdr: stellar_sdk_1.xdr.TransactionMeta.fromXDR('AAAAAwAAAAAAAAACAAAAAwAOgggAAAAAAAAAAFBASCSXn/T00voyqd7Oqs2WBynZaF3xrCVh+ffvMXR7AAAAF0h255wADoHgAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAQAOgggAAAAAAAAAAFBASCSXn/T00voyqd7Oqs2WBynZaF3xrCVh+ffvMXR7AAAAF0h255wADoHgAAAAAQAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAMAAAAAAA6CCAAAAABmDqzhAAAAAAAAAAEAAAAAAAAAAAAAAAA=', 'base64'),
};
const MOCKED_MISSING_RESPONSE = {
status: stellar_sdk_1.rpc.Api.GetTransactionStatus.NOT_FOUND,
};
const mockConveyorBeltErrorMeta = (item) => {
return {
item,
meta: {
itemId: 'mocked-id',
beltId: 'mocked-belt-id',
beltType: types_1.SorobanGetTransactionPipelineType.id,
},
};
};
describe('SorobanGetTransaction', () => {
describe('Initialize', () => {
it('should initialize the pipeline', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline();
expect(pipeline).toBeDefined();
}));
it('should initialize the pipeline with the default options', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline();
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
const mockedOptions = jest.mocked(pipeline.options);
expect(mockedOptions).toBeDefined();
expect(mockedOptions.defaultSecondsToWait).toBe(30);
expect(mockedOptions.useEnvelopeTimeout).toBe(true);
}));
it('should initialize the pipeline with the given options', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const customOptions = {
defaultSecondsToWait: 10,
useEnvelopeTimeout: false,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline({ options: customOptions });
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
const spyOptions = jest.mocked(pipeline.options);
expect(spyOptions).toBeDefined();
expect(spyOptions.defaultSecondsToWait).toBe(customOptions.defaultSecondsToWait);
expect(spyOptions.useEnvelopeTimeout).toBe(customOptions.useEnvelopeTimeout);
}));
it('should initialize the pipeline with the given plugins', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
const mockedPlugin = jest.fn().mockImplementation(() => ({
preProcess: jest.fn(),
type: types_1.SorobanGetTransactionPipelineType.id,
}));
const customPlugins = [mockedPlugin];
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline({ plugins: customPlugins });
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment
const spyPlugins = jest.mocked(pipeline.plugins);
expect(spyPlugins).toBeDefined();
expect(spyPlugins).toBe(customPlugins);
}));
});
describe('Core functionalities', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should process the transaction and return if successful', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest.fn().mockResolvedValue(MOCKED_SUCCESSFUL_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const mockedTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS).build();
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline();
const spyGetTransaction = jest.spyOn(mockedRpcHandler, 'getTransaction');
const response = yield pipeline.execute(mockedItem);
expect(response).toBeDefined();
expect(response).toEqual({ response: MOCKED_SUCCESSFUL_RESPONSE });
expect(spyGetTransaction).toHaveBeenCalledTimes(1);
expect(spyGetTransaction).toHaveBeenCalledWith(MOCKED_SOROBAN_SUBMISSION.hash);
}));
it('should process the transaction and continue trying if missing', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest
.fn()
.mockResolvedValue(MOCKED_SUCCESSFUL_RESPONSE)
.mockResolvedValueOnce(MOCKED_MISSING_RESPONSE)
.mockResolvedValueOnce(MOCKED_MISSING_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const mockedTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS).build();
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline();
const spyGetTransaction = jest.spyOn(mockedRpcHandler, 'getTransaction');
const response = yield pipeline.execute(mockedItem);
expect(response).toBeDefined();
expect(response).toEqual({ response: MOCKED_SUCCESSFUL_RESPONSE });
expect(spyGetTransaction).toHaveBeenCalledTimes(3);
expect(spyGetTransaction).toHaveBeenCalledWith(MOCKED_SOROBAN_SUBMISSION.hash);
}));
it('should get the timeout from the transaction envelope when useEnvelopeTimeout is true', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest.fn().mockResolvedValue(MOCKED_SUCCESSFUL_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const timeoutSeconds = 100;
const mockedTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS)
.setTimeout(timeoutSeconds)
.build();
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline({
options: { defaultSecondsToWait: 30, useEnvelopeTimeout: true },
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const spyGetSecondsToWait = jest.spyOn(pipeline, 'getSecondsToWait');
yield pipeline.execute(mockedItem);
expect(spyGetSecondsToWait).toHaveBeenCalledTimes(1);
expect(spyGetSecondsToWait).toHaveReturnedWith(timeoutSeconds);
}));
it('should get the timeout from the inner transaction envelope when useEnvelopeTimeout is true and transaction is a fee bump', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest.fn().mockResolvedValue(MOCKED_SUCCESSFUL_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const timeoutSeconds = 17;
const mockedInnerTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS)
.setTimeout(timeoutSeconds)
.build();
const mockedFeeBumpTransactionEnvelope = stellar_sdk_1.TransactionBuilder.buildFeeBumpTransaction(MOCKED_PK_A, MOCKED_TX_OPTIONS.fee + 1, // Fee bump fee needs to be higher than ineer transaction fee
mockedInnerTransactionEnvelope, TESTNET_CONFIG.networkPassphrase);
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedFeeBumpTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline({
options: { defaultSecondsToWait: 30, useEnvelopeTimeout: true },
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const spyGetSecondsToWait = jest.spyOn(pipeline, 'getSecondsToWait');
yield pipeline.execute(mockedItem);
expect(spyGetSecondsToWait).toHaveBeenCalledTimes(1);
expect(spyGetSecondsToWait).toHaveReturnedWith(timeoutSeconds);
}));
});
describe('Error handling', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should throw an error if the transaction failed', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest.fn().mockResolvedValue(MOCKED_FAILED_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const mockedTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS).build();
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline();
yield expect(pipeline.execute(mockedItem)).rejects.toThrow(errors_1.SGTError.transactionFailed(mockConveyorBeltErrorMeta(mockedItem), MOCKED_FAILED_RESPONSE));
}));
it('should throw an error if the transaction is not found', () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
MOCKED_RPC_HANDLER.mockImplementationOnce(() => ({
getTransaction: jest.fn().mockResolvedValue(MOCKED_MISSING_RESPONSE),
}));
const mockedRpcHandler = new default_handler_1.DefaultRpcHandler(TESTNET_CONFIG);
const mockedTransactionEnvelope = new stellar_sdk_1.TransactionBuilder(MOCKED_ACCOUNT_A, MOCKED_TX_OPTIONS).build();
const mockedItem = {
rpcHandler: mockedRpcHandler,
sorobanSubmission: MOCKED_SOROBAN_SUBMISSION,
transactionEnvelope: mockedTransactionEnvelope,
};
const pipeline = new soroban_get_transaction_1.SorobanGetTransactionPipeline({
options: { defaultSecondsToWait: 3, useEnvelopeTimeout: false },
});
yield expect(pipeline.execute(mockedItem)).rejects.toThrow(errors_1.SGTError.transactionNotFound(mockConveyorBeltErrorMeta(mockedItem), 30, MOCKED_SOROBAN_SUBMISSION.hash));
}));
});
});