import { repairJSON, extractJSONFromText, validateJSONSchema, safeParseJSON } from '../src/utils/jsonRepair.js'; describe('repairJSON', () => { test('parses valid JSON', () => { const input = '{"name": "test", "value": 42}'; const result = repairJSON(input); expect(result).toEqual({ name: 'test', value: 42 }); }); test('handles trailing commas', () => { const input = '{"name": "test", "value": 42,}'; const result = repairJSON(input); expect(result).toEqual({ name: 'test', value: 42 }); }); test('handles markdown code fences', () => { const input = '```json\n{"name": "test"}\n```'; const result = repairJSON(input); expect(result).toEqual({ name: 'test' }); }); test('removes thinking tags', () => { const input = '```json\n{"name": "test"}\n```'; const result = repairJSON(input); expect(result).toEqual({ name: 'test' }); }); test('returns null for invalid input', () => { expect(repairJSON(null)).toBeNull(); expect(repairJSON(123)).toBeNull(); expect(repairJSON('')).toBeNull(); expect(repairJSON('not json at all')).toBeNull(); }); test('handles JSON arrays', () => { const input = '[1, 2, 3]'; const result = repairJSON(input); expect(result).toEqual([1, 2, 3]); }); test('handles nested objects', () => { const input = '{"outer": {"inner": {"deep": true}}}'; const result = repairJSON(input); expect(result).toEqual({ outer: { inner: { deep: true } } }); }); test('removes JavaScript comments', () => { const input = '{"name": "test"} // comment'; const result = repairJSON(input); expect(result).toEqual({ name: 'test' }); }); }); describe('extractJSONFromText', () => { test('extracts from json code fence', () => { const input = 'Here is some text\n```json\n{"key": "value"}\n```\nMore text'; const result = extractJSONFromText(input); expect(result).toBe('{"key": "value"}'); }); test('extracts from generic code fence', () => { const input = '```{"key": "value"}```'; const result = extractJSONFromText(input); expect(result).toBe('{"key": "value"}'); }); test('extracts standalone JSON object', () => { const input = 'Some text {"key": "value"} more text'; const result = extractJSONFromText(input); expect(result).toBe('{"key": "value"}'); }); test('extracts standalone JSON array', () => { const input = 'Some text [1, 2, 3] more text'; const result = extractJSONFromText(input); expect(result).toBe('[1, 2, 3]'); }); test('returns null for no JSON', () => { expect(extractJSONFromText('no json here')).toBeNull(); expect(extractJSONFromText(null)).toBeNull(); expect(extractJSONFromText(123)).toBeNull(); }); }); describe('validateJSONSchema', () => { test('validates userStats schema', () => { const valid = { stats: [{ id: 'health', name: 'Health', value: 100 }] }; const invalid = { stats: [{ id: 'health', name: 'Health' }] }; // missing value expect(validateJSONSchema(valid, 'userStats')).toBe(true); expect(validateJSONSchema(invalid, 'userStats')).toBe(false); }); test('validates infoBox schema', () => { const valid = { date: '2024-01-01' }; const invalid = { unrelated: 'data' }; // Note: validateJSONSchema returns the truthy field value, not strictly true expect(validateJSONSchema(valid, 'infoBox')).toBeTruthy(); expect(validateJSONSchema(invalid, 'infoBox')).toBeFalsy(); }); test('validates characters schema', () => { const valid = { characters: [{ name: 'Alice' }] }; const invalid = { characters: [{ noName: true }] }; expect(validateJSONSchema(valid, 'characters')).toBe(true); expect(validateJSONSchema(invalid, 'characters')).toBe(false); }); test('returns false for invalid types', () => { expect(validateJSONSchema(null, 'userStats')).toBe(false); expect(validateJSONSchema('string', 'userStats')).toBe(false); expect(validateJSONSchema({}, 'unknown')).toBe(false); }); }); describe('safeParseJSON', () => { test('successfully parses and validates', () => { const result = safeParseJSON('{"stats": [{"id": "health", "name": "Health", "value": 100}]}', 'userStats'); expect(result.success).toBe(true); expect(result.data).toEqual({ stats: [{ id: 'health', name: 'Health', value: 100 }] }); expect(result.error).toBeNull(); }); test('returns error when no JSON found', () => { const result = safeParseJSON('no json here'); expect(result.success).toBe(false); expect(result.error).toBe('No JSON found in text'); }); test('returns error when schema validation fails', () => { const result = safeParseJSON('{"unrelated": "data"}', 'userStats'); expect(result.success).toBe(false); expect(result.error).toContain('does not match expected schema'); expect(result.data).not.toBeNull(); // Still returns data }); });