|
1 | | -import { validateCustomMode } from "../CustomModesSchema" |
2 | | -import { ModeConfig } from "../../../shared/modes" |
3 | | -import { ZodError } from "zod" |
4 | | - |
5 | | -describe("CustomModesSchema", () => { |
6 | | - describe("validateCustomMode", () => { |
7 | | - test("accepts valid mode configuration", () => { |
8 | | - const validMode = { |
9 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
10 | | - name: "Test Mode", |
11 | | - roleDefinition: "Test role definition", |
12 | | - groups: ["read"] as const, |
13 | | - } satisfies ModeConfig |
14 | | - |
15 | | - expect(() => validateCustomMode(validMode)).not.toThrow() |
16 | | - }) |
17 | | - |
18 | | - test("accepts mode with multiple groups", () => { |
19 | | - const validMode = { |
20 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
21 | | - name: "Test Mode", |
22 | | - roleDefinition: "Test role definition", |
23 | | - groups: ["read", "edit", "browser"] as const, |
24 | | - } satisfies ModeConfig |
25 | | - |
26 | | - expect(() => validateCustomMode(validMode)).not.toThrow() |
27 | | - }) |
28 | | - |
29 | | - test("accepts mode with optional customInstructions", () => { |
30 | | - const validMode = { |
31 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
32 | | - name: "Test Mode", |
33 | | - roleDefinition: "Test role definition", |
34 | | - customInstructions: "Custom instructions", |
35 | | - groups: ["read"] as const, |
36 | | - } satisfies ModeConfig |
37 | | - |
38 | | - expect(() => validateCustomMode(validMode)).not.toThrow() |
39 | | - }) |
40 | | - |
41 | | - test("rejects missing required fields", () => { |
42 | | - const invalidModes = [ |
43 | | - {}, // All fields missing |
44 | | - { name: "Test" }, // Missing most fields |
45 | | - { |
46 | | - name: "Test", |
47 | | - roleDefinition: "Role", |
48 | | - }, // Missing slug and groups |
49 | | - ] |
50 | | - |
51 | | - invalidModes.forEach((invalidMode) => { |
52 | | - expect(() => validateCustomMode(invalidMode)).toThrow(ZodError) |
53 | | - }) |
54 | | - }) |
55 | | - |
56 | | - test("rejects invalid slug format", () => { |
57 | | - const invalidMode = { |
58 | | - slug: "not@a@valid@slug", |
59 | | - name: "Test Mode", |
60 | | - roleDefinition: "Test role definition", |
61 | | - groups: ["read"] as const, |
62 | | - } satisfies Omit<ModeConfig, "slug"> & { slug: string } |
| 1 | +import { CustomModeSchema } from "../CustomModesSchema" |
| 2 | + |
| 3 | +describe("CustomModeSchema", () => { |
| 4 | + it("validates a basic mode configuration", () => { |
| 5 | + const validMode = { |
| 6 | + slug: "test-mode", |
| 7 | + name: "Test Mode", |
| 8 | + roleDefinition: "Test role definition", |
| 9 | + groups: ["read", "browser"], |
| 10 | + } |
| 11 | + |
| 12 | + expect(() => CustomModeSchema.parse(validMode)).not.toThrow() |
| 13 | + }) |
63 | 14 |
|
64 | | - expect(() => validateCustomMode(invalidMode)).toThrow(ZodError) |
65 | | - expect(() => validateCustomMode(invalidMode)).toThrow("Slug must contain only letters numbers and dashes") |
66 | | - }) |
| 15 | + it("validates a mode with file restrictions", () => { |
| 16 | + const modeWithFileRestrictions = { |
| 17 | + slug: "markdown-editor", |
| 18 | + name: "Markdown Editor", |
| 19 | + roleDefinition: "Markdown editing mode", |
| 20 | + groups: ["read", ["edit", { fileRegex: "\\.md$" }], "browser"], |
| 21 | + } |
67 | 22 |
|
68 | | - test("rejects empty strings in required fields", () => { |
69 | | - const emptyNameMode = { |
70 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
71 | | - name: "", |
72 | | - roleDefinition: "Test role definition", |
73 | | - groups: ["read"] as const, |
74 | | - } satisfies ModeConfig |
| 23 | + expect(() => CustomModeSchema.parse(modeWithFileRestrictions)).not.toThrow() |
| 24 | + }) |
75 | 25 |
|
76 | | - const emptyRoleMode = { |
77 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
78 | | - name: "Test Mode", |
79 | | - roleDefinition: "", |
80 | | - groups: ["read"] as const, |
81 | | - } satisfies ModeConfig |
| 26 | + it("validates file regex patterns", () => { |
| 27 | + const validPatterns = ["\\.md$", ".*\\.txt$", "[a-z]+\\.js$"] |
| 28 | + const invalidPatterns = ["[", "(unclosed", "\\"] |
82 | 29 |
|
83 | | - expect(() => validateCustomMode(emptyNameMode)).toThrow("Name is required") |
84 | | - expect(() => validateCustomMode(emptyRoleMode)).toThrow("Role definition is required") |
| 30 | + validPatterns.forEach((pattern) => { |
| 31 | + const mode = { |
| 32 | + slug: "test", |
| 33 | + name: "Test", |
| 34 | + roleDefinition: "Test", |
| 35 | + groups: ["read", ["edit", { fileRegex: pattern }]], |
| 36 | + } |
| 37 | + expect(() => CustomModeSchema.parse(mode)).not.toThrow() |
85 | 38 | }) |
86 | 39 |
|
87 | | - test("rejects invalid group configurations", () => { |
88 | | - const invalidGroupMode = { |
89 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
90 | | - name: "Test Mode", |
91 | | - roleDefinition: "Test role definition", |
92 | | - groups: ["not-a-valid-group"] as any, |
| 40 | + invalidPatterns.forEach((pattern) => { |
| 41 | + const mode = { |
| 42 | + slug: "test", |
| 43 | + name: "Test", |
| 44 | + roleDefinition: "Test", |
| 45 | + groups: ["read", ["edit", { fileRegex: pattern }]], |
93 | 46 | } |
94 | | - |
95 | | - expect(() => validateCustomMode(invalidGroupMode)).toThrow(ZodError) |
| 47 | + expect(() => CustomModeSchema.parse(mode)).toThrow() |
96 | 48 | }) |
| 49 | + }) |
97 | 50 |
|
98 | | - test("rejects empty groups array", () => { |
99 | | - const invalidMode = { |
100 | | - slug: "123e4567-e89b-12d3-a456-426614174000", |
101 | | - name: "Test Mode", |
102 | | - roleDefinition: "Test role definition", |
103 | | - groups: [] as const, |
104 | | - } satisfies ModeConfig |
105 | | - |
106 | | - expect(() => validateCustomMode(invalidMode)).toThrow("At least one tool group is required") |
107 | | - }) |
| 51 | + it("prevents duplicate groups", () => { |
| 52 | + const modeWithDuplicates = { |
| 53 | + slug: "test", |
| 54 | + name: "Test", |
| 55 | + roleDefinition: "Test", |
| 56 | + groups: ["read", "read", ["edit", { fileRegex: "\\.md$" }], ["edit", { fileRegex: "\\.txt$" }]], |
| 57 | + } |
108 | 58 |
|
109 | | - test("handles null and undefined gracefully", () => { |
110 | | - expect(() => validateCustomMode(null)).toThrow(ZodError) |
111 | | - expect(() => validateCustomMode(undefined)).toThrow(ZodError) |
112 | | - }) |
| 59 | + expect(() => CustomModeSchema.parse(modeWithDuplicates)).toThrow(/Duplicate groups/) |
| 60 | + }) |
113 | 61 |
|
114 | | - test("rejects non-object inputs", () => { |
115 | | - const invalidInputs = [42, "string", true, [], () => {}] |
| 62 | + it("requires at least one group", () => { |
| 63 | + const modeWithNoGroups = { |
| 64 | + slug: "test", |
| 65 | + name: "Test", |
| 66 | + roleDefinition: "Test", |
| 67 | + groups: [], |
| 68 | + } |
116 | 69 |
|
117 | | - invalidInputs.forEach((input) => { |
118 | | - expect(() => validateCustomMode(input)).toThrow(ZodError) |
119 | | - }) |
120 | | - }) |
| 70 | + expect(() => CustomModeSchema.parse(modeWithNoGroups)).toThrow(/At least one tool group is required/) |
121 | 71 | }) |
122 | 72 | }) |
0 commit comments