/** * Unit tests for src/services/MarketplaceService.ts */ import { MarketplaceService } from '../../../src/services/MarketplaceService'; import { AgentRepository } from '../../../src/repositories/AgentRepository'; import { AgentNotFoundError } from '../../../src/utils/errors'; import { IAgent, IMarketplaceFilters } from '../../../src/types/index'; jest.mock('../../../src/repositories/AgentRepository'); const MockAgentRepo = AgentRepository as jest.MockedClass; const BASE_FILTERS: IMarketplaceFilters = { page: 1, limit: 10 }; function makeAgent(overrides: Partial = {}): IAgent { return { agentId: 'agent-001', organizationId: 'org-001', email: 'agent@example.com', agentType: 'screener', version: 'v1.0.0', capabilities: ['resume:read'], owner: 'test-team', deploymentEnv: 'production', status: 'active', isPublic: true, createdAt: new Date('2026-01-01'), updatedAt: new Date('2026-01-02'), did: null, didCreatedAt: null, ...overrides, }; } describe('MarketplaceService', () => { let service: MarketplaceService; let agentRepo: jest.Mocked; beforeEach(() => { jest.clearAllMocks(); agentRepo = new MockAgentRepo({} as never) as jest.Mocked; service = new MarketplaceService(agentRepo); }); describe('listPublicAgents()', () => { it('should return mapped agent cards', async () => { const agent = makeAgent(); agentRepo.findPublicAgents = jest.fn().mockResolvedValue({ agents: [agent], total: 1 }); const result = await service.listPublicAgents(BASE_FILTERS); expect(result.data).toHaveLength(1); expect(result.data[0].agentId).toBe('agent-001'); expect(result.total).toBe(1); expect(result.page).toBe(1); expect(result.limit).toBe(10); }); it('should strip private fields (email, organizationId) from cards', async () => { const agent = makeAgent(); agentRepo.findPublicAgents = jest.fn().mockResolvedValue({ agents: [agent], total: 1 }); const result = await service.listPublicAgents(BASE_FILTERS); const card = result.data[0] as Record; expect(card['email']).toBeUndefined(); expect(card['organizationId']).toBeUndefined(); }); it('should include a minimal DID document when agent has a DID', async () => { const agent = makeAgent({ did: 'did:web:sentryagent.ai:agents:agent-001' }); agentRepo.findPublicAgents = jest.fn().mockResolvedValue({ agents: [agent], total: 1 }); const result = await service.listPublicAgents(BASE_FILTERS); expect(result.data[0].didDocument).not.toBeNull(); expect(result.data[0].didDocument?.id).toBe('did:web:sentryagent.ai:agents:agent-001'); }); it('should return null DID document when agent has no DID', async () => { const agent = makeAgent({ did: null }); agentRepo.findPublicAgents = jest.fn().mockResolvedValue({ agents: [agent], total: 1 }); const result = await service.listPublicAgents(BASE_FILTERS); expect(result.data[0].didDocument).toBeNull(); }); it('should return empty data array when no public agents exist', async () => { agentRepo.findPublicAgents = jest.fn().mockResolvedValue({ agents: [], total: 0 }); const result = await service.listPublicAgents(BASE_FILTERS); expect(result.data).toHaveLength(0); expect(result.total).toBe(0); }); }); describe('getPublicAgent()', () => { it('should return a card for a public agent', async () => { const agent = makeAgent(); agentRepo.findPublicById = jest.fn().mockResolvedValue(agent); const card = await service.getPublicAgent('agent-001'); expect(card.agentId).toBe('agent-001'); expect(card.owner).toBe('test-team'); }); it('should throw AgentNotFoundError when agent is not found', async () => { agentRepo.findPublicById = jest.fn().mockResolvedValue(null); await expect(service.getPublicAgent('nonexistent')).rejects.toThrow(AgentNotFoundError); }); }); });