Skip to content

Commit 0431dc4

Browse files
committed
fix: update tests to match new automated spec generation behavior
Updated 9 failing tests to match new Gear 3 implementation: create-specs.test.ts (8 tests fixed): - Updated test expectations from guidance text to automated spec generation - Added setupTestDirectory() helper to create proper test environment - Added missing development standards sections to sample-functional-spec.md - Tests now verify automated spec generation results (success, stats, etc.) - Added template copying to test directory for constitution generation markdown-parser.test.ts (1 test fixed): - Fixed malformed-functional-spec.md fixture to have truly unclosed code block - Parser now correctly throws ParseError as expected Result: All 446 tests passing ✅ Build Status: - TypeScript: ✅ Clean compilation - Tests: ✅ 446/446 passing - ESLint: Warnings only (no blocking errors)
1 parent 5305698 commit 0431dc4

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

mcp-server/src/tools/__tests__/create-specs.test.ts

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,53 @@ describe('Create Specs Tool Tests', () => {
2020
let testDir: string;
2121
let stateManager: StateManager;
2222

23+
// Helper to set up test directory with all required files
24+
async function setupTestDirectory(dir: string) {
25+
// Create reverse engineering docs directory and copy sample functional spec
26+
const docsDir = path.join(dir, 'docs', 'reverse-engineering');
27+
await fs.mkdir(docsDir, { recursive: true });
28+
29+
// Copy sample functional spec from fixtures
30+
const fixtureDir = path.join(process.cwd(), 'src', 'utils', '__tests__', 'fixtures');
31+
const sampleSpec = await fs.readFile(
32+
path.join(fixtureDir, 'sample-functional-spec.md'),
33+
'utf-8'
34+
);
35+
await fs.writeFile(path.join(docsDir, 'functional-specification.md'), sampleSpec);
36+
37+
// Copy templates from root project to test directory
38+
const sourceTemplatesDir = path.join(process.cwd(), '..', 'plugin', 'templates');
39+
const destTemplatesDir = path.join(dir, 'plugin', 'templates');
40+
await fs.mkdir(destTemplatesDir, { recursive: true });
41+
42+
const templates = [
43+
'constitution-agnostic-template.md',
44+
'constitution-prescriptive-template.md',
45+
'feature-spec-template.md',
46+
'implementation-status-template.md',
47+
];
48+
49+
for (const template of templates) {
50+
try {
51+
const content = await fs.readFile(path.join(sourceTemplatesDir, template), 'utf-8');
52+
await fs.writeFile(path.join(destTemplatesDir, template), content);
53+
} catch (error) {
54+
// Template may not exist, skip
55+
console.warn(`Warning: Could not copy template ${template}:`, error);
56+
}
57+
}
58+
}
59+
2360
beforeEach(async () => {
2461
// Create temporary test directory
2562
testDir = path.join(tmpdir(), `stackshift-test-${randomBytes(8).toString('hex')}`);
2663
await fs.mkdir(testDir, { recursive: true });
2764

2865
// Initialize state manager
2966
stateManager = new StateManager(testDir);
67+
68+
// Set up test directory with all required files
69+
await setupTestDirectory(testDir);
3070
});
3171

3272
afterEach(async () => {
@@ -93,9 +133,9 @@ describe('Create Specs Tool Tests', () => {
93133
const result = await createSpecsToolHandler({ directory: testDir });
94134

95135
expect(result.content[0].text).toContain('Greenfield');
96-
expect(result.content[0].text).toContain('Tech-Agnostic Template');
97-
expect(result.content[0].text).toContain('Business requirements only');
98-
expect(result.content[0].text).not.toContain('Current implementation details');
136+
expect(result.content[0].text).toContain('Automated Spec Generation Complete');
137+
expect(result.content[0].text).toContain('Feature Specifications');
138+
expect(result.content[0].text).toContain('Constitution');
99139
});
100140

101141
it('should handle brownfield route correctly', async () => {
@@ -104,9 +144,9 @@ describe('Create Specs Tool Tests', () => {
104144
const result = await createSpecsToolHandler({ directory: testDir });
105145

106146
expect(result.content[0].text).toContain('Brownfield');
107-
expect(result.content[0].text).toContain('Tech-Prescriptive Template');
108-
expect(result.content[0].text).toContain('Current implementation details');
109-
expect(result.content[0].text).toContain('Exact technical architecture');
147+
expect(result.content[0].text).toContain('Automated Spec Generation Complete');
148+
expect(result.content[0].text).toContain('Feature Specifications');
149+
expect(result.content[0].text).toContain('Constitution');
110150
});
111151

112152
it('should throw error if route not set', async () => {
@@ -180,15 +220,15 @@ describe('Create Specs Tool Tests', () => {
180220
expect(result.content[0].text).toContain('stackshift_gap_analysis');
181221
});
182222

183-
it('should include GitHub Spec Kit integration instructions', async () => {
223+
it('should include constitution and feature spec counts', async () => {
184224
await stateManager.initialize(testDir, 'brownfield');
185225

186226
const result = await createSpecsToolHandler({ directory: testDir });
187227

188-
expect(result.content[0].text).toContain('GitHub Spec Kit Integration');
189-
expect(result.content[0].text).toContain('specify init');
190-
expect(result.content[0].text).toContain('--ai claude');
191-
expect(result.content[0].text).toContain('.specify/memory/constitution.md');
228+
expect(result.content[0].text).toContain('Constitution');
229+
expect(result.content[0].text).toContain('Feature Specifications');
230+
expect(result.content[0].text).toContain('Total Features');
231+
expect(result.content[0].text).toContain('Implementation Plans');
192232
});
193233

194234
it('should include output structure for both routes', async () => {
@@ -199,32 +239,40 @@ describe('Create Specs Tool Tests', () => {
199239

200240
const result = await createSpecsToolHandler({ directory: testDir });
201241

242+
expect(result.content[0].text).toContain('specs/');
202243
expect(result.content[0].text).toContain('.specify/');
203244
expect(result.content[0].text).toContain('memory/');
204245
expect(result.content[0].text).toContain('constitution.md');
205-
expect(result.content[0].text).toContain('specifications/');
206-
expect(result.content[0].text).toContain('plans/');
207246

208247
// Clean state for next iteration
209248
await fs.rm(testDir, { recursive: true, force: true });
210249
await fs.mkdir(testDir, { recursive: true });
211250
stateManager = new StateManager(testDir);
251+
252+
// Recreate test directory structure
253+
await setupTestDirectory(testDir);
212254
}
213255
});
214256

215-
it('should reference correct manual prompt for each route', async () => {
257+
it('should include validation and next steps', async () => {
216258
// Greenfield
217259
await stateManager.initialize(testDir, 'greenfield');
218260
let result = await createSpecsToolHandler({ directory: testDir });
219-
expect(result.content[0].text).toContain('03-create-agnostic-specs.md');
261+
expect(result.content[0].text).toContain('/speckit.analyze');
262+
expect(result.content[0].text).toContain('stackshift_gap_analysis');
220263

221264
// Brownfield
222265
await fs.rm(testDir, { recursive: true, force: true });
223266
await fs.mkdir(testDir, { recursive: true });
224267
stateManager = new StateManager(testDir);
268+
269+
// Recreate test directory structure
270+
await setupTestDirectory(testDir);
271+
225272
await stateManager.initialize(testDir, 'brownfield');
226273
result = await createSpecsToolHandler({ directory: testDir });
227-
expect(result.content[0].text).toContain('03-create-prescriptive-specs.md');
274+
expect(result.content[0].text).toContain('/speckit.analyze');
275+
expect(result.content[0].text).toContain('stackshift_gap_analysis');
228276
});
229277
});
230278

@@ -236,15 +284,18 @@ describe('Create Specs Tool Tests', () => {
236284
);
237285
});
238286

239-
it('should wrap errors with descriptive message', async () => {
287+
it('should return helpful error message when docs are missing', async () => {
240288
await stateManager.initialize(testDir, 'greenfield');
241289

242-
// Try with a directory that doesn't exist for validation
243-
const nonExistentPath = path.join(testDir, 'nonexistent', 'path');
290+
// Remove the docs directory to simulate missing prerequisite
291+
await fs.rm(path.join(testDir, 'docs'), { recursive: true, force: true });
244292

245-
await expect(createSpecsToolHandler({ directory: nonExistentPath })).rejects.toThrow(
246-
/Spec creation failed/
247-
);
293+
const result = await createSpecsToolHandler({ directory: testDir });
294+
295+
// Should return error response, not throw
296+
expect(result.content[0].text).toContain('Error During Spec Generation');
297+
expect(result.content[0].text).toContain('Functional specification not found');
298+
expect(result.content[0].text).toContain('stackshift_reverse_engineer');
248299
});
249300
});
250301

@@ -265,7 +316,7 @@ describe('Create Specs Tool Tests', () => {
265316
const result = await createSpecsToolHandler({ directory: testDir });
266317

267318
expect(result.content[0].text).toContain('/speckit.analyze');
268-
expect(result.content[0].text).toContain('validate specs');
319+
expect(result.content[0].text).toContain('Validate Specifications');
269320
});
270321
});
271322
});

mcp-server/src/utils/__tests__/fixtures/malformed-functional-spec.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ This feature has no criteria at all.
5050
```typescript
5151
const x = 1;
5252
const y = 2;
53-
```
5453

5554
No closing markers
5655

mcp-server/src/utils/__tests__/fixtures/sample-functional-spec.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,25 @@ As a user, I want to set my display name, so that others can identify me.
134134
- CDN for static assets
135135
- Caching layer with Redis
136136

137+
### Code Quality
138+
- Follow TypeScript strict mode
139+
- ESLint with Airbnb style guide
140+
- Prettier for code formatting
141+
- SonarQube code quality scans
142+
- Code review required for all PRs
143+
144+
### Testing
145+
- Unit test coverage: ≥ 80%
146+
- Integration tests for all API endpoints
147+
- E2E tests for critical user flows
148+
- Run tests in CI/CD pipeline
149+
150+
### Documentation
151+
- JSDoc comments for all public APIs
152+
- README with setup instructions
153+
- API documentation with Swagger/OpenAPI
154+
- Architecture decision records (ADRs)
155+
137156
## Technical Stack
138157

139158
- **Frontend:** React 18.2, TypeScript, Tailwind CSS

0 commit comments

Comments
 (0)