From 91af15a43e44e21baad6f18cfe04d425c43bee7f Mon Sep 17 00:00:00 2001 From: leanworld7-netizen Date: Sat, 1 Aug 2026 01:01:40 +0000 Subject: [PATCH 1/2] feat(test): add sorobanMock.js --- tests/mocks/sorobanMock.js | 62 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 tests/mocks/sorobanMock.js diff --git a/tests/mocks/sorobanMock.js b/tests/mocks/sorobanMock.js new file mode 100644 index 00000000..310227f1 --- /dev/null +++ b/tests/mocks/sorobanMock.js @@ -0,0 +1,62 @@ +/** + * Mock Soroban RPC layer for testing contract interactions + * without requiring a live network connection. + * + * Configurable responses for getContractData, simulateTransaction, + * sendTransaction, and getTransactionStatus. + */ + +class SorobanMock { + constructor() { + this.responses = { + getContractData: { success: true, data: null }, + simulateTransaction: { success: true, results: [] }, + sendTransaction: { success: true, hash: '0x' + 'a'.repeat(64) }, + getTransactionStatus: { status: 'SUCCESS' } + }; + this.callLog = []; + this.errorMode = null; + } + + setErrorMode(mode) { this.errorMode = mode; } + setResponse(method, response) { this.responses[method] = response; } + + reset() { + this.responses = { + getContractData: { success: true, data: null }, + simulateTransaction: { success: true, results: [] }, + sendTransaction: { success: true, hash: '0x' + 'a'.repeat(64) }, + getTransactionStatus: { status: 'SUCCESS' } + }; + this.callLog = []; + this.errorMode = null; + } + + async getContractData(contractId, key) { + this.callLog.push({ method: 'getContractData', contractId, key }); + if (this.errorMode === 'getContractData') return { success: false, error: 'CONTRACT_NOT_FOUND' }; + return this.responses.getContractData; + } + + async simulateTransaction(tx) { + this.callLog.push({ method: 'simulateTransaction', tx }); + if (this.errorMode === 'simulateTransaction') return { success: false, error: 'SIMULATION_FAILED' }; + return this.responses.simulateTransaction; + } + + async sendTransaction(tx) { + this.callLog.push({ method: 'sendTransaction', tx }); + if (this.errorMode === 'sendTransaction') return { success: false, error: 'TX_REJECTED' }; + return this.responses.sendTransaction; + } + + async getTransactionStatus(hash) { + this.callLog.push({ method: 'getTransactionStatus', hash }); + if (this.errorMode === 'getTransactionStatus') return { status: 'FAILED', error: 'TIMEOUT' }; + return this.responses.getTransactionStatus; + } + + getCallLog() { return this.callLog; } +} + +module.exports = { SorobanMock }; From 24ae3097383cf302c3f702f7ea6777ac41da4969 Mon Sep 17 00:00:00 2001 From: leanworld7-netizen Date: Sat, 1 Aug 2026 01:01:41 +0000 Subject: [PATCH 2/2] feat(test): add sorobanMock.test.js --- tests/unit/sorobanMock.test.js | 59 ++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 tests/unit/sorobanMock.test.js diff --git a/tests/unit/sorobanMock.test.js b/tests/unit/sorobanMock.test.js new file mode 100644 index 00000000..d93024f3 --- /dev/null +++ b/tests/unit/sorobanMock.test.js @@ -0,0 +1,59 @@ +const { test, describe, beforeEach } = require('node:test'); +const assert = require('node:assert'); +const { SorobanMock } = require('../mocks/sorobanMock'); + +describe('Soroban Mock Layer', () => { + let mock; + + beforeEach(() => { + mock = new SorobanMock(); + }); + + test('returns default success for getContractData', async () => { + const result = await mock.getContractData('contract-1', 'key-1'); + assert.strictEqual(result.success, true); + assert.strictEqual(result.data, null); + }); + + test('logs all calls', async () => { + await mock.getContractData('c1', 'k1'); + await mock.simulateTransaction({ tx: 'test' }); + await mock.sendTransaction({ tx: 'test' }); + await mock.getTransactionStatus('hash123'); + const log = mock.getCallLog(); + assert.strictEqual(log.length, 4); + assert.strictEqual(log[0].method, 'getContractData'); + assert.strictEqual(log[1].method, 'simulateTransaction'); + assert.strictEqual(log[2].method, 'sendTransaction'); + assert.strictEqual(log[3].method, 'getTransactionStatus'); + }); + + test('supports error mode for getContractData', async () => { + mock.setErrorMode('getContractData'); + const result = await mock.getContractData('c1', 'k1'); + assert.strictEqual(result.success, false); + assert.strictEqual(result.error, 'CONTRACT_NOT_FOUND'); + }); + + test('supports error mode for simulateTransaction', async () => { + mock.setErrorMode('simulateTransaction'); + const result = await mock.simulateTransaction({ tx: 'test' }); + assert.strictEqual(result.success, false); + assert.strictEqual(result.error, 'SIMULATION_FAILED'); + }); + + test('supports custom responses', async () => { + mock.setResponse('getContractData', { success: true, data: { balance: 1000 } }); + const result = await mock.getContractData('c1', 'k1'); + assert.strictEqual(result.data.balance, 1000); + }); + + test('resets to defaults', async () => { + mock.setErrorMode('getContractData'); + mock.setResponse('getContractData', { success: true, data: 'custom' }); + mock.reset(); + const result = await mock.getContractData('c1', 'k1'); + assert.strictEqual(result.success, true); + assert.strictEqual(result.data, null); + }); +});