119 lines
3.7 KiB
TypeScript
119 lines
3.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
|
|
import { normalizeDocumentTransform } from '@/lib/document';
|
|
import type { DocumentArtifact } from '@/lib/document';
|
|
|
|
const context = {
|
|
purpose: 'course-generation' as const,
|
|
budget: { maxTextChars: 1000, maxVisionImages: 5 },
|
|
};
|
|
|
|
describe('document normalization transform', () => {
|
|
it('sanitizes text, removes empty text blocks, and merges adjacent compatible blocks', async () => {
|
|
const input: DocumentArtifact = {
|
|
metadata: { fileName: 'notes.txt' },
|
|
blocks: [
|
|
{ id: 'a', type: 'text', text: ' First\r\nline\u0000 ' },
|
|
{ id: 'empty', type: 'text', text: ' \n ' },
|
|
{ id: 'b', type: 'text', text: 'Second line' },
|
|
{ id: 'formula', type: 'formula', text: '' },
|
|
],
|
|
assets: [],
|
|
citations: [{ id: 'citation-b', blockId: 'b' }],
|
|
};
|
|
|
|
const output = await normalizeDocumentTransform.apply(input, context);
|
|
|
|
expect(input.blocks).toHaveLength(4);
|
|
expect(output.artifact.blocks).toEqual([
|
|
{
|
|
id: 'a',
|
|
type: 'text',
|
|
text: 'First\nline\n\nSecond line',
|
|
html: undefined,
|
|
metadata: { sourceBlockIds: ['a', 'b'] },
|
|
},
|
|
{ id: 'formula', type: 'formula', text: '', html: undefined },
|
|
]);
|
|
expect(output.artifact.citations?.[0].blockId).toBe('a');
|
|
expect(output.diagnostics?.[0].metadata).toEqual({
|
|
removedEmptyBlocks: 1,
|
|
mergedBlockCount: 1,
|
|
});
|
|
});
|
|
|
|
it('does not merge blocks across pages', async () => {
|
|
const input: DocumentArtifact = {
|
|
metadata: {},
|
|
blocks: [
|
|
{ id: 'p1', type: 'text', text: 'Page one', pageNumber: 1 },
|
|
{ id: 'p2', type: 'text', text: 'Page two', pageNumber: 2 },
|
|
],
|
|
assets: [],
|
|
};
|
|
|
|
const output = await normalizeDocumentTransform.apply(input, context);
|
|
expect(output.artifact.blocks.map((block) => block.id)).toEqual(['p1', 'p2']);
|
|
});
|
|
|
|
it('preserves indentation and whitespace-significant Markdown', async () => {
|
|
const markdown = [
|
|
' def f():',
|
|
' return 1',
|
|
'',
|
|
'```text',
|
|
'column A column B',
|
|
'```',
|
|
'hard break ',
|
|
'next line',
|
|
].join('\r\n');
|
|
const input: DocumentArtifact = {
|
|
metadata: { mimeType: 'text/markdown' },
|
|
blocks: [{ id: 'markdown', type: 'markdown', text: markdown }],
|
|
assets: [],
|
|
};
|
|
|
|
const output = await normalizeDocumentTransform.apply(input, context);
|
|
|
|
expect(output.artifact.blocks[0].text).toBe(markdown.replace(/\r\n/g, '\n'));
|
|
});
|
|
|
|
it('does not merge text blocks that carry HTML payloads', async () => {
|
|
const input: DocumentArtifact = {
|
|
metadata: {},
|
|
blocks: [
|
|
{ id: 'a', type: 'text', text: 'First', html: '<p>First</p>' },
|
|
{ id: 'b', type: 'text', text: 'Second', html: '<p>Second</p>' },
|
|
],
|
|
assets: [],
|
|
};
|
|
|
|
const output = await normalizeDocumentTransform.apply(input, context);
|
|
|
|
expect(output.artifact.blocks).toHaveLength(2);
|
|
expect(output.artifact.blocks.map((block) => block.html)).toEqual([
|
|
'<p>First</p>',
|
|
'<p>Second</p>',
|
|
]);
|
|
});
|
|
|
|
it('removes citations to discarded empty blocks', async () => {
|
|
const input: DocumentArtifact = {
|
|
metadata: {},
|
|
blocks: [
|
|
{ id: 'empty', type: 'text', text: ' ' },
|
|
{ id: 'keep', type: 'text', text: 'Keep this content' },
|
|
],
|
|
assets: [],
|
|
citations: [
|
|
{ id: 'empty-citation', blockId: 'empty' },
|
|
{ id: 'keep-citation', blockId: 'keep' },
|
|
],
|
|
};
|
|
|
|
const output = await normalizeDocumentTransform.apply(input, context);
|
|
|
|
expect(output.artifact.citations).toEqual([{ id: 'keep-citation', blockId: 'keep' }]);
|
|
});
|
|
});
|