@oalacea/daemon 0.5.0 → 0.5.1
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 +46 -38
- package/LICENSE +23 -23
- package/README.md +147 -141
- package/agents/deps-analyzer.js +366 -366
- package/agents/detector.js +570 -570
- package/agents/fix-engine.js +305 -305
- package/agents/lighthouse-scanner.js +405 -405
- package/agents/perf-analyzer.js +294 -294
- package/agents/perf-front-analyzer.js +229 -229
- package/agents/test-generator.js +387 -387
- package/agents/test-runner.js +318 -318
- package/bin/Dockerfile +75 -74
- package/bin/cli.js +449 -449
- package/lib/config.js +250 -250
- package/lib/docker.js +207 -207
- package/lib/reporter.js +297 -297
- package/package.json +34 -34
- package/prompts/DEPS_EFFICIENCY.md +558 -558
- package/prompts/E2E.md +491 -491
- package/prompts/EXECUTE.md +1060 -1060
- package/prompts/INTEGRATION_API.md +484 -484
- package/prompts/INTEGRATION_DB.md +425 -425
- package/prompts/PERF_API.md +433 -433
- package/prompts/PERF_DB.md +430 -430
- package/prompts/PERF_FRONT.md +357 -357
- package/prompts/REMEDIATION.md +482 -482
- package/prompts/UNIT.md +260 -260
- package/scripts/dev.js +106 -106
- package/templates/README.md +38 -38
- package/templates/k6/load-test.js +54 -54
- package/templates/playwright/e2e.spec.ts +61 -61
- package/templates/vitest/angular-component.test.ts +38 -38
- package/templates/vitest/api.test.ts +51 -51
- package/templates/vitest/component.test.ts +27 -27
- package/templates/vitest/hook.test.ts +36 -36
- package/templates/vitest/solid-component.test.ts +34 -34
- package/templates/vitest/svelte-component.test.ts +33 -33
- package/templates/vitest/vue-component.test.ts +39 -39
package/agents/test-runner.js
CHANGED
|
@@ -1,318 +1,318 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Daemon - Test Runner Agent
|
|
3
|
-
*
|
|
4
|
-
* Executes tests and parses results.
|
|
5
|
-
* Supports Vitest, Jest, and Playwright.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { execSync } = require('child_process');
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
|
|
12
|
-
// Configuration
|
|
13
|
-
const CONFIG = {
|
|
14
|
-
container: 'daemon-tools',
|
|
15
|
-
docker: 'docker exec',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Run tests inside the Docker container
|
|
20
|
-
*/
|
|
21
|
-
function runTests(command, options = {}) {
|
|
22
|
-
const dockerCmd = `${CONFIG.docker} ${CONFIG.container} ${command}`;
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
const output = execSync(dockerCmd, {
|
|
26
|
-
encoding: 'utf-8',
|
|
27
|
-
stdio: options.silent ? 'pipe' : 'inherit',
|
|
28
|
-
timeout: options.timeout || 120000,
|
|
29
|
-
cwd: options.cwd || process.cwd(),
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
success: true,
|
|
34
|
-
output,
|
|
35
|
-
exitCode: 0,
|
|
36
|
-
};
|
|
37
|
-
} catch (error) {
|
|
38
|
-
return {
|
|
39
|
-
success: false,
|
|
40
|
-
output: error.stdout || '',
|
|
41
|
-
error: error.stderr || error.message,
|
|
42
|
-
exitCode: error.status || 1,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Run unit tests
|
|
49
|
-
*/
|
|
50
|
-
function runUnitTests(testFile = null) {
|
|
51
|
-
const cmd = testFile
|
|
52
|
-
? `npm test -- ${testFile}`
|
|
53
|
-
: `npm test`;
|
|
54
|
-
|
|
55
|
-
return runTests(cmd);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Run integration tests
|
|
60
|
-
*/
|
|
61
|
-
function runIntegrationTests(testFile = null) {
|
|
62
|
-
const cmd = testFile
|
|
63
|
-
? `npm test -- ${testFile}`
|
|
64
|
-
: `npm test -- tests/integration`;
|
|
65
|
-
|
|
66
|
-
return runTests(cmd);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Run E2E tests
|
|
71
|
-
*/
|
|
72
|
-
function runE2ETests(testFile = null) {
|
|
73
|
-
const cmd = testFile
|
|
74
|
-
? `npx playwright test ${testFile}`
|
|
75
|
-
: `npx playwright test`;
|
|
76
|
-
|
|
77
|
-
return runTests(cmd);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Run performance tests
|
|
82
|
-
*/
|
|
83
|
-
function runPerformanceTests(testFile = null) {
|
|
84
|
-
const cmd = testFile
|
|
85
|
-
? `k6 run ${testFile}`
|
|
86
|
-
: `k6 run tests/performance`;
|
|
87
|
-
|
|
88
|
-
return runTests(cmd);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Parse Vitest/Jest output
|
|
93
|
-
*/
|
|
94
|
-
function parseTestOutput(output) {
|
|
95
|
-
const results = {
|
|
96
|
-
total: 0,
|
|
97
|
-
passed: 0,
|
|
98
|
-
failed: 0,
|
|
99
|
-
skipped: 0,
|
|
100
|
-
failures: [],
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// Parse Vitest output
|
|
104
|
-
const testFiles = output.match(/Test Files\s+\d+ passed/g);
|
|
105
|
-
if (testFiles) {
|
|
106
|
-
results.total += parseInt(testFiles[0].match(/\d+/)[0]);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const passed = output.match(/(\d+) passed/);
|
|
110
|
-
if (passed) {
|
|
111
|
-
results.passed += parseInt(passed[1]);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const failed = output.match(/(\d+) failed/);
|
|
115
|
-
if (failed) {
|
|
116
|
-
results.failed += parseInt(failed[1]);
|
|
117
|
-
// Parse failure details
|
|
118
|
-
const failOutput = output.match(/FAIL\s+(.+)/g);
|
|
119
|
-
if (failOutput) {
|
|
120
|
-
results.failures = failOutput.map((f) => {
|
|
121
|
-
const match = f.match(/FAIL\s+(.+?)\s+/);
|
|
122
|
-
return match ? match[1] : f;
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const skipped = output.match(/(\d+) skipped/);
|
|
128
|
-
if (skipped) {
|
|
129
|
-
results.skipped += parseInt(skipped[1]);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return results;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Parse Playwright output
|
|
137
|
-
*/
|
|
138
|
-
function parseE2EOutput(output) {
|
|
139
|
-
const results = {
|
|
140
|
-
total: 0,
|
|
141
|
-
passed: 0,
|
|
142
|
-
failed: 0,
|
|
143
|
-
skipped: 0,
|
|
144
|
-
failures: [],
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const passed = output.match(/passed\s+(\d+)/);
|
|
148
|
-
if (passed) results.passed += parseInt(passed[1]);
|
|
149
|
-
|
|
150
|
-
const failed = output.match(/failed\s+(\d+)/);
|
|
151
|
-
if (failed) {
|
|
152
|
-
results.failed += parseInt(failed[1]);
|
|
153
|
-
// Parse failure details
|
|
154
|
-
const failLines = output.match(/^.*?\[ERROR\].*$/gm);
|
|
155
|
-
if (failLines) {
|
|
156
|
-
results.failures = failLines;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const skipped = output.match(/skipped\s+(\d+)/);
|
|
161
|
-
if (skipped) results.skipped += parseInt(skipped[1]);
|
|
162
|
-
|
|
163
|
-
results.total = results.passed + results.failed + results.skipped;
|
|
164
|
-
|
|
165
|
-
return results;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Parse k6 output
|
|
170
|
-
*/
|
|
171
|
-
function parsePerfOutput(output) {
|
|
172
|
-
const results = {
|
|
173
|
-
requests: 0,
|
|
174
|
-
duration: 0,
|
|
175
|
-
avgResponseTime: 0,
|
|
176
|
-
p95: 0,
|
|
177
|
-
p99: 0,
|
|
178
|
-
rps: 0,
|
|
179
|
-
failureRate: 0,
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// Parse k6 summary output
|
|
183
|
-
const checks = output.match(/checks.*?:\s+([\d.]+)%/);
|
|
184
|
-
if (checks) results.failureRate = 100 - parseFloat(checks[1]);
|
|
185
|
-
|
|
186
|
-
const dataReceived = output.match(/data_received\s+([\d.]+\s+\w+)/);
|
|
187
|
-
if (dataReceived) results.dataReceived = dataReceived[1];
|
|
188
|
-
|
|
189
|
-
const httpReqDuration = output.match(/http_req_duration.*?avg=\s*([\d.]+)ms.*?p\(95\)=\s*([\d.]+)ms/);
|
|
190
|
-
if (httpReqDuration) {
|
|
191
|
-
results.avgResponseTime = parseFloat(httpReqDuration[1]);
|
|
192
|
-
results.p95 = parseFloat(httpReqDuration[2]);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const httpReqs = output.match(/http_reqs\s+([\d.]+)/);
|
|
196
|
-
if (httpReqs) results.requests = parseInt(httpReqs[1]);
|
|
197
|
-
|
|
198
|
-
const iterationDuration = output.match(/iteration_duration.*?avg=\s*([\d.]+)/);
|
|
199
|
-
if (iterationDuration) results.duration = parseFloat(iterationDuration[1]);
|
|
200
|
-
|
|
201
|
-
return results;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Get test coverage
|
|
206
|
-
*/
|
|
207
|
-
function getCoverage() {
|
|
208
|
-
const result = runTests('npm test -- --coverage');
|
|
209
|
-
|
|
210
|
-
if (!result.success) {
|
|
211
|
-
return null;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const coverage = {
|
|
215
|
-
lines: 0,
|
|
216
|
-
functions: 0,
|
|
217
|
-
branches: 0,
|
|
218
|
-
statements: 0,
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
// Parse coverage output
|
|
222
|
-
const lines = result.output.match(/All files[^]*?(\d+)%/);
|
|
223
|
-
if (lines) coverage.lines = parseInt(lines[1]);
|
|
224
|
-
|
|
225
|
-
const functions = result.output.match(/functions[^]*?(\d+)%/);
|
|
226
|
-
if (functions) coverage.functions = parseInt(functions[1]);
|
|
227
|
-
|
|
228
|
-
const branches = result.output.match(/branches[^]*?(\d+)%/);
|
|
229
|
-
if (branches) coverage.branches = parseInt(branches[1]);
|
|
230
|
-
|
|
231
|
-
const statements = result.output.match(/statements[^]*?(\d+)%/);
|
|
232
|
-
if (statements) coverage.statements = parseInt(statements[1]);
|
|
233
|
-
|
|
234
|
-
return coverage;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Run all tests and return summary
|
|
239
|
-
*/
|
|
240
|
-
async function runAllTests() {
|
|
241
|
-
const summary = {
|
|
242
|
-
unit: null,
|
|
243
|
-
integration: null,
|
|
244
|
-
e2e: null,
|
|
245
|
-
performance: null,
|
|
246
|
-
coverage: null,
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
// Unit tests
|
|
250
|
-
const unitResult = runUnitTests();
|
|
251
|
-
summary.unit = {
|
|
252
|
-
...parseTestOutput(unitResult.output),
|
|
253
|
-
success: unitResult.success,
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// Integration tests
|
|
257
|
-
const integrationResult = runIntegrationTests();
|
|
258
|
-
summary.integration = {
|
|
259
|
-
...parseTestOutput(integrationResult.output),
|
|
260
|
-
success: integrationResult.success,
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
// E2E tests
|
|
264
|
-
const e2eResult = runE2ETests();
|
|
265
|
-
summary.e2e = {
|
|
266
|
-
...parseE2EOutput(e2eResult.output),
|
|
267
|
-
success: e2eResult.success,
|
|
268
|
-
};
|
|
269
|
-
|
|
270
|
-
// Performance tests
|
|
271
|
-
const perfResult = runPerformanceTests();
|
|
272
|
-
summary.performance = {
|
|
273
|
-
...parsePerfOutput(perfResult.output),
|
|
274
|
-
success: perfResult.success,
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
// Coverage
|
|
278
|
-
summary.coverage = getCoverage();
|
|
279
|
-
|
|
280
|
-
return summary;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Run a single test file
|
|
285
|
-
*/
|
|
286
|
-
function runSingleTest(testPath) {
|
|
287
|
-
return runTests(`npm test -- ${testPath}`);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Watch tests
|
|
292
|
-
*/
|
|
293
|
-
function watchTests() {
|
|
294
|
-
return runTests('npm test -- --watch');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Debug a failing test
|
|
299
|
-
*/
|
|
300
|
-
function debugTest(testPath) {
|
|
301
|
-
return runTests(`npm test -- ${testPath} --reporter=verbose --no-coverage`);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
module.exports = {
|
|
305
|
-
runTests,
|
|
306
|
-
runUnitTests,
|
|
307
|
-
runIntegrationTests,
|
|
308
|
-
runE2ETests,
|
|
309
|
-
runPerformanceTests,
|
|
310
|
-
parseTestOutput,
|
|
311
|
-
parseE2EOutput,
|
|
312
|
-
parsePerfOutput,
|
|
313
|
-
getCoverage,
|
|
314
|
-
runAllTests,
|
|
315
|
-
runSingleTest,
|
|
316
|
-
watchTests,
|
|
317
|
-
debugTest,
|
|
318
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Daemon - Test Runner Agent
|
|
3
|
+
*
|
|
4
|
+
* Executes tests and parses results.
|
|
5
|
+
* Supports Vitest, Jest, and Playwright.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { execSync } = require('child_process');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
|
|
12
|
+
// Configuration
|
|
13
|
+
const CONFIG = {
|
|
14
|
+
container: 'daemon-tools',
|
|
15
|
+
docker: 'docker exec',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Run tests inside the Docker container
|
|
20
|
+
*/
|
|
21
|
+
function runTests(command, options = {}) {
|
|
22
|
+
const dockerCmd = `${CONFIG.docker} ${CONFIG.container} ${command}`;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const output = execSync(dockerCmd, {
|
|
26
|
+
encoding: 'utf-8',
|
|
27
|
+
stdio: options.silent ? 'pipe' : 'inherit',
|
|
28
|
+
timeout: options.timeout || 120000,
|
|
29
|
+
cwd: options.cwd || process.cwd(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
output,
|
|
35
|
+
exitCode: 0,
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
output: error.stdout || '',
|
|
41
|
+
error: error.stderr || error.message,
|
|
42
|
+
exitCode: error.status || 1,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Run unit tests
|
|
49
|
+
*/
|
|
50
|
+
function runUnitTests(testFile = null) {
|
|
51
|
+
const cmd = testFile
|
|
52
|
+
? `npm test -- ${testFile}`
|
|
53
|
+
: `npm test`;
|
|
54
|
+
|
|
55
|
+
return runTests(cmd);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Run integration tests
|
|
60
|
+
*/
|
|
61
|
+
function runIntegrationTests(testFile = null) {
|
|
62
|
+
const cmd = testFile
|
|
63
|
+
? `npm test -- ${testFile}`
|
|
64
|
+
: `npm test -- tests/integration`;
|
|
65
|
+
|
|
66
|
+
return runTests(cmd);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Run E2E tests
|
|
71
|
+
*/
|
|
72
|
+
function runE2ETests(testFile = null) {
|
|
73
|
+
const cmd = testFile
|
|
74
|
+
? `npx playwright test ${testFile}`
|
|
75
|
+
: `npx playwright test`;
|
|
76
|
+
|
|
77
|
+
return runTests(cmd);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Run performance tests
|
|
82
|
+
*/
|
|
83
|
+
function runPerformanceTests(testFile = null) {
|
|
84
|
+
const cmd = testFile
|
|
85
|
+
? `k6 run ${testFile}`
|
|
86
|
+
: `k6 run tests/performance`;
|
|
87
|
+
|
|
88
|
+
return runTests(cmd);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Parse Vitest/Jest output
|
|
93
|
+
*/
|
|
94
|
+
function parseTestOutput(output) {
|
|
95
|
+
const results = {
|
|
96
|
+
total: 0,
|
|
97
|
+
passed: 0,
|
|
98
|
+
failed: 0,
|
|
99
|
+
skipped: 0,
|
|
100
|
+
failures: [],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Parse Vitest output
|
|
104
|
+
const testFiles = output.match(/Test Files\s+\d+ passed/g);
|
|
105
|
+
if (testFiles) {
|
|
106
|
+
results.total += parseInt(testFiles[0].match(/\d+/)[0]);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const passed = output.match(/(\d+) passed/);
|
|
110
|
+
if (passed) {
|
|
111
|
+
results.passed += parseInt(passed[1]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const failed = output.match(/(\d+) failed/);
|
|
115
|
+
if (failed) {
|
|
116
|
+
results.failed += parseInt(failed[1]);
|
|
117
|
+
// Parse failure details
|
|
118
|
+
const failOutput = output.match(/FAIL\s+(.+)/g);
|
|
119
|
+
if (failOutput) {
|
|
120
|
+
results.failures = failOutput.map((f) => {
|
|
121
|
+
const match = f.match(/FAIL\s+(.+?)\s+/);
|
|
122
|
+
return match ? match[1] : f;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const skipped = output.match(/(\d+) skipped/);
|
|
128
|
+
if (skipped) {
|
|
129
|
+
results.skipped += parseInt(skipped[1]);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return results;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse Playwright output
|
|
137
|
+
*/
|
|
138
|
+
function parseE2EOutput(output) {
|
|
139
|
+
const results = {
|
|
140
|
+
total: 0,
|
|
141
|
+
passed: 0,
|
|
142
|
+
failed: 0,
|
|
143
|
+
skipped: 0,
|
|
144
|
+
failures: [],
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const passed = output.match(/passed\s+(\d+)/);
|
|
148
|
+
if (passed) results.passed += parseInt(passed[1]);
|
|
149
|
+
|
|
150
|
+
const failed = output.match(/failed\s+(\d+)/);
|
|
151
|
+
if (failed) {
|
|
152
|
+
results.failed += parseInt(failed[1]);
|
|
153
|
+
// Parse failure details
|
|
154
|
+
const failLines = output.match(/^.*?\[ERROR\].*$/gm);
|
|
155
|
+
if (failLines) {
|
|
156
|
+
results.failures = failLines;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const skipped = output.match(/skipped\s+(\d+)/);
|
|
161
|
+
if (skipped) results.skipped += parseInt(skipped[1]);
|
|
162
|
+
|
|
163
|
+
results.total = results.passed + results.failed + results.skipped;
|
|
164
|
+
|
|
165
|
+
return results;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Parse k6 output
|
|
170
|
+
*/
|
|
171
|
+
function parsePerfOutput(output) {
|
|
172
|
+
const results = {
|
|
173
|
+
requests: 0,
|
|
174
|
+
duration: 0,
|
|
175
|
+
avgResponseTime: 0,
|
|
176
|
+
p95: 0,
|
|
177
|
+
p99: 0,
|
|
178
|
+
rps: 0,
|
|
179
|
+
failureRate: 0,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Parse k6 summary output
|
|
183
|
+
const checks = output.match(/checks.*?:\s+([\d.]+)%/);
|
|
184
|
+
if (checks) results.failureRate = 100 - parseFloat(checks[1]);
|
|
185
|
+
|
|
186
|
+
const dataReceived = output.match(/data_received\s+([\d.]+\s+\w+)/);
|
|
187
|
+
if (dataReceived) results.dataReceived = dataReceived[1];
|
|
188
|
+
|
|
189
|
+
const httpReqDuration = output.match(/http_req_duration.*?avg=\s*([\d.]+)ms.*?p\(95\)=\s*([\d.]+)ms/);
|
|
190
|
+
if (httpReqDuration) {
|
|
191
|
+
results.avgResponseTime = parseFloat(httpReqDuration[1]);
|
|
192
|
+
results.p95 = parseFloat(httpReqDuration[2]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const httpReqs = output.match(/http_reqs\s+([\d.]+)/);
|
|
196
|
+
if (httpReqs) results.requests = parseInt(httpReqs[1]);
|
|
197
|
+
|
|
198
|
+
const iterationDuration = output.match(/iteration_duration.*?avg=\s*([\d.]+)/);
|
|
199
|
+
if (iterationDuration) results.duration = parseFloat(iterationDuration[1]);
|
|
200
|
+
|
|
201
|
+
return results;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get test coverage
|
|
206
|
+
*/
|
|
207
|
+
function getCoverage() {
|
|
208
|
+
const result = runTests('npm test -- --coverage');
|
|
209
|
+
|
|
210
|
+
if (!result.success) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const coverage = {
|
|
215
|
+
lines: 0,
|
|
216
|
+
functions: 0,
|
|
217
|
+
branches: 0,
|
|
218
|
+
statements: 0,
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Parse coverage output
|
|
222
|
+
const lines = result.output.match(/All files[^]*?(\d+)%/);
|
|
223
|
+
if (lines) coverage.lines = parseInt(lines[1]);
|
|
224
|
+
|
|
225
|
+
const functions = result.output.match(/functions[^]*?(\d+)%/);
|
|
226
|
+
if (functions) coverage.functions = parseInt(functions[1]);
|
|
227
|
+
|
|
228
|
+
const branches = result.output.match(/branches[^]*?(\d+)%/);
|
|
229
|
+
if (branches) coverage.branches = parseInt(branches[1]);
|
|
230
|
+
|
|
231
|
+
const statements = result.output.match(/statements[^]*?(\d+)%/);
|
|
232
|
+
if (statements) coverage.statements = parseInt(statements[1]);
|
|
233
|
+
|
|
234
|
+
return coverage;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Run all tests and return summary
|
|
239
|
+
*/
|
|
240
|
+
async function runAllTests() {
|
|
241
|
+
const summary = {
|
|
242
|
+
unit: null,
|
|
243
|
+
integration: null,
|
|
244
|
+
e2e: null,
|
|
245
|
+
performance: null,
|
|
246
|
+
coverage: null,
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Unit tests
|
|
250
|
+
const unitResult = runUnitTests();
|
|
251
|
+
summary.unit = {
|
|
252
|
+
...parseTestOutput(unitResult.output),
|
|
253
|
+
success: unitResult.success,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Integration tests
|
|
257
|
+
const integrationResult = runIntegrationTests();
|
|
258
|
+
summary.integration = {
|
|
259
|
+
...parseTestOutput(integrationResult.output),
|
|
260
|
+
success: integrationResult.success,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// E2E tests
|
|
264
|
+
const e2eResult = runE2ETests();
|
|
265
|
+
summary.e2e = {
|
|
266
|
+
...parseE2EOutput(e2eResult.output),
|
|
267
|
+
success: e2eResult.success,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// Performance tests
|
|
271
|
+
const perfResult = runPerformanceTests();
|
|
272
|
+
summary.performance = {
|
|
273
|
+
...parsePerfOutput(perfResult.output),
|
|
274
|
+
success: perfResult.success,
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// Coverage
|
|
278
|
+
summary.coverage = getCoverage();
|
|
279
|
+
|
|
280
|
+
return summary;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Run a single test file
|
|
285
|
+
*/
|
|
286
|
+
function runSingleTest(testPath) {
|
|
287
|
+
return runTests(`npm test -- ${testPath}`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Watch tests
|
|
292
|
+
*/
|
|
293
|
+
function watchTests() {
|
|
294
|
+
return runTests('npm test -- --watch');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Debug a failing test
|
|
299
|
+
*/
|
|
300
|
+
function debugTest(testPath) {
|
|
301
|
+
return runTests(`npm test -- ${testPath} --reporter=verbose --no-coverage`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
module.exports = {
|
|
305
|
+
runTests,
|
|
306
|
+
runUnitTests,
|
|
307
|
+
runIntegrationTests,
|
|
308
|
+
runE2ETests,
|
|
309
|
+
runPerformanceTests,
|
|
310
|
+
parseTestOutput,
|
|
311
|
+
parseE2EOutput,
|
|
312
|
+
parsePerfOutput,
|
|
313
|
+
getCoverage,
|
|
314
|
+
runAllTests,
|
|
315
|
+
runSingleTest,
|
|
316
|
+
watchTests,
|
|
317
|
+
debugTest,
|
|
318
|
+
};
|