import { CrawlSession } from '../../src/modules/crawling/domain/entities/CrawlSession'; import { StartCrawlCommand } from '../../src/modules/crawling/application/commands/StartCrawlCommand'; import { ICrawlSessionRepository } from '../../src/modules/crawling/domain/ports/ICrawlSessionRepository'; import { EventBus } from '../../src/shared/application/EventBus'; import { DomainEvent } from '../../src/shared/domain/DomainEvent'; import { EventHandler } from '../../src/shared/application/EventHandler'; import { UniqueId } from '../../src/shared/domain/UniqueId'; import { isOk, isErr } from '../../src/shared/domain/Result'; // --- CrawlSession domain --- describe('CrawlSession', () => { it('create returns Ok for valid url', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 42, maxStates: 10 }); expect(isOk(result)).toBe(true); }); it('create returns Err for invalid url', () => { const result = CrawlSession.create({ url: 'not-a-url', seed: 42, maxStates: 10 }); expect(isErr(result)).toBe(true); }); it('emits CrawlStarted event on create', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!result.ok) throw new Error('Expected Ok'); const session = result.value; expect(session.domainEvents).toHaveLength(1); expect(session.domainEvents[0]?.eventName).toBe('crawl.started'); }); it('status starts as running', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!result.ok) throw new Error('Expected Ok'); expect(result.value.status).toBe('running'); }); it('complete changes status and adds event', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!result.ok) throw new Error('Expected Ok'); const session = result.value; session.clearEvents(); session.complete(); expect(session.status).toBe('completed'); expect(session.domainEvents[0]?.eventName).toBe('crawl.completed'); }); it('fail changes status and adds CrawlFailed event', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!result.ok) throw new Error('Expected Ok'); const session = result.value; session.clearEvents(); session.fail('browser crashed'); expect(session.status).toBe('failed'); expect(session.domainEvents[0]?.eventName).toBe('crawl.failed'); }); it('incrementStatesVisited increments counter', () => { const result = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!result.ok) throw new Error('Expected Ok'); const session = result.value; session.incrementStatesVisited(); session.incrementStatesVisited(); expect(session.statesVisited).toBe(2); }); it('equals compares by id', () => { const r1 = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); const r2 = CrawlSession.create({ url: 'https://example.com', seed: 1, maxStates: 5 }); if (!r1.ok || !r2.ok) throw new Error('Expected Ok'); expect(r1.value.equals(r2.value)).toBe(false); // different ids }); }); // --- StartCrawlCommand --- describe('StartCrawlCommand', () => { const makeMockRepo = (): ICrawlSessionRepository => { const store = new Map(); return { save: async (session) => { store.set(session.id.toString(), session); }, findById: async (id: UniqueId) => store.get(id.toString()) ?? null, findAll: async () => [...store.values()], update: async (session) => { store.set(session.id.toString(), session); }, }; }; const makeMockBus = (): EventBus & { events: DomainEvent[] } => { const events: DomainEvent[] = []; return { events, publish: async (event: DomainEvent) => { events.push(event); }, subscribe: (_name: string, _handler: EventHandler) => {}, }; }; it('returns Ok with sessionId for valid url', async () => { const cmd = new StartCrawlCommand(makeMockRepo(), makeMockBus()); const result = await cmd.execute({ url: 'https://example.com', seed: 42, maxStates: 10 }); expect(isOk(result)).toBe(true); if (result.ok) { expect(typeof result.value.sessionId).toBe('string'); } }); it('returns Err for invalid url', async () => { const cmd = new StartCrawlCommand(makeMockRepo(), makeMockBus()); const result = await cmd.execute({ url: 'not-a-url', seed: 42, maxStates: 10 }); expect(isErr(result)).toBe(true); }); it('publishes CrawlStarted event via EventBus', async () => { const bus = makeMockBus(); const cmd = new StartCrawlCommand(makeMockRepo(), bus); await cmd.execute({ url: 'https://example.com', seed: 1, maxStates: 5 }); expect(bus.events.some(e => e.eventName === 'crawl.started')).toBe(true); }); });