server-errors.test.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import { describe, expect, test } from "bun:test"
  2. import type { ConfigInvalidError, ProviderModelNotFoundError } from "./server-errors"
  3. import { formatServerError, parseReadableConfigInvalidError } from "./server-errors"
  4. function fill(text: string, vars?: Record<string, string | number>) {
  5. if (!vars) return text
  6. return text.replace(/{{\s*(\w+)\s*}}/g, (_, key: string) => {
  7. const value = vars[key]
  8. if (value === undefined) return ""
  9. return String(value)
  10. })
  11. }
  12. function useLanguageMock() {
  13. const dict: Record<string, string> = {
  14. "error.chain.unknown": "Erro desconhecido",
  15. "error.chain.configInvalid": "Arquivo de config em {{path}} invalido",
  16. "error.chain.configInvalidWithMessage": "Arquivo de config em {{path}} invalido: {{message}}",
  17. "error.chain.modelNotFound": "Modelo nao encontrado: {{provider}}/{{model}}",
  18. "error.chain.didYouMean": "Voce quis dizer: {{suggestions}}",
  19. "error.chain.checkConfig": "Revise provider/model no config",
  20. }
  21. return {
  22. t(key: string, vars?: Record<string, string | number>) {
  23. const text = dict[key]
  24. if (!text) return key
  25. return fill(text, vars)
  26. },
  27. }
  28. }
  29. const language = useLanguageMock()
  30. describe("parseReadableConfigInvalidError", () => {
  31. test("formats issues with file path", () => {
  32. const error = {
  33. name: "ConfigInvalidError",
  34. data: {
  35. path: "opencode.config.ts",
  36. issues: [
  37. { path: ["settings", "host"], message: "Required" },
  38. { path: ["mode"], message: "Invalid" },
  39. ],
  40. },
  41. } satisfies ConfigInvalidError
  42. const result = parseReadableConfigInvalidError(error, language.t)
  43. expect(result).toBe(
  44. ["Arquivo de config em opencode.config.ts invalido: settings.host: Required", "mode: Invalid"].join("\n"),
  45. )
  46. })
  47. test("uses trimmed message when issues are missing", () => {
  48. const error = {
  49. name: "ConfigInvalidError",
  50. data: {
  51. path: "config",
  52. message: " Bad value ",
  53. },
  54. } satisfies ConfigInvalidError
  55. const result = parseReadableConfigInvalidError(error, language.t)
  56. expect(result).toBe("Arquivo de config em config invalido: Bad value")
  57. })
  58. })
  59. describe("formatServerError", () => {
  60. test("formats config invalid errors", () => {
  61. const error = {
  62. name: "ConfigInvalidError",
  63. data: {
  64. message: "Missing host",
  65. },
  66. } satisfies ConfigInvalidError
  67. const result = formatServerError(error, language.t)
  68. expect(result).toBe("Arquivo de config em config invalido: Missing host")
  69. })
  70. test("returns error messages", () => {
  71. expect(formatServerError(new Error("Request failed with status 503"), language.t)).toBe(
  72. "Request failed with status 503",
  73. )
  74. })
  75. test("returns provided string errors", () => {
  76. expect(formatServerError("Failed to connect to server", language.t)).toBe("Failed to connect to server")
  77. })
  78. test("uses translated unknown fallback", () => {
  79. expect(formatServerError(0, language.t)).toBe("Erro desconhecido")
  80. })
  81. test("falls back for unknown error objects and names", () => {
  82. expect(formatServerError({ name: "ServerTimeoutError", data: { seconds: 30 } }, language.t)).toBe(
  83. "Erro desconhecido",
  84. )
  85. })
  86. test("formats provider model errors using provider/model", () => {
  87. const error = {
  88. name: "ProviderModelNotFoundError",
  89. data: {
  90. providerID: "openai",
  91. modelID: "gpt-4.1",
  92. },
  93. } satisfies ProviderModelNotFoundError
  94. expect(formatServerError(error, language.t)).toBe(
  95. ["Modelo nao encontrado: openai/gpt-4.1", "Revise provider/model no config"].join("\n"),
  96. )
  97. })
  98. test("formats provider model suggestions", () => {
  99. const error = {
  100. name: "ProviderModelNotFoundError",
  101. data: {
  102. providerID: "x",
  103. modelID: "y",
  104. suggestions: ["x/y2", "x/y3"],
  105. },
  106. } satisfies ProviderModelNotFoundError
  107. expect(formatServerError(error, language.t)).toBe(
  108. ["Modelo nao encontrado: x/y", "Voce quis dizer: x/y2, x/y3", "Revise provider/model no config"].join("\n"),
  109. )
  110. })
  111. })