import { Test, TestingModule } from '@nestjs/testing'; import { ScrapeUseCase } from '../src//application/use-cases/scrape.use-case'; import { DirectFetchAdapter } from '../src//infrastructure/adapters/direct-fetch.adapter'; import { BrowserlessAdapter } from '../src//infrastructure/adapters/browserless.adapter'; import { ReadabilityMarkdownConverter } from '../src//infrastructure/adapters/readability-markdown.converter'; describe('ScrapeUseCase', () => { let useCase: ScrapeUseCase; let directMock: Mock; let browserlessMock: Mock; let converterMock: Mock; const sampleHtml = (len: number) => '' + 'x'.repeat(len) + ''; beforeEach(async () => { directMock = { fetch: vi.fn() } as any; browserlessMock = { fetch: vi.fn() } as any; converterMock = { convert: vi.fn() } as any; const module: TestingModule = await Test.createTestingModule({ providers: [ ScrapeUseCase, { provide: DirectFetchAdapter, useValue: directMock }, { provide: BrowserlessAdapter, useValue: browserlessMock }, { provide: ReadabilityMarkdownConverter, useValue: converterMock }, ], }).compile(); useCase = module.get(ScrapeUseCase); }); it('uses direct fetch when content is sufficient', async () => { const html = sampleHtml(2000); directMock.fetch.mockResolvedValue(html); converterMock.convert.mockResolvedValue({ title: 'T', markdown: 'M' }); const result = await useCase.execute({ url: 'https://example.com' }); expect(directMock.fetch).toHaveBeenCalled(); expect(browserlessMock.fetch).not.toHaveBeenCalled(); expect(result.metadata.source).toBe('direct'); }); it('falls back to browserless when direct content is insufficient', async () => { const shortHtml = 'short'; directMock.fetch.mockResolvedValue(shortHtml); browserlessMock.fetch.mockResolvedValue(sampleHtml(2000)); converterMock.convert.mockResolvedValue({ title: 'T', markdown: 'M' }); const result = await useCase.execute({ url: 'https://example.com' }); expect(browserlessMock.fetch).toHaveBeenCalled(); expect(result.metadata.source).toBe('browserless'); }); it('uses browserless directly when render=true', async () => { browserlessMock.fetch.mockResolvedValue(sampleHtml(2000)); converterMock.convert.mockResolvedValue({ title: 'T', markdown: 'M' }); const result = await useCase.execute({ url: 'https://example.com', render: true }); expect(directMock.fetch).not.toHaveBeenCalled(); expect(browserlessMock.fetch).toHaveBeenCalled(); expect(result.metadata.source).toBe('browserless'); }); it('returns markdown and title from converter', async () => { directMock.fetch.mockResolvedValue(sampleHtml(2000)); converterMock.convert.mockResolvedValue({ title: 'Page Title', markdown: '# Hello' }); const result = await useCase.execute({ url: 'https://example.com' }); expect(result.title).toBe('Page Title'); expect(result.markdown).toBe('# Hello'); }); });