Test fixes (type mismatches introduced by V&V resolution changes):
- HealthDetailedController.test.ts: replace pool/makePool with dbProbe/makeDbProbe
to match refactored HealthDetailedDeps interface (Pool → DbProbe abstraction)
- EventPublisher.test.ts: pass all 4 required constructor args to WebhookDeliveryWorker
mock (pool, vaultClient, redisClient, redisUrl) — was passing only 1
- MarketplaceService.test.ts: IAgent.did/didCreatedAt are string|undefined (not null);
fix makeAgent defaults and makeAgent({did:null}) call; fix type assertion to unknown first
- OIDCTrustPolicyService.test.ts: ICreateTrustPolicyRequest.branch is string|undefined
(not nullable); replace all branch:null with branch:undefined
Security fix:
- npm audit fix: lodash ≤4.17.23 (HIGH) → patched; 0 vulnerabilities remaining
Result: 50/50 test suites pass, 722/722 tests pass, 0 vulnerabilities
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
118 lines
4.1 KiB
TypeScript
118 lines
4.1 KiB
TypeScript
/**
|
|
* 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<typeof AgentRepository>;
|
|
|
|
const BASE_FILTERS: IMarketplaceFilters = { page: 1, limit: 10 };
|
|
|
|
function makeAgent(overrides: Partial<IAgent> = {}): 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: undefined,
|
|
didCreatedAt: undefined,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('MarketplaceService', () => {
|
|
let service: MarketplaceService;
|
|
let agentRepo: jest.Mocked<AgentRepository>;
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
agentRepo = new MockAgentRepo({} as never) as jest.Mocked<AgentRepository>;
|
|
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 unknown as Record<string, unknown>;
|
|
|
|
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: undefined });
|
|
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);
|
|
});
|
|
});
|
|
});
|