Files
diegosouzapw--omniroute/tests/unit/ui/combo-form-deselect-handler.test.tsx
2026-07-13 13:39:12 +08:00

67 lines
2.8 KiB
TypeScript

// Pure unit test for the deselect filter semantics used by ComboFormModal in
// src/app/(dashboard)/dashboard/combos/page.tsx — ported from upstream PR
// decolua/9router#889 (Fajar Hidayat).
//
// The page-level handler removes every step whose qualified `model` matches
// the value sent from the ModelSelectModal, matching upstream JS behavior
// (`setModels(models.filter((m) => m !== model.value))`). Duplicates with
// different providerId/weight pointing at the same model id are all stripped.
import { describe, expect, it } from "vitest";
type Step = { model: string; providerId?: string; weight?: number };
// Mirror of src/app/(dashboard)/dashboard/combos/page.tsx::handleDeselectModel.
// Kept in lockstep so the same filter behavior is checked here, leaf-only.
function deselectModel(models: Step[], model: { value?: string } | string): Step[] {
const value =
typeof (model as any)?.value === "string"
? (model as any).value
: typeof model === "string"
? model
: "";
if (!value) return models;
return models.filter((m) => m.model !== value);
}
describe("ComboFormModal deselect handler (upstream PR #889)", () => {
it("removes the single matching step when called with { value }", () => {
const models: Step[] = [
{ model: "openai/gpt-4o", weight: 50 },
{ model: "anthropic/claude-3-5-sonnet", weight: 50 },
];
const next = deselectModel(models, { value: "openai/gpt-4o" });
expect(next).toEqual([{ model: "anthropic/claude-3-5-sonnet", weight: 50 }]);
});
it("strips every duplicate of the same qualified model", () => {
const models: Step[] = [
{ model: "openai/gpt-4o", providerId: "openai-a", weight: 30 },
{ model: "openai/gpt-4o", providerId: "openai-b", weight: 70 },
{ model: "anthropic/claude-3-5-sonnet", weight: 0 },
];
const next = deselectModel(models, { value: "openai/gpt-4o" });
expect(next).toEqual([{ model: "anthropic/claude-3-5-sonnet", weight: 0 }]);
});
it("is a no-op when the value is not in the list", () => {
const models: Step[] = [{ model: "openai/gpt-4o", weight: 100 }];
const next = deselectModel(models, { value: "openai/gpt-3.5" });
expect(next).toEqual(models);
});
it("is a no-op for empty/missing value (defensive guard)", () => {
const models: Step[] = [{ model: "openai/gpt-4o", weight: 100 }];
expect(deselectModel(models, { value: "" })).toEqual(models);
expect(deselectModel(models, {})).toEqual(models);
});
it("accepts a raw string model identifier (legacy upstream call shape)", () => {
const models: Step[] = [
{ model: "openai/gpt-4o", weight: 50 },
{ model: "anthropic/claude-3-5-sonnet", weight: 50 },
];
const next = deselectModel(models, "openai/gpt-4o");
expect(next).toEqual([{ model: "anthropic/claude-3-5-sonnet", weight: 50 }]);
});
});