mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-24 02:01:11 +00:00
* refactor(normalization): consolidate string helpers * refactor(normalization): consolidate agent ids * refactor(paths): consolidate user path resolution * refactor(gateway): preserve transcript helper facade * fix(normalization): align helper build aliases * fix(memory): keep helper import line neutral * chore(plugin-sdk): align consolidated helper surface * refactor(normalization): reuse lowercase string helper * refactor(normalization): reuse record guard * refactor(normalization): share surrogate boundary helper * refactor(agents): share token estimate constant * refactor(memory): distinguish standalone helper contracts * refactor(normalization): share error cause formatter * refactor(config): distinguish eligibility predicates * refactor(plugins): share registry state symbol * refactor(cli): reuse outbound dependency adapter * refactor(cron): distinguish positive duration parser * fix(gateway): keep transcript helper private * fix(paths): preserve public helper status * refactor(channels): reuse registry normalizer * refactor(agents): reuse agent core runtime facade * refactor(auth): reuse locked profile upsert * refactor(records): distinguish trap-safe guard * refactor(migrations): distinguish sync directory helper * test(plugins): drop stale duration alias expectations * fix(channels): remove stale registry import * chore(plugin-sdk): refresh helper API baseline * fix(memory): keep renamed helpers private * fix(plugins): keep registry state key private * fix(plugin-sdk): tighten wildcard surface budget * chore(plugin-sdk): refresh rebased helper API baseline
73 lines
3.0 KiB
TypeScript
73 lines
3.0 KiB
TypeScript
// Normalization core tests cover shared error coercion and formatting behavior.
|
|
import { describe, expect, it } from "vitest";
|
|
import { formatErrorMessage, stringifyNonErrorCause, toErrorObject } from "./error-coercion.js";
|
|
|
|
const keepText = (text: string): string => text;
|
|
const format = (value: unknown): string => formatErrorMessage(value, { redact: keepText });
|
|
|
|
describe("formatErrorMessage", () => {
|
|
it("walks and deduplicates Error cause chains while preserving codes", () => {
|
|
const root = Object.assign(new Error("socket closed"), { code: "ECONNRESET" });
|
|
const inner = new Error("request failed", { cause: root });
|
|
const outer = new Error("request failed", { cause: inner });
|
|
|
|
expect(format(outer)).toBe("request failed | socket closed | ECONNRESET");
|
|
});
|
|
|
|
it("formats status/code records and structured non-Error causes", () => {
|
|
expect(format({ status: 500, code: "EPIPE" })).toBe("status=500 code=EPIPE");
|
|
expect(format({ status: 404 })).toBe("status=404 code=unknown");
|
|
expect(format({ code: "ENOENT" })).toBe("status=unknown code=ENOENT");
|
|
expect(format({ code: 42, why: "boom" })).toBe('{"code":42,"why":"boom"}');
|
|
expect(format(new Error("request failed", { cause: { status: 429 } }))).toBe(
|
|
"request failed | status=429 code=unknown",
|
|
);
|
|
expect(format(new Error("request failed", { cause: { statusCode: 429 } }))).toBe(
|
|
"request failed",
|
|
);
|
|
});
|
|
|
|
it("stringifies primitives and circular records without throwing", () => {
|
|
const circular: { self?: unknown } = {};
|
|
circular.self = circular;
|
|
|
|
expect(format(null)).toBe("null");
|
|
expect(format(undefined)).toBe("undefined");
|
|
expect(format(123n)).toBe("123");
|
|
expect(format(circular)).toBe("[object Object]");
|
|
});
|
|
|
|
it("requires an owner-supplied redactor", () => {
|
|
expect(formatErrorMessage("sensitive", { redact: () => "redacted" })).toBe("redacted");
|
|
});
|
|
});
|
|
|
|
describe("toErrorObject", () => {
|
|
it("preserves Error and string inputs", () => {
|
|
const error = new Error("boom");
|
|
expect(toErrorObject(error, "fallback")).toBe(error);
|
|
expect(toErrorObject("boom", "fallback")).toMatchObject({ message: "boom" });
|
|
});
|
|
|
|
it("preserves structured details from non-Error objects", () => {
|
|
const value = { code: "EPIPE", status: 500 };
|
|
const error = toErrorObject(value, "request failed") as Error & typeof value;
|
|
|
|
expect(error).toMatchObject({ message: "request failed", code: "EPIPE", status: 500 });
|
|
expect(error.cause).toBe(value);
|
|
});
|
|
});
|
|
|
|
describe("stringifyNonErrorCause", () => {
|
|
it("renders primitive and structured values", () => {
|
|
expect(stringifyNonErrorCause(null)).toBe("null");
|
|
expect(stringifyNonErrorCause(42)).toBe("42");
|
|
expect(stringifyNonErrorCause({ ok: true })).toBe('{"ok":true}');
|
|
});
|
|
|
|
it("falls back to object tags when JSON has no string result", () => {
|
|
expect(stringifyNonErrorCause(undefined)).toBe("[object Undefined]");
|
|
expect(stringifyNonErrorCause(Symbol("value"))).toBe("[object Symbol]");
|
|
});
|
|
});
|