@memberjunction/testing-cli 5.37.0 → 5.38.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/dist/commands/compare.d.ts +36 -11
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +464 -29
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +137 -7
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/suite.d.ts +10 -0
- package/dist/commands/suite.d.ts.map +1 -1
- package/dist/commands/suite.js +94 -6
- package/dist/commands/suite.js.map +1 -1
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +5 -3
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/oracle-module-loader.d.ts +25 -0
- package/dist/utils/oracle-module-loader.d.ts.map +1 -0
- package/dist/utils/oracle-module-loader.js +135 -0
- package/dist/utils/oracle-module-loader.js.map +1 -0
- package/package.json +7 -7
|
@@ -1,24 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Compare command
|
|
2
|
+
* @fileoverview Compare command — compares two test suite runs to detect regressions
|
|
3
3
|
* @module @memberjunction/testing-cli
|
|
4
4
|
*/
|
|
5
5
|
import { UserInfo } from '@memberjunction/core';
|
|
6
6
|
import { CompareFlags } from '../types.js';
|
|
7
7
|
/**
|
|
8
|
-
* Compare command
|
|
9
|
-
*
|
|
10
|
-
* Note: This is a placeholder implementation. Full comparison requires
|
|
11
|
-
* tracking test runs with version/commit metadata.
|
|
8
|
+
* Compare command — Compare two test suite runs to detect regressions
|
|
12
9
|
*/
|
|
13
10
|
export declare class CompareCommand {
|
|
11
|
+
execute(runId1: string | undefined, runId2: string | undefined, flags: CompareFlags, contextUser?: UserInfo): Promise<void>;
|
|
14
12
|
/**
|
|
15
|
-
*
|
|
13
|
+
* Resolve --from-json flag values into a {previous, current} file pair.
|
|
14
|
+
*
|
|
15
|
+
* Supports two modes:
|
|
16
|
+
* - Two file paths → returns them in declared order
|
|
17
|
+
* - One directory → finds two newest regression runs by mtime, looking for:
|
|
18
|
+
* (a) <dir>/run-* /results.json — per-run folder pattern (current)
|
|
19
|
+
* (b) <dir>/results-*.json — flat archive pattern (legacy)
|
|
20
|
+
* Both patterns are scanned together and sorted by mtime,
|
|
21
|
+
* so a directory with a mix works fine.
|
|
16
22
|
*
|
|
17
|
-
*
|
|
18
|
-
* @param runId2 - Second run ID (optional)
|
|
19
|
-
* @param flags - Command flags
|
|
20
|
-
* @param contextUser - Optional user context (will be fetched if not provided)
|
|
23
|
+
* Returns null (and prints an error) if the inputs can't be resolved.
|
|
21
24
|
*/
|
|
22
|
-
|
|
25
|
+
private resolveFromJsonPaths;
|
|
26
|
+
/**
|
|
27
|
+
* Compare two results.json files directly without querying the database.
|
|
28
|
+
* Used when the Docker regression DB is ephemeral and results are archived
|
|
29
|
+
* as JSON artifacts instead.
|
|
30
|
+
*/
|
|
31
|
+
private executeFromJson;
|
|
32
|
+
/**
|
|
33
|
+
* Parse a results.json file into the normalized SuiteRunSummary shape.
|
|
34
|
+
* Expected shape matches what `mj test suite --format=json --output=...` produces.
|
|
35
|
+
*/
|
|
36
|
+
private parseResultsJson;
|
|
37
|
+
/**
|
|
38
|
+
* Core comparison logic — takes two normalized suite runs and produces the
|
|
39
|
+
* full ComparisonResult. Shared between the DB path and the JSON path.
|
|
40
|
+
*/
|
|
41
|
+
private buildComparisonResult;
|
|
42
|
+
/**
|
|
43
|
+
* Find the most recent completed suite run matching a given field/value.
|
|
44
|
+
* Used to resolve --version and --commit flags to concrete run IDs.
|
|
45
|
+
*/
|
|
46
|
+
private findLatestSuiteRunBy;
|
|
47
|
+
private formatComparison;
|
|
23
48
|
}
|
|
24
49
|
//# sourceMappingURL=compare.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAqB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAmDxC;;GAEG;AACH,qBAAa,cAAc;IACjB,OAAO,CACT,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,YAAY,EACnB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,IAAI,CAAC;IA0LhB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;;;OAIG;YACW,eAAe;IA4B7B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA+CxB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqE7B;;;OAGG;YACW,oBAAoB;IAwBlC,OAAO,CAAC,gBAAgB;CA8F3B"}
|
package/dist/commands/compare.js
CHANGED
|
@@ -1,46 +1,481 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview Compare command
|
|
2
|
+
* @fileoverview Compare command — compares two test suite runs to detect regressions
|
|
3
3
|
* @module @memberjunction/testing-cli
|
|
4
4
|
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { RunView, Metadata } from '@memberjunction/core';
|
|
5
8
|
import { OutputFormatter } from '../utils/output-formatter.js';
|
|
9
|
+
import { initializeMJProvider, closeMJProvider, getContextUser } from '../lib/mj-provider.js';
|
|
6
10
|
/**
|
|
7
|
-
* Compare command
|
|
8
|
-
*
|
|
9
|
-
* Note: This is a placeholder implementation. Full comparison requires
|
|
10
|
-
* tracking test runs with version/commit metadata.
|
|
11
|
+
* Compare command — Compare two test suite runs to detect regressions
|
|
11
12
|
*/
|
|
12
13
|
export class CompareCommand {
|
|
14
|
+
async execute(runId1, runId2, flags, contextUser) {
|
|
15
|
+
// --from-json: compare two results.json files directly (no DB required).
|
|
16
|
+
// Designed for comparing Docker regression runs where the DB is ephemeral.
|
|
17
|
+
//
|
|
18
|
+
// Accepts either:
|
|
19
|
+
// - Two file paths: --from-json PREV.json --from-json CURR.json
|
|
20
|
+
// - One directory: --from-json <dir> (picks two newest results-*.json by mtime)
|
|
21
|
+
if (flags.fromJson && flags.fromJson.length > 0) {
|
|
22
|
+
if (flags.tag) {
|
|
23
|
+
console.warn(`Warning: --tag is ignored with --from-json — results.json does not currently emit the Tags field. ` +
|
|
24
|
+
`Use DB mode (drop --from-json) to filter by tag.`);
|
|
25
|
+
}
|
|
26
|
+
const resolved = this.resolveFromJsonPaths(flags.fromJson);
|
|
27
|
+
if (resolved) {
|
|
28
|
+
return this.executeFromJson(resolved.previous, resolved.current, flags);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
await initializeMJProvider();
|
|
33
|
+
if (!contextUser) {
|
|
34
|
+
contextUser = await getContextUser();
|
|
35
|
+
}
|
|
36
|
+
const rv = new RunView();
|
|
37
|
+
let previousRunId;
|
|
38
|
+
let currentRunId;
|
|
39
|
+
// Detect if user provided any explicit selector
|
|
40
|
+
const hasVersionFlag = flags.version && flags.version.length >= 2;
|
|
41
|
+
const hasCommitFlag = flags.commit && flags.commit.length >= 2;
|
|
42
|
+
const hasExplicitIds = Boolean(runId1 && runId2);
|
|
43
|
+
if (hasExplicitIds) {
|
|
44
|
+
// Explicit two-run comparison
|
|
45
|
+
previousRunId = runId1;
|
|
46
|
+
currentRunId = runId2;
|
|
47
|
+
}
|
|
48
|
+
else if (hasVersionFlag) {
|
|
49
|
+
// Compare by version: -v <previous> -v <current>
|
|
50
|
+
const [prevRun, currRun] = await Promise.all([
|
|
51
|
+
this.findLatestSuiteRunBy(rv, 'AgentVersion', flags.version[0], contextUser, flags.tag),
|
|
52
|
+
this.findLatestSuiteRunBy(rv, 'AgentVersion', flags.version[1], contextUser, flags.tag),
|
|
53
|
+
]);
|
|
54
|
+
if (!prevRun) {
|
|
55
|
+
console.error(OutputFormatter.formatError(`No completed suite run found with AgentVersion='${flags.version[0]}'`));
|
|
56
|
+
process.exit(2);
|
|
57
|
+
}
|
|
58
|
+
if (!currRun) {
|
|
59
|
+
console.error(OutputFormatter.formatError(`No completed suite run found with AgentVersion='${flags.version[1]}'`));
|
|
60
|
+
process.exit(2);
|
|
61
|
+
}
|
|
62
|
+
previousRunId = prevRun.ID;
|
|
63
|
+
currentRunId = currRun.ID;
|
|
64
|
+
}
|
|
65
|
+
else if (hasCommitFlag) {
|
|
66
|
+
// Compare by git commit: -c <previous> -c <current>
|
|
67
|
+
const [prevRun, currRun] = await Promise.all([
|
|
68
|
+
this.findLatestSuiteRunBy(rv, 'GitCommit', flags.commit[0], contextUser, flags.tag),
|
|
69
|
+
this.findLatestSuiteRunBy(rv, 'GitCommit', flags.commit[1], contextUser, flags.tag),
|
|
70
|
+
]);
|
|
71
|
+
if (!prevRun) {
|
|
72
|
+
console.error(OutputFormatter.formatError(`No completed suite run found with GitCommit='${flags.commit[0]}'`));
|
|
73
|
+
process.exit(2);
|
|
74
|
+
}
|
|
75
|
+
if (!currRun) {
|
|
76
|
+
console.error(OutputFormatter.formatError(`No completed suite run found with GitCommit='${flags.commit[1]}'`));
|
|
77
|
+
process.exit(2);
|
|
78
|
+
}
|
|
79
|
+
previousRunId = prevRun.ID;
|
|
80
|
+
currentRunId = currRun.ID;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Default behavior: compare the two most recent completed suite runs.
|
|
84
|
+
// Triggered by --latest OR by running `mj test compare` with no args.
|
|
85
|
+
// When --tag is provided, restrict to runs whose Tags JSON array
|
|
86
|
+
// includes the tag. Tags is stored as a JSON array string like
|
|
87
|
+
// `["staging-nightly","sonnet-4.6"]`, so we LIKE-match the quoted
|
|
88
|
+
// form to avoid false-positives where the tag is a substring of
|
|
89
|
+
// another tag (e.g. "prod" matching "production").
|
|
90
|
+
let extraFilter = "Status IN ('Completed', 'Failed')";
|
|
91
|
+
if (flags.tag) {
|
|
92
|
+
const escaped = flags.tag.replace(/'/g, "''");
|
|
93
|
+
extraFilter += ` AND Tags LIKE '%"${escaped}"%'`;
|
|
94
|
+
}
|
|
95
|
+
const runs = await rv.RunView({
|
|
96
|
+
EntityName: 'MJ: Test Suite Runs',
|
|
97
|
+
ExtraFilter: extraFilter,
|
|
98
|
+
OrderBy: 'StartedAt DESC',
|
|
99
|
+
MaxRows: 2,
|
|
100
|
+
ResultType: 'entity_object'
|
|
101
|
+
}, contextUser);
|
|
102
|
+
if (!runs.Success || runs.Results.length < 2) {
|
|
103
|
+
const tagSuffix = flags.tag ? ` matching tag '${flags.tag}'` : '';
|
|
104
|
+
console.error(OutputFormatter.formatError(`Need at least 2 completed suite runs to compare${tagSuffix} (found ${runs.Results?.length ?? 0})`));
|
|
105
|
+
process.exit(2);
|
|
106
|
+
}
|
|
107
|
+
currentRunId = runs.Results[0].ID;
|
|
108
|
+
previousRunId = runs.Results[1].ID;
|
|
109
|
+
}
|
|
110
|
+
// Load both suite runs
|
|
111
|
+
const md = new Metadata(); // global-provider-ok: CLI tool runs in single-user, single-connection context
|
|
112
|
+
const previousRun = await md.GetEntityObject('MJ: Test Suite Runs', contextUser);
|
|
113
|
+
const currentRun = await md.GetEntityObject('MJ: Test Suite Runs', contextUser);
|
|
114
|
+
const prevLoaded = await previousRun.Load(previousRunId);
|
|
115
|
+
const currLoaded = await currentRun.Load(currentRunId);
|
|
116
|
+
if (!prevLoaded) {
|
|
117
|
+
console.error(OutputFormatter.formatError(`Suite run not found: ${previousRunId}`));
|
|
118
|
+
process.exit(2);
|
|
119
|
+
}
|
|
120
|
+
if (!currLoaded) {
|
|
121
|
+
console.error(OutputFormatter.formatError(`Suite run not found: ${currentRunId}`));
|
|
122
|
+
process.exit(2);
|
|
123
|
+
}
|
|
124
|
+
// Load test runs for both suite runs
|
|
125
|
+
const [prevTestsResult, currTestsResult] = await Promise.all([
|
|
126
|
+
rv.RunView({
|
|
127
|
+
EntityName: 'MJ: Test Runs',
|
|
128
|
+
ExtraFilter: `TestSuiteRunID='${previousRunId}'`,
|
|
129
|
+
OrderBy: 'Sequence',
|
|
130
|
+
ResultType: 'entity_object'
|
|
131
|
+
}, contextUser),
|
|
132
|
+
rv.RunView({
|
|
133
|
+
EntityName: 'MJ: Test Runs',
|
|
134
|
+
ExtraFilter: `TestSuiteRunID='${currentRunId}'`,
|
|
135
|
+
OrderBy: 'Sequence',
|
|
136
|
+
ResultType: 'entity_object'
|
|
137
|
+
}, contextUser)
|
|
138
|
+
]);
|
|
139
|
+
// Normalize to SuiteRunSummary shape so we can share comparison logic with --from-json path
|
|
140
|
+
const previousSummary = {
|
|
141
|
+
RunId: previousRunId,
|
|
142
|
+
SuiteName: previousRun.Suite,
|
|
143
|
+
StartedAt: previousRun.StartedAt?.toISOString().split('T')[0] ?? 'unknown',
|
|
144
|
+
Tests: (prevTestsResult.Success ? prevTestsResult.Results : []).map(t => ({
|
|
145
|
+
TestID: t.TestID,
|
|
146
|
+
TestName: t.Test,
|
|
147
|
+
Status: t.Status,
|
|
148
|
+
Score: t.Score,
|
|
149
|
+
DurationSeconds: t.DurationSeconds,
|
|
150
|
+
})),
|
|
151
|
+
};
|
|
152
|
+
const currentSummary = {
|
|
153
|
+
RunId: currentRunId,
|
|
154
|
+
SuiteName: currentRun.Suite,
|
|
155
|
+
StartedAt: currentRun.StartedAt?.toISOString().split('T')[0] ?? 'unknown',
|
|
156
|
+
Tests: (currTestsResult.Success ? currTestsResult.Results : []).map(t => ({
|
|
157
|
+
TestID: t.TestID,
|
|
158
|
+
TestName: t.Test,
|
|
159
|
+
Status: t.Status,
|
|
160
|
+
Score: t.Score,
|
|
161
|
+
DurationSeconds: t.DurationSeconds,
|
|
162
|
+
})),
|
|
163
|
+
};
|
|
164
|
+
const result = this.buildComparisonResult(previousSummary, currentSummary);
|
|
165
|
+
// Format output
|
|
166
|
+
const format = flags.format || 'console';
|
|
167
|
+
const output = this.formatComparison(result, format, flags.diffOnly);
|
|
168
|
+
console.log(output);
|
|
169
|
+
if (flags.output) {
|
|
170
|
+
OutputFormatter.writeToFile(output, flags.output);
|
|
171
|
+
}
|
|
172
|
+
await closeMJProvider();
|
|
173
|
+
// Exit codes: 0 = no regressions, 1 = regressions detected, 2 = data error
|
|
174
|
+
process.exit(result.Regressions > 0 ? 1 : 0);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.error(OutputFormatter.formatError('Failed to compare test runs', error));
|
|
178
|
+
try {
|
|
179
|
+
await closeMJProvider();
|
|
180
|
+
}
|
|
181
|
+
catch { /* ignore */ }
|
|
182
|
+
process.exit(2);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
13
185
|
/**
|
|
14
|
-
*
|
|
186
|
+
* Resolve --from-json flag values into a {previous, current} file pair.
|
|
15
187
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
188
|
+
* Supports two modes:
|
|
189
|
+
* - Two file paths → returns them in declared order
|
|
190
|
+
* - One directory → finds two newest regression runs by mtime, looking for:
|
|
191
|
+
* (a) <dir>/run-* /results.json — per-run folder pattern (current)
|
|
192
|
+
* (b) <dir>/results-*.json — flat archive pattern (legacy)
|
|
193
|
+
* Both patterns are scanned together and sorted by mtime,
|
|
194
|
+
* so a directory with a mix works fine.
|
|
195
|
+
*
|
|
196
|
+
* Returns null (and prints an error) if the inputs can't be resolved.
|
|
20
197
|
*/
|
|
21
|
-
|
|
198
|
+
resolveFromJsonPaths(inputs) {
|
|
199
|
+
if (inputs.length >= 2) {
|
|
200
|
+
return { previous: inputs[0], current: inputs[1] };
|
|
201
|
+
}
|
|
202
|
+
// Single argument — must be a directory
|
|
203
|
+
const candidate = path.resolve(inputs[0]);
|
|
204
|
+
if (!fs.existsSync(candidate)) {
|
|
205
|
+
console.error(OutputFormatter.formatError(`Path does not exist: ${candidate}`));
|
|
206
|
+
process.exit(2);
|
|
207
|
+
}
|
|
208
|
+
const stats = fs.statSync(candidate);
|
|
209
|
+
if (!stats.isDirectory()) {
|
|
210
|
+
console.error(OutputFormatter.formatError(`--from-json needs either two file paths or one directory (got one file: ${candidate})`));
|
|
211
|
+
process.exit(2);
|
|
212
|
+
}
|
|
213
|
+
const entries = fs.readdirSync(candidate, { withFileTypes: true });
|
|
214
|
+
const found = [];
|
|
215
|
+
for (const entry of entries) {
|
|
216
|
+
// Per-run folder pattern: <dir>/run-*/results.json
|
|
217
|
+
if (entry.isDirectory() && entry.name.startsWith('run-')) {
|
|
218
|
+
const resultsFile = path.join(candidate, entry.name, 'results.json');
|
|
219
|
+
if (fs.existsSync(resultsFile)) {
|
|
220
|
+
found.push({ path: resultsFile, mtime: fs.statSync(resultsFile).mtimeMs });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Flat archive pattern: <dir>/results-*.json (legacy)
|
|
224
|
+
else if (entry.isFile() && /^results-.*\.json$/.test(entry.name)) {
|
|
225
|
+
const full = path.join(candidate, entry.name);
|
|
226
|
+
found.push({ path: full, mtime: fs.statSync(full).mtimeMs });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
found.sort((a, b) => b.mtime - a.mtime);
|
|
230
|
+
if (found.length < 2) {
|
|
231
|
+
console.error(OutputFormatter.formatError(`Need at least 2 archived regression runs in ${candidate} (found ${found.length}). ` +
|
|
232
|
+
`Looked for: run-*/results.json and results-*.json`));
|
|
233
|
+
process.exit(2);
|
|
234
|
+
}
|
|
235
|
+
// Newest is "current", second-newest is "previous"
|
|
236
|
+
return { previous: found[1].path, current: found[0].path };
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Compare two results.json files directly without querying the database.
|
|
240
|
+
* Used when the Docker regression DB is ephemeral and results are archived
|
|
241
|
+
* as JSON artifacts instead.
|
|
242
|
+
*/
|
|
243
|
+
async executeFromJson(previousJsonPath, currentJsonPath, flags) {
|
|
22
244
|
try {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
console.log(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// - Load two test runs from database
|
|
35
|
-
// - Compare scores, pass/fail status, duration, cost
|
|
36
|
-
// - Identify regressions (score decreased, new failures)
|
|
37
|
-
// - Display side-by-side comparison
|
|
38
|
-
// - Exit with non-zero if regressions detected
|
|
245
|
+
const previous = this.parseResultsJson(previousJsonPath);
|
|
246
|
+
const current = this.parseResultsJson(currentJsonPath);
|
|
247
|
+
const result = this.buildComparisonResult(previous, current);
|
|
248
|
+
const format = flags.format || 'console';
|
|
249
|
+
const output = this.formatComparison(result, format, flags.diffOnly);
|
|
250
|
+
console.log(output);
|
|
251
|
+
if (flags.output) {
|
|
252
|
+
OutputFormatter.writeToFile(output, flags.output);
|
|
253
|
+
}
|
|
254
|
+
// Exit codes: 0 = no regressions, 1 = regressions detected, 2 = data error
|
|
255
|
+
process.exit(result.Regressions > 0 ? 1 : 0);
|
|
39
256
|
}
|
|
40
257
|
catch (error) {
|
|
41
|
-
console.error(OutputFormatter.formatError('Failed to compare
|
|
42
|
-
process.exit(
|
|
258
|
+
console.error(OutputFormatter.formatError('Failed to compare results.json files', error));
|
|
259
|
+
process.exit(2);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Parse a results.json file into the normalized SuiteRunSummary shape.
|
|
264
|
+
* Expected shape matches what `mj test suite --format=json --output=...` produces.
|
|
265
|
+
*/
|
|
266
|
+
parseResultsJson(filePath) {
|
|
267
|
+
const resolvedPath = path.resolve(filePath);
|
|
268
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
269
|
+
throw new Error(`Results file not found: ${resolvedPath}`);
|
|
270
|
+
}
|
|
271
|
+
let raw;
|
|
272
|
+
try {
|
|
273
|
+
raw = JSON.parse(fs.readFileSync(resolvedPath, 'utf-8'));
|
|
274
|
+
}
|
|
275
|
+
catch (e) {
|
|
276
|
+
throw new Error(`Invalid JSON in ${resolvedPath}: ${e.message}`);
|
|
277
|
+
}
|
|
278
|
+
const data = raw;
|
|
279
|
+
if (!data || !Array.isArray(data.testResults)) {
|
|
280
|
+
throw new Error(`${resolvedPath} does not look like a suite results file (missing testResults array)`);
|
|
281
|
+
}
|
|
282
|
+
const startedAt = data.startedAt ? data.startedAt.split('T')[0] : 'unknown';
|
|
283
|
+
return {
|
|
284
|
+
RunId: data.suiteRunId ?? path.basename(resolvedPath),
|
|
285
|
+
SuiteName: data.suiteName ?? 'unknown',
|
|
286
|
+
StartedAt: startedAt,
|
|
287
|
+
Tests: data.testResults.map(t => ({
|
|
288
|
+
TestID: t.testId ?? t.testName ?? 'unknown',
|
|
289
|
+
TestName: t.testName ?? t.testId ?? 'unknown',
|
|
290
|
+
Status: t.status ?? 'Unknown',
|
|
291
|
+
Score: typeof t.score === 'number' ? t.score : null,
|
|
292
|
+
DurationSeconds: typeof t.durationMs === 'number' ? t.durationMs / 1000 : null,
|
|
293
|
+
})),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Core comparison logic — takes two normalized suite runs and produces the
|
|
298
|
+
* full ComparisonResult. Shared between the DB path and the JSON path.
|
|
299
|
+
*/
|
|
300
|
+
buildComparisonResult(previous, current) {
|
|
301
|
+
const prevMap = new Map();
|
|
302
|
+
for (const t of previous.Tests)
|
|
303
|
+
prevMap.set(t.TestID, t);
|
|
304
|
+
const currMap = new Map();
|
|
305
|
+
for (const t of current.Tests)
|
|
306
|
+
currMap.set(t.TestID, t);
|
|
307
|
+
const allTestIds = new Set([...prevMap.keys(), ...currMap.keys()]);
|
|
308
|
+
const comparisons = [];
|
|
309
|
+
for (const testId of allTestIds) {
|
|
310
|
+
const prev = prevMap.get(testId);
|
|
311
|
+
const curr = currMap.get(testId);
|
|
312
|
+
const prevScore = prev?.Score ?? null;
|
|
313
|
+
const currScore = curr?.Score ?? null;
|
|
314
|
+
const prevStatus = prev?.Status ?? null;
|
|
315
|
+
const currStatus = curr?.Status ?? null;
|
|
316
|
+
const scoreDelta = (prevScore != null && currScore != null) ? currScore - prevScore : null;
|
|
317
|
+
let change;
|
|
318
|
+
if (!prev) {
|
|
319
|
+
change = 'new';
|
|
320
|
+
}
|
|
321
|
+
else if (!curr) {
|
|
322
|
+
change = 'removed';
|
|
323
|
+
}
|
|
324
|
+
else if (prevStatus === 'Passed' && currStatus !== 'Passed') {
|
|
325
|
+
change = 'regression';
|
|
326
|
+
}
|
|
327
|
+
else if (prevStatus !== 'Passed' && currStatus === 'Passed') {
|
|
328
|
+
change = 'improvement';
|
|
329
|
+
}
|
|
330
|
+
else if (scoreDelta != null && scoreDelta < -0.1) {
|
|
331
|
+
change = 'regression';
|
|
332
|
+
}
|
|
333
|
+
else if (scoreDelta != null && scoreDelta > 0.1) {
|
|
334
|
+
change = 'improvement';
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
change = 'unchanged';
|
|
338
|
+
}
|
|
339
|
+
comparisons.push({
|
|
340
|
+
TestID: testId,
|
|
341
|
+
TestName: curr?.TestName ?? prev?.TestName ?? testId,
|
|
342
|
+
PreviousStatus: prevStatus,
|
|
343
|
+
CurrentStatus: currStatus,
|
|
344
|
+
PreviousScore: prevScore,
|
|
345
|
+
CurrentScore: currScore,
|
|
346
|
+
ScoreDelta: scoreDelta,
|
|
347
|
+
PreviousDurationS: prev?.DurationSeconds ?? null,
|
|
348
|
+
CurrentDurationS: curr?.DurationSeconds ?? null,
|
|
349
|
+
Change: change,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
const order = { regression: 0, improvement: 1, new: 2, removed: 3, unchanged: 4 };
|
|
353
|
+
comparisons.sort((a, b) => order[a.Change] - order[b.Change]);
|
|
354
|
+
return {
|
|
355
|
+
PreviousRunId: previous.RunId,
|
|
356
|
+
CurrentRunId: current.RunId,
|
|
357
|
+
PreviousSuiteName: previous.SuiteName,
|
|
358
|
+
CurrentSuiteName: current.SuiteName,
|
|
359
|
+
PreviousDate: previous.StartedAt,
|
|
360
|
+
CurrentDate: current.StartedAt,
|
|
361
|
+
Regressions: comparisons.filter(c => c.Change === 'regression').length,
|
|
362
|
+
Improvements: comparisons.filter(c => c.Change === 'improvement').length,
|
|
363
|
+
Unchanged: comparisons.filter(c => c.Change === 'unchanged').length,
|
|
364
|
+
NewTests: comparisons.filter(c => c.Change === 'new').length,
|
|
365
|
+
RemovedTests: comparisons.filter(c => c.Change === 'removed').length,
|
|
366
|
+
Tests: comparisons,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Find the most recent completed suite run matching a given field/value.
|
|
371
|
+
* Used to resolve --version and --commit flags to concrete run IDs.
|
|
372
|
+
*/
|
|
373
|
+
async findLatestSuiteRunBy(rv, fieldName, value, contextUser, tag) {
|
|
374
|
+
// Escape single quotes for SQL safety
|
|
375
|
+
const safeValue = value.replace(/'/g, "''");
|
|
376
|
+
let extraFilter = `${fieldName}='${safeValue}' AND Status IN ('Completed', 'Failed')`;
|
|
377
|
+
if (tag) {
|
|
378
|
+
const safeTag = tag.replace(/'/g, "''");
|
|
379
|
+
extraFilter += ` AND Tags LIKE '%"${safeTag}"%'`;
|
|
380
|
+
}
|
|
381
|
+
const result = await rv.RunView({
|
|
382
|
+
EntityName: 'MJ: Test Suite Runs',
|
|
383
|
+
ExtraFilter: extraFilter,
|
|
384
|
+
OrderBy: 'StartedAt DESC',
|
|
385
|
+
MaxRows: 1,
|
|
386
|
+
ResultType: 'entity_object'
|
|
387
|
+
}, contextUser);
|
|
388
|
+
return result.Success && result.Results.length > 0 ? result.Results[0] : null;
|
|
389
|
+
}
|
|
390
|
+
formatComparison(result, format, diffOnly) {
|
|
391
|
+
if (format === 'json') {
|
|
392
|
+
return JSON.stringify(diffOnly ? { ...result, Tests: result.Tests.filter(t => t.Change !== 'unchanged') } : result, null, 2);
|
|
393
|
+
}
|
|
394
|
+
const lines = [];
|
|
395
|
+
const tests = diffOnly ? result.Tests.filter(t => t.Change !== 'unchanged') : result.Tests;
|
|
396
|
+
if (format === 'markdown') {
|
|
397
|
+
lines.push('# Regression Comparison');
|
|
398
|
+
lines.push('');
|
|
399
|
+
lines.push(`**Previous**: ${result.PreviousSuiteName} (${result.PreviousDate}, run ${result.PreviousRunId.substring(0, 8)})`);
|
|
400
|
+
lines.push(`**Current**: ${result.CurrentSuiteName} (${result.CurrentDate}, run ${result.CurrentRunId.substring(0, 8)})`);
|
|
401
|
+
lines.push('');
|
|
402
|
+
lines.push('## Summary');
|
|
403
|
+
lines.push('');
|
|
404
|
+
lines.push(`- **Regressions**: ${result.Regressions}`);
|
|
405
|
+
lines.push(`- **Improvements**: ${result.Improvements}`);
|
|
406
|
+
lines.push(`- **Unchanged**: ${result.Unchanged}`);
|
|
407
|
+
if (result.NewTests > 0)
|
|
408
|
+
lines.push(`- **New tests**: ${result.NewTests}`);
|
|
409
|
+
if (result.RemovedTests > 0)
|
|
410
|
+
lines.push(`- **Removed tests**: ${result.RemovedTests}`);
|
|
411
|
+
lines.push('');
|
|
412
|
+
if (result.Regressions > 0) {
|
|
413
|
+
lines.push('## Regressions');
|
|
414
|
+
lines.push('');
|
|
415
|
+
lines.push('| Test | Previous | Current | Delta |');
|
|
416
|
+
lines.push('|------|----------|---------|-------|');
|
|
417
|
+
for (const t of tests.filter(t => t.Change === 'regression')) {
|
|
418
|
+
const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}% ${t.PreviousStatus}` : '-';
|
|
419
|
+
const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}% ${t.CurrentStatus}` : '-';
|
|
420
|
+
const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
|
|
421
|
+
lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} |`);
|
|
422
|
+
}
|
|
423
|
+
lines.push('');
|
|
424
|
+
}
|
|
425
|
+
if (result.Improvements > 0) {
|
|
426
|
+
lines.push('## Improvements');
|
|
427
|
+
lines.push('');
|
|
428
|
+
lines.push('| Test | Previous | Current | Delta |');
|
|
429
|
+
lines.push('|------|----------|---------|-------|');
|
|
430
|
+
for (const t of tests.filter(t => t.Change === 'improvement')) {
|
|
431
|
+
const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}% ${t.PreviousStatus}` : '-';
|
|
432
|
+
const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}% ${t.CurrentStatus}` : '-';
|
|
433
|
+
const delta = t.ScoreDelta != null ? `+${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
|
|
434
|
+
lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} |`);
|
|
435
|
+
}
|
|
436
|
+
lines.push('');
|
|
437
|
+
}
|
|
438
|
+
if (!diffOnly) {
|
|
439
|
+
lines.push('## All Tests');
|
|
440
|
+
lines.push('');
|
|
441
|
+
lines.push('| Test | Previous | Current | Delta | Change |');
|
|
442
|
+
lines.push('|------|----------|---------|-------|--------|');
|
|
443
|
+
for (const t of tests) {
|
|
444
|
+
const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}%` : '-';
|
|
445
|
+
const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}%` : '-';
|
|
446
|
+
const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : '-';
|
|
447
|
+
lines.push(`| ${t.TestName} | ${prev} | ${curr} | ${delta} | ${t.Change} |`);
|
|
448
|
+
}
|
|
449
|
+
lines.push('');
|
|
450
|
+
}
|
|
451
|
+
lines.push('---');
|
|
452
|
+
lines.push('*Generated by MJ Regression Test Runner*');
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
// Console format
|
|
456
|
+
const hasRegressions = result.Regressions > 0;
|
|
457
|
+
lines.push('');
|
|
458
|
+
lines.push(` Regression Comparison`);
|
|
459
|
+
lines.push(` ─────────────────────────────────────────`);
|
|
460
|
+
lines.push(` Previous: ${result.PreviousDate} (${result.PreviousRunId.substring(0, 8)})`);
|
|
461
|
+
lines.push(` Current: ${result.CurrentDate} (${result.CurrentRunId.substring(0, 8)})`);
|
|
462
|
+
lines.push('');
|
|
463
|
+
lines.push(` Regressions: ${result.Regressions}${hasRegressions ? ' ⚠️' : ''}`);
|
|
464
|
+
lines.push(` Improvements: ${result.Improvements}`);
|
|
465
|
+
lines.push(` Unchanged: ${result.Unchanged}`);
|
|
466
|
+
lines.push('');
|
|
467
|
+
for (const t of tests) {
|
|
468
|
+
if (diffOnly && t.Change === 'unchanged')
|
|
469
|
+
continue;
|
|
470
|
+
const icon = t.Change === 'regression' ? '▼' : t.Change === 'improvement' ? '▲' : t.Change === 'new' ? '+' : t.Change === 'removed' ? '-' : ' ';
|
|
471
|
+
const prev = t.PreviousScore != null ? `${(t.PreviousScore * 100).toFixed(0)}%` : ' -';
|
|
472
|
+
const curr = t.CurrentScore != null ? `${(t.CurrentScore * 100).toFixed(0)}%` : ' -';
|
|
473
|
+
const delta = t.ScoreDelta != null ? `${t.ScoreDelta > 0 ? '+' : ''}${(t.ScoreDelta * 100).toFixed(0)}%` : ' -';
|
|
474
|
+
lines.push(` ${icon} ${t.TestName.padEnd(45)} ${prev.padStart(4)} → ${curr.padStart(4)} (${delta.padStart(5)}) ${t.Change}`);
|
|
475
|
+
}
|
|
476
|
+
lines.push('');
|
|
43
477
|
}
|
|
478
|
+
return lines.join('\n');
|
|
44
479
|
}
|
|
45
480
|
}
|
|
46
481
|
//# sourceMappingURL=compare.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACvB;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,CACT,MAA0B,EAC1B,MAA0B,EAC1B,KAAmB,EACnB,WAAsB;QAEtB,IAAI,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,UAAU,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC/E,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;YACnC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;YAEnE,kCAAkC;YAClC,qCAAqC;YACrC,qDAAqD;YACrD,yDAAyD;YACzD,oCAAoC;YACpC,+CAA+C;QAEnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,eAAe,CAAC,WAAW,CAAC,6BAA6B,EAAE,KAAc,CAAC,CAAC,CAAC;YAC1F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;CACJ"}
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/run.d.ts
CHANGED
|
@@ -17,5 +17,10 @@ export declare class RunCommand {
|
|
|
17
17
|
* @param contextUser - Optional user context (will be fetched if not provided)
|
|
18
18
|
*/
|
|
19
19
|
execute(testId: string | undefined, flags: RunFlags, contextUser?: UserInfo): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Validate that a test is ready to execute without actually running it.
|
|
22
|
+
* Catches misconfigured oracles, malformed JSON, and missing drivers.
|
|
23
|
+
*/
|
|
24
|
+
private dryRunValidation;
|
|
20
25
|
}
|
|
21
26
|
//# sourceMappingURL=run.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQpC;;GAEG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,OAAO,CAAwB;IAEvC;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA8KjG;;;OAGG;IACH,OAAO,CAAC,gBAAgB;CA2F3B"}
|