Files
botpress--botpress/packages/zai/e2e/errors.test.ts
T
2026-07-13 13:34:48 +08:00

288 lines
7.9 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { z } from '@bpinternal/zui'
import { JsonParsingError } from '../src/operations/errors'
describe('JsonParsingError', () => {
it('formats simple zod validation error in LLM-friendly way', () => {
const schema = z.object({
name: z.string(),
age: z.number(),
})
try {
schema.parse({ name: 'John', age: 'not a number' })
} catch (error) {
const jsonParsingError = new JsonParsingError('{"name":"John","age":"not a number"}', error as Error)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"name":"John","age":"not a number"}
---Validation Errors---
1. Field: "age"
Problem: Expected number, but received string
Message: Expected number, received string
"
`)
}
})
it('formats complex nested zod validation error in LLM-friendly way', () => {
const schema = z.object({
name: z.string().min(3),
email: z.string().email(),
age: z.number().positive(),
address: z.object({
street: z.string(),
city: z.string(),
zipCode: z.string().length(5),
}),
tags: z.array(z.string()),
})
try {
schema.parse({
name: 'Jo',
email: 'invalid-email',
age: -5,
address: {
street: 'Main St',
city: '',
zipCode: '1234',
},
tags: ['valid', 123, null],
})
} catch (error) {
const jsonParsingError = new JsonParsingError(
JSON.stringify({
name: 'Jo',
email: 'invalid-email',
age: -5,
address: { street: 'Main St', city: '', zipCode: '1234' },
tags: ['valid', 123, null],
}),
error as Error
)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"name":"Jo","email":"invalid-email","age":-5,"address":{"street":"Main St","city":"","zipCode":"1234"},"tags":["valid",123,null]}
---Validation Errors---
1. Field: "name"
Problem: String must be at least 3 characters
Message: String must contain at least 3 character(s)
2. Field: "email"
Problem: Invalid email format
Message: Invalid email
3. Field: "age"
Problem: Number must be greater than 0
Message: Number must be greater than 0
4. Field: "address.zipCode"
Problem: String must be exactly 5 characters
Message: String must contain exactly 5 character(s)
5. Field: "tags.1"
Problem: Expected string, but received number
Message: Expected string, received number
6. Field: "tags.2"
Problem: Expected string, but received null
Message: Expected string, received null
"
`)
}
})
it('formats array validation error in LLM-friendly way', () => {
const schema = z.array(
z.object({
id: z.number(),
name: z.string(),
})
)
try {
schema.parse([
{ id: 1, name: 'Valid' },
{ id: 'invalid', name: 'Invalid ID' },
{ id: 3, name: 123 },
])
} catch (error) {
const jsonParsingError = new JsonParsingError(
JSON.stringify([
{ id: 1, name: 'Valid' },
{ id: 'invalid', name: 'Invalid ID' },
{ id: 3, name: 123 },
]),
error as Error
)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
[{"id":1,"name":"Valid"},{"id":"invalid","name":"Invalid ID"},{"id":3,"name":123}]
---Validation Errors---
1. Field: "1.id"
Problem: Expected number, but received string
Message: Expected number, received string
2. Field: "2.name"
Problem: Expected string, but received number
Message: Expected string, received number
"
`)
}
})
it('formats missing required field error in LLM-friendly way', () => {
const schema = z.object({
requiredField: z.string(),
optionalField: z.string().optional(),
})
try {
schema.parse({ optionalField: 'present' })
} catch (error) {
const jsonParsingError = new JsonParsingError('{"optionalField":"present"}', error as Error)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"optionalField":"present"}
---Validation Errors---
1. Field: "requiredField"
Problem: Expected string, but received undefined
Message: Required
"
`)
}
})
it('formats union/enum validation error in LLM-friendly way', () => {
const schema = z.object({
status: z.enum(['pending', 'approved', 'rejected']),
priority: z.union([z.literal('low'), z.literal('medium'), z.literal('high')]),
})
try {
schema.parse({ status: 'invalid-status', priority: 'urgent' })
} catch (error) {
const jsonParsingError = new JsonParsingError('{"status":"invalid-status","priority":"urgent"}', error as Error)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"status":"invalid-status","priority":"urgent"}
---Validation Errors---
1. Field: "status"
Problem: Invalid value "invalid-status"
Allowed values: "pending", "approved", "rejected"
Message: Invalid enum value. Expected 'pending' | 'approved' | 'rejected', received 'invalid-status'
2. Field: "priority"
Problem: Value doesn't match any of the expected formats
Message: Invalid input
"
`)
}
})
it('formats type mismatch errors in LLM-friendly way', () => {
const schema = z.object({
string: z.string(),
number: z.number(),
boolean: z.boolean(),
array: z.array(z.string()),
object: z.object({ nested: z.string() }),
})
try {
schema.parse({
string: 123,
number: 'not a number',
boolean: 'yes',
array: 'not an array',
object: 'not an object',
})
} catch (error) {
const jsonParsingError = new JsonParsingError(
JSON.stringify({
string: 123,
number: 'not a number',
boolean: 'yes',
array: 'not an array',
object: 'not an object',
}),
error as Error
)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"string":123,"number":"not a number","boolean":"yes","array":"not an array","object":"not an object"}
---Validation Errors---
1. Field: "string"
Problem: Expected string, but received number
Message: Expected string, received number
2. Field: "number"
Problem: Expected number, but received string
Message: Expected number, received string
3. Field: "boolean"
Problem: Expected boolean, but received string
Message: Expected boolean, received string
4. Field: "array"
Problem: Expected array, but received string
Message: Expected array, received string
5. Field: "object"
Problem: Expected object, but received string
Message: Expected object, received string
"
`)
}
})
it('handles non-zod errors gracefully', () => {
const regularError = new Error('This is a regular parsing error')
const jsonParsingError = new JsonParsingError('{"invalid json"}', regularError)
expect(jsonParsingError.message).toMatchInlineSnapshot(`
"Error parsing JSON:
---JSON---
{"invalid json"}
---Error---
The JSON provided is not valid JSON.
Details: This is a regular parsing error
"
`)
})
})