opencode-swarm-plugin 0.12.25 → 0.12.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.beads/issues.jsonl +17 -0
- package/README.md +105 -0
- package/global-skills/agent-patterns/SKILL.md +682 -0
- package/global-skills/learning-systems/SKILL.md +644 -0
- package/global-skills/mcp-tool-authoring/SKILL.md +695 -0
- package/global-skills/resilience-patterns/SKILL.md +648 -0
- package/global-skills/tacit-knowledge-extraction/SKILL.md +387 -0
- package/global-skills/testing-strategies/SKILL.md +558 -0
- package/global-skills/zod-validation/SKILL.md +763 -0
- package/package.json +1 -1
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-strategies
|
|
3
|
+
description: Testing patterns for TypeScript/Bun projects with vitest. Use when writing unit tests, integration tests, or testing async/swarm operations. Covers mocking, test organization, fixtures, and testing MCP tools.
|
|
4
|
+
tags:
|
|
5
|
+
- testing
|
|
6
|
+
- vitest
|
|
7
|
+
- typescript
|
|
8
|
+
- integration
|
|
9
|
+
tools:
|
|
10
|
+
- Read
|
|
11
|
+
- Write
|
|
12
|
+
- Bash
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Testing Strategies
|
|
16
|
+
|
|
17
|
+
Testing patterns for TypeScript projects using vitest. Focused on unit tests, integration tests, and testing async/distributed operations.
|
|
18
|
+
|
|
19
|
+
## Test Organization
|
|
20
|
+
|
|
21
|
+
### File Naming
|
|
22
|
+
|
|
23
|
+
**Unit tests**: `*.test.ts` alongside source
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
src/
|
|
27
|
+
skills.ts
|
|
28
|
+
skills.test.ts
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Integration tests**: `*.integration.test.ts` with separate config
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
src/
|
|
35
|
+
swarm.ts
|
|
36
|
+
swarm.integration.test.ts
|
|
37
|
+
vitest.integration.config.ts
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Test Structure
|
|
41
|
+
|
|
42
|
+
Use `describe` blocks for logical grouping. Nest deeply when needed.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
describe("parseFrontmatter", () => {
|
|
46
|
+
it("parses valid frontmatter with all fields", () => {
|
|
47
|
+
const result = parseFrontmatter(VALID_SKILL_MD);
|
|
48
|
+
expect(result).not.toBeNull();
|
|
49
|
+
expect(result.metadata.name).toBe("test-skill");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns null for missing name value", () => {
|
|
53
|
+
const result = parseFrontmatter(INVALID_FRONTMATTER_MD);
|
|
54
|
+
expect(result.metadata.name).toBeNull();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Lifecycle Hooks
|
|
60
|
+
|
|
61
|
+
**beforeEach/afterEach**: Reset state between tests
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
describe("discoverSkills", () => {
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
cleanupTestSkillsDir();
|
|
67
|
+
setupTestSkillsDir();
|
|
68
|
+
invalidateSkillsCache(); // Clear caches!
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
cleanupTestSkillsDir();
|
|
73
|
+
invalidateSkillsCache();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**beforeAll/afterAll**: Setup/teardown shared resources
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
describe("swarm_status", () => {
|
|
82
|
+
let beadsAvailable = false;
|
|
83
|
+
|
|
84
|
+
beforeAll(async () => {
|
|
85
|
+
beadsAvailable = await isBeadsAvailable();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Vitest Basics
|
|
91
|
+
|
|
92
|
+
### Assertions
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// Equality
|
|
96
|
+
expect(result).toBe(expected);
|
|
97
|
+
expect(result).toEqual(expected); // Deep equality for objects
|
|
98
|
+
|
|
99
|
+
// Truthiness
|
|
100
|
+
expect(result).toBeTruthy();
|
|
101
|
+
expect(result).toBeFalsy();
|
|
102
|
+
expect(result).toBeDefined();
|
|
103
|
+
expect(result).toBeNull();
|
|
104
|
+
|
|
105
|
+
// Collections
|
|
106
|
+
expect(array).toContain(item);
|
|
107
|
+
expect(array).toHaveLength(3);
|
|
108
|
+
expect(object).toHaveProperty("key");
|
|
109
|
+
expect(object).toHaveProperty("key", "value");
|
|
110
|
+
|
|
111
|
+
// Strings
|
|
112
|
+
expect(string).toContain("substring");
|
|
113
|
+
expect(string).toMatch(/regex/);
|
|
114
|
+
|
|
115
|
+
// Numbers
|
|
116
|
+
expect(num).toBeGreaterThan(5);
|
|
117
|
+
expect(num).toBeGreaterThanOrEqual(5);
|
|
118
|
+
expect(num).toBeLessThan(10);
|
|
119
|
+
|
|
120
|
+
// Exceptions
|
|
121
|
+
expect(() => dangerousFn()).toThrow();
|
|
122
|
+
expect(() => dangerousFn()).toThrow("specific message");
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Conditional Tests
|
|
126
|
+
|
|
127
|
+
**Skip tests when dependencies unavailable**:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
it.skipIf(!agentMailAvailable)("reports progress to Agent Mail", async () => {
|
|
131
|
+
// Test that requires Agent Mail
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Only run specific tests**:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
it.only("focus on this test", () => {
|
|
139
|
+
// Only this test runs
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Test Fixtures
|
|
144
|
+
|
|
145
|
+
### Unique Temp Directories
|
|
146
|
+
|
|
147
|
+
Avoid collisions between test runs:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const TEST_RUN_ID = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
151
|
+
const TEST_DIR = join(process.cwd(), `.test-skills-${TEST_RUN_ID}`);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Setup/Teardown Helpers
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
function setupTestSkillsDir() {
|
|
158
|
+
mkdirSync(SKILLS_DIR, { recursive: true });
|
|
159
|
+
mkdirSync(join(SKILLS_DIR, "test-skill"), { recursive: true });
|
|
160
|
+
writeFileSync(join(SKILLS_DIR, "test-skill", "SKILL.md"), VALID_SKILL_MD);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function cleanupTestSkillsDir() {
|
|
164
|
+
if (existsSync(TEST_DIR)) {
|
|
165
|
+
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Fixture Constants
|
|
171
|
+
|
|
172
|
+
Keep test data at top of file for reuse:
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const VALID_SKILL_MD = `---
|
|
176
|
+
name: test-skill
|
|
177
|
+
description: A test skill for unit testing
|
|
178
|
+
tags:
|
|
179
|
+
- testing
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
# Test Skill
|
|
183
|
+
|
|
184
|
+
Content here.
|
|
185
|
+
`;
|
|
186
|
+
|
|
187
|
+
const MINIMAL_SKILL_MD = `---
|
|
188
|
+
name: minimal-skill
|
|
189
|
+
description: Minimal skill
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
Just the basics.
|
|
193
|
+
`;
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Mocking Patterns
|
|
197
|
+
|
|
198
|
+
### Mock External Services
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const mockContext = {
|
|
202
|
+
sessionID: `test-session-${Date.now()}`,
|
|
203
|
+
messageID: `test-message-${Date.now()}`,
|
|
204
|
+
agent: "test-agent",
|
|
205
|
+
abort: new AbortController().signal,
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Check Service Availability
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
async function isAgentMailAvailable(): Promise<boolean> {
|
|
213
|
+
try {
|
|
214
|
+
const url = process.env.AGENT_MAIL_URL || AGENT_MAIL_URL;
|
|
215
|
+
const response = await fetch(`${url}/health/liveness`);
|
|
216
|
+
return response.ok;
|
|
217
|
+
} catch {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function isBeadsAvailable(): Promise<boolean> {
|
|
223
|
+
try {
|
|
224
|
+
const result = await Bun.$`bd --version`.quiet().nothrow();
|
|
225
|
+
return result.exitCode === 0;
|
|
226
|
+
} catch {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Conditional Test Execution
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
describe("swarm_status (integration)", () => {
|
|
236
|
+
let beadsAvailable = false;
|
|
237
|
+
|
|
238
|
+
beforeAll(async () => {
|
|
239
|
+
beadsAvailable = await isBeadsAvailable();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it.skipIf(!beadsAvailable)("returns status for epic", async () => {
|
|
243
|
+
// Test logic
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Testing Async Operations
|
|
249
|
+
|
|
250
|
+
### Promises
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
it("generates valid decomposition prompt", async () => {
|
|
254
|
+
const result = await swarm_decompose.execute(
|
|
255
|
+
{
|
|
256
|
+
task: "Add user authentication",
|
|
257
|
+
max_subtasks: 3,
|
|
258
|
+
},
|
|
259
|
+
mockContext,
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
const parsed = JSON.parse(result);
|
|
263
|
+
expect(parsed).toHaveProperty("prompt");
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Error Handling
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
it("rejects invalid JSON", async () => {
|
|
271
|
+
const result = await swarm_validate_decomposition.execute(
|
|
272
|
+
{ response: "not valid json {" },
|
|
273
|
+
mockContext,
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const parsed = JSON.parse(result);
|
|
277
|
+
expect(parsed.valid).toBe(false);
|
|
278
|
+
expect(parsed.error).toContain("Invalid JSON");
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it("throws for non-existent epic", async () => {
|
|
282
|
+
try {
|
|
283
|
+
await swarm_status.execute(
|
|
284
|
+
{
|
|
285
|
+
epic_id: "bd-nonexistent",
|
|
286
|
+
project_key: TEST_PROJECT_PATH,
|
|
287
|
+
},
|
|
288
|
+
mockContext,
|
|
289
|
+
);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
expect(error).toBeInstanceOf(Error);
|
|
292
|
+
if (error instanceof Error && "operation" in error) {
|
|
293
|
+
expect((error as { operation: string }).operation).toBe("query_subtasks");
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## Testing Zod Schemas
|
|
300
|
+
|
|
301
|
+
### Valid Cases
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
it("validates a complete bead", () => {
|
|
305
|
+
const bead = {
|
|
306
|
+
id: "bd-abc123",
|
|
307
|
+
title: "Fix the thing",
|
|
308
|
+
type: "bug",
|
|
309
|
+
status: "open",
|
|
310
|
+
priority: 1,
|
|
311
|
+
created_at: "2025-01-01T00:00:00Z",
|
|
312
|
+
updated_at: "2025-01-01T00:00:00Z",
|
|
313
|
+
};
|
|
314
|
+
expect(() => BeadSchema.parse(bead)).not.toThrow();
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Invalid Cases
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
it("rejects invalid priority", () => {
|
|
322
|
+
const bead = {
|
|
323
|
+
id: "bd-abc123",
|
|
324
|
+
title: "Fix the thing",
|
|
325
|
+
type: "bug",
|
|
326
|
+
status: "open",
|
|
327
|
+
priority: 5, // Invalid: max is 3
|
|
328
|
+
created_at: "2025-01-01T00:00:00Z",
|
|
329
|
+
updated_at: "2025-01-01T00:00:00Z",
|
|
330
|
+
};
|
|
331
|
+
expect(() => BeadSchema.parse(bead)).toThrow();
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Enum Validation
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
it("accepts all valid types", () => {
|
|
339
|
+
const types = ["bug", "feature", "task", "epic", "chore"];
|
|
340
|
+
for (const type of types) {
|
|
341
|
+
expect(() => BeadTypeSchema.parse(type)).not.toThrow();
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Default Values
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
it("validates minimal create args with defaults", () => {
|
|
350
|
+
const args = { title: "New bead" };
|
|
351
|
+
const result = BeadCreateArgsSchema.parse(args);
|
|
352
|
+
expect(result.title).toBe("New bead");
|
|
353
|
+
expect(result.type).toBe("task"); // default
|
|
354
|
+
expect(result.priority).toBe(2); // default
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Integration Test Config
|
|
359
|
+
|
|
360
|
+
Create separate vitest config for integration tests:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// vitest.integration.config.ts
|
|
364
|
+
import { defineConfig } from "vitest/config";
|
|
365
|
+
|
|
366
|
+
export default defineConfig({
|
|
367
|
+
test: {
|
|
368
|
+
include: ["src/**/*.integration.test.ts"],
|
|
369
|
+
testTimeout: 30000, // Integration tests may be slower
|
|
370
|
+
hookTimeout: 30000,
|
|
371
|
+
// Run serially to avoid race conditions
|
|
372
|
+
sequence: {
|
|
373
|
+
concurrent: false,
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Run with:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
vitest --config vitest.integration.config.ts
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Testing MCP Tools
|
|
386
|
+
|
|
387
|
+
### Tool Execute Pattern
|
|
388
|
+
|
|
389
|
+
MCP tools implement `execute(args, context)`:
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const result = await swarm_decompose.execute(
|
|
393
|
+
{
|
|
394
|
+
task: "Add OAuth authentication",
|
|
395
|
+
max_subtasks: 3,
|
|
396
|
+
},
|
|
397
|
+
mockContext,
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
const parsed = JSON.parse(result);
|
|
401
|
+
expect(parsed).toHaveProperty("prompt");
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### JSON Output Validation
|
|
405
|
+
|
|
406
|
+
Many tools return JSON strings:
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
it("returns expected schema", async () => {
|
|
410
|
+
const result = await swarm_plan_prompt.execute(
|
|
411
|
+
{
|
|
412
|
+
task: "Some task",
|
|
413
|
+
max_subtasks: 5,
|
|
414
|
+
query_cass: false,
|
|
415
|
+
},
|
|
416
|
+
mockContext,
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
const parsed = JSON.parse(result);
|
|
420
|
+
expect(parsed).toHaveProperty("expected_schema", "BeadTree");
|
|
421
|
+
expect(parsed).toHaveProperty("validation_note");
|
|
422
|
+
expect(parsed.schema_hint).toHaveProperty("epic");
|
|
423
|
+
expect(parsed.schema_hint).toHaveProperty("subtasks");
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
## Edge Cases
|
|
428
|
+
|
|
429
|
+
Test boundary conditions:
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
describe("edge cases", () => {
|
|
433
|
+
it("handles non-existent directory gracefully", async () => {
|
|
434
|
+
setSkillsProjectDirectory("/non/existent/path");
|
|
435
|
+
invalidateSkillsCache();
|
|
436
|
+
|
|
437
|
+
const skills = await discoverSkills();
|
|
438
|
+
expect(skills instanceof Map).toBe(true);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it("handles empty skills directory", async () => {
|
|
442
|
+
mkdirSync(SKILLS_DIR, { recursive: true });
|
|
443
|
+
setSkillsProjectDirectory(TEST_DIR);
|
|
444
|
+
invalidateSkillsCache();
|
|
445
|
+
|
|
446
|
+
const skills = await discoverSkills();
|
|
447
|
+
expect(skills instanceof Map).toBe(true);
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
it("returns null for empty name", async () => {
|
|
451
|
+
const skill = await getSkill("");
|
|
452
|
+
expect(skill).toBeNull();
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## End-to-End Tests
|
|
458
|
+
|
|
459
|
+
Full workflow tests combining multiple operations:
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
it("creates epic, reports progress, completes subtask", async () => {
|
|
463
|
+
// 1. Setup
|
|
464
|
+
await mcpCall("ensure_project", { human_key: uniqueProjectKey });
|
|
465
|
+
const agent = await mcpCall("register_agent", {
|
|
466
|
+
project_key: uniqueProjectKey,
|
|
467
|
+
program: "opencode-test",
|
|
468
|
+
model: "test",
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// 2. Create epic
|
|
472
|
+
const epicResult = await Bun.$`bd create "Feature" -t epic --json`.quiet();
|
|
473
|
+
const epic = JSON.parse(epicResult.stdout.toString());
|
|
474
|
+
|
|
475
|
+
// 3. Report progress
|
|
476
|
+
await swarm_progress.execute(
|
|
477
|
+
{
|
|
478
|
+
project_key: uniqueProjectKey,
|
|
479
|
+
agent_name: agent.name,
|
|
480
|
+
bead_id: subtask.id,
|
|
481
|
+
status: "in_progress",
|
|
482
|
+
},
|
|
483
|
+
ctx,
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
// 4. Complete
|
|
487
|
+
const result = await swarm_complete.execute(
|
|
488
|
+
{
|
|
489
|
+
project_key: uniqueProjectKey,
|
|
490
|
+
agent_name: agent.name,
|
|
491
|
+
bead_id: subtask.id,
|
|
492
|
+
summary: "Done",
|
|
493
|
+
},
|
|
494
|
+
ctx,
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
expect(result.success).toBe(true);
|
|
498
|
+
});
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Common Patterns
|
|
502
|
+
|
|
503
|
+
### Test Data Validation
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
it("includes confidence score and reasoning", async () => {
|
|
507
|
+
const result = await swarm_select_strategy.execute(
|
|
508
|
+
{ task: "Implement dashboard" },
|
|
509
|
+
mockContext,
|
|
510
|
+
);
|
|
511
|
+
const parsed = JSON.parse(result);
|
|
512
|
+
|
|
513
|
+
expect(parsed).toHaveProperty("strategy");
|
|
514
|
+
expect(parsed).toHaveProperty("confidence");
|
|
515
|
+
expect(typeof parsed.confidence).toBe("number");
|
|
516
|
+
expect(parsed.confidence).toBeGreaterThanOrEqual(0);
|
|
517
|
+
expect(parsed.confidence).toBeLessThanOrEqual(1);
|
|
518
|
+
});
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Array/Collection Testing
|
|
522
|
+
|
|
523
|
+
```typescript
|
|
524
|
+
it("includes alternatives with scores", async () => {
|
|
525
|
+
const result = await swarm_select_strategy.execute(
|
|
526
|
+
{ task: "Build module" },
|
|
527
|
+
mockContext,
|
|
528
|
+
);
|
|
529
|
+
const parsed = JSON.parse(result);
|
|
530
|
+
|
|
531
|
+
expect(parsed.alternatives).toBeInstanceOf(Array);
|
|
532
|
+
expect(parsed.alternatives.length).toBe(2);
|
|
533
|
+
|
|
534
|
+
for (const alt of parsed.alternatives) {
|
|
535
|
+
expect(alt).toHaveProperty("strategy");
|
|
536
|
+
expect(alt).toHaveProperty("score");
|
|
537
|
+
expect(typeof alt.score).toBe("number");
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### String Content Testing
|
|
543
|
+
|
|
544
|
+
```typescript
|
|
545
|
+
it("includes context in prompt when provided", async () => {
|
|
546
|
+
const result = await swarm_decompose.execute(
|
|
547
|
+
{
|
|
548
|
+
task: "Refactor API",
|
|
549
|
+
context: "Using Next.js App Router",
|
|
550
|
+
},
|
|
551
|
+
mockContext,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
const parsed = JSON.parse(result);
|
|
555
|
+
expect(parsed.prompt).toContain("Next.js App Router");
|
|
556
|
+
expect(parsed.prompt).toContain("Additional Context");
|
|
557
|
+
});
|
|
558
|
+
```
|