import { describe, expect, it } from 'vitest'; import type { RawTenderRecord, SourceType } from './tender.types'; import type { TenderSourceAdapter } from './adapters/tender-source-adapter.interface'; import { DeniedPortalError, SourceRegistry } from './source-registry'; /** * Fake adapter stub — no real scraping/HTTP, just satisfies the * TenderSourceAdapter contract for registry-behavior tests. */ function fakeAdapter( sourceType: SourceType, portals: readonly string[], ): TenderSourceAdapter { return { sourceType, portals, async fetchTenders(_dayCursor: string): Promise { return []; }, }; } describe('SourceRegistry', () => { it('throws DeniedPortalError when registering an adapter serving vergabe24', () => { const registry = new SourceRegistry(); const adapter = fakeAdapter('ai-netserver', ['vergabe24']); expect(() => registry.register(adapter)).toThrow(DeniedPortalError); }); it('throws DeniedPortalError when registering an adapter serving aumass', () => { const registry = new SourceRegistry(); const adapter = fakeAdapter('cosinex-dtvp', ['aumass']); expect(() => registry.register(adapter)).toThrow(DeniedPortalError); }); it('rejects a mixed portals array wholesale when one entry is denylisted', () => { const registry = new SourceRegistry(); const adapter = fakeAdapter('ai-netserver', ['tender24', 'aumass']); expect(() => registry.register(adapter)).toThrow(DeniedPortalError); expect(registry.get('ai-netserver')).toBeUndefined(); }); it('registers a legitimate adapter and returns it via get()', () => { const registry = new SourceRegistry(); const adapter = fakeAdapter('ai-netserver', ['tender24']); expect(() => registry.register(adapter)).not.toThrow(); expect(registry.get('ai-netserver')).toBe(adapter); }); it('activeAdapters() returns all registered adapters', () => { const registry = new SourceRegistry(); const doe = fakeAdapter('doe-opendata', ['doe-opendata']); const netserver = fakeAdapter('ai-netserver', ['tender24']); registry.register(doe); registry.register(netserver); expect(registry.activeAdapters()).toHaveLength(2); expect(registry.activeAdapters()).toEqual( expect.arrayContaining([doe, netserver]), ); }); it('get() returns undefined for an unregistered sourceType (no throw)', () => { const registry = new SourceRegistry(); expect(registry.get('cosinex-dtvp')).toBeUndefined(); }); });