Files
0pt/tests/document-workbench/export-validated-output.test.ts
admin eec8cb2396
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 6s
CI (SIAX Cloud) / sonar (pull_request) Skipped
masterplan-lock / check (pull_request) Successful in 3s
CI (SIAX Cloud) / security (push) Successful in 18s
CI (SIAX Cloud) / security (pull_request) Successful in 20s
Security Scan (SIAX Cloud) / security (push) Successful in 35s
CI (SIAX Cloud) / integration (pull_request) Successful in 43s
CI (SIAX Cloud) / quality (push) Successful in 1m23s
CI (SIAX Cloud) / quality (pull_request) Successful in 1m22s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 2m4s
feat: validate source-backed decimals and dates
2026-11-02 02:20:54 +01:00

50 lines
3.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { exportValidatedOutput } from '../../src/document-workbench/export-validated-output';
const fields = [
{ name: 'name', type: 'string' as const, required: true },
{ name: 'count', type: 'integer' as const, required: true },
];
const sources = [{ id: 'source', text: 'Acme, "North"\n-2' }];
const evidence = [
{ field: 'name', sourceId: 'source', start: 0, end: 13, transform: 'exact' as const },
{ field: 'count', sourceId: 'source', start: 14, end: 16, transform: 'integer' as const },
];
const input = { fields, sources, evidence, value: { name: 'Acme, "North"', count: -2 } };
describe('validated document exports', () => {
it('preserves JSON values and produces correctly escaped, ordered CSV', () => {
const json = exportValidatedOutput({ ...input, format: 'json' });
expect(json.status).toBe('ready');
if (json.status === 'ready') expect(JSON.parse(json.content)).toEqual(input.value);
expect(exportValidatedOutput({ ...input, format: 'csv' })).toEqual({
status: 'ready', mediaType: 'text/csv', content: '"name","count"\r\n"Acme, ""North""","-2"\r\n',
});
});
it('revalidates evidence and refuses unsupported or absent data', () => {
expect(exportValidatedOutput({ ...input, value: { ...input.value, name: 'invented' }, format: 'json' }).status).toBe('needs_review');
expect(exportValidatedOutput({ ...input, evidence: [], format: 'csv' }).status).toBe('needs_review');
const optional = { ...input, fields: [...fields, { name: 'note', type: 'string' as const, required: false }] };
expect(exportValidatedOutput({ ...optional, format: 'csv' })).toMatchObject({ status: 'needs_review', issues: [{ field: 'note', code: 'csv_missing_value' }] });
expect(exportValidatedOutput({ ...optional, format: 'json' }).status).toBe('ready');
expect(exportValidatedOutput({ ...input, format: 'xml' as 'json' })).toMatchObject({ status: 'needs_review', issues: [{ code: 'unsupported_export_format' }] });
});
it('rejects formula-like CSV values and headers without changing JSON', () => {
const bad = { fields: [{ name: 'cell', type: 'string' as const, required: true }], sources: [{ id: 's', text: ' =1+1' }], evidence: [{ field: 'cell', sourceId: 's', start: 0, end: 6, transform: 'exact' as const }], value: { cell: ' =1+1' } };
expect(exportValidatedOutput({ ...bad, format: 'csv' })).toMatchObject({ status: 'needs_review', issues: [{ code: 'csv_unsafe_cell' }] });
expect(exportValidatedOutput({ ...bad, format: 'json' }).status).toBe('ready');
const header = { fields: [{ name: '=header', type: 'string' as const, required: true }], sources: [{ id: 's', text: 'safe' }], evidence: [{ field: '=header', sourceId: 's', start: 0, end: 4, transform: 'exact' as const }], value: { '=header': 'safe' } };
expect(exportValidatedOutput({ ...header, format: 'csv' })).toMatchObject({ status: 'needs_review', issues: [{ code: 'csv_unsafe_cell' }] });
});
it('preserves a source-backed decimal as text without floating-point rounding', () => {
const text = '9007199254740993.20';
const decimal = { fields: [{ name: 'amount', type: 'decimal' as const, required: true }], sources: [{ id: 's', text }], evidence: [{ field: 'amount', sourceId: 's', start: 0, end: text.length, transform: 'decimal' as const }], value: { amount: text } };
const result = exportValidatedOutput({ ...decimal, format: 'json' });
expect(result.status).toBe('ready');
if (result.status === 'ready') expect(JSON.parse(result.content)).toEqual({ amount: text });
});
});