116 lines
4.8 KiB
TypeScript
116 lines
4.8 KiB
TypeScript
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<string, CrawlSession>();
|
|
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);
|
|
});
|
|
});
|