Files
OmniRoute/tests/unit/paid-model-target-6540.test.ts
Diego Rodrigues de Sa e Souza 8143d8e3a6 feat: replace free-text model inputs with hidePaid-aware Selects (#6540) (#7229)
* feat(dashboard): replace free-text model inputs with hidePaid-aware Selects (#6540)

Swap RoutingTab.webSearchRouteModel, ComboDefaultsTab.handoffModel, and
BackgroundDegradationTab's from/to fields from free-text inputs to a new
shared ModelSelectField fed by the already hidePaidModels-aware
GET /api/models, with an off-catalog "(custom)" fallback so an existing
saved value is never silently dropped. ModelRoutingSection's glob pattern
field gets a fail-open "matches only paid models" warning instead, since
it's a wildcard matcher rather than a single model id.

Adds save-time paid-target rejection (PAID_MODEL_TARGET_BLOCKED, 400) on
PATCH /api/settings, PATCH /api/settings/combo-defaults, and PUT
/api/settings/background-degradation when hidePaidModels is on, failing
open for aliases/combo names/unrecognized providers.

globToRegex is extracted from lib/db/modelComboMappings.ts into a new
dependency-free shared/utils/globPattern.ts so both the DB module and the
new client-side pattern heuristic reuse the same regex-building logic.

* refactor(6540): extract paid-target guard in background-degradation PUT

The inline hidePaid check nested if>if>for>if inside the PUT handler,
pushing its cognitive complexity to 16 (>15) — a NEW violation that broke
the check:complexity-ratchets gate (891 > baseline 890). Extracted the
check into a module-local hasBlockedPaidTarget() helper; behaviour and
response body are unchanged. cognitive-complexity back to 890 = baseline.

* fix(i18n): mirror paidModelPatternWarning into pt-BR.json (#6540)

The new key landed only in en.json; the i18n pt-BR integrity test
(no drift, #6695) requires pt-BR.json to carry every en.json key.
2026-07-17 10:40:18 -03:00

46 lines
1.8 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { isPaidModelTarget, matchesOnlyPaidModels } from "@/shared/utils/freeModels";
test("isPaidModelTarget — documented free model → 'free'", () => {
assert.equal(isPaidModelTarget("openrouter/auto"), "free");
});
test("isPaidModelTarget — provider in free catalog but model not listed free → 'paid'", () => {
assert.equal(isPaidModelTarget("together/Qwen/Qwen3-235B-A22B"), "paid");
});
test("isPaidModelTarget — no separator (combo/alias name) → 'unknown' (fail open)", () => {
assert.equal(isPaidModelTarget("my-combo-name"), "unknown");
});
test("isPaidModelTarget — provider not in free catalog at all → 'unknown' (fail open)", () => {
assert.equal(isPaidModelTarget("totally-unknown-provider/whatever"), "unknown");
});
test("isPaidModelTarget — comma-separated form matches slash form", () => {
assert.equal(isPaidModelTarget("openrouter,auto"), isPaidModelTarget("openrouter/auto"));
});
test("isPaidModelTarget — empty/non-string input → 'unknown'", () => {
assert.equal(isPaidModelTarget(""), "unknown");
// @ts-expect-error — exercising runtime guard against non-string input
assert.equal(isPaidModelTarget(undefined), "unknown");
});
test("matchesOnlyPaidModels — true when every match is paid", () => {
assert.equal(matchesOnlyPaidModels("together/*"), true);
});
test("matchesOnlyPaidModels — false when at least one match is free", () => {
assert.equal(matchesOnlyPaidModels("openrouter/*"), false);
});
test("matchesOnlyPaidModels — false (fail open) when there are zero matches", () => {
assert.equal(matchesOnlyPaidModels("zzz-totally-nonexistent-pattern-*"), false);
});
test("matchesOnlyPaidModels — false on empty pattern", () => {
assert.equal(matchesOnlyPaidModels(""), false);
});