import { ExtractContentUseCase } from './ExtractContentUseCase.js';
import { IGenAI } from '../adapter/IGenAI.js';
import { Url } from '../domain/Url.js';
import { ModelName } from '../domain/ModelName.js';
describe('ExtractContentUseCase', () => {
let useCase: ExtractContentUseCase;
let mockGenAI: jest.Mocked<IGenAI>;
beforeEach(() => {
mockGenAI = {
generateUrlContextJson: jest.fn()
};
useCase = new ExtractContentUseCase(mockGenAI);
});
describe('Should_ReturnJsonWithPages_When_SingleUrl', () => {
it('extracts content from single URL and returns formatted JSON', async () => {
// Arrange
const urls = [Url.create('https://example.com')];
const query = '見出しを要約して';
const model = ModelName.create('gemini-2.0-flash-exp');
const maxChars = 8000;
const mockResponse = {
pages: [{
url: 'https://example.com',
title: 'Example Site',
text: 'This is example content',
images: ['https://example.com/image.jpg']
}],
answer: 'サイトの見出し: Example Site',
url_context_metadata: {
status: 'success' as const,
totalUrls: 1,
successfulUrls: 1,
failedUrls: [],
processingTimeMs: 1500
}
};
mockGenAI.generateUrlContextJson.mockResolvedValue(mockResponse);
// Act
const result = await useCase.execute(urls, query, model, maxChars);
// Assert
expect(result.pages).toHaveLength(1);
expect(result.pages[0].url.toString()).toBe('https://example.com');
expect(result.pages[0].title).toBe('Example Site');
expect(result.pages[0].text).toBe('This is example content');
expect(result.pages[0].images).toEqual(['https://example.com/image.jpg']);
expect(result.answer).toBe('サイトの見出し: Example Site');
expect(result.urlContextMetadata.status).toBe('success');
expect(result.urlContextMetadata.totalUrls).toBe(1);
expect(result.urlContextMetadata.successfulUrls).toBe(1);
});
});
describe('Should_HandleMultipleUrls_When_ArrayProvided', () => {
it('processes multiple URLs and returns aggregated result', async () => {
// Arrange
const urls = [
Url.create('https://example1.com'),
Url.create('https://example2.com'),
Url.create('https://example3.com')
];
const query = '全体の要約';
const model = ModelName.create('gemini-2.0-flash-exp');
const maxChars = 8000;
const mockResponse = {
pages: [
{
url: 'https://example1.com',
title: 'Site 1',
text: 'Content 1',
images: []
},
{
url: 'https://example2.com',
title: 'Site 2',
text: 'Content 2',
images: ['https://example2.com/pic.png']
},
{
url: 'https://example3.com',
title: 'Site 3',
text: 'Content 3',
images: []
}
],
answer: '3つのサイトの横断要約結果',
url_context_metadata: {
status: 'success' as const,
totalUrls: 3,
successfulUrls: 3,
failedUrls: [],
processingTimeMs: 3000
}
};
mockGenAI.generateUrlContextJson.mockResolvedValue(mockResponse);
// Act
const result = await useCase.execute(urls, query, model, maxChars);
// Assert
expect(result.pages).toHaveLength(3);
expect(result.answer).toBe('3つのサイトの横断要約結果');
expect(result.urlContextMetadata.totalUrls).toBe(3);
expect(result.urlContextMetadata.successfulUrls).toBe(3);
});
});
describe('Should_PassCorrectParameters_When_Called', () => {
it('passes URLs, query, model and maxChars to GenAI service', async () => {
// Arrange
const urls = [Url.create('https://test.com')];
const query = 'テストクエリ';
const model = ModelName.create('gemini-1.5-flash');
const maxChars = 5000;
const mockResponse = {
pages: [],
answer: '',
url_context_metadata: {
status: 'success' as const,
totalUrls: 1,
successfulUrls: 0,
failedUrls: ['https://test.com'],
processingTimeMs: 500
}
};
mockGenAI.generateUrlContextJson.mockResolvedValue(mockResponse);
// Act
await useCase.execute(urls, query, model, maxChars);
// Assert
expect(mockGenAI.generateUrlContextJson).toHaveBeenCalledWith({
urls: ['https://test.com'],
query: 'テストクエリ',
model: 'gemini-1.5-flash',
maxCharsPerPage: 5000
});
});
});
});