import request from 'supertest'; import express from 'express'; import fundsRoutes from '../../src/routes/funds.routes'; import { exec } from 'child_process'; // Mock de child_process jest.mock('child_process'); const mockExec = exec as jest.MockedFunction; describe('Funds Routes', () => { let app: express.Application; beforeEach(() => { app = express(); app.use(express.json()); app.use('/api/v1/funds', fundsRoutes); // Reset des mocks jest.clearAllMocks(); }); describe('POST /api/v1/funds/transfer', () => { it('devrait transférer des fonds avec succès', async () => { // Mock des commandes bitcoin-cli mockExec.mockImplementation((command, callback) => { if (command.includes('getblockchaininfo')) { callback(null, { stdout: '{"chain":"signet","blocks":1000}', stderr: '' }); } else if (command.includes('loadwallet')) { callback(null, { stdout: '{"name":"default","warning":""}', stderr: '' }); } else if (command.includes('getbalance')) { callback(null, { stdout: '1.5', stderr: '' }); } else if (command.includes('getnewaddress')) { callback(null, { stdout: 'bc1qtest123', stderr: '' }); } else if (command.includes('sendtoaddress')) { callback(null, { stdout: 'txid123456789', stderr: '' }); } else if (command.includes('generatetoaddress')) { callback(null, { stdout: '["blockhash123"]', stderr: '' }); } else if (command.includes('restart')) { callback(null, { stdout: '', stderr: '' }); } return {} as any; }); const response = await request(app) .post('/api/v1/funds/transfer') .send({ amount: 0.01, source: 'mining_mnemonic', target: 'default' }); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.message).toContain('Transfert de 0.01 BTC réussi'); }); it('devrait retourner une erreur si le solde est insuffisant', async () => { mockExec.mockImplementation((command, callback) => { if (command.includes('getbalance')) { callback(null, { stdout: '0.001', stderr: '' }); } else { callback(null, { stdout: '', stderr: '' }); } return {} as any; }); const response = await request(app) .post('/api/v1/funds/transfer') .send({ amount: 0.01, source: 'mining_mnemonic', target: 'default' }); expect(response.status).toBe(400); expect(response.body.success).toBe(false); expect(response.body.error).toContain('Solde insuffisant'); }); it('devrait gérer les erreurs de commande bitcoin-cli', async () => { mockExec.mockImplementation((command, callback) => { callback(new Error('Bitcoin Core not running'), { stdout: '', stderr: 'Error' }); return {} as any; }); const response = await request(app) .post('/api/v1/funds/transfer') .send({ amount: 0.01, source: 'mining_mnemonic', target: 'default' }); expect(response.status).toBe(500); expect(response.body.success).toBe(false); expect(response.body.error).toContain('Erreur lors du transfert'); }); }); describe('GET /api/v1/funds/check', () => { it('devrait vérifier les fonds avec succès', async () => { mockExec.mockImplementation((command, callback) => { if (command.includes('cat /home/bitcoin/.4nk/default')) { callback(null, { stdout: '{"outputs":[{"value":1000000}]}', stderr: '' }); } else if (command.includes('getbalance')) { callback(null, { stdout: '0.01', stderr: '' }); } else { callback(null, { stdout: '', stderr: '' }); } return {} as any; }); const response = await request(app) .get('/api/v1/funds/check'); expect(response.status).toBe(200); expect(response.body.success).toBe(true); expect(response.body.relay.outputsCount).toBe(1); expect(response.body.relay.balance).toBe(0.01); }); it('devrait gérer les erreurs de vérification', async () => { mockExec.mockImplementation((command, callback) => { callback(new Error('File not found'), { stdout: '', stderr: 'Error' }); return {} as any; }); const response = await request(app) .get('/api/v1/funds/check'); expect(response.status).toBe(500); expect(response.body.success).toBe(false); expect(response.body.error).toContain('Erreur lors de la vérification'); }); }); });