UNPKG

@reown/appkit-utils

Version:

The full stack toolkit to build onchain app UX.

314 lines • 12.8 kB
import { PublicKey, Transaction } from '@solana/web3.js'; import bs58 from 'bs58'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { createNamespaces } from '../src/WCNamespaceUtil.js'; import { SolConstantsUtil } from '../src/solana/SolanaConstantsUtil.js'; import { SolanaWalletConnectStandardWallet } from '../src/wallet-standard/SolanaWalletConnectStandardWallet.js'; const SOLANA_CHAINS = ['solana:mainnet', 'solana:devnet', 'solana:testnet', 'solana:localnet']; vi.mock('@walletconnect/universal-provider'); vi.mock('@wallet-standard/wallet'); const mockAddress = 'HPAccp9wmUAP4kxATmf1CjARHfPzB1HXKWoEaNiZqvUQ'; const mockPublicKey = bs58.decode(mockAddress); const mockTransactionBytes = Uint8Array.from([ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]); describe('SolanaWalletConnectStandardWallet', () => { let mockProvider; let wallet; beforeEach(() => { vi.clearAllMocks(); mockProvider = { connect: vi.fn(), disconnect: vi.fn(), request: vi.fn(), on: vi.fn(), session: vi.fn() }; SolanaWalletConnectStandardWallet.register(mockProvider); wallet = new SolanaWalletConnectStandardWallet(mockProvider); }); describe('constructor and initialization', () => { it('should initialize with correct properties', () => { expect(wallet.name).toBe('WalletConnect'); expect(wallet.version).toBe('1.0.0'); expect(wallet.chains).toEqual(SOLANA_CHAINS); }); it('should set up event listeners on provider', () => { expect(mockProvider.on).toHaveBeenCalledWith('connect', expect.any(Function)); expect(mockProvider.on).toHaveBeenCalledWith('disconnect', expect.any(Function)); expect(mockProvider.on).toHaveBeenCalledWith('accountsChanged', expect.any(Function)); expect(mockProvider.on).toHaveBeenCalledWith('chainChanged', expect.any(Function)); }); }); describe('connect', () => { beforeEach(() => { vi.spyOn(mockProvider, 'connect').mockResolvedValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: [ 'solana:signAndSendTransaction', 'solana:signTransaction', 'solana:signMessage' ], events: ['change'] } } }); }); it('should connect successfully', async () => { const connectResult = await wallet.features['standard:connect'].connect(); expect(connectResult.accounts).toBeDefined(); expect(mockProvider.connect).toHaveBeenCalledWith({ namespaces: createNamespaces([SolConstantsUtil.DEFAULT_CHAIN]) }); }); }); describe('disconnect', () => { beforeEach(() => { vi.spyOn(mockProvider, 'session', 'get').mockReturnValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: [ 'solana:signAndSendTransaction', 'solana:signTransaction', 'solana:signMessage' ], events: ['change'] } } }); }); afterEach(() => { vi.clearAllMocks(); }); it('should disconnect successfully', async () => { await wallet.features['standard:disconnect'].disconnect(); expect(mockProvider.disconnect).toHaveBeenCalled(); }); }); describe('signAndSendTransaction', () => { const mockAccount = { address: mockAddress, publicKey: new PublicKey(mockPublicKey).toBytes(), chains: ['solana:mainnet'], features: ['solana:signAndSendTransaction'] }; beforeEach(async () => { vi.restoreAllMocks(); vi.spyOn(mockProvider, 'session', 'get').mockReturnValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: ['solana:signAndSendTransaction'], events: ['change'] } } }); }); afterEach(() => { vi.clearAllMocks(); }); it('should throw error when not connected', async () => { const mockTransactionBytes = new Uint8Array([1, 2, 3, 4, 5]); await expect(wallet.features['solana:signAndSendTransaction'].signAndSendTransaction({ transaction: mockTransactionBytes, account: mockAccount, chain: 'solana:mainnet' })).rejects.toThrow('not connected'); }); it('should sign and send transaction successfully', async () => { await wallet.features['standard:connect'].connect(); const mockSignature = 'mockSignature'; vi.spyOn(mockProvider, 'request').mockResolvedValueOnce({ signature: mockSignature }); const result = await wallet.features['solana:signAndSendTransaction'].signAndSendTransaction({ transaction: mockTransactionBytes, account: mockAccount, chain: 'solana:mainnet' }); expect(result?.[0]?.signature).toBeDefined(); expect(mockProvider.request).toHaveBeenCalledWith({ method: 'solana_signAndSendTransaction', params: expect.any(Object) }); }); }); describe('signTransaction', () => { const mockAccount = { address: mockAddress, publicKey: new PublicKey(mockPublicKey).toBytes(), chains: ['solana:mainnet'], features: ['solana:signTransaction'] }; beforeEach(async () => { vi.restoreAllMocks(); vi.spyOn(mockProvider, 'session', 'get').mockReturnValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: ['solana:signTransaction'], events: ['change'] } } }); }); afterEach(() => { vi.clearAllMocks(); }); it('should throw error when not connected', async () => { await expect(wallet.features['solana:signTransaction'].signTransaction({ transaction: mockTransactionBytes, account: mockAccount, chain: 'solana:mainnet' })).rejects.toThrow('not connected'); }); it('should sign transaction successfully', async () => { vi.spyOn(Transaction, 'from').mockImplementation(buffer => { return { serialize: vi.fn().mockReturnValue(new Uint8Array(buffer)), recentBlockhash: 'mockBlockhash', feePayer: new PublicKey(mockPublicKey) }; }); await wallet.features['standard:connect'].connect(); const mockSignedTx = 'mockSignedTransaction'; vi.spyOn(mockProvider, 'request').mockResolvedValueOnce({ transaction: mockSignedTx }); const result = await wallet.features['solana:signTransaction'].signTransaction({ transaction: mockTransactionBytes, account: mockAccount, chain: 'solana:mainnet' }); expect(result?.[0]?.signedTransaction).toBeDefined(); expect(mockProvider.request).toHaveBeenCalledWith({ method: 'solana_signTransaction', params: expect.any(Object) }); }); }); describe('signMessage', () => { const mockAccount = { address: mockAddress, publicKey: new PublicKey(mockPublicKey).toBytes(), chains: ['solana:mainnet'], features: ['solana:signMessage'] }; beforeEach(() => { vi.restoreAllMocks(); vi.spyOn(mockProvider, 'session', 'get').mockReturnValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: ['solana:signMessage'], events: ['change'] } } }); }); afterEach(() => { vi.clearAllMocks(); }); it('should throw error when not connected', async () => { vi.spyOn(mockProvider, 'session', 'get').mockReturnValue(undefined); const mockMessage = new Uint8Array([1, 2, 3]); await expect(wallet.features['solana:signMessage'].signMessage({ message: mockMessage, account: mockAccount })).rejects.toThrow('not connected'); }); it('should sign message successfully', async () => { await wallet.features['standard:connect'].connect(); const mockMessage = new Uint8Array([1, 2, 3]); const mockSignature = 'mockSignature'; vi.spyOn(mockProvider, 'request').mockResolvedValueOnce({ signature: mockSignature }); const result = await wallet.features['solana:signMessage'].signMessage({ message: mockMessage, account: mockAccount }); expect(result?.[0]?.signature).toBeDefined(); expect(result?.[0]?.signedMessage).toEqual(mockMessage); expect(mockProvider.request).toHaveBeenCalledWith({ method: 'solana_signMessage', params: expect.any(Object) }); }); }); describe('events', () => { let connectHandler; let disconnectHandler; beforeEach(() => { vi.restoreAllMocks(); vi.spyOn(mockProvider, 'session', 'get').mockReturnValue({ namespaces: { solana: { accounts: [`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:${mockAddress}`], chains: ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'], methods: [ 'solana:signAndSendTransaction', 'solana:signTransaction', 'solana:signMessage' ], events: ['change'] } } }); vi.spyOn(mockProvider, 'on').mockImplementation((event, handler) => { if (event === 'connect') { connectHandler = handler; } else if (event === 'disconnect') { disconnectHandler = handler; } }); wallet.setProvider(mockProvider); }); afterEach(() => { vi.clearAllMocks(); }); it('should handle connect event', () => { const mockListener = vi.fn(); wallet.features['standard:events'].on('change', mockListener); if (connectHandler) { connectHandler(); } expect(mockListener).toHaveBeenCalled(); }); it('should handle disconnect event', () => { const mockListener = vi.fn(); wallet.features['standard:events'].on('change', mockListener); if (disconnectHandler) { disconnectHandler(); } expect(mockListener).toHaveBeenCalled(); }); }); }); //# sourceMappingURL=WalletConnectWalletStandard.test.js.map