forked from openclaw/openclaw
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig-schema.test.ts
More file actions
155 lines (140 loc) · 4.68 KB
/
Copy pathconfig-schema.test.ts
File metadata and controls
155 lines (140 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import { describe, expect, it, vi } from "vitest";
import { z } from "zod";
import {
buildJsonPluginConfigSchema,
buildPluginConfigSchema,
emptyPluginConfigSchema,
} from "./config-schema.js";
function expectSafeParseCases(
safeParse: ((value: unknown) => unknown) | undefined,
cases: ReadonlyArray<readonly [unknown, unknown]>,
) {
if (safeParse === undefined) {
throw new Error("expected config schema safeParse function");
}
expect(cases.map(([value]) => safeParse(value))).toEqual(cases.map(([, expected]) => expected));
}
function expectJsonSchema(
result: ReturnType<typeof buildPluginConfigSchema>,
expected: Record<string, unknown>,
) {
expect(result.jsonSchema).toEqual(expected);
}
describe("buildPluginConfigSchema", () => {
it("builds json schema when toJSONSchema is available", () => {
const schema = z.strictObject({ enabled: z.boolean().default(true) });
const result = buildPluginConfigSchema(schema);
expectJsonSchema(result, {
type: "object",
additionalProperties: false,
properties: { enabled: { type: "boolean", default: true } },
});
});
it("uses input mode and strips helper-only draft metadata", () => {
const toJSONSchema = vi.fn(() => ({
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
propertyNames: { type: "string" },
required: [],
properties: {
enabled: { type: "boolean", default: true },
},
}));
const schema = { toJSONSchema } as unknown as Parameters<typeof buildPluginConfigSchema>[0];
const result = buildPluginConfigSchema(schema);
expect(toJSONSchema).toHaveBeenCalledWith({
target: "draft-07",
io: "input",
unrepresentable: "any",
});
expect(result.jsonSchema).toEqual({
type: "object",
properties: {
enabled: { type: "boolean", default: true },
},
});
});
it("falls back when toJSONSchema is missing", () => {
const legacySchema = {} as unknown as Parameters<typeof buildPluginConfigSchema>[0];
const result = buildPluginConfigSchema(legacySchema);
expectJsonSchema(result, { type: "object", additionalProperties: true });
});
it("uses zod runtime parsing by default", () => {
const result = buildPluginConfigSchema(z.strictObject({ enabled: z.boolean().default(true) }));
expect(result.safeParse?.({})).toEqual({
success: true,
data: { enabled: true },
});
});
it("allows custom safeParse overrides", () => {
const safeParse = vi.fn(() => ({ success: true as const, data: { normalized: true } }));
const result = buildPluginConfigSchema(z.strictObject({ enabled: z.boolean().optional() }), {
safeParse,
});
expect(result.safeParse?.({ enabled: false })).toEqual({
success: true,
data: { normalized: true },
});
expect(safeParse).toHaveBeenCalledWith({ enabled: false });
});
});
describe("buildJsonPluginConfigSchema", () => {
it("validates direct JSON schemas without zod conversion", () => {
const result = buildJsonPluginConfigSchema(
{
type: "object",
additionalProperties: false,
properties: {
enabled: { type: "boolean", default: true },
},
},
{ cacheKey: "config-schema.test.json-plugin" },
);
expect(result.jsonSchema).toEqual({
type: "object",
additionalProperties: false,
properties: {
enabled: { type: "boolean", default: true },
},
});
expect(result.safeParse?.({})).toEqual({
success: true,
data: { enabled: true },
});
expect(result.safeParse?.({ enabled: "yes" })).toEqual({
success: false,
error: { issues: [{ path: ["enabled"], message: "must be boolean" }] },
});
});
it("keeps numeric-looking object keys outside array-index range as strings", () => {
const result = buildJsonPluginConfigSchema(
{
type: "object",
required: ["100001"],
properties: {
"100001": { type: "boolean" },
},
},
{ cacheKey: "config-schema.test.large-numeric-key" },
);
expect(result.safeParse?.({})).toEqual({
success: false,
error: {
issues: [{ path: ["100001"], message: "must have required property '100001'" }],
},
});
});
});
describe("emptyPluginConfigSchema", () => {
it("accepts undefined and empty objects only", () => {
const schema = emptyPluginConfigSchema();
expectSafeParseCases(schema.safeParse, [
[undefined, { success: true, data: undefined }],
[{}, { success: true, data: {} }],
[
{ nope: true },
{ success: false, error: { issues: [{ path: [], message: "config must be empty" }] } },
],
] as const);
});
});