/** * MetaMask Integration Tests * * Unit tests for MetaMask integration helpers */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; // Mock window.ethereum const mockEthereum = { isMetaMask: true, request: vi.fn(), on: vi.fn(), removeListener: vi.fn(), }; describe('MetaMask Integration', () => { beforeEach(() => { // Reset mocks vi.clearAllMocks(); // Mock window.ethereum Object.defineProperty(window, 'ethereum', { value: mockEthereum, writable: true, configurable: true, }); }); afterEach(() => { // Clean up delete (window as any).ethereum; }); describe('addNetwork', () => { it('should add network successfully', async () => { mockEthereum.request.mockResolvedValue(null); const { addNetwork } = await import('../metamask-sdk/src/addNetwork'); await addNetwork(); expect(mockEthereum.request).toHaveBeenCalledWith({ method: 'wallet_addEthereumChain', params: [expect.objectContaining({ chainId: '0x8a', chainName: 'DeFi Oracle Meta Mainnet', })], }); }); it('should handle network already added error', async () => { const error = new Error('Network already added'); (error as any).code = 4902; mockEthereum.request.mockRejectedValue(error); // Mock switchNetwork mockEthereum.request.mockResolvedValueOnce(null); const { addNetwork } = await import('../metamask-sdk/src/addNetwork'); await expect(addNetwork()).resolves.not.toThrow(); }); it('should throw error if MetaMask is not installed', async () => { delete (window as any).ethereum; const { addNetwork } = await import('../metamask-sdk/src/addNetwork'); await expect(addNetwork()).rejects.toThrow('MetaMask is not installed'); }); }); describe('switchNetwork', () => { it('should switch network successfully', async () => { mockEthereum.request.mockResolvedValue(null); const { switchNetwork } = await import('../metamask-sdk/src/switchNetwork'); await switchNetwork(); expect(mockEthereum.request).toHaveBeenCalledWith({ method: 'wallet_switchEthereumChain', params: [{ chainId: '0x8a' }], }); }); it('should throw error if network not added', async () => { const error = new Error('Network not added'); (error as any).code = 4902; mockEthereum.request.mockRejectedValue(error); const { switchNetwork } = await import('../metamask-sdk/src/switchNetwork'); await expect(switchNetwork()).rejects.toThrow('ChainID 138 is not added'); }); }); describe('addToken', () => { it('should add token successfully', async () => { mockEthereum.request.mockResolvedValue(null); const { addToken } = await import('../metamask-sdk/src/addToken'); await addToken('0x1234567890123456789012345678901234567890', 'WETH', 18); expect(mockEthereum.request).toHaveBeenCalledWith({ method: 'wallet_watchAsset', params: { type: 'ERC20', options: { address: '0x1234567890123456789012345678901234567890', symbol: 'WETH', decimals: 18, }, }, }); }); it('should validate token address format', async () => { const { addToken } = await import('../metamask-sdk/src/addToken'); await expect(addToken('invalid', 'WETH', 18)).rejects.toThrow('Invalid token address format'); }); it('should validate decimals', async () => { const { addToken } = await import('../metamask-sdk/src/addToken'); await expect(addToken('0x1234567890123456789012345678901234567890', 'WETH', 19)).rejects.toThrow('Invalid decimals'); }); }); describe('isOnChain138', () => { it('should return true if on ChainID 138', async () => { mockEthereum.request.mockResolvedValue('0x8a'); const { isOnChain138 } = await import('../metamask-sdk/src/switchNetwork'); const result = await isOnChain138(); expect(result).toBe(true); }); it('should return false if not on ChainID 138', async () => { mockEthereum.request.mockResolvedValue('0x1'); const { isOnChain138 } = await import('../metamask-sdk/src/switchNetwork'); const result = await isOnChain138(); expect(result).toBe(false); }); }); });