UNPKG

@dolaned/wallet-sdk-ts

Version:

Wallet SDK for the Nexa blockchain

456 lines (363 loc) 16.5 kB
import { describe, test, expect, beforeEach, vi } from 'vitest' import { TransactionBuilder, Networks, Transaction } from 'libnexa-ts' import { TransactionCreator } from '../../../src/wallet/transactions/interfaces/TransactionCreator' import { PermissionLabel } from '../../../src/models/transaction.entities' // Mock the rostrumProvider vi.mock('../../../src/network/RostrumProvider', () => ({ rostrumProvider: { broadcast: vi.fn().mockResolvedValue('txid123') } })) // Mock the WalletUtils vi.mock('../../../src/utils/WalletUtils', () => ({ isValidNexaAddress: vi.fn().mockReturnValue(true) })) // Create a concrete implementation of TransactionCreator for testing class TestTransactionCreator extends TransactionCreator { constructor(tx?: TransactionBuilder | string | Buffer) { super(tx) } public parseTxHex(tx: string): this { // Mock implementation return this } public parseTxBuffer(tx: Buffer): this { // Mock implementation return this } public populate(): this { // Mock implementation return this } } describe('TransactionCreator', () => { let creator: TestTransactionCreator beforeEach(() => { creator = new TestTransactionCreator() }) describe('constructor', () => { test('should create instance without transaction builder', () => { const creator = new TestTransactionCreator() expect(creator).toBeInstanceOf(TransactionCreator) expect(creator.network).toBe(Networks.mainnet) expect(creator.totalValue).toBe(BigInt(0)) }) test('should create instance with transaction builder', () => { const txBuilder = new TransactionBuilder() const creator = new TestTransactionCreator(txBuilder) expect(creator).toBeInstanceOf(TransactionCreator) }) }) describe('onNetwork', () => { test('should set network by string', () => { const result = creator.onNetwork('testnet') expect(result).toBe(creator) expect(creator.network).toBe(Networks.testnet) }) test('should set network by Networkish object', () => { const result = creator.onNetwork(Networks.testnet) expect(result).toBe(creator) expect(creator.network).toBe(Networks.testnet) }) test('should be chainable', () => { const result = creator .onNetwork('testnet') .onNetwork('mainnet') expect(result).toBe(creator) expect(creator.network).toBe(Networks.mainnet) }) }) describe('property getters and setters', () => { test('should get and set txOptions', () => { const options = { feeFromAmount: true } creator.txOptions = options expect(creator.txOptions).toEqual(options) }) test('should get and set network', () => { creator.network = Networks.testnet expect(creator.network).toBe(Networks.testnet) }) test('should get and set totalValue', () => { const value = BigInt(1000) creator.totalValue = value expect(creator.totalValue).toBe(value) }) test('should get and set builder', () => { const mockFn = vi.fn() creator.builder = [mockFn] expect(creator.builder).toHaveLength(1) expect(creator.builder[0]).toBe(mockFn) }) test('should get and set tokens', () => { const tokenAction = { token: 'test-token', amount: BigInt(100), action: 'send' } creator.tokens.add(tokenAction) expect(creator.tokens.size).toBe(1) expect(creator.tokens.has(tokenAction)).toBe(true) }) }) describe('consolidate', () => { test('should add consolidate operation to builder', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const result = creator.consolidate(toAddr) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const result = creator .consolidate(toAddr) .consolidate(toAddr) expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('feeFromAmount', () => { test('should add feeFromAmount operation to builder', () => { const result = creator.feeFromAmount() expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const result = creator .feeFromAmount() .feeFromAmount() expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('sendToToken', () => { test('should add token send operation to builder', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const amount = '1000' const token = 'nexatest:tqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const result = creator.sendToToken(toAddr, amount, token) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const amount = '1000' const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const result = creator .sendToToken(toAddr, amount, token) .sendToToken(toAddr, amount, token) expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('sendTo', () => { test('should add NEXA send operation to builder', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const amount = '1000' const result = creator.sendTo(toAddr, amount) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const amount = '1000' const result = creator .sendTo(toAddr, amount) .sendTo(toAddr, amount) expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('renewAuthority', () => { test('should add renew authority operation to builder', () => { const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const perms: PermissionLabel[] = ['mint', 'melt'] const result = creator.renewAuthority(token, perms) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should add renew authority operation with address', () => { const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const perms: PermissionLabel[] = ['mint', 'melt'] const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const result = creator.renewAuthority(token, perms, toAddr) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) }) describe('deleteAuthority', () => { test('should add delete authority operation to builder', () => { const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const outpoint = 'abc123:0' const result = creator.deleteAuthority(token, outpoint) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const outpoint = 'abc123:0' const result = creator .deleteAuthority(token, outpoint) .deleteAuthority(token, outpoint) expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('legacy methods', () => { test('legacyToken should add operation to builder', () => { const result = creator.legacyToken('Test Token', 'TEST', 2, 'https://test.com', 'hash123') expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('legacyGroup should add operation to builder', () => { const result = creator.legacyGroup('Test Group', 'TGRP', 'https://group.com', 'hash456') expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const result = creator .legacyToken('Test Token', 'TEST', 2, 'https://test.com', 'hash123') .legacyGroup('Test Group', 'TGRP', 'https://group.com', 'hash456') expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('token', () => { test('should add token creation to builder', () => { const result = creator.token('Test Token', 'TEST', 2, 'https://test.com', 'hash123') expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const result = creator .token('Test Token', 'TEST', 2, 'https://test.com', 'hash123') .token('Test Token 2', 'TEST2', 4, 'https://test2.com', 'hash456') expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('collection', () => { test('should add collection creation to builder', () => { const result = creator.collection('Test Collection', 'TCOL', 'https://collection.com', 'hash123') expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const result = creator .collection('Test Collection', 'TCOL', 'https://collection.com', 'hash123') .collection('Test Collection 2', 'TCOL2', 'https://collection2.com', 'hash456') expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('NFT', () => { test('should add NFT creation to builder', () => { const parent = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const result = creator.nft(parent, 'https://nft.com/content.zip', 'hash123') expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const parent = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const result = creator .nft(parent, 'https://nft1.com/content.zip', 'hash123') .nft(parent, 'https://nft2.com/content.zip', 'hash456') expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('addOpReturn', () => { test('should add OP_RETURN with string data', () => { const data = 'Hello World' const result = creator.addOpReturn(data) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should add OP_RETURN with buffer data', () => { const data = Buffer.from('Hello World') const result = creator.addOpReturn(data) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should add OP_RETURN with full script', () => { const data = 'Hello World' const result = creator.addOpReturn(data, true) expect(result).toBe(creator) expect(creator.builder).toHaveLength(1) }) test('should be chainable', () => { const result = creator .addOpReturn('Hello') .addOpReturn('World') expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) }) }) describe('build', () => { test('should execute all builder functions and return serialized transaction', async () => { const mockFunction = vi.fn().mockResolvedValue(undefined) creator.builder = [mockFunction] const result = await creator.build() expect(mockFunction).toHaveBeenCalledTimes(1) expect(typeof result).toBe('string') }) test('should execute multiple builder functions in order', async () => { const mockFunction1 = vi.fn().mockResolvedValue(undefined) const mockFunction2 = vi.fn().mockResolvedValue(undefined) creator.builder = [mockFunction1, mockFunction2] await creator.build() expect(mockFunction1).toHaveBeenCalledTimes(1) expect(mockFunction2).toHaveBeenCalledTimes(1) }) }) describe('integration tests', () => { test('should handle complete transaction flow', async () => { const toAddr = 'nexatest:nqtsq5g5jsdmqqywaqd82lhnnk3a8wqunjz6gtxdtavnnekc' const amount = '1000' const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const result = creator .onNetwork('testnet') .sendTo(toAddr, amount) .sendToToken(toAddr, amount, token) .addOpReturn('Transaction data') .feeFromAmount() .populate() expect(result).toBe(creator) expect(creator.builder).toHaveLength(4) // sendTo, sendToToken, addOpReturn, feeFromAmount (populate not called yet) expect(creator.network).toBe(Networks.testnet) const tx = await creator.build() expect(typeof tx).toBe('string') }) test('should handle token authority operations', async () => { const token = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const perms: PermissionLabel[] = ['mint', 'melt'] const outpoint = 'abc123:0' const result = creator .renewAuthority(token, perms) .deleteAuthority(token, outpoint) .populate() expect(result).toBe(creator) expect(creator.builder).toHaveLength(2) // renewAuthority, deleteAuthority (populate not called yet) const tx = await creator.build() expect(typeof tx).toBe('string') }) test('should handle token and collection creation', async () => { const parent = 'nexatest:tq8r37lcjlqazz7vuvug84q2ev50573hesrnxkv9y6hvhhl5k5qqqnmyf79mx' const result = creator .token('Test Token', 'TEST', 2, 'https://test.com', 'hash123') .collection('Test Collection', 'TCOL', 'https://collection.com', 'hash456') .nft(parent, 'https://nft.com/content.zip', 'hash789') .populate() expect(result).toBe(creator) expect(creator.builder).toHaveLength(3) // token, collection, NFT (populate not called yet) const tx = await creator.build() expect(typeof tx).toBe('string') }) }) describe('error handling', () => { test('should handle async errors in builder functions', async () => { const errorFunction = vi.fn().mockRejectedValue(new Error('Test error')) creator.builder = [errorFunction] await expect(creator.build()).rejects.toThrow('Test error') }) }) })