test(session-recovery): add tests for detect-error-type resilience
Add test coverage for detectErrorType and extractMessageIndex with edge cases: circular references, non-standard proxy errors, null input. Wrap both functions in try/catch to prevent crashes from malformed error objects returned by non-standard providers like Antigravity.
This commit is contained in:
parent
daf011c616
commit
dd9eeaa6d6
129
src/hooks/session-recovery/detect-error-type.test.ts
Normal file
129
src/hooks/session-recovery/detect-error-type.test.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/// <reference types="bun-types" />
|
||||||
|
import { describe, expect, it } from "bun:test"
|
||||||
|
import { detectErrorType, extractMessageIndex } from "./detect-error-type"
|
||||||
|
|
||||||
|
describe("detectErrorType", () => {
|
||||||
|
it("#given a tool_use/tool_result error #when detecting #then returns tool_result_missing", () => {
|
||||||
|
//#given
|
||||||
|
const error = { message: "tool_use block must be followed by tool_result" }
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBe("tool_result_missing")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a thinking block order error #when detecting #then returns thinking_block_order", () => {
|
||||||
|
//#given
|
||||||
|
const error = { message: "thinking must be the first block in the response" }
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBe("thinking_block_order")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a thinking disabled violation #when detecting #then returns thinking_disabled_violation", () => {
|
||||||
|
//#given
|
||||||
|
const error = { message: "thinking is disabled and cannot contain thinking blocks" }
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBe("thinking_disabled_violation")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given an unrecognized error #when detecting #then returns null", () => {
|
||||||
|
//#given
|
||||||
|
const error = { message: "some random error" }
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a malformed error with circular references #when detecting #then returns null without crashing", () => {
|
||||||
|
//#given
|
||||||
|
const circular: Record<string, unknown> = {}
|
||||||
|
circular.self = circular
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(circular)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a proxy error with non-standard structure #when detecting #then returns null without crashing", () => {
|
||||||
|
//#given
|
||||||
|
const proxyError = {
|
||||||
|
data: "not-an-object",
|
||||||
|
error: 42,
|
||||||
|
nested: { deeply: { error: true } },
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(proxyError)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a null error #when detecting #then returns null", () => {
|
||||||
|
//#given
|
||||||
|
const error = null
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given an error with data.error containing message #when detecting #then extracts correctly", () => {
|
||||||
|
//#given
|
||||||
|
const error = {
|
||||||
|
data: {
|
||||||
|
error: {
|
||||||
|
message: "tool_use block requires tool_result",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = detectErrorType(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBe("tool_result_missing")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("extractMessageIndex", () => {
|
||||||
|
it("#given an error referencing messages.5 #when extracting #then returns 5", () => {
|
||||||
|
//#given
|
||||||
|
const error = { message: "Invalid value at messages.5: tool_result is required" }
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = extractMessageIndex(error)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBe(5)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("#given a malformed error #when extracting #then returns null without crashing", () => {
|
||||||
|
//#given
|
||||||
|
const circular: Record<string, unknown> = {}
|
||||||
|
circular.self = circular
|
||||||
|
|
||||||
|
//#when
|
||||||
|
const result = extractMessageIndex(circular)
|
||||||
|
|
||||||
|
//#then
|
||||||
|
expect(result).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -34,12 +34,17 @@ function getErrorMessage(error: unknown): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function extractMessageIndex(error: unknown): number | null {
|
export function extractMessageIndex(error: unknown): number | null {
|
||||||
|
try {
|
||||||
const message = getErrorMessage(error)
|
const message = getErrorMessage(error)
|
||||||
const match = message.match(/messages\.(\d+)/)
|
const match = message.match(/messages\.(\d+)/)
|
||||||
return match ? parseInt(match[1], 10) : null
|
return match ? parseInt(match[1], 10) : null
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function detectErrorType(error: unknown): RecoveryErrorType {
|
export function detectErrorType(error: unknown): RecoveryErrorType {
|
||||||
|
try {
|
||||||
const message = getErrorMessage(error)
|
const message = getErrorMessage(error)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -70,4 +75,7 @@ export function detectErrorType(error: unknown): RecoveryErrorType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user