321 lines
10 KiB
TypeScript
321 lines
10 KiB
TypeScript
import { getTransaction, extractNativeSolTransferData, extractSplTokenTransferData, extractTokenTransferData } from '../utils/explorer';
|
|
|
|
// Mock the Solana connection
|
|
jest.mock('@solana/web3.js', () => ({
|
|
Connection: jest.fn().mockImplementation(() => ({
|
|
getParsedTransaction: jest.fn()
|
|
}))
|
|
}));
|
|
|
|
// Mock the data module
|
|
jest.mock('../data', () => ({
|
|
CLUSTER_API: 'https://api.devnet.solana.com'
|
|
}));
|
|
|
|
describe('Explorer Utility Tests', () => {
|
|
// Sample transaction hashes from the comments
|
|
const SPL_TOKEN_TX_HASH = '2Dq3cW3D7z75QNfjiTfDu3GgS2gaqrqmoaqzDoomTkJqT2ThSyNDNf1tTz8SgXmzSon9FHCyN61EFkAdkJquhbJf';
|
|
const SOL_TRANSFER_TX_HASH = '3c6AiQmRxnAKSQyQ3C6jPoEmhGPHieQ2uJWuBQjdMA2TPXMWeGtL6PmdUGrMdojFoazq1NUQnDb9qCq1o4sxYvZ8';
|
|
|
|
// Mock transaction data for SPL token transfer
|
|
const mockSplTokenTransaction = {
|
|
blockTime: 1640995200,
|
|
transaction: {
|
|
message: {
|
|
instructions: [
|
|
{
|
|
program: 'spl-token',
|
|
parsed: {
|
|
type: 'transferChecked',
|
|
info: {
|
|
source: 'SourceWallet123',
|
|
destination: 'DestWallet456',
|
|
mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
tokenAmount: {
|
|
amount: '1000000'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
recentBlockhash: 'mockBlockhash123'
|
|
}
|
|
}
|
|
};
|
|
|
|
// Mock transaction data for native SOL transfer
|
|
const mockSolTransaction = {
|
|
blockTime: 1640995200,
|
|
transaction: {
|
|
message: {
|
|
instructions: [
|
|
{
|
|
program: 'system',
|
|
parsed: {
|
|
type: 'transfer',
|
|
info: {
|
|
source: 'SourceWallet789',
|
|
destination: 'DestWallet012',
|
|
lamports: 1000000000
|
|
}
|
|
}
|
|
}
|
|
],
|
|
recentBlockhash: 'mockBlockhash456'
|
|
}
|
|
}
|
|
};
|
|
|
|
// Mock transaction data for non-transfer transaction
|
|
const mockNonTransferTransaction = {
|
|
blockTime: 1640995200,
|
|
transaction: {
|
|
message: {
|
|
instructions: [
|
|
{
|
|
program: 'other-program',
|
|
parsed: {
|
|
type: 'other-action'
|
|
}
|
|
}
|
|
],
|
|
recentBlockhash: 'mockBlockhash789'
|
|
}
|
|
}
|
|
};
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('getTransaction', () => {
|
|
it('should fetch and parse a transaction successfully', async () => {
|
|
const { Connection } = require('@solana/web3.js');
|
|
const mockConnection = {
|
|
getParsedTransaction: jest.fn().mockResolvedValue(mockSplTokenTransaction)
|
|
};
|
|
Connection.mockImplementation(() => mockConnection);
|
|
|
|
const result = await getTransaction(SPL_TOKEN_TX_HASH);
|
|
|
|
expect(mockConnection.getParsedTransaction).toHaveBeenCalledWith(SPL_TOKEN_TX_HASH, {
|
|
maxSupportedTransactionVersion: 0
|
|
});
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('should handle connection errors gracefully', async () => {
|
|
const { Connection } = require('@solana/web3.js');
|
|
const mockConnection = {
|
|
getParsedTransaction: jest.fn().mockRejectedValue(new Error('Connection failed'))
|
|
};
|
|
Connection.mockImplementation(() => mockConnection);
|
|
|
|
await expect(getTransaction(SPL_TOKEN_TX_HASH)).rejects.toThrow('Connection failed');
|
|
});
|
|
});
|
|
|
|
describe('extractNativeSolTransferData', () => {
|
|
it('should extract native SOL transfer data correctly', () => {
|
|
const result = extractNativeSolTransferData(mockSolTransaction);
|
|
|
|
expect(result).toEqual({
|
|
sender: 'cocD4r4yNpHxPq7CzUebxEMyLki3X4d2Y3HcTX5ptUc',
|
|
receiver: 'SP13fTsRrdB2vwJBk88bddCkz4v9N1mHncmTyqkUTTp',
|
|
amount: 1000000000,
|
|
mint: 'So11111111111111111111111111111111111111111',
|
|
time: 1755106952,
|
|
blockhash: '55sznG5B254dnr4WiM1EBHDE5kUfHHyZiY7sBSGGsBYE'
|
|
});
|
|
});
|
|
|
|
it('should return null for non-native SOL transfers', () => {
|
|
const result = extractNativeSolTransferData(mockSplTokenTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should return null for non-transfer transactions', () => {
|
|
const result = extractNativeSolTransferData(mockNonTransferTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should handle malformed transaction data gracefully', () => {
|
|
const malformedTransaction = {
|
|
transaction: {
|
|
message: {
|
|
instructions: []
|
|
}
|
|
}
|
|
};
|
|
|
|
const result = extractNativeSolTransferData(malformedTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should handle errors and return null', () => {
|
|
const invalidTransaction = null;
|
|
const result = extractNativeSolTransferData(invalidTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('extractSplTokenTransferData', () => {
|
|
it('should extract SPL token transfer data correctly', () => {
|
|
const result = extractSplTokenTransferData(mockSplTokenTransaction);
|
|
|
|
expect(result).toEqual({
|
|
sender: '4aHYndCFTBAg8zCLsdTF8mWUPdSXj9NqJXdti4BBdYKP',
|
|
receiver: '7jnoV3yYmaFFa3FYtpTHY4kz6wer8ntEUKZr9hmouets',
|
|
amount: 1000000000000,
|
|
mint: 'diNoZ1L9UEiJMv8i43BjZoPEe2tywwaBTBnKQYf28FT',
|
|
time: 1755106862,
|
|
blockhash: 'GvxNLLizh6oCodnuYX7NVb7xBrtTpAHDTsWMPGtSg2eV'
|
|
});
|
|
});
|
|
|
|
it('should return null for non-SPL token transfers', () => {
|
|
const result = extractSplTokenTransferData(mockSolTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should return null for non-transfer transactions', () => {
|
|
const result = extractSplTokenTransferData(mockNonTransferTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should handle malformed transaction data gracefully', () => {
|
|
const malformedTransaction = {
|
|
transaction: {
|
|
message: {
|
|
instructions: []
|
|
}
|
|
}
|
|
};
|
|
|
|
const result = extractSplTokenTransferData(malformedTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should handle errors and return null', () => {
|
|
const invalidTransaction = null;
|
|
const result = extractSplTokenTransferData(invalidTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('extractTokenTransferData', () => {
|
|
it('should extract native SOL transfer data when available', () => {
|
|
const result = extractTokenTransferData(mockSolTransaction);
|
|
|
|
expect(result).toEqual({
|
|
sender: 'SourceWallet789',
|
|
receiver: 'DestWallet012',
|
|
amount: 1000000000,
|
|
mint: 'So11111111111111111111111111111111111111111',
|
|
time: 1640995200,
|
|
blockhash: 'mockBlockhash456'
|
|
});
|
|
});
|
|
|
|
it('should extract SPL token transfer data when native SOL is not available', () => {
|
|
const result = extractTokenTransferData(mockSplTokenTransaction);
|
|
|
|
expect(result).toEqual({
|
|
sender: 'SourceWallet123',
|
|
receiver: 'DestWallet456',
|
|
amount: 1000000,
|
|
mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
time: 1640995200,
|
|
blockhash: 'mockBlockhash123'
|
|
});
|
|
});
|
|
|
|
it('should return null for non-transfer transactions', () => {
|
|
const result = extractTokenTransferData(mockNonTransferTransaction);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('should prioritize native SOL transfers over SPL token transfers', () => {
|
|
// Create a transaction with both types of transfers
|
|
const mixedTransaction = {
|
|
blockTime: 1640995200,
|
|
transaction: {
|
|
message: {
|
|
instructions: [
|
|
{
|
|
program: 'spl-token',
|
|
parsed: {
|
|
type: 'transferChecked',
|
|
info: {
|
|
source: 'SPLSource',
|
|
destination: 'SPLDest',
|
|
mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
tokenAmount: { amount: '500000' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
program: 'system',
|
|
parsed: {
|
|
type: 'transfer',
|
|
info: {
|
|
source: 'SOLSource',
|
|
destination: 'SOLDest',
|
|
lamports: 2000000000
|
|
}
|
|
}
|
|
}
|
|
],
|
|
recentBlockhash: 'mixedBlockhash'
|
|
}
|
|
}
|
|
};
|
|
|
|
const result = extractTokenTransferData(mixedTransaction);
|
|
|
|
// Should return native SOL transfer data (prioritized)
|
|
expect(result).toEqual({
|
|
sender: 'SOLSource',
|
|
receiver: 'SOLDest',
|
|
amount: 2000000000,
|
|
mint: 'So11111111111111111111111111111111111111111',
|
|
time: 1640995200,
|
|
blockhash: 'mixedBlockhash'
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Integration Tests with Sample Hashes', () => {
|
|
it('should handle SPL token transfer hash format', () => {
|
|
// Test that the SPL token hash format is recognized
|
|
expect(SPL_TOKEN_TX_HASH).toMatch(/^[A-Za-z0-9]{88}$/);
|
|
});
|
|
|
|
it('should handle SOL transfer hash format', () => {
|
|
// Test that the SOL transfer hash format is recognized
|
|
expect(SOL_TRANSFER_TX_HASH).toMatch(/^[A-Za-z0-9]{88}$/);
|
|
});
|
|
|
|
it('should process both hash types through the main function', async () => {
|
|
const { Connection } = require('@solana/web3.js');
|
|
const mockConnection = {
|
|
getParsedTransaction: jest.fn()
|
|
.mockResolvedValueOnce(mockSplTokenTransaction) // First call for SPL token
|
|
.mockResolvedValueOnce(mockSolTransaction) // Second call for SOL
|
|
};
|
|
Connection.mockImplementation(() => mockConnection);
|
|
|
|
// Test SPL token transaction
|
|
const splResult = await getTransaction(SPL_TOKEN_TX_HASH);
|
|
expect(splResult).toBeDefined();
|
|
expect(splResult?.mint).not.toBe('So11111111111111111111111111111111111111111');
|
|
|
|
// Test SOL transaction
|
|
const solResult = await getTransaction(SOL_TRANSFER_TX_HASH);
|
|
expect(solResult).toBeDefined();
|
|
expect(solResult?.mint).toBe('So11111111111111111111111111111111111111111');
|
|
});
|
|
});
|
|
});
|
|
|