cc33b2a813
Co-authored-by: ayattara <alassane.yattara@savoirfairelinux.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
169 lines
5.3 KiB
TypeScript
169 lines
5.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
SECRET_MASK,
|
|
buildInitialValues,
|
|
missingRequiredFields,
|
|
parseConfigSchema,
|
|
serializeConfigValues,
|
|
} from "./config-schema";
|
|
|
|
const githubSchema = {
|
|
type: "object",
|
|
required: ["github_token"],
|
|
properties: {
|
|
github_token: {
|
|
type: "string",
|
|
title: "Personal access token",
|
|
description: "Fine-grained PAT with repo scope.",
|
|
secret: true,
|
|
},
|
|
webhook_key: { type: "string", format: "password" },
|
|
org: { type: "string" },
|
|
max_items: { type: "integer", default: 25 },
|
|
channel: { type: "string", enum: ["dev", "ops"] },
|
|
verbose: { type: "boolean", default: true },
|
|
},
|
|
} satisfies Record<string, unknown>;
|
|
|
|
describe("parseConfigSchema", () => {
|
|
it("maps properties to fields with titles, requiredness, and secrecy", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
const byName = Object.fromEntries(fields.map((f) => [f.name, f]));
|
|
|
|
expect(fields).toHaveLength(6);
|
|
expect(byName.github_token).toMatchObject({
|
|
type: "string",
|
|
label: "Personal access token",
|
|
description: "Fine-grained PAT with repo scope.",
|
|
required: true,
|
|
secret: true,
|
|
});
|
|
expect(byName.webhook_key.secret).toBe(true);
|
|
expect(byName.org).toMatchObject({ label: "org", required: false, secret: false });
|
|
expect(byName.max_items).toMatchObject({ type: "integer", defaultValue: 25 });
|
|
expect(byName.channel).toMatchObject({ type: "enum", enumValues: ["dev", "ops"] });
|
|
expect(byName.verbose.type).toBe("boolean");
|
|
});
|
|
|
|
it("returns [] for missing or unusable schemas", () => {
|
|
expect(parseConfigSchema(undefined)).toEqual([]);
|
|
expect(parseConfigSchema({})).toEqual([]);
|
|
expect(parseConfigSchema({ properties: "nope" })).toEqual([]);
|
|
});
|
|
|
|
it("maps the utility-agent format to a utility agent picker field", () => {
|
|
const fields = parseConfigSchema({
|
|
type: "object",
|
|
required: ["utility_agent"],
|
|
properties: {
|
|
utility_agent: {
|
|
type: "string",
|
|
format: "utility-agent",
|
|
title: "Utility agent",
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(fields).toEqual([
|
|
expect.objectContaining({
|
|
name: "utility_agent",
|
|
type: "utility_agent",
|
|
label: "Utility agent",
|
|
required: true,
|
|
}),
|
|
]);
|
|
});
|
|
|
|
it("maps the agent-profile format to a direct profile picker field", () => {
|
|
const fields = parseConfigSchema({
|
|
type: "object",
|
|
required: ["agent_profile"],
|
|
properties: {
|
|
agent_profile: {
|
|
type: "string",
|
|
format: "agent-profile",
|
|
title: "Notes agent",
|
|
},
|
|
},
|
|
});
|
|
|
|
expect(fields).toEqual([
|
|
expect.objectContaining({
|
|
name: "agent_profile",
|
|
type: "agent_profile",
|
|
label: "Notes agent",
|
|
required: true,
|
|
}),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("buildInitialValues", () => {
|
|
it("prefers stored config, then defaults, then empties", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
const values = buildInitialValues(fields, { github_token: SECRET_MASK, org: "kdlbs" });
|
|
|
|
expect(values.github_token).toBe(SECRET_MASK);
|
|
expect(values.org).toBe("kdlbs");
|
|
expect(values.max_items).toBe("25");
|
|
expect(values.verbose).toBe(true);
|
|
expect(values.channel).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("serializeConfigValues", () => {
|
|
it("parses numerics, keeps booleans, and drops empty strings", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
const config = serializeConfigValues(fields, {
|
|
github_token: SECRET_MASK,
|
|
webhook_key: "",
|
|
org: "kdlbs",
|
|
max_items: "10",
|
|
channel: "",
|
|
verbose: false,
|
|
});
|
|
|
|
expect(config).toEqual({
|
|
github_token: SECRET_MASK,
|
|
org: "kdlbs",
|
|
max_items: 10,
|
|
verbose: false,
|
|
});
|
|
});
|
|
|
|
it("omits unparseable numeric input", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
const config = serializeConfigValues(fields, { max_items: "abc", verbose: true });
|
|
expect(config).not.toHaveProperty("max_items");
|
|
});
|
|
|
|
it("rejects (omits) non-integral input for integer fields instead of truncating", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
// parseInt would silently turn "1.5" into 1 — the field must be omitted
|
|
// so the operator is told rather than getting a corrupted value.
|
|
const config = serializeConfigValues(fields, { max_items: "1.5", verbose: true });
|
|
expect(config).not.toHaveProperty("max_items");
|
|
expect(
|
|
serializeConfigValues(fields, { max_items: "Infinity", verbose: true }),
|
|
).not.toHaveProperty("max_items");
|
|
});
|
|
|
|
it("submits numeric enum selections with their original type", () => {
|
|
const fields = parseConfigSchema({
|
|
properties: { level: { type: "integer", enum: [1, 2, 3] } },
|
|
});
|
|
const config = serializeConfigValues(fields, { level: "2" });
|
|
expect(config.level).toBe(2);
|
|
});
|
|
});
|
|
|
|
describe("missingRequiredFields", () => {
|
|
it("flags blank required fields and accepts the secret mask as set", () => {
|
|
const fields = parseConfigSchema(githubSchema);
|
|
|
|
expect(missingRequiredFields(fields, { github_token: "" })).toEqual(["Personal access token"]);
|
|
expect(missingRequiredFields(fields, { github_token: SECRET_MASK })).toEqual([]);
|
|
expect(missingRequiredFields(fields, { github_token: "ghp_x" })).toEqual([]);
|
|
});
|
|
});
|