124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
assertPlainJsonValue,
|
|
DEFAULT_PLAIN_JSON_LIMITS,
|
|
} from "../../lib/server/validation/plainJson";
|
|
import {
|
|
createFlowStateSchema,
|
|
publishRuleBodySchema,
|
|
putDraftBodySchema,
|
|
} from "../../lib/server/validation/createFlowSchemas";
|
|
|
|
describe("assertPlainJsonValue", () => {
|
|
it("accepts plain JSON structures", () => {
|
|
expect(
|
|
assertPlainJsonValue(
|
|
{ a: [1, "x", { b: null }], c: true },
|
|
0,
|
|
DEFAULT_PLAIN_JSON_LIMITS,
|
|
),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("rejects __proto__ keys", () => {
|
|
const obj = JSON.parse('{"__proto__": {"x": 1}}') as Record<
|
|
string,
|
|
unknown
|
|
>;
|
|
expect(assertPlainJsonValue(obj, 0, DEFAULT_PLAIN_JSON_LIMITS)).toBe(
|
|
"Unsafe object key",
|
|
);
|
|
});
|
|
|
|
it("rejects non-finite numbers", () => {
|
|
expect(assertPlainJsonValue(Number.NaN, 0, DEFAULT_PLAIN_JSON_LIMITS)).toBe(
|
|
"Invalid number value",
|
|
);
|
|
});
|
|
|
|
it("rejects excessive depth", () => {
|
|
let v: unknown = 1;
|
|
for (let i = 0; i < 50; i++) {
|
|
v = { x: v };
|
|
}
|
|
expect(assertPlainJsonValue(v, 0, DEFAULT_PLAIN_JSON_LIMITS)).toBe(
|
|
"Maximum nesting depth exceeded",
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("createFlowStateSchema", () => {
|
|
it("accepts empty object", () => {
|
|
const r = createFlowStateSchema.safeParse({});
|
|
expect(r.success).toBe(true);
|
|
});
|
|
|
|
it("accepts known fields and passthrough keys", () => {
|
|
const r = createFlowStateSchema.safeParse({
|
|
title: "My rule",
|
|
currentStep: "cards",
|
|
customField: { nested: [1, 2] },
|
|
});
|
|
expect(r.success).toBe(true);
|
|
});
|
|
|
|
it("rejects invalid currentStep", () => {
|
|
const r = createFlowStateSchema.safeParse({ currentStep: "not-a-step" });
|
|
expect(r.success).toBe(false);
|
|
});
|
|
|
|
it("rejects title that is too long", () => {
|
|
const r = createFlowStateSchema.safeParse({ title: "x".repeat(600) });
|
|
expect(r.success).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("putDraftBodySchema", () => {
|
|
it("requires payload object", () => {
|
|
expect(putDraftBodySchema.safeParse({}).success).toBe(false);
|
|
expect(putDraftBodySchema.safeParse({ payload: {} }).success).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("publishRuleBodySchema", () => {
|
|
it("accepts minimal valid body", () => {
|
|
const r = publishRuleBodySchema.safeParse({
|
|
title: " Hello ",
|
|
document: { body: "text" },
|
|
});
|
|
expect(r.success).toBe(true);
|
|
if (r.success) {
|
|
expect(r.data.title).toBe("Hello");
|
|
expect(r.data.summary).toBeNull();
|
|
}
|
|
});
|
|
|
|
it("trims summary and maps empty to null", () => {
|
|
const r = publishRuleBodySchema.safeParse({
|
|
title: "T",
|
|
summary: " ",
|
|
document: {},
|
|
});
|
|
expect(r.success).toBe(true);
|
|
if (r.success) {
|
|
expect(r.data.summary).toBeNull();
|
|
}
|
|
});
|
|
|
|
it("rejects empty title", () => {
|
|
const r = publishRuleBodySchema.safeParse({
|
|
title: " ",
|
|
document: {},
|
|
});
|
|
expect(r.success).toBe(false);
|
|
});
|
|
|
|
it("rejects non-object document", () => {
|
|
const r = publishRuleBodySchema.safeParse({
|
|
title: "Ok",
|
|
document: "nope",
|
|
});
|
|
expect(r.success).toBe(false);
|
|
});
|
|
});
|