Files
diegosouzapw--omniroute/tests/unit/provider-page-helpers-3501.test.ts
2026-07-13 13:39:12 +08:00

239 lines
10 KiB
TypeScript

// Phase 2 unit tests for Issue #3501: the pure helpers extracted from the
// provider-detail god-component into providerPageHelpers.ts. Beyond asserting
// behaviour, exercising EVERY exported function guards against a missing
// transitive import in the extracted module (the Phase 0 smoke test caught one
// such gap — isSelfHostedChatProvider — at mount time; this locks it down).
import { test } from "node:test";
import assert from "node:assert/strict";
import {
providerText,
providerCountText,
readBooleanToggle,
getLocalProviderMetadata,
isBaseUrlConfigurableProvider,
getProviderBaseUrlDefault,
getProviderBaseUrlHint,
getProviderBaseUrlPlaceholder,
isGlmProvider,
parseRoutingTagsInput,
parseExcludedModelsInput,
formatRoutingTagsInput,
formatExcludedModelsInput,
// Phase 2b additions
getWebSessionCredentialLabel,
getWebSessionCredentialHint,
getWebSessionCredentialCheckLabel,
getAddCredentialModalTitle,
upstreamHeadersRecordsEqual,
UPSTREAM_HEADERS_UI_MAX,
headerRowsToRecord,
effectiveUpstreamHeadersForProtocol,
anyUpstreamHeadersBadge,
getProtoSlice,
CODEX_REASONING_STRENGTH_OPTIONS,
CODEX_ACCOUNT_SERVICE_TIER_VALUES,
CODEX_GLOBAL_SERVICE_MODE_VALUES,
getCodexServiceTierLabel,
normalizeCodexLimitPolicy,
getCodexRequestDefaults,
getClaudeCodeCompatibleRequestDefaults,
compatProtocolLabelKey,
extractCommandCodeCredentialInput,
normalizeAndValidateHttpBaseUrl,
SILICONFLOW_ENDPOINTS,
type HeaderDraftRow,
type CompatModelRow,
type CompatModelMap,
} from "../../src/app/(dashboard)/dashboard/providers/[id]/providerPageHelpers.ts";
const tStub = Object.assign((key: string) => key, { has: (_k: string) => false });
test("providerText falls back when key missing and interpolates values", () => {
assert.equal(providerText(tStub, "missing.key", "Hello {name}", { name: "X" }), "Hello X");
const tHas = Object.assign((key: string) => `T:${key}`, { has: (_k: string) => true });
assert.equal(providerText(tHas, "present.key", "fallback"), "T:present.key");
});
test("providerCountText picks singular/plural by count", () => {
assert.equal(providerCountText(tStub, "k", 1, "{count} item", "{count} items"), "1 item");
assert.equal(providerCountText(tStub, "k", 3, "{count} item", "{count} items"), "3 items");
});
test("readBooleanToggle coerces booleans/numbers/strings with fallback", () => {
assert.equal(readBooleanToggle(true, false), true);
assert.equal(readBooleanToggle(1, false), true);
assert.equal(readBooleanToggle("false", true), false);
assert.equal(readBooleanToggle(undefined, true), true);
});
test("base-url helpers run without throwing (transitive imports present)", () => {
// The key regression guard: isBaseUrlConfigurableProvider internally calls
// isSelfHostedChatProvider — a transitive import that must be wired up.
assert.doesNotThrow(() => isBaseUrlConfigurableProvider("openai"));
assert.equal(typeof isBaseUrlConfigurableProvider("openai"), "boolean");
assert.doesNotThrow(() => getLocalProviderMetadata("openai"));
assert.doesNotThrow(() => getProviderBaseUrlDefault("openai"));
assert.doesNotThrow(() => getProviderBaseUrlHint("openai", null));
assert.doesNotThrow(() => getProviderBaseUrlPlaceholder("openai"));
assert.equal(typeof isGlmProvider("glm"), "boolean");
assert.doesNotThrow(() => isBaseUrlConfigurableProvider(null));
});
test("routing-tags / excluded-models parse + format round-trip", () => {
assert.deepEqual(parseRoutingTagsInput("a, b ,c"), ["a", "b", "c"]);
assert.equal(parseRoutingTagsInput(" "), undefined);
assert.deepEqual(parseExcludedModelsInput("m1, m2"), ["m1", "m2"]);
assert.equal(formatRoutingTagsInput(["x", "y"]), "x, y");
assert.equal(formatExcludedModelsInput(["a", "b"]), "a, b");
assert.equal(formatRoutingTagsInput(undefined), "");
});
// ---------------------------------------------------------------------------
// Phase 2b — runtime guards for the newly-moved helpers
// ---------------------------------------------------------------------------
const tokenReq = { kind: "token" as const, credentialName: "myToken" };
const cookieReq = { kind: "cookie" as const, credentialName: "SESS" };
const noneReq = { kind: "none" as const, credentialName: "" };
test("getWebSessionCredentialLabel (Phase 2b — transitive import guard)", () => {
assert.ok(getWebSessionCredentialLabel(tStub, tokenReq, false).length > 0);
assert.ok(getWebSessionCredentialLabel(tStub, cookieReq, true).length > 0);
assert.ok(getWebSessionCredentialLabel(tStub, noneReq, false).length > 0);
});
test("getWebSessionCredentialHint returns undefined for none-kind, string otherwise", () => {
assert.equal(getWebSessionCredentialHint(tStub, noneReq, "Acme", false), undefined);
assert.equal(typeof getWebSessionCredentialHint(tStub, tokenReq, "Acme", false), "string");
assert.equal(typeof getWebSessionCredentialHint(tStub, cookieReq, "Acme", true), "string");
});
test("getWebSessionCredentialCheckLabel returns a non-empty string", () => {
assert.ok(getWebSessionCredentialCheckLabel(tStub, tokenReq).length > 0);
assert.ok(getWebSessionCredentialCheckLabel(tStub, cookieReq).length > 0);
});
test("getAddCredentialModalTitle handles null/none/token/cookie requirements", () => {
assert.ok(getAddCredentialModalTitle(tStub, "Acme", null).length > 0);
assert.ok(getAddCredentialModalTitle(tStub, "Acme", noneReq).length > 0);
assert.ok(getAddCredentialModalTitle(tStub, "Acme", tokenReq).length > 0);
assert.ok(getAddCredentialModalTitle(tStub, "Acme", cookieReq).length > 0);
});
test("upstreamHeadersRecordsEqual is order-insensitive and correct", () => {
assert.ok(upstreamHeadersRecordsEqual({ a: "1", b: "2" }, { b: "2", a: "1" }));
assert.ok(!upstreamHeadersRecordsEqual({ a: "1" }, { a: "2" }));
assert.ok(!upstreamHeadersRecordsEqual({ a: "1" }, { a: "1", b: "2" }));
assert.equal(UPSTREAM_HEADERS_UI_MAX, 16);
});
test("headerRowsToRecord filters blank name rows and builds record", () => {
const rows: HeaderDraftRow[] = [
{ id: "1", name: "X-Foo", value: "bar" },
{ id: "2", name: " ", value: "ignored" },
{ id: "3", name: "X-Baz", value: "qux" },
];
assert.deepEqual(headerRowsToRecord(rows), { "X-Foo": "bar", "X-Baz": "qux" });
});
test("effectiveUpstreamHeadersForProtocol merges base and protocol-specific headers", () => {
const row: CompatModelRow = {
id: "m1",
upstreamHeaders: { "X-Base": "base" },
compatByProtocol: { openai: { upstreamHeaders: { "X-Proto": "proto" } } },
};
const customMap: CompatModelMap = new Map([["m1", row]]);
const overrideMap: CompatModelMap = new Map();
const result = effectiveUpstreamHeadersForProtocol("m1", "openai", customMap, overrideMap);
assert.equal(result["X-Base"], "base");
assert.equal(result["X-Proto"], "proto");
});
test("anyUpstreamHeadersBadge detects non-empty upstream headers", () => {
const row: CompatModelRow = { id: "m1", upstreamHeaders: { "X-Foo": "bar" } };
const customMap: CompatModelMap = new Map([["m1", row]]);
const overrideMap: CompatModelMap = new Map();
assert.ok(anyUpstreamHeadersBadge("m1", customMap, overrideMap));
const emptyRow: CompatModelRow = { id: "m2", upstreamHeaders: {} };
const emptyMap: CompatModelMap = new Map([["m2", emptyRow]]);
assert.ok(!anyUpstreamHeadersBadge("m2", emptyMap, new Map()));
});
test("getProtoSlice returns custom compat over override", () => {
const custom: CompatModelRow = {
compatByProtocol: { openai: { normalizeToolCallId: true } },
};
const override: CompatModelRow = {
compatByProtocol: { openai: { normalizeToolCallId: false } },
};
const result = getProtoSlice(custom, override, "openai");
assert.equal(result?.normalizeToolCallId, true);
});
test("CODEX_REASONING_STRENGTH_OPTIONS has expected values", () => {
const values = CODEX_REASONING_STRENGTH_OPTIONS.map((o) => o.value);
assert.ok(values.includes("none"));
assert.ok(values.includes("high"));
});
test("CODEX_ACCOUNT_SERVICE_TIER_VALUES contains expected tiers", () => {
assert.ok(CODEX_ACCOUNT_SERVICE_TIER_VALUES.includes("default"));
assert.ok(CODEX_ACCOUNT_SERVICE_TIER_VALUES.includes("flex"));
});
test("CODEX_GLOBAL_SERVICE_MODE_VALUES starts with none", () => {
assert.equal(CODEX_GLOBAL_SERVICE_MODE_VALUES[0], "none");
assert.ok(CODEX_GLOBAL_SERVICE_MODE_VALUES.includes("priority"));
});
test("getCodexServiceTierLabel returns a string for every mode (transitive import guard)", () => {
for (const mode of CODEX_GLOBAL_SERVICE_MODE_VALUES) {
assert.equal(typeof getCodexServiceTierLabel(tStub, mode), "string");
}
});
test("normalizeCodexLimitPolicy defaults use5h and useWeekly to true", () => {
assert.deepEqual(normalizeCodexLimitPolicy(null), { use5h: true, useWeekly: true });
assert.deepEqual(normalizeCodexLimitPolicy({ use5h: false }), { use5h: false, useWeekly: true });
});
test("getCodexRequestDefaults returns reasoningEffort (transitive import guard)", () => {
const result = getCodexRequestDefaults(null);
assert.equal(typeof result.reasoningEffort, "string");
});
test("getClaudeCodeCompatibleRequestDefaults returns CC-compatible booleans", () => {
const result = getClaudeCodeCompatibleRequestDefaults(null);
assert.equal(typeof result.context1m, "boolean");
assert.equal(typeof result.redactThinking, "boolean");
assert.equal(typeof result.summarizeThinking, "boolean");
});
test("compatProtocolLabelKey maps protocol strings to i18n keys", () => {
assert.equal(compatProtocolLabelKey("openai"), "compatProtocolOpenAI");
assert.equal(compatProtocolLabelKey("claude"), "compatProtocolClaude");
assert.equal(compatProtocolLabelKey("unknown"), "compatProtocolOpenAI");
});
test("extractCommandCodeCredentialInput extracts from JSON/URL/raw (transitive import guard)", () => {
assert.equal(extractCommandCodeCredentialInput(" "), "");
assert.equal(extractCommandCodeCredentialInput("rawtoken"), "rawtoken");
assert.equal(extractCommandCodeCredentialInput(JSON.stringify({ apiKey: "abc123" })), "abc123");
});
test("normalizeAndValidateHttpBaseUrl validates http/https URLs", () => {
const ok = normalizeAndValidateHttpBaseUrl("https://api.example.com/v1", "");
assert.equal(ok.error, null);
assert.equal(ok.value, "https://api.example.com/v1");
const bad = normalizeAndValidateHttpBaseUrl("ftp://nope.com", "");
assert.ok(bad.error !== null);
const invalid = normalizeAndValidateHttpBaseUrl("not-a-url", "");
assert.ok(invalid.error !== null);
});
test("SILICONFLOW_ENDPOINTS has global and china entries", () => {
const ids = SILICONFLOW_ENDPOINTS.map((e) => e.id);
assert.ok(ids.includes("siliconflow"));
assert.ok(ids.includes("siliconflow-cn"));
});