@elench/testkit 0.1.80 → 0.1.81
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/README.md +50 -35
- package/lib/cli/args.mjs +2 -14
- package/lib/cli/args.test.mjs +1 -17
- package/lib/cli/command-helpers.mjs +1 -20
- package/lib/cli/entrypoint.mjs +0 -4
- package/lib/cli/presentation/colors.mjs +1 -1
- package/lib/cli/presentation/failure-presentation.mjs +4 -4
- package/lib/cli/presentation/run-reporter.mjs +23 -9
- package/lib/cli/presentation/run-reporter.test.mjs +12 -6
- package/lib/cli/presentation/summary-box.test.mjs +4 -4
- package/lib/cli/viewer.mjs +18 -19
- package/lib/config/index.mjs +6 -6
- package/lib/config/runtime.mjs +8 -8
- package/lib/config-api/index.d.ts +4 -4
- package/lib/package.test.mjs +4 -4
- package/lib/{known-failures → regressions}/github.mjs +36 -78
- package/lib/regressions/github.test.mjs +324 -0
- package/lib/regressions/index.d.ts +189 -0
- package/lib/{known-failures → regressions}/index.mjs +90 -93
- package/lib/{known-failures → regressions}/index.test.mjs +37 -48
- package/lib/runner/formatting.mjs +49 -34
- package/lib/runner/formatting.test.mjs +16 -15
- package/lib/runner/metadata.mjs +1 -1
- package/lib/runner/orchestrator.mjs +7 -9
- package/lib/runner/regressions.mjs +304 -0
- package/lib/runner/{triage.test.mjs → regressions.test.mjs} +50 -36
- package/lib/runner/reporting.mjs +2 -2
- package/lib/runner/reporting.test.mjs +2 -2
- package/lib/runner/run-finalization.mjs +18 -30
- package/lib/runner/template-steps.mjs +2 -2
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +8 -8
- package/lib/cli/commands/known-failures/render.mjs +0 -19
- package/lib/cli/commands/known-failures/validate.mjs +0 -20
- package/lib/cli/known-failures.mjs +0 -164
- package/lib/known-failures/github.test.mjs +0 -512
- package/lib/known-failures/index.d.ts +0 -192
- package/lib/runner/triage.mjs +0 -221
- /package/lib/{known-failures → regressions}/github-cache.mjs +0 -0
- /package/lib/{known-failures → regressions}/github-transport.mjs +0 -0
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
export type KnownFailureClassification =
|
|
2
|
-
| "expected_failure"
|
|
3
|
-
| "infra"
|
|
4
|
-
| "product_bug"
|
|
5
|
-
| "stale_test"
|
|
6
|
-
| "test_bug";
|
|
7
|
-
|
|
8
|
-
export type KnownFailureState = "closed" | "open";
|
|
9
|
-
|
|
10
|
-
export interface KnownFailureIssueRef {
|
|
11
|
-
repo: string;
|
|
12
|
-
number: number;
|
|
13
|
-
url: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface KnownFailureMatch {
|
|
17
|
-
service?: string;
|
|
18
|
-
type?: string;
|
|
19
|
-
path: string;
|
|
20
|
-
failureKey?: string;
|
|
21
|
-
errorIncludes?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface KnownFailureEntry {
|
|
25
|
-
id: string;
|
|
26
|
-
/** Exact issue-tracker title for the linked issue. */
|
|
27
|
-
title: string;
|
|
28
|
-
classification: KnownFailureClassification;
|
|
29
|
-
state: KnownFailureState;
|
|
30
|
-
issue: KnownFailureIssueRef;
|
|
31
|
-
/** Product-local bug slice or route-family summary. */
|
|
32
|
-
description: string;
|
|
33
|
-
/** Underlying technical cause of the failure. */
|
|
34
|
-
whyFailing: string;
|
|
35
|
-
lastReviewedAt: string;
|
|
36
|
-
matches: KnownFailureMatch[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface KnownFailuresDocument {
|
|
40
|
-
schemaVersion: 1;
|
|
41
|
-
issueRepo?: string | null;
|
|
42
|
-
entries: KnownFailureEntry[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface KnownFailuresValidationResult {
|
|
46
|
-
errors: string[];
|
|
47
|
-
warnings: string[];
|
|
48
|
-
stats: {
|
|
49
|
-
entries: number;
|
|
50
|
-
matches: number;
|
|
51
|
-
failedTests: number;
|
|
52
|
-
triagedFailedTests: number;
|
|
53
|
-
untriagedFailedTests: number;
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface KnownFailureIssueValidationConfig {
|
|
58
|
-
provider?: "github";
|
|
59
|
-
mode?: "off" | "warn" | "error";
|
|
60
|
-
cacheTtlSeconds?: number;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface KnownFailureIssueValidationFinding {
|
|
64
|
-
code: string;
|
|
65
|
-
severity: "warning" | "error";
|
|
66
|
-
message: string;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export interface KnownFailureIssueValidationEntry {
|
|
70
|
-
id: string;
|
|
71
|
-
title: string;
|
|
72
|
-
issue: KnownFailureIssueRef;
|
|
73
|
-
observed: {
|
|
74
|
-
matchedTests: number;
|
|
75
|
-
executedTests: number;
|
|
76
|
-
passedTests: number;
|
|
77
|
-
failedTests: number;
|
|
78
|
-
skippedTests: number;
|
|
79
|
-
notRunTests: number;
|
|
80
|
-
reproduced: boolean;
|
|
81
|
-
};
|
|
82
|
-
github: {
|
|
83
|
-
exists: boolean | null;
|
|
84
|
-
title: string | null;
|
|
85
|
-
state: string | null;
|
|
86
|
-
url: string | null;
|
|
87
|
-
checkedAt: string | null;
|
|
88
|
-
cached: boolean;
|
|
89
|
-
};
|
|
90
|
-
findings: KnownFailureIssueValidationFinding[];
|
|
91
|
-
status: string;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface KnownFailureIssueValidationResult {
|
|
95
|
-
schemaVersion: 2;
|
|
96
|
-
provider: "github";
|
|
97
|
-
mode: "off" | "warn" | "error";
|
|
98
|
-
checkedAt: string;
|
|
99
|
-
repo: {
|
|
100
|
-
detected: string | null;
|
|
101
|
-
remoteUrl: string | null;
|
|
102
|
-
configured: string | null;
|
|
103
|
-
};
|
|
104
|
-
availability: {
|
|
105
|
-
hasFreshData: boolean;
|
|
106
|
-
usedCachedFallback: boolean;
|
|
107
|
-
};
|
|
108
|
-
findings: KnownFailureIssueValidationFinding[];
|
|
109
|
-
summary: {
|
|
110
|
-
entries: number;
|
|
111
|
-
observedEntries: number;
|
|
112
|
-
errors: number;
|
|
113
|
-
warnings: number;
|
|
114
|
-
byCode: Record<string, number>;
|
|
115
|
-
byStatus: Record<string, number>;
|
|
116
|
-
};
|
|
117
|
-
entries: KnownFailureIssueValidationEntry[];
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export declare function loadKnownFailuresConfig(
|
|
121
|
-
productDir: string,
|
|
122
|
-
config: { knownFailuresFile?: string | null } | null
|
|
123
|
-
): KnownFailuresDocument | null;
|
|
124
|
-
export declare function loadKnownFailuresDocument(
|
|
125
|
-
filePath: string,
|
|
126
|
-
relativePath?: string
|
|
127
|
-
): KnownFailuresDocument;
|
|
128
|
-
export declare function normalizeKnownFailuresDocument(
|
|
129
|
-
document: unknown,
|
|
130
|
-
relativePath?: string
|
|
131
|
-
): KnownFailuresDocument;
|
|
132
|
-
export declare function validateKnownFailuresDocument(
|
|
133
|
-
document: KnownFailuresDocument,
|
|
134
|
-
options?: {
|
|
135
|
-
productDir?: string;
|
|
136
|
-
statusArtifactPath?: string;
|
|
137
|
-
statusArtifact?: unknown;
|
|
138
|
-
}
|
|
139
|
-
): KnownFailuresValidationResult;
|
|
140
|
-
export declare function renderKnownFailuresMarkdown(document: KnownFailuresDocument): string;
|
|
141
|
-
export declare function findMatchingKnownFailureEntries(
|
|
142
|
-
document: KnownFailuresDocument,
|
|
143
|
-
fileSummary: {
|
|
144
|
-
service?: string;
|
|
145
|
-
type?: string;
|
|
146
|
-
path: string;
|
|
147
|
-
status?: string;
|
|
148
|
-
error?: string | null;
|
|
149
|
-
failureDetails?: Array<{ key?: string }>;
|
|
150
|
-
}
|
|
151
|
-
): KnownFailureEntry[];
|
|
152
|
-
export declare function matchesKnownFailureEntry(
|
|
153
|
-
entry: KnownFailureEntry,
|
|
154
|
-
fileSummary: {
|
|
155
|
-
service?: string;
|
|
156
|
-
type?: string;
|
|
157
|
-
path: string;
|
|
158
|
-
error?: string | null;
|
|
159
|
-
failureDetails?: Array<{ key?: string }>;
|
|
160
|
-
}
|
|
161
|
-
): boolean;
|
|
162
|
-
export declare function buildKnownFailureFileIdentity(
|
|
163
|
-
service: string,
|
|
164
|
-
type: string,
|
|
165
|
-
filePath: string
|
|
166
|
-
): string;
|
|
167
|
-
|
|
168
|
-
export declare function normalizeKnownFailureIssueValidationConfig(
|
|
169
|
-
value: unknown
|
|
170
|
-
): {
|
|
171
|
-
provider: "github";
|
|
172
|
-
mode: "off" | "warn" | "error";
|
|
173
|
-
cacheTtlSeconds: number;
|
|
174
|
-
} | null;
|
|
175
|
-
export declare function validateKnownFailureIssues(options: {
|
|
176
|
-
productDir: string;
|
|
177
|
-
document: KnownFailuresDocument | null;
|
|
178
|
-
runArtifact?: unknown;
|
|
179
|
-
statusArtifact?: unknown;
|
|
180
|
-
config?: KnownFailureIssueValidationConfig | null;
|
|
181
|
-
gitMetadata?: {
|
|
182
|
-
repoSlug?: string | null;
|
|
183
|
-
remoteUrl?: string | null;
|
|
184
|
-
} | null;
|
|
185
|
-
}): Promise<KnownFailureIssueValidationResult | null>;
|
|
186
|
-
export declare function shouldFailKnownFailureIssueValidation(
|
|
187
|
-
result: KnownFailureIssueValidationResult | null
|
|
188
|
-
): boolean;
|
|
189
|
-
export declare function buildKnownFailureIssueValidationSummaryLines(
|
|
190
|
-
result: KnownFailureIssueValidationResult | null
|
|
191
|
-
): string[];
|
|
192
|
-
export declare function parseGitHubRepoSlug(remoteUrl: string | null | undefined): string | null;
|
package/lib/runner/triage.mjs
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildKnownFailureFileIdentity,
|
|
3
|
-
findMatchingKnownFailureEntries,
|
|
4
|
-
loadKnownFailuresConfig,
|
|
5
|
-
} from "../known-failures/index.mjs";
|
|
6
|
-
|
|
7
|
-
export { loadKnownFailuresConfig };
|
|
8
|
-
|
|
9
|
-
export function applyKnownFailuresToArtifacts(runArtifact, statusArtifact, knownFailures) {
|
|
10
|
-
if (!knownFailures) return { runArtifact, statusArtifact };
|
|
11
|
-
|
|
12
|
-
const runEntries = extractRunFileEntries(runArtifact);
|
|
13
|
-
const statusEntries = extractStatusFileEntries(statusArtifact);
|
|
14
|
-
const fileSummaries = new Map();
|
|
15
|
-
|
|
16
|
-
for (const entry of [...runEntries, ...statusEntries]) {
|
|
17
|
-
const key = buildKnownFailureFileIdentity(entry.service, entry.type, entry.path);
|
|
18
|
-
if (!fileSummaries.has(key)) {
|
|
19
|
-
fileSummaries.set(key, {
|
|
20
|
-
service: entry.service,
|
|
21
|
-
type: entry.type,
|
|
22
|
-
path: entry.path,
|
|
23
|
-
status: entry.status,
|
|
24
|
-
error: entry.error || null,
|
|
25
|
-
failureDetails: Array.isArray(entry.failureDetails) ? entry.failureDetails : [],
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const matchesByFileKey = new Map();
|
|
31
|
-
const matchedByFailedEntryIds = new Set();
|
|
32
|
-
|
|
33
|
-
for (const fileSummary of fileSummaries.values()) {
|
|
34
|
-
const matches = findMatchingKnownFailureEntries(knownFailures, fileSummary);
|
|
35
|
-
if (matches.length === 0) continue;
|
|
36
|
-
|
|
37
|
-
const fileKey = buildKnownFailureFileIdentity(
|
|
38
|
-
fileSummary.service,
|
|
39
|
-
fileSummary.type,
|
|
40
|
-
fileSummary.path
|
|
41
|
-
);
|
|
42
|
-
matchesByFileKey.set(fileKey, matches.map((entry) => toArtifactTriageEntry(entry)));
|
|
43
|
-
if (fileSummary.status === "failed") {
|
|
44
|
-
for (const entry of matches) {
|
|
45
|
-
matchedByFailedEntryIds.add(entry.id);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
for (const entry of [...runEntries, ...statusEntries]) {
|
|
51
|
-
const fileKey = buildKnownFailureFileIdentity(entry.service, entry.type, entry.path);
|
|
52
|
-
const matches = matchesByFileKey.get(fileKey) || [];
|
|
53
|
-
if (matches.length === 0) {
|
|
54
|
-
if (entry.status === "failed") {
|
|
55
|
-
setEntryTriage(entry, {
|
|
56
|
-
status: "untriaged",
|
|
57
|
-
entries: [],
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
setEntryTriage(entry, {
|
|
64
|
-
status: entry.status === "failed" ? "known_failure" : "known_issue_not_reproduced",
|
|
65
|
-
classifications: [...new Set(matches.map((match) => match.classification))].sort(),
|
|
66
|
-
entries: matches,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const summaryTests = statusArtifact?.tests || runEntries;
|
|
71
|
-
const triageSummary = buildTriageSummary(
|
|
72
|
-
summaryTests,
|
|
73
|
-
knownFailures.entries,
|
|
74
|
-
matchedByFailedEntryIds
|
|
75
|
-
);
|
|
76
|
-
runArtifact.triageSummary = triageSummary;
|
|
77
|
-
if (statusArtifact) {
|
|
78
|
-
statusArtifact.triageSummary = triageSummary;
|
|
79
|
-
}
|
|
80
|
-
return { runArtifact, statusArtifact };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function applyKnownFailureIssueValidationToArtifacts(
|
|
84
|
-
runArtifact,
|
|
85
|
-
statusArtifact,
|
|
86
|
-
issueValidation
|
|
87
|
-
) {
|
|
88
|
-
if (!issueValidation) return { runArtifact, statusArtifact };
|
|
89
|
-
|
|
90
|
-
const validationById = new Map(
|
|
91
|
-
(issueValidation.entries || []).map((entry) => [entry.id, entry])
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
for (const entry of [...extractRunFileEntries(runArtifact), ...extractStatusFileEntries(statusArtifact)]) {
|
|
95
|
-
const triage = entry.target ? entry.target.triage : entry.triage;
|
|
96
|
-
if (!triage?.entries?.length) continue;
|
|
97
|
-
|
|
98
|
-
const matchedValidationEntries = triage.entries
|
|
99
|
-
.map((triageEntry) => validationById.get(triageEntry.id))
|
|
100
|
-
.filter(Boolean);
|
|
101
|
-
|
|
102
|
-
if (matchedValidationEntries.length === 0) continue;
|
|
103
|
-
|
|
104
|
-
const enrichedEntries = triage.entries.map((triageEntry) => {
|
|
105
|
-
const validationEntry = validationById.get(triageEntry.id);
|
|
106
|
-
if (!validationEntry) return triageEntry;
|
|
107
|
-
return {
|
|
108
|
-
...triageEntry,
|
|
109
|
-
github: validationEntry.github,
|
|
110
|
-
validationStatus: validationEntry.status,
|
|
111
|
-
findings: validationEntry.findings,
|
|
112
|
-
};
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const nextTriage = {
|
|
116
|
-
...triage,
|
|
117
|
-
entries: enrichedEntries,
|
|
118
|
-
availability: summarizeIssueValidationAvailability(issueValidation, matchedValidationEntries),
|
|
119
|
-
};
|
|
120
|
-
setEntryTriage(entry, nextTriage);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return { runArtifact, statusArtifact };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function toArtifactTriageEntry(entry) {
|
|
127
|
-
return {
|
|
128
|
-
id: entry.id,
|
|
129
|
-
title: entry.title,
|
|
130
|
-
classification: entry.classification,
|
|
131
|
-
state: entry.state,
|
|
132
|
-
issue: entry.issue,
|
|
133
|
-
description: entry.description,
|
|
134
|
-
whyFailing: entry.whyFailing,
|
|
135
|
-
lastReviewedAt: entry.lastReviewedAt,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function buildTriageSummary(tests, entries, matchedEntryIds) {
|
|
140
|
-
const failedTests = tests.filter((test) => test.status === "failed");
|
|
141
|
-
const knownFailedTests = failedTests.filter((test) => test.triage?.status === "known_failure");
|
|
142
|
-
const byClassification = {};
|
|
143
|
-
|
|
144
|
-
for (const test of knownFailedTests) {
|
|
145
|
-
for (const classification of test.triage?.classifications || []) {
|
|
146
|
-
byClassification[classification] = (byClassification[classification] || 0) + 1;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
failed: {
|
|
152
|
-
total: failedTests.length,
|
|
153
|
-
known: knownFailedTests.length,
|
|
154
|
-
untriaged: failedTests.length - knownFailedTests.length,
|
|
155
|
-
byClassification,
|
|
156
|
-
},
|
|
157
|
-
entries: {
|
|
158
|
-
total: entries.length,
|
|
159
|
-
matchedByFailedTests: matchedEntryIds.size,
|
|
160
|
-
unmatched: entries.length - matchedEntryIds.size,
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function extractRunFileEntries(runArtifact) {
|
|
166
|
-
const entries = [];
|
|
167
|
-
|
|
168
|
-
for (const service of runArtifact.services || []) {
|
|
169
|
-
for (const suite of service.suites || []) {
|
|
170
|
-
for (const file of suite.files || []) {
|
|
171
|
-
entries.push({
|
|
172
|
-
target: file,
|
|
173
|
-
service: service.name,
|
|
174
|
-
type: suite.type,
|
|
175
|
-
path: file.path,
|
|
176
|
-
status: file.status,
|
|
177
|
-
error: file.error || null,
|
|
178
|
-
failureDetails: Array.isArray(file.failureDetails) ? file.failureDetails : [],
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return entries;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function extractStatusFileEntries(statusArtifact) {
|
|
188
|
-
return statusArtifact?.tests || [];
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function setEntryTriage(entry, triage) {
|
|
192
|
-
if (entry?.target) {
|
|
193
|
-
entry.target.triage = triage;
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
entry.triage = triage;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function summarizeIssueValidationAvailability(issueValidation, entries) {
|
|
200
|
-
if (entries.some((entry) => entry.github?.cached)) {
|
|
201
|
-
return {
|
|
202
|
-
mode: "cache",
|
|
203
|
-
reason: issueValidation.availability?.usedCachedFallback
|
|
204
|
-
? "used stale cache"
|
|
205
|
-
: "used cached issue metadata",
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
if (entries.some((entry) => entry.status === "validation_unavailable")) {
|
|
209
|
-
const globalReason = (issueValidation.findings || []).find(
|
|
210
|
-
(finding) => finding.code === "validation_unavailable"
|
|
211
|
-
);
|
|
212
|
-
return {
|
|
213
|
-
mode: "offline",
|
|
214
|
-
reason: globalReason?.message || "validation unavailable",
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
return {
|
|
218
|
-
mode: "live",
|
|
219
|
-
reason: null,
|
|
220
|
-
};
|
|
221
|
-
}
|
|
File without changes
|
|
File without changes
|