|
1 | 1 | import { describe, it, expect, beforeEach } from 'vitest'; |
2 | 2 | import { z } from 'zod'; |
3 | 3 | import { createMockExecutor } from '../../../../test-utils/mock-executors.ts'; |
| 4 | +import { sessionStore } from '../../../../utils/session-store.ts'; |
4 | 5 |
|
5 | 6 | // Import the plugin and logic function |
6 | 7 | import buildSim, { build_simLogic } from '../build_sim.ts'; |
7 | 8 |
|
8 | 9 | describe('build_sim tool', () => { |
9 | | - // Only clear any remaining mocks if needed |
| 10 | + beforeEach(() => { |
| 11 | + sessionStore.clear(); |
| 12 | + }); |
10 | 13 |
|
11 | 14 | describe('Export Field Validation (Literal)', () => { |
12 | 15 | it('should have correct name', () => { |
13 | 16 | expect(buildSim.name).toBe('build_sim'); |
14 | 17 | }); |
15 | 18 |
|
16 | 19 | it('should have correct description', () => { |
17 | | - expect(buildSim.description).toBe( |
18 | | - "Builds an app from a project or workspace for a specific simulator by UUID or name. Provide exactly one of projectPath or workspacePath, and exactly one of simulatorId or simulatorName. IMPORTANT: Requires either projectPath or workspacePath, plus scheme and either simulatorId or simulatorName. Example: build_sim({ projectPath: '/path/to/MyProject.xcodeproj', scheme: 'MyScheme', simulatorName: 'iPhone 16' })", |
19 | | - ); |
| 20 | + expect(buildSim.description).toBe('Builds an app for an iOS simulator.'); |
20 | 21 | }); |
21 | 22 |
|
22 | 23 | it('should have handler function', () => { |
23 | 24 | expect(typeof buildSim.handler).toBe('function'); |
24 | 25 | }); |
25 | 26 |
|
26 | | - it('should have correct schema with required and optional fields', () => { |
| 27 | + it('should have correct public schema (only non-session fields)', () => { |
27 | 28 | const schema = z.object(buildSim.schema); |
28 | 29 |
|
29 | | - // Valid inputs - workspace |
30 | | - expect( |
31 | | - schema.safeParse({ |
32 | | - workspacePath: '/path/to/workspace', |
33 | | - scheme: 'MyScheme', |
34 | | - simulatorName: 'iPhone 16', |
35 | | - }).success, |
36 | | - ).toBe(true); |
| 30 | + // Public schema should allow empty input |
| 31 | + expect(schema.safeParse({}).success).toBe(true); |
37 | 32 |
|
38 | | - // Valid inputs - project |
| 33 | + // Valid public inputs |
39 | 34 | expect( |
40 | 35 | schema.safeParse({ |
41 | | - projectPath: '/path/to/project.xcodeproj', |
42 | | - scheme: 'MyScheme', |
43 | | - simulatorName: 'iPhone 16', |
44 | | - }).success, |
45 | | - ).toBe(true); |
46 | | - |
47 | | - expect( |
48 | | - schema.safeParse({ |
49 | | - workspacePath: '/path/to/workspace', |
50 | | - scheme: 'MyScheme', |
51 | | - simulatorName: 'iPhone 16', |
52 | | - configuration: 'Release', |
53 | 36 | derivedDataPath: '/path/to/derived', |
54 | 37 | extraArgs: ['--verbose'], |
55 | | - useLatestOS: true, |
56 | 38 | preferXcodebuild: false, |
57 | 39 | }).success, |
58 | 40 | ).toBe(true); |
59 | 41 |
|
60 | | - // Invalid inputs - missing required fields |
61 | | - // Note: simulatorId/simulatorName are optional at schema level, XOR validation at runtime |
62 | | - expect( |
63 | | - schema.safeParse({ |
64 | | - workspacePath: '/path/to/workspace', |
65 | | - scheme: 'MyScheme', |
66 | | - }).success, |
67 | | - ).toBe(true); // Schema validation passes, runtime XOR validation would catch missing simulator fields |
68 | | - |
69 | | - expect( |
70 | | - schema.safeParse({ |
71 | | - workspacePath: '/path/to/workspace', |
72 | | - simulatorName: 'iPhone 16', |
73 | | - }).success, |
74 | | - ).toBe(false); |
75 | | - |
76 | | - expect( |
77 | | - schema.safeParse({ |
78 | | - scheme: 'MyScheme', |
79 | | - simulatorName: 'iPhone 16', |
80 | | - }).success, |
81 | | - ).toBe(true); // Base schema allows both fields optional, XOR validation happens at handler level |
82 | | - |
83 | | - // Invalid types |
84 | | - expect( |
85 | | - schema.safeParse({ |
86 | | - workspacePath: 123, |
87 | | - scheme: 'MyScheme', |
88 | | - simulatorName: 'iPhone 16', |
89 | | - }).success, |
90 | | - ).toBe(false); |
91 | | - |
92 | | - expect( |
93 | | - schema.safeParse({ |
94 | | - workspacePath: '/path/to/workspace', |
95 | | - scheme: 123, |
96 | | - simulatorName: 'iPhone 16', |
97 | | - }).success, |
98 | | - ).toBe(false); |
99 | | - |
100 | | - expect( |
101 | | - schema.safeParse({ |
102 | | - workspacePath: '/path/to/workspace', |
103 | | - scheme: 'MyScheme', |
104 | | - simulatorName: 123, |
105 | | - }).success, |
106 | | - ).toBe(false); |
107 | | - }); |
108 | | - |
109 | | - it('should validate XOR constraint between projectPath and workspacePath', () => { |
110 | | - const schema = z.object(buildSim.schema); |
111 | | - |
112 | | - // Both projectPath and workspacePath provided - should be invalid |
113 | | - expect( |
114 | | - schema.safeParse({ |
115 | | - projectPath: '/path/to/project.xcodeproj', |
116 | | - workspacePath: '/path/to/workspace', |
117 | | - scheme: 'MyScheme', |
118 | | - simulatorName: 'iPhone 16', |
119 | | - }).success, |
120 | | - ).toBe(true); // Schema validation passes, but handler validation will catch this |
121 | | - |
122 | | - // Neither provided - should be invalid |
123 | | - expect( |
124 | | - schema.safeParse({ |
125 | | - scheme: 'MyScheme', |
126 | | - simulatorName: 'iPhone 16', |
127 | | - }).success, |
128 | | - ).toBe(true); // Schema validation passes, but handler validation will catch this |
| 42 | + // Invalid types on public inputs |
| 43 | + expect(schema.safeParse({ derivedDataPath: 123 }).success).toBe(false); |
| 44 | + expect(schema.safeParse({ extraArgs: [123] }).success).toBe(false); |
| 45 | + expect(schema.safeParse({ preferXcodebuild: 'yes' }).success).toBe(false); |
129 | 46 | }); |
130 | 47 | }); |
131 | 48 |
|
132 | 49 | describe('Parameter Validation', () => { |
133 | 50 | it('should handle missing both projectPath and workspacePath', async () => { |
134 | | - const mockExecutor = createMockExecutor({ success: true, output: 'Build succeeded' }); |
135 | | - |
136 | | - // Since we use XOR validation, this should fail at the handler level |
137 | 51 | const result = await buildSim.handler({ |
138 | 52 | scheme: 'MyScheme', |
139 | 53 | simulatorName: 'iPhone 16', |
140 | 54 | }); |
141 | 55 |
|
142 | 56 | expect(result.isError).toBe(true); |
143 | | - expect(result.content[0].text).toContain('Parameter validation failed'); |
144 | | - expect(result.content[0].text).toContain('Either projectPath or workspacePath is required'); |
| 57 | + expect(result.content[0].text).toContain('Missing required session defaults'); |
| 58 | + expect(result.content[0].text).toContain('Provide a project or workspace'); |
145 | 59 | }); |
146 | 60 |
|
147 | 61 | it('should handle both projectPath and workspacePath provided', async () => { |
148 | | - const mockExecutor = createMockExecutor({ success: true, output: 'Build succeeded' }); |
149 | | - |
150 | | - // Since we use XOR validation, this should fail at the handler level |
151 | 62 | const result = await buildSim.handler({ |
152 | 63 | projectPath: '/path/to/project.xcodeproj', |
153 | 64 | workspacePath: '/path/to/workspace', |
@@ -188,19 +99,14 @@ describe('build_sim tool', () => { |
188 | 99 | }); |
189 | 100 |
|
190 | 101 | it('should handle missing scheme parameter', async () => { |
191 | | - const mockExecutor = createMockExecutor({ success: true, output: 'Build succeeded' }); |
192 | | - |
193 | | - // Since we removed manual validation, this test now checks that Zod validation works |
194 | | - // by testing the typed tool handler through the default export |
195 | 102 | const result = await buildSim.handler({ |
196 | 103 | workspacePath: '/path/to/workspace', |
197 | 104 | simulatorName: 'iPhone 16', |
198 | 105 | }); |
199 | 106 |
|
200 | 107 | expect(result.isError).toBe(true); |
201 | | - expect(result.content[0].text).toContain('Parameter validation failed'); |
202 | | - expect(result.content[0].text).toContain('scheme'); |
203 | | - expect(result.content[0].text).toContain('Required'); |
| 108 | + expect(result.content[0].text).toContain('Missing required session defaults'); |
| 109 | + expect(result.content[0].text).toContain('scheme is required'); |
204 | 110 | }); |
205 | 111 |
|
206 | 112 | it('should handle empty scheme parameter', async () => { |
@@ -229,17 +135,14 @@ describe('build_sim tool', () => { |
229 | 135 | }); |
230 | 136 |
|
231 | 137 | it('should handle missing both simulatorId and simulatorName', async () => { |
232 | | - const mockExecutor = createMockExecutor({ success: true, output: 'Build succeeded' }); |
233 | | - |
234 | | - // Should fail with XOR validation |
235 | 138 | const result = await buildSim.handler({ |
236 | 139 | workspacePath: '/path/to/workspace', |
237 | 140 | scheme: 'MyScheme', |
238 | 141 | }); |
239 | 142 |
|
240 | 143 | expect(result.isError).toBe(true); |
241 | | - expect(result.content[0].text).toContain('Parameter validation failed'); |
242 | | - expect(result.content[0].text).toContain('Either simulatorId or simulatorName is required'); |
| 144 | + expect(result.content[0].text).toContain('Missing required session defaults'); |
| 145 | + expect(result.content[0].text).toContain('Provide simulatorId or simulatorName'); |
243 | 146 | }); |
244 | 147 |
|
245 | 148 | it('should handle both simulatorId and simulatorName provided', async () => { |
|
0 commit comments