Skip to main content
Glama
Seitrace

Seitrace Insights MCP Server

Official
by Seitrace
ethers_snippet_generator.test.mjs15.2 kB
import { generateEthersSnippet, validateEthersPayload } from '../build/src/utils/snippet_generator/ethers.js'; import { dbg } from './utils.mjs'; /** * Comprehensive tests for ethers snippet generator */ export const testEthersSnippetGenerator = async () => { dbg('Testing ethers snippet generator...'); // Test validation function testPayloadValidation(); // Test snippet generation with valid payloads testSnippetGeneration(); // Test error handling for invalid payloads testErrorHandling(); // Test edge cases testEdgeCases(); dbg('✅ All ethers snippet generator tests passed'); }; function testPayloadValidation() { dbg('Testing Zod-based payload validation...'); // Valid payload const validPayload = { abi: [ { "constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function" } ], contract_address: "0x1234567890123456789012345678901234567890", payload: [ { methodName: "totalSupply", arguments: [] } ], chain_id: "pacific-1" }; const validResult = validateEthersPayload(validPayload); if (!validResult.isValid) { throw new Error(`Valid payload should pass validation: ${validResult.errors.join(', ')}`); } if (!validResult.data) { throw new Error('Valid payload should return parsed data'); } // Test missing ABI const missingAbi = { ...validPayload }; delete missingAbi.abi; const missingAbiResult = validateEthersPayload(missingAbi); if (missingAbiResult.isValid || !missingAbiResult.errors.some(e => e.includes('Required'))) { throw new Error('Should fail validation when ABI is missing'); } // Test empty ABI const emptyAbi = { ...validPayload, abi: [] }; const emptyAbiResult = validateEthersPayload(emptyAbi); if (emptyAbiResult.isValid || !emptyAbiResult.errors.some(e => e.includes('at least one item'))) { throw new Error('Should fail validation for empty ABI'); } // Test invalid contract address const invalidAddress = { ...validPayload, contract_address: "invalid" }; const invalidAddressResult = validateEthersPayload(invalidAddress); if (invalidAddressResult.isValid || !invalidAddressResult.errors.some(e => e.includes('valid Ethereum address'))) { throw new Error('Should fail validation for invalid contract address'); } // Test invalid chain ID const invalidChain = { ...validPayload, chain_id: "invalid-chain" }; const invalidChainResult = validateEthersPayload(invalidChain); if (invalidChainResult.isValid || !invalidChainResult.errors.some(e => e.includes('pacific-1, atlantic-2, arctic-1'))) { throw new Error('Should fail validation for invalid chain ID'); } // Test empty payload array const emptyPayload = { ...validPayload, payload: [] }; const emptyPayloadResult = validateEthersPayload(emptyPayload); if (emptyPayloadResult.isValid || !emptyPayloadResult.errors.some(e => e.includes('at least one method call'))) { throw new Error('Should fail validation for empty payload array'); } // Test method not in ABI const methodNotInAbi = { ...validPayload, payload: [{ methodName: "nonExistentMethod", arguments: [] }] }; const methodNotInAbiResult = validateEthersPayload(methodNotInAbi); if (methodNotInAbiResult.isValid || !methodNotInAbiResult.errors.some(e => e.includes('must exist as functions in the contract ABI'))) { throw new Error('Should fail validation when method is not in ABI'); } // Test ABI function without name const abiWithoutName = { ...validPayload, abi: [ { "type": "function", "inputs": [], "outputs": [] // missing name } ] }; const abiWithoutNameResult = validateEthersPayload(abiWithoutName); if (abiWithoutNameResult.isValid || !abiWithoutNameResult.errors.some(e => e.includes('valid name'))) { throw new Error('Should fail validation for function ABI without name'); } // Test null/undefined payload const nullResult = validateEthersPayload(null); if (nullResult.isValid) { throw new Error('Should fail validation for null payload'); } const undefinedResult = validateEthersPayload(undefined); if (undefinedResult.isValid) { throw new Error('Should fail validation for undefined payload'); } // Test array as payload (should be object) const arrayResult = validateEthersPayload([]); if (arrayResult.isValid) { throw new Error('Should fail validation for array payload'); } // Test invalid methodName type const invalidMethodName = { ...validPayload, payload: [{ methodName: "", arguments: [] }] }; const invalidMethodNameResult = validateEthersPayload(invalidMethodName); if (invalidMethodNameResult.isValid || !invalidMethodNameResult.errors.some(e => e.includes('Method name is required'))) { throw new Error('Should fail validation for empty method name'); } // Test arguments defaults to empty array const noArguments = { ...validPayload, payload: [{ methodName: "totalSupply" }] // no arguments field }; const noArgumentsResult = validateEthersPayload(noArguments); if (!noArgumentsResult.isValid) { throw new Error(`Should pass validation when arguments is omitted: ${noArgumentsResult.errors.join(', ')}`); } if (!noArgumentsResult.data || noArgumentsResult.data.payload[0].arguments?.length !== 0) { throw new Error('Arguments should default to empty array'); } dbg('✅ Zod-based payload validation tests passed'); } function testSnippetGeneration() { dbg('Testing snippet generation...'); const validPayload = { abi: [ { "constant": true, "inputs": [], "name": "balanceOf", "outputs": [{"name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function" } ], contract_address: "0x1234567890123456789012345678901234567890", payload: [ { methodName: "balanceOf", arguments: ["0x1234567890123456789012345678901234567890"] } ], chain_id: "pacific-1" }; // Test JavaScript snippet generation const jsSnippet = generateEthersSnippet({}, 'query_contract_state', 'javascript', validPayload); if (!jsSnippet.includes('ethers')) { throw new Error('JavaScript snippet should include ethers import'); } if (!jsSnippet.includes('aggregate3')) { throw new Error('JavaScript snippet should use Multicall3 aggregate3'); } if (!jsSnippet.includes(validPayload.contract_address)) { throw new Error('JavaScript snippet should include contract address'); } if (!jsSnippet.includes('balanceOf')) { throw new Error('JavaScript snippet should include method name'); } // Test Node.js snippet generation const nodeSnippet = generateEthersSnippet({}, 'query_contract_state', 'node', validPayload); if (!nodeSnippet.includes('ethers')) { throw new Error('Node.js snippet should include ethers import'); } // Test Python snippet generation const pythonSnippet = generateEthersSnippet({}, 'query_contract_state', 'python', validPayload); if (!pythonSnippet.includes('Web3')) { throw new Error('Python snippet should include Web3 import'); } if (!pythonSnippet.includes(validPayload.contract_address.replace(/"/g, "'"))) { throw new Error('Python snippet should include contract address'); } if (!pythonSnippet.includes('balanceOf')) { throw new Error('Python snippet should include method name'); } // Test fallback for unsupported language const fallbackSnippet = generateEthersSnippet({}, 'query_contract_state', 'ruby', validPayload); if (!fallbackSnippet.includes('Ethers.js contract query example')) { throw new Error('Fallback snippet should include example comment'); } dbg('✅ Snippet generation tests passed'); } function testErrorHandling() { dbg('Testing error handling with Zod validation...'); const invalidPayload = { abi: "not an array", contract_address: "invalid", payload: "not an array", chain_id: "invalid" }; // Test JavaScript error snippet const jsErrorSnippet = generateEthersSnippet({}, 'query_contract_state', 'javascript', invalidPayload); if (!jsErrorSnippet.includes('Error: Invalid payload')) { throw new Error('JavaScript error snippet should indicate invalid payload'); } if (!jsErrorSnippet.includes('Validation errors')) { throw new Error('JavaScript error snippet should include validation errors header'); } if (!jsErrorSnippet.includes('validPayload')) { throw new Error('JavaScript error snippet should include example valid payload'); } // Test Python error snippet const pythonErrorSnippet = generateEthersSnippet({}, 'query_contract_state', 'python', invalidPayload); if (!pythonErrorSnippet.includes('Error: Invalid payload')) { throw new Error('Python error snippet should indicate invalid payload'); } if (!pythonErrorSnippet.includes('Validation errors')) { throw new Error('Python error snippet should include validation errors'); } // Test fallback error snippet const fallbackErrorSnippet = generateEthersSnippet({}, 'query_contract_state', 'ruby', invalidPayload); if (!fallbackErrorSnippet.includes('Error: Invalid payload')) { throw new Error('Fallback error snippet should indicate invalid payload'); } // Test specific Zod error messages const validation = validateEthersPayload(invalidPayload); if (validation.isValid) { throw new Error('Invalid payload should fail validation'); } // Check that we get specific Zod error messages const hasAbiError = validation.errors.some(e => e.includes('abi') && (e.includes('array') || e.includes('Expected'))); const hasAddressError = validation.errors.some(e => e.includes('contract_address') && e.includes('Ethereum address')); const hasChainError = validation.errors.some(e => e.includes('chain_id')); const hasPayloadError = validation.errors.some(e => e.includes('payload') && (e.includes('array') || e.includes('Expected'))); if (!hasAbiError) { throw new Error('Should have ABI validation error'); } if (!hasAddressError) { throw new Error('Should have contract address validation error'); } if (!hasChainError) { throw new Error('Should have chain ID validation error'); } if (!hasPayloadError) { throw new Error('Should have payload validation error'); } dbg('✅ Zod-based error handling tests passed'); } function testEdgeCases() { dbg('Testing edge cases with Zod validation...'); // Test with no payload (should use sample) const noPayloadSnippet = generateEthersSnippet({}, 'query_contract_state', 'javascript'); if (!noPayloadSnippet.includes('totalSupply')) { throw new Error('No payload should use sample payload with totalSupply'); } // Test with minimal valid ABI const minimalPayload = { abi: [ { "type": "function", "name": "test", "inputs": [], "outputs": [] } ], contract_address: "0x1234567890123456789012345678901234567890", payload: [ { methodName: "test" } ], chain_id: "atlantic-2" }; const minimalResult = validateEthersPayload(minimalPayload); if (!minimalResult.isValid) { throw new Error(`Minimal payload should be valid: ${minimalResult.errors.join(', ')}`); } // Verify arguments defaults to empty array if (!minimalResult.data || minimalResult.data.payload[0].arguments?.length !== 0) { throw new Error('Arguments should default to empty array'); } // Test with complex ABI including events and constructors const complexPayload = { abi: [ { "type": "constructor", "inputs": [{"name": "owner", "type": "address"}] }, { "type": "event", "name": "Transfer", "inputs": [ {"name": "from", "type": "address", "indexed": true}, {"name": "to", "type": "address", "indexed": true} ] }, { "type": "function", "name": "transfer", "inputs": [{"name": "to", "type": "address"}, {"name": "amount", "type": "uint256"}], "outputs": [{"name": "", "type": "bool"}] } ], contract_address: "0x1234567890123456789012345678901234567890", payload: [ { methodName: "transfer", arguments: ["0x1234567890123456789012345678901234567890", "1000"] } ], chain_id: "arctic-1" }; const complexResult = validateEthersPayload(complexPayload); if (!complexResult.isValid) { throw new Error(`Complex payload should be valid: ${complexResult.errors.join(', ')}`); } // Test different chain IDs for (const chainId of ['pacific-1', 'atlantic-2', 'arctic-1']) { const chainPayload = { ...minimalPayload, chain_id: chainId }; const chainResult = validateEthersPayload(chainPayload); if (!chainResult.isValid) { throw new Error(`Chain ID ${chainId} should be valid`); } const snippet = generateEthersSnippet({}, 'query_contract_state', 'javascript', chainPayload); if (!snippet.includes(chainId)) { throw new Error(`Snippet should include chain ID ${chainId}`); } } // Test case sensitivity in contract address const uppercaseAddress = { ...minimalPayload, contract_address: "0X1234567890123456789012345678901234567890" }; const uppercaseResult = validateEthersPayload(uppercaseAddress); if (!uppercaseResult.isValid) { throw new Error('Uppercase contract address should be valid'); } // Test contract address validation edge cases const shortAddress = { ...minimalPayload, contract_address: "0x123" }; const shortResult = validateEthersPayload(shortAddress); if (shortResult.isValid) { throw new Error('Short address should be invalid'); } const longAddress = { ...minimalPayload, contract_address: "0x12345678901234567890123456789012345678901" }; const longResult = validateEthersPayload(longAddress); if (longResult.isValid) { throw new Error('Long address should be invalid'); } const noHexPrefix = { ...minimalPayload, contract_address: "1234567890123456789012345678901234567890" }; const noHexResult = validateEthersPayload(noHexPrefix); if (noHexResult.isValid) { throw new Error('Address without 0x prefix should be invalid'); } // Test ABI with non-function types (should be allowed) const abiWithEvents = { ...minimalPayload, abi: [ { "type": "event", "name": "TestEvent", "inputs": [] }, { "type": "function", "name": "test", "inputs": [], "outputs": [] } ] }; const eventsResult = validateEthersPayload(abiWithEvents); if (!eventsResult.isValid) { throw new Error(`ABI with events should be valid: ${eventsResult.errors.join(', ')}`); } dbg('✅ Zod-based edge case tests passed'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Seitrace/seitrace-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server