From c8723c293d06ee7b8fa829a0129c50a36a420bb5 Mon Sep 17 00:00:00 2001 From: Alabi Ibrahim Abimbola Date: Sat, 18 Jul 2026 12:54:17 +0100 Subject: [PATCH] test(wallets): stabilize wallet activity integration tests with Prisma mocks Improve the wallet activity integration test suite by removing its dependency on a live database and aligning assertions with the API's actual response format. ### Test fixes - Mock Prisma at the module level to isolate integration tests from a running PostgreSQL instance - Eliminate failures caused by unavailable database connections - Ensure tests execute consistently in local development and CI ### Assertion updates - Correct response validation to match the API error structure - Update assertions from: - 'response.body.details' - To: - 'response.body.error.details' - Verify validation errors against the actual response payload returned by the controller ### Empty wallet coverage - Replace the previous test that accepted both 200 and 404 - Add a deterministic test for a valid Stellar wallet with no transaction history - Verify the endpoint returns: - HTTP 200 - an empty data array - meta.total === 0 - Align test expectations with the service implementation, which already treats an empty wallet as a successful query rather than an error ### Verification - Confirm existing service behavior remains unchanged - Run the complete wallet activity test suite - All 5 wallet activity integration tests pass This change improves test reliability, removes external infrastructure dependencies, and ensures the integration suite accurately reflects the wallet activity API contract. --- ...tivity-invalid-address.integration.test.ts | 157 ++++++++++-------- 1 file changed, 91 insertions(+), 66 deletions(-) diff --git a/src/modules/wallets/wallet-activity-invalid-address.integration.test.ts b/src/modules/wallets/wallet-activity-invalid-address.integration.test.ts index db20a1a..80620ee 100644 --- a/src/modules/wallets/wallet-activity-invalid-address.integration.test.ts +++ b/src/modules/wallets/wallet-activity-invalid-address.integration.test.ts @@ -1,71 +1,96 @@ import request from 'supertest'; +import { prisma } from '../../utils/prisma.utils'; + +jest.mock('../../utils/prisma.utils', () => ({ + prisma: { + activity: { + findMany: jest.fn(), + count: jest.fn(), + }, + creatorProfile: { + findMany: jest.fn(), + }, + }, +})); + import app from '../../app'; +const mockPrisma = prisma as unknown as { + activity: { findMany: jest.Mock; count: jest.Mock }; + creatorProfile: { findMany: jest.Mock }; +}; + +const VALID_ADDRESS = 'GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'; + describe('GET /api/v1/wallets/:address/activity - Malformed Stellar Address', () => { - it('should return 400 for address with wrong prefix', async () => { - const response = await request(app) - .get( - '/api/v1/wallets/XBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB/activity' - ) - .expect(400); - - expect(response.body.error).toBeDefined(); - expect(response.body.details).toBeDefined(); - expect( - response.body.details.some((d: any) => d.field === 'address') - ).toBeTruthy(); - }); - - it('should return 400 for too-short address', async () => { - const response = await request(app) - .get('/api/v1/wallets/GASHORT/activity') - .expect(400); - - expect(response.body.error).toBeDefined(); - expect(response.body.details).toBeDefined(); - expect( - response.body.details.some((d: any) => d.field === 'address') - ).toBeTruthy(); - }); - - it('should return 400 for address with invalid characters', async () => { - const response = await request(app) - .get( - '/api/v1/wallets/GA!!!INVALID!!!CHARACTERS!!!HERE!!!AAAAAAAAAAAAAAAAA/activity' - ) - .expect(400); - - expect(response.body.error).toBeDefined(); - expect(response.body.details).toBeDefined(); - expect( - response.body.details.some((d: any) => d.field === 'address') - ).toBeTruthy(); - }); - - it('should return 400 for completely invalid address format', async () => { - const response = await request(app) - .get('/api/v1/wallets/not-a-stellar-address/activity') - .expect(400); - - expect(response.body.error).toBeDefined(); - expect(response.body.details).toBeDefined(); - expect( - response.body.details.some((d: any) => d.field === 'address') - ).toBeTruthy(); - }); - - it('should not return 400 for valid Stellar address format', async () => { - // Using a properly formatted Stellar address (may return 200 with empty data or 404) - const response = await request(app) - .get( - '/api/v1/wallets/GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF/activity' - ) - .expect(res => { - // Should be 200 (valid request) or potentially 404 (wallet not found) - // But NOT 400 (validation error) - expect([200, 404]).toContain(res.status); - }); - - expect(response.status).not.toBe(400); - }); + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should return 400 for address with wrong prefix', async () => { + const response = await request(app) + .get( + '/api/v1/wallets/XBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB/activity' + ) + .expect(400); + + expect(response.body.error).toBeDefined(); + expect(response.body.error.details).toBeDefined(); + expect( + response.body.error.details.some((d: any) => d.field === 'address') + ).toBeTruthy(); + }); + + it('should return 400 for too-short address', async () => { + const response = await request(app) + .get('/api/v1/wallets/GASHORT/activity') + .expect(400); + + expect(response.body.error).toBeDefined(); + expect(response.body.error.details).toBeDefined(); + expect( + response.body.error.details.some((d: any) => d.field === 'address') + ).toBeTruthy(); + }); + + it('should return 400 for address with invalid characters', async () => { + const response = await request(app) + .get( + '/api/v1/wallets/GA!!!INVALID!!!CHARACTERS!!!HERE!!!AAAAAAAAAAAAAAAAA/activity' + ) + .expect(400); + + expect(response.body.error).toBeDefined(); + expect(response.body.error.details).toBeDefined(); + expect( + response.body.error.details.some((d: any) => d.field === 'address') + ).toBeTruthy(); + }); + + it('should return 400 for completely invalid address format', async () => { + const response = await request(app) + .get('/api/v1/wallets/not-a-stellar-address/activity') + .expect(400); + + expect(response.body.error).toBeDefined(); + expect(response.body.error.details).toBeDefined(); + expect( + response.body.error.details.some((d: any) => d.field === 'address') + ).toBeTruthy(); + }); + + it('should return 200 with empty data array for a valid Stellar address with no trade history', async () => { + mockPrisma.activity.findMany.mockResolvedValue([]); + mockPrisma.activity.count.mockResolvedValue(0); + mockPrisma.creatorProfile.findMany.mockResolvedValue([]); + + const response = await request(app) + .get(`/api/v1/wallets/${VALID_ADDRESS}/activity`) + .expect(200); + + expect(response.body.success).toBe(true); + expect(response.body.data.items).toEqual([]); + expect(response.body.data.meta.total).toBe(0); + expect(response.body.data.meta.hasMore).toBe(false); + }); });