/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/app/src/utils/server-errors.test.ts
175 строк
6 KB
Brendan Allan
fix(app): close missing session tabs (#33785)
25 июн 2026, 08:28
Не верифицирован
25 июн 2026, 08:28
bdee94c
Код
Авторство
О чём код?
import { describe, expect, test } from "bun:test" import type { SessionNotFoundError } from "@opencode-ai/sdk/v2/client" import type { ConfigInvalidError, ProviderModelNotFoundError } from "./server-errors" import { formatServerError, isSessionNotFoundError, parseReadableConfigInvalidError } from "./server-errors" function fill(text: string, vars?: Record<string, string | number>) { if (!vars) return text return text.replace(/{{\s*(\w+)\s*}}/g, (_, key: string) => { const value = vars[key] if (value === undefined) return "" return String(value) }) } function useLanguageMock() { const dict: Record<string, string> = { "error.chain.unknown": "Erro desconhecido", "error.chain.configInvalid": "Arquivo de config em {{path}} invalido", "error.chain.configInvalidWithMessage": "Arquivo de config em {{path}} invalido: {{message}}", "error.chain.modelNotFound": "Modelo nao encontrado: {{provider}}/{{model}}", "error.chain.didYouMean": "Voce quis dizer: {{suggestions}}", "error.chain.checkConfig": "Revise provider/model no config", } return { t(key: string, vars?: Record<string, string | number>) { const text = dict[key] if (!text) return key return fill(text, vars) }, } } const language = useLanguageMock() describe("parseReadableConfigInvalidError", () => { test("formats issues with file path", () => { const error = { name: "ConfigInvalidError", data: { path: "opencode.config.ts", issues: [ { path: ["settings", "host"], message: "Required" }, { path: ["mode"], message: "Invalid" }, ], }, } satisfies ConfigInvalidError const result = parseReadableConfigInvalidError(error, language.t) expect(result).toBe( ["Arquivo de config em opencode.config.ts invalido: settings.host: Required", "mode: Invalid"].join("\n"), ) }) test("uses trimmed message when issues are missing", () => { const error = { name: "ConfigInvalidError", data: { path: "config", message: " Bad value ", }, } satisfies ConfigInvalidError const result = parseReadableConfigInvalidError(error, language.t) expect(result).toBe("Arquivo de config em config invalido: Bad value") }) }) describe("formatServerError", () => { test("formats config invalid errors", () => { const error = { name: "ConfigInvalidError", data: { message: "Missing host", }, } satisfies ConfigInvalidError const result = formatServerError(error, language.t) expect(result).toBe("Arquivo de config em config invalido: Missing host") }) test("returns error messages", () => { expect(formatServerError(new Error("Request failed with status 503"), language.t)).toBe( "Request failed with status 503", ) }) test("returns provided string errors", () => { expect(formatServerError("Failed to connect to server", language.t)).toBe("Failed to connect to server") }) test("uses translated unknown fallback", () => { expect(formatServerError(0, language.t)).toBe("Erro desconhecido") }) test("falls back for unknown error objects and names", () => { expect(formatServerError({ name: "ServerTimeoutError", data: { seconds: 30 } }, language.t)).toBe( "Erro desconhecido", ) }) test("formats provider model errors using provider/model", () => { const error = { name: "ProviderModelNotFoundError", data: { providerID: "openai", modelID: "gpt-4.1", }, } satisfies ProviderModelNotFoundError expect(formatServerError(error, language.t)).toBe( ["Modelo nao encontrado: openai/gpt-4.1", "Revise provider/model no config"].join("\n"), ) }) test("formats provider model suggestions", () => { const error = { name: "ProviderModelNotFoundError", data: { providerID: "x", modelID: "y", suggestions: ["x/y2", "x/y3"], }, } satisfies ProviderModelNotFoundError expect(formatServerError(error, language.t)).toBe( ["Modelo nao encontrado: x/y", "Voce quis dizer: x/y2, x/y3", "Revise provider/model no config"].join("\n"), ) }) test("unwraps SDK-wrapped errors from cause.body", () => { const body = { name: "ConfigInvalidError", data: { message: "Missing host", }, } satisfies ConfigInvalidError const wrapped = new Error("ConfigInvalidError", { cause: { body, status: 400 } }) expect(formatServerError(wrapped, language.t)).toBe("Arquivo de config em config invalido: Missing host") }) }) describe("isSessionNotFoundError", () => { test("matches an SDK-wrapped error for the requested session", () => { const body = { _tag: "SessionNotFoundError", sessionID: "ses_missing", message: "Session not found", } satisfies SessionNotFoundError expect(isSessionNotFoundError(new Error(body.message, { cause: { body, status: 404 } }), body.sessionID)).toBe(true) }) test("rejects errors for other sessions and other 404 responses", () => { const body = { _tag: "SessionNotFoundError", sessionID: "ses_parent", message: "Session not found", } satisfies SessionNotFoundError expect(isSessionNotFoundError(new Error(body.message, { cause: { body, status: 404 } }), "ses_tab")).toBe(false) expect( isSessionNotFoundError( new Error("Provider not found", { cause: { body: { _tag: "ProviderNotFoundError", providerID: "missing" }, status: 404 }, }), "ses_tab", ), ).toBe(false) }) })