Files
kilocode/packages/kilo-vscode/tests/unit/errorUtils.test.ts
T
2026-06-15 14:17:44 +02:00

168 lines
6.0 KiB
TypeScript

import { describe, it, expect } from "bun:test"
import type { AssistantMessage } from "@kilocode/sdk/v2"
import {
unwrapError,
parseAssistantError,
parseProviderAuthError,
isUnauthorizedPaidModelError,
isUnauthorizedPromotionLimitError,
} from "../../webview-ui/src/utils/errorUtils"
type AssistantError = AssistantMessage["error"]
describe("unwrapError", () => {
it("returns plain string messages unchanged", () => {
expect(unwrapError("something went wrong")).toBe("something went wrong")
})
it("extracts message from JSON error object with error.message", () => {
const input = JSON.stringify({ error: { message: "rate limit exceeded" } })
expect(unwrapError(input)).toBe("rate limit exceeded")
})
it("returns original message for malformed JSON", () => {
expect(unwrapError("{not valid json")).toBe("{not valid json")
})
it("strips leading 'Error: ' prefix before parsing", () => {
const json = JSON.stringify({ message: "connection refused" })
expect(unwrapError(`Error: ${json}`)).toBe("connection refused")
})
it("formats empty provider rate-limit errors", () => {
const body = {
type: "error",
sequence_number: 2,
error: { type: "tokens", code: "rate_limit_exceeded", message: "", param: null },
}
const input = JSON.stringify({ message: JSON.stringify(body) })
expect(unwrapError(input)).toBe("Provider rate limit exceeded. Please try again shortly.")
})
it("preserves provider details when a rate-limit message is present", () => {
const input = JSON.stringify({
type: "error",
error: { type: "tokens", code: "rate_limit_exceeded", message: "Try again in 30 seconds." },
})
expect(unwrapError(input)).toBe("tokens: Try again in 30 seconds.")
})
})
describe("parseAssistantError", () => {
it("returns null for null input", () => {
expect(parseAssistantError(null)).toBeNull()
})
it("returns null for undefined input", () => {
expect(parseAssistantError(undefined)).toBeNull()
})
it("returns null for non-APIError (e.g. MessageAbortedError)", () => {
const error: AssistantError = { name: "MessageAbortedError", data: { message: "aborted" } }
expect(parseAssistantError(error)).toBeNull()
})
it("returns null when APIError has no data", () => {
// Simulate a malformed error where data is missing at runtime
const error = { name: "APIError" } as unknown as AssistantError
expect(parseAssistantError(error)).toBeNull()
})
it("extracts statusCode and message from APIError data", () => {
const error: AssistantError = {
name: "APIError",
data: { statusCode: 401, message: "Unauthorized", isRetryable: false },
}
const result = parseAssistantError(error)
expect(result).toEqual({ statusCode: 401, code: undefined, message: "Unauthorized" })
})
it("extracts code from responseBody JSON with error.code", () => {
const responseBody = JSON.stringify({ error: { code: "PAID_MODEL_AUTH_REQUIRED" } })
const error: AssistantError = {
name: "APIError",
data: { statusCode: 401, message: "Unauthorized", isRetryable: false, responseBody },
}
const result = parseAssistantError(error)
expect(result).toEqual({ statusCode: 401, code: "PAID_MODEL_AUTH_REQUIRED", message: "Unauthorized" })
})
it("extracts code from responseBody JSON with top-level code", () => {
const responseBody = JSON.stringify({ code: "PROMOTION_MODEL_LIMIT_REACHED" })
const error: AssistantError = {
name: "APIError",
data: { statusCode: 429, message: "Too Many Requests", isRetryable: false, responseBody },
}
const result = parseAssistantError(error)
expect(result).toEqual({ statusCode: 429, code: "PROMOTION_MODEL_LIMIT_REACHED", message: "Too Many Requests" })
})
it("handles invalid responseBody JSON gracefully", () => {
const error: AssistantError = {
name: "APIError",
data: { statusCode: 500, message: "Server Error", isRetryable: false, responseBody: "not json" },
}
const result = parseAssistantError(error)
expect(result).toEqual({ statusCode: 500, code: undefined, message: "Server Error" })
})
it("handles missing responseBody", () => {
const error: AssistantError = {
name: "APIError",
data: { statusCode: 403, message: "Forbidden", isRetryable: false },
}
const result = parseAssistantError(error)
expect(result).toEqual({ statusCode: 403, code: undefined, message: "Forbidden" })
})
})
describe("parseProviderAuthError", () => {
it("extracts provider auth errors", () => {
const error: AssistantError = {
name: "ProviderAuthError",
data: { providerID: "openai", message: "Sign in again" },
}
expect(parseProviderAuthError(error)).toEqual({ providerID: "openai", message: "Sign in again" })
})
it("returns null for non-provider-auth errors", () => {
const error: AssistantError = {
name: "APIError",
data: { statusCode: 401, message: "Unauthorized", isRetryable: false },
}
expect(parseProviderAuthError(error)).toBeNull()
})
})
describe("isUnauthorizedPaidModelError", () => {
it("returns true for 401 + PAID_MODEL_AUTH_REQUIRED", () => {
expect(isUnauthorizedPaidModelError({ statusCode: 401, code: "PAID_MODEL_AUTH_REQUIRED" })).toBe(true)
})
it("returns false for 401 + different code", () => {
expect(isUnauthorizedPaidModelError({ statusCode: 401, code: "SOMETHING_ELSE" })).toBe(false)
})
it("returns false for null input", () => {
expect(isUnauthorizedPaidModelError(null)).toBe(false)
})
})
describe("isUnauthorizedPromotionLimitError", () => {
it("returns true for 401 + PROMOTION_MODEL_LIMIT_REACHED", () => {
expect(isUnauthorizedPromotionLimitError({ statusCode: 401, code: "PROMOTION_MODEL_LIMIT_REACHED" })).toBe(true)
})
it("returns true for 429 + PROMOTION_MODEL_LIMIT_REACHED", () => {
expect(isUnauthorizedPromotionLimitError({ statusCode: 429, code: "PROMOTION_MODEL_LIMIT_REACHED" })).toBe(true)
})
it("returns false for null input", () => {
expect(isUnauthorizedPromotionLimitError(null)).toBe(false)
})
})