@oalacea/daemon 0.5.0
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/CHANGELOG.md +38 -0
- package/LICENSE +23 -0
- package/README.md +141 -0
- package/agents/deps-analyzer.js +366 -0
- package/agents/detector.js +570 -0
- package/agents/fix-engine.js +305 -0
- package/agents/lighthouse-scanner.js +405 -0
- package/agents/perf-analyzer.js +294 -0
- package/agents/perf-front-analyzer.js +229 -0
- package/agents/test-generator.js +387 -0
- package/agents/test-runner.js +318 -0
- package/bin/Dockerfile +74 -0
- package/bin/cli.js +449 -0
- package/lib/config.js +250 -0
- package/lib/docker.js +207 -0
- package/lib/reporter.js +297 -0
- package/package.json +34 -0
- package/prompts/DEPS_EFFICIENCY.md +558 -0
- package/prompts/E2E.md +491 -0
- package/prompts/EXECUTE.md +1060 -0
- package/prompts/INTEGRATION_API.md +484 -0
- package/prompts/INTEGRATION_DB.md +425 -0
- package/prompts/PERF_API.md +433 -0
- package/prompts/PERF_DB.md +430 -0
- package/prompts/PERF_FRONT.md +357 -0
- package/prompts/REMEDIATION.md +482 -0
- package/prompts/UNIT.md +260 -0
- package/scripts/dev.js +106 -0
- package/templates/README.md +38 -0
- package/templates/k6/load-test.js +54 -0
- package/templates/playwright/e2e.spec.ts +61 -0
- package/templates/vitest/angular-component.test.ts +38 -0
- package/templates/vitest/api.test.ts +51 -0
- package/templates/vitest/component.test.ts +27 -0
- package/templates/vitest/hook.test.ts +36 -0
- package/templates/vitest/solid-component.test.ts +34 -0
- package/templates/vitest/svelte-component.test.ts +33 -0
- package/templates/vitest/vue-component.test.ts +39 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
# Test Remediation Guide
|
|
2
|
+
|
|
3
|
+
This prompt is included by EXECUTE.md. It provides detailed guidance for fixing failing tests.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Remediation Workflow
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────┐
|
|
11
|
+
│ Test Fails │
|
|
12
|
+
└────────┬────────┘
|
|
13
|
+
│
|
|
14
|
+
▼
|
|
15
|
+
┌─────────────────┐
|
|
16
|
+
│ Analyze Error │
|
|
17
|
+
│ - Read output │
|
|
18
|
+
│ - Categorize │
|
|
19
|
+
└────────┬────────┘
|
|
20
|
+
│
|
|
21
|
+
▼
|
|
22
|
+
┌─────────────────┐
|
|
23
|
+
│ Determine Fix │
|
|
24
|
+
│ - Test issue? │ → Fix test
|
|
25
|
+
│ - Code bug? │ → Fix code
|
|
26
|
+
│ - Setup issue? │ → Fix setup
|
|
27
|
+
└────────┬────────┘
|
|
28
|
+
│
|
|
29
|
+
▼
|
|
30
|
+
┌─────────────────┐
|
|
31
|
+
│ Apply Fix │
|
|
32
|
+
│ - Edit file │
|
|
33
|
+
│ - Add mock │
|
|
34
|
+
│ - Update config │
|
|
35
|
+
└────────┬────────┘
|
|
36
|
+
│
|
|
37
|
+
▼
|
|
38
|
+
┌─────────────────┐
|
|
39
|
+
│ Verify Fix │
|
|
40
|
+
│ - Re-run test │
|
|
41
|
+
│ - Check related │
|
|
42
|
+
└────────┬────────┘
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
┌─────────────────┐
|
|
46
|
+
│ Document │
|
|
47
|
+
│ - Note fix │
|
|
48
|
+
│ - Update report │
|
|
49
|
+
└─────────────────┘
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Error Categorization
|
|
55
|
+
|
|
56
|
+
### Test Setup Errors
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// Error: Cannot find module '@/components/Button'
|
|
60
|
+
// Cause: Import path incorrect or alias not configured
|
|
61
|
+
|
|
62
|
+
// Fix 1: Check import path
|
|
63
|
+
import { Button } from '@/components/Button'; // Correct
|
|
64
|
+
import { Button } from './components/Button'; // Relative path
|
|
65
|
+
|
|
66
|
+
// Fix 2: Configure path alias
|
|
67
|
+
// vitest.config.ts
|
|
68
|
+
export default defineConfig({
|
|
69
|
+
resolve: {
|
|
70
|
+
alias: {
|
|
71
|
+
'@': path.resolve(__dirname, './src'),
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Mock Errors
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// Error: Cannot read property 'mockReturnValue' of undefined
|
|
81
|
+
|
|
82
|
+
// Fix: Add proper mock
|
|
83
|
+
vi.mock('@/lib/api', () => ({
|
|
84
|
+
fetchUsers: vi.fn(),
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
// Or mock the return value
|
|
88
|
+
vi.mocked(fetchUsers).mockResolvedValue([{ id: '1', name: 'Test' }]);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Async Errors
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Error: Expected promise to be resolved, but it was rejected
|
|
95
|
+
|
|
96
|
+
// Fix 1: Use async/await properly
|
|
97
|
+
it('should fetch user', async () => {
|
|
98
|
+
const user = await fetchUser('1');
|
|
99
|
+
expect(user).toBeDefined();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Fix 2: Handle rejection
|
|
103
|
+
it('should reject for invalid id', async () => {
|
|
104
|
+
await expect(fetchUser('invalid')).rejects.toThrow();
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Timeout Errors
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// Error: Test timeout of 5000ms exceeded
|
|
112
|
+
|
|
113
|
+
// Fix 1: Increase timeout for slow operations
|
|
114
|
+
it('should process large file', async () => {
|
|
115
|
+
const result = await processFile('large.csv');
|
|
116
|
+
expect(result).toBeDefined();
|
|
117
|
+
}, 10000); // 10 second timeout
|
|
118
|
+
|
|
119
|
+
// Fix 2: Fix the actual slow code
|
|
120
|
+
// - Optimize query
|
|
121
|
+
// - Add caching
|
|
122
|
+
// - Use Promise.all for parallel operations
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Common Fixes by Category
|
|
128
|
+
|
|
129
|
+
### Component Test Fixes
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Issue: "querySelector" returns null for missing element
|
|
133
|
+
// Cause: Element not rendered or wrong selector
|
|
134
|
+
|
|
135
|
+
// Before (failing):
|
|
136
|
+
it('should show error message', () => {
|
|
137
|
+
render(<Form />);
|
|
138
|
+
expect(screen.getByText('Error')).toBeInTheDocument(); // Throws
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// After (fixed):
|
|
142
|
+
it('should show error message when error exists', () => {
|
|
143
|
+
render(<Form error="Invalid input" />);
|
|
144
|
+
expect(screen.getByText('Invalid input')).toBeInTheDocument();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Or with queryBy:
|
|
148
|
+
it('should not show error initially', () => {
|
|
149
|
+
render(<Form />);
|
|
150
|
+
expect(screen.queryByText('Error')).not.toBeInTheDocument();
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Hook Test Fixes
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Issue: Hook state not updating
|
|
158
|
+
// Cause: Not using act() for state updates
|
|
159
|
+
|
|
160
|
+
// Before (failing):
|
|
161
|
+
it('should increment counter', () => {
|
|
162
|
+
const { result } = renderHook(() => useCounter());
|
|
163
|
+
result.current.increment();
|
|
164
|
+
expect(result.current.count).toBe(1); // Fails - not updated yet
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// After (fixed):
|
|
168
|
+
it('should increment counter', () => {
|
|
169
|
+
const { result } = renderHook(() => useCounter());
|
|
170
|
+
act(() => {
|
|
171
|
+
result.current.increment();
|
|
172
|
+
});
|
|
173
|
+
expect(result.current.count).toBe(1);
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### API Test Fixes
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Issue: Test fails with ECONNREFUSED
|
|
181
|
+
// Cause: API server not running or wrong URL
|
|
182
|
+
|
|
183
|
+
// Fix 1: Mock the fetch
|
|
184
|
+
import { vi } from 'vitest';
|
|
185
|
+
|
|
186
|
+
global.fetch = vi.fn(() =>
|
|
187
|
+
Promise.resolve({
|
|
188
|
+
ok: true,
|
|
189
|
+
json: () => Promise.resolve({ data: 'test' }),
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// Fix 2: Use test server
|
|
194
|
+
import { createServer } from 'http';
|
|
195
|
+
|
|
196
|
+
const server = createServer((req, res) => {
|
|
197
|
+
if (req.url === '/api/users') {
|
|
198
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
199
|
+
res.end(JSON.stringify({ users: [] }));
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
beforeAll(async () => {
|
|
204
|
+
await new Promise((resolve) => server.listen(3001, resolve));
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
afterAll((done) => server.close(done));
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### DB Test Fixes
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Issue: Test modifies real data
|
|
214
|
+
// Cause: Not using transaction rollback
|
|
215
|
+
|
|
216
|
+
// Fix: Wrap in transaction
|
|
217
|
+
beforeEach(async () => {
|
|
218
|
+
await db.beginTransaction();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
afterEach(async () => {
|
|
222
|
+
await db.rollbackTransaction();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Issue: Tests interfere with each other
|
|
226
|
+
// Cause: Not cleaning up between tests
|
|
227
|
+
|
|
228
|
+
// Fix: Use beforeEach/afterEach
|
|
229
|
+
beforeEach(async () => {
|
|
230
|
+
await db.reset(); // Clear test data
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Or use unique test data
|
|
234
|
+
it('should create user', async () => {
|
|
235
|
+
const user = await db.user.create({
|
|
236
|
+
data: { email: `test-${Date.now()}@example.com` }
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Fix Templates
|
|
244
|
+
|
|
245
|
+
### Adding Missing Mock
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Test file before fix
|
|
249
|
+
import { useAuth } from '@/hooks/useAuth';
|
|
250
|
+
|
|
251
|
+
vi.mock('@/hooks/useAuth'); // Mock exists but no implementation
|
|
252
|
+
|
|
253
|
+
// Test file after fix
|
|
254
|
+
import { useAuth } from '@/hooks/useAuth';
|
|
255
|
+
|
|
256
|
+
vi.mock('@/hooks/useAuth', () => ({
|
|
257
|
+
useAuth: vi.fn(() => ({
|
|
258
|
+
user: null,
|
|
259
|
+
login: vi.fn(),
|
|
260
|
+
logout: vi.fn(),
|
|
261
|
+
})),
|
|
262
|
+
}));
|
|
263
|
+
|
|
264
|
+
// Or with vi.mocked
|
|
265
|
+
vi.mocked(useAuth).mockReturnValue({
|
|
266
|
+
user: { id: '1', name: 'Test' },
|
|
267
|
+
login: vi.fn(),
|
|
268
|
+
logout: vi.fn(),
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Fixing Async Issues
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
// Before: Missing await
|
|
276
|
+
it('should delete post', async () => {
|
|
277
|
+
deletePost('1'); // Not awaited
|
|
278
|
+
const posts = await getPosts();
|
|
279
|
+
expect(posts).not.toContain(post); // Fails
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// After: Add await
|
|
283
|
+
it('should delete post', async () => {
|
|
284
|
+
await deletePost('1');
|
|
285
|
+
const posts = await getPosts();
|
|
286
|
+
expect(posts).not.toContain(post);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Before: Not waiting for state update
|
|
290
|
+
it('should update user', () => {
|
|
291
|
+
const { result } = renderHook(() => useUser());
|
|
292
|
+
result.current.setName('New Name');
|
|
293
|
+
expect(result.current.user.name).toBe('New Name'); // Fails
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// After: Use waitFor
|
|
297
|
+
it('should update user', async () => {
|
|
298
|
+
const { result } = renderHook(() => useUser());
|
|
299
|
+
act(() => {
|
|
300
|
+
result.current.setName('New Name');
|
|
301
|
+
});
|
|
302
|
+
await waitFor(() => {
|
|
303
|
+
expect(result.current.user.name).toBe('New Name');
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Fixing Selector Issues
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
// Before: Using textContent which includes nested text
|
|
312
|
+
it('should show welcome message', () => {
|
|
313
|
+
render(<Dashboard name="John" />);
|
|
314
|
+
expect(screen.getByText('Welcome')).toBeInTheDocument();
|
|
315
|
+
// Fails because <div>Welcome <span>John</span></div>
|
|
316
|
+
// textContent is "Welcome John", not "Welcome"
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// After: Use more specific selector
|
|
320
|
+
it('should show welcome message', () => {
|
|
321
|
+
render(<Dashboard name="John" />);
|
|
322
|
+
expect(screen.getByText(/Welcome/)).toBeInTheDocument();
|
|
323
|
+
// Or use testId
|
|
324
|
+
expect(screen.getByTestId('welcome-message')).toBeInTheDocument();
|
|
325
|
+
});
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## E2E Test Fixes
|
|
331
|
+
|
|
332
|
+
### Wait Issues
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
// Before: Not waiting for element
|
|
336
|
+
test('should show dashboard', async ({ page }) => {
|
|
337
|
+
await page.goto('/dashboard');
|
|
338
|
+
const heading = page.locator('h1');
|
|
339
|
+
await expect(heading).toContainText('Dashboard'); // Fails
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// After: Wait for element
|
|
343
|
+
test('should show dashboard', async ({ page }) => {
|
|
344
|
+
await page.goto('/dashboard');
|
|
345
|
+
await page.waitForSelector('h1');
|
|
346
|
+
const heading = page.locator('h1');
|
|
347
|
+
await expect(heading).toContainText('Dashboard');
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Or use waitForLoadState
|
|
351
|
+
await page.waitForLoadState('networkidle');
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Navigation Issues
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
// Before: Not waiting for navigation
|
|
358
|
+
test('should login', async ({ page }) => {
|
|
359
|
+
await page.goto('/login');
|
|
360
|
+
await page.click('button[type="submit"]');
|
|
361
|
+
expect(page.url()).toContain('/dashboard'); // Fails
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// After: Wait for navigation
|
|
365
|
+
test('should login', async ({ page }) => {
|
|
366
|
+
await page.goto('/login');
|
|
367
|
+
await page.click('button[type="submit"]');
|
|
368
|
+
await page.waitForURL('/dashboard');
|
|
369
|
+
expect(page.url()).toContain('/dashboard');
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Performance Test Fixes
|
|
376
|
+
|
|
377
|
+
### Threshold Adjustments
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
// Before: Threshold too strict
|
|
381
|
+
export const options = {
|
|
382
|
+
thresholds: {
|
|
383
|
+
'http_req_duration': ['p(95)<100'], // Too strict
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// After: Realistic threshold
|
|
388
|
+
export const options = {
|
|
389
|
+
thresholds: {
|
|
390
|
+
'http_req_duration': ['p(95)<200', 'p(99)<500'],
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Stage Configuration
|
|
396
|
+
|
|
397
|
+
```javascript
|
|
398
|
+
// Before: VUs ramp too fast
|
|
399
|
+
stages: [
|
|
400
|
+
{ duration: '1s', target: 100 }, // Instant spike
|
|
401
|
+
]
|
|
402
|
+
|
|
403
|
+
// After: Gradual ramp
|
|
404
|
+
stages: [
|
|
405
|
+
{ duration: '30s', target: 100 }, // Gradual ramp
|
|
406
|
+
]
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## Fix Documentation Template
|
|
412
|
+
|
|
413
|
+
```markdown
|
|
414
|
+
### FIX-XXX: [Brief Description]
|
|
415
|
+
|
|
416
|
+
**File:** `path/to/file.ts:line`
|
|
417
|
+
|
|
418
|
+
**Error Message:**
|
|
419
|
+
```
|
|
420
|
+
Expected: X
|
|
421
|
+
Received: Y
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Root Cause:**
|
|
425
|
+
[Explanation of why the test failed]
|
|
426
|
+
|
|
427
|
+
**Fix Applied:**
|
|
428
|
+
[Description of the fix]
|
|
429
|
+
|
|
430
|
+
**Code Change:**
|
|
431
|
+
```typescript
|
|
432
|
+
// Before
|
|
433
|
+
[X code]
|
|
434
|
+
|
|
435
|
+
// After
|
|
436
|
+
[Y code]
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
**Verification:**
|
|
440
|
+
```bash
|
|
441
|
+
docker exec daemon-tools npm test -- specific.test.ts
|
|
442
|
+
# ✓ Pass
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Related Tests:**
|
|
446
|
+
- [ ] test-a.test.ts - Still passing
|
|
447
|
+
- [ ] test-b.test.ts - Still passing
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
## Batch Fix Strategy
|
|
453
|
+
|
|
454
|
+
When many tests fail with similar issues:
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
# 1. Group failures by error type
|
|
458
|
+
docker exec daemon-tools npm test 2>&1 | grep "Error:" | sort | uniq -c
|
|
459
|
+
|
|
460
|
+
# 2. Identify common patterns
|
|
461
|
+
# - Import errors → Fix vitest.config.ts
|
|
462
|
+
# - Mock errors → Create setup file with common mocks
|
|
463
|
+
# - Async errors → Add waitFor wrappers
|
|
464
|
+
|
|
465
|
+
# 3. Create shared setup
|
|
466
|
+
// tests/setup.ts
|
|
467
|
+
import { vi } from 'vitest';
|
|
468
|
+
|
|
469
|
+
// Common mocks
|
|
470
|
+
vi.mock('@/lib/api', () => ({
|
|
471
|
+
fetch: vi.fn(),
|
|
472
|
+
post: vi.fn(),
|
|
473
|
+
}));
|
|
474
|
+
|
|
475
|
+
// Common utilities
|
|
476
|
+
export async function waitForElement(screen, text) {
|
|
477
|
+
return await waitFor(() => screen.getByText(text));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 4. Run subset to verify
|
|
481
|
+
docker exec daemon-tools npm test -- --grep="pattern"
|
|
482
|
+
```
|