@sentinelqa/playwright-reporter 0.1.47 → 0.1.50
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/localReport.js +34 -11
- package/dist/quickDiagnosis.d.ts +68 -4
- package/dist/quickDiagnosis.js +813 -97
- package/dist/reporter.d.ts +1 -0
- package/dist/reporter.js +81 -20
- package/dist/runHistory.d.ts +4 -0
- package/dist/runHistory.js +113 -3
- package/dist/terminalSummary.d.ts +27 -1
- package/dist/terminalSummary.js +229 -40
- package/package.json +2 -2
package/dist/localReport.js
CHANGED
|
@@ -95,21 +95,25 @@ const safeSlug = (value) => {
|
|
|
95
95
|
.replace(/^-+|-+$/g, "")
|
|
96
96
|
.slice(0, 64) || "artifact");
|
|
97
97
|
};
|
|
98
|
+
const cleanTitleParts = (parts) => {
|
|
99
|
+
const normalized = parts.map((part) => String(part || "").trim()).filter(Boolean);
|
|
100
|
+
const withoutUnnamed = normalized.filter((part) => part !== "Unnamed test");
|
|
101
|
+
return withoutUnnamed.length ? withoutUnnamed : normalized;
|
|
102
|
+
};
|
|
98
103
|
const buildTitlePath = (baseTitles, test) => {
|
|
99
104
|
const title = typeof test?.title === "string" ? test.title : null;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return [...baseTitles, title].filter(Boolean);
|
|
105
|
+
const next = !title || baseTitles[baseTitles.length - 1] === title
|
|
106
|
+
? baseTitles.filter(Boolean)
|
|
107
|
+
: [...baseTitles, title].filter(Boolean);
|
|
108
|
+
return cleanTitleParts(next);
|
|
105
109
|
};
|
|
106
110
|
const buildTestIdentity = (test, titlePath) => {
|
|
107
111
|
const file = test?.location?.file || "unknown";
|
|
108
112
|
const project = test?.projectName || "default";
|
|
109
|
-
const joined = titlePath.join(" > ");
|
|
113
|
+
const joined = cleanTitleParts(titlePath).join(" > ");
|
|
110
114
|
return {
|
|
111
115
|
id: [file, project, joined].join("::"),
|
|
112
|
-
matchKey: [file, joined].join("::")
|
|
116
|
+
matchKey: [file, project, joined].join("::")
|
|
113
117
|
};
|
|
114
118
|
};
|
|
115
119
|
const formatDuration = (durationMs) => {
|
|
@@ -223,6 +227,18 @@ const resolveExistingFile = (candidate, baseDirs) => {
|
|
|
223
227
|
}
|
|
224
228
|
return null;
|
|
225
229
|
};
|
|
230
|
+
const readAttachmentJson = (attachments, name, baseDirs) => {
|
|
231
|
+
const attachment = attachments.find((item) => item?.name === name && item?.path);
|
|
232
|
+
const resolved = resolveExistingFile(attachment?.path, baseDirs);
|
|
233
|
+
if (!resolved)
|
|
234
|
+
return null;
|
|
235
|
+
try {
|
|
236
|
+
return JSON.parse(fs_1.default.readFileSync(resolved, "utf8"));
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
226
242
|
const copyArtifact = (sourcePath, kind, reportDir, usedRelativePaths, testId) => {
|
|
227
243
|
const hash = crypto_1.default
|
|
228
244
|
.createHash("sha1")
|
|
@@ -253,6 +269,8 @@ const copyArtifact = (sourcePath, kind, reportDir, usedRelativePaths, testId) =>
|
|
|
253
269
|
const createReportTest = (test, titlePath) => {
|
|
254
270
|
const results = Array.isArray(test?.results) ? test.results : [];
|
|
255
271
|
const lastResult = results.length > 0 ? results[results.length - 1] : null;
|
|
272
|
+
const attachments = Array.isArray(lastResult?.attachments) ? lastResult.attachments : [];
|
|
273
|
+
const baseDirs = [process.cwd(), path_1.default.resolve(process.cwd(), "test-results")];
|
|
256
274
|
const errors = results.flatMap((result) => Array.isArray(result?.errors)
|
|
257
275
|
? result.errors
|
|
258
276
|
.map((error) => error?.message || error?.stack || String(error || ""))
|
|
@@ -265,15 +283,20 @@ const createReportTest = (test, titlePath) => {
|
|
|
265
283
|
return {
|
|
266
284
|
id: identity.id,
|
|
267
285
|
matchKey: identity.matchKey,
|
|
268
|
-
title: test?.title || titlePath[titlePath.length - 1] || "Untitled test",
|
|
269
|
-
titlePath,
|
|
286
|
+
title: cleanTitleParts(titlePath).slice(-1)[0] || test?.title || titlePath[titlePath.length - 1] || "Untitled test",
|
|
287
|
+
titlePath: cleanTitleParts(titlePath),
|
|
270
288
|
file: test?.location?.file || null,
|
|
271
289
|
projectName: test?.projectName || null,
|
|
272
290
|
status,
|
|
273
291
|
duration,
|
|
274
292
|
errors,
|
|
275
293
|
diagnosis: ["failed", "timedOut", "interrupted"].includes(status) && primaryError
|
|
276
|
-
? (0, quickDiagnosis_1.parseFailureFacts)(test?.title || titlePath[titlePath.length - 1] || "Untitled test", titlePath, primaryError, status
|
|
294
|
+
? (0, quickDiagnosis_1.parseFailureFacts)(cleanTitleParts(titlePath).slice(-1)[0] || test?.title || titlePath[titlePath.length - 1] || "Untitled test", cleanTitleParts(titlePath), primaryError, status, test?.location?.file || null, {
|
|
295
|
+
projectName: test?.projectName || null,
|
|
296
|
+
timeoutBudgetMs: typeof test?.timeout === "number" ? test.timeout : null,
|
|
297
|
+
codeContext: readAttachmentJson(attachments, "sentinel-code-context", baseDirs),
|
|
298
|
+
domCapture: readAttachmentJson(attachments, "sentinel-dom-capture", baseDirs)
|
|
299
|
+
})
|
|
277
300
|
: null,
|
|
278
301
|
artifacts: []
|
|
279
302
|
};
|
|
@@ -384,7 +407,7 @@ const buildRunSnapshot = (tests, summary) => ({
|
|
|
384
407
|
tests: tests.map((test) => ({
|
|
385
408
|
id: test.id,
|
|
386
409
|
matchKey: test.matchKey,
|
|
387
|
-
title: test.titlePath.join(" > ") || test.title,
|
|
410
|
+
title: cleanTitleParts(test.titlePath).join(" > ") || test.title,
|
|
388
411
|
status: test.status,
|
|
389
412
|
signal: test.diagnosis?.signal || null,
|
|
390
413
|
locator: test.diagnosis?.locator || null,
|
package/dist/quickDiagnosis.d.ts
CHANGED
|
@@ -1,24 +1,88 @@
|
|
|
1
|
-
type DiagnosisSignal = "timeout" | "assertion_mismatch" | "locator_not_found" | "actionability" | "network" | "runtime" | "unknown";
|
|
1
|
+
type DiagnosisSignal = "timeout" | "assertion_mismatch" | "locator_not_found" | "actionability" | "network" | "runtime" | "infra" | "unknown";
|
|
2
2
|
type QuickDiagnosis = {
|
|
3
3
|
lines: string[];
|
|
4
|
+
footer?: string[];
|
|
5
|
+
};
|
|
6
|
+
type CodeContextCapture = {
|
|
7
|
+
file?: string | null;
|
|
8
|
+
line?: number | null;
|
|
9
|
+
column?: number | null;
|
|
10
|
+
action?: string | null;
|
|
11
|
+
locator?: string | null;
|
|
12
|
+
expectedText?: string | null;
|
|
13
|
+
timeoutMs?: number | null;
|
|
14
|
+
apiCall?: string | null;
|
|
15
|
+
assertion?: string | null;
|
|
16
|
+
methodName?: string | null;
|
|
17
|
+
focusLine?: string | null;
|
|
18
|
+
previousActionLine?: string | null;
|
|
19
|
+
found?: boolean;
|
|
20
|
+
};
|
|
21
|
+
type DomCapture = {
|
|
22
|
+
locator?: string | null;
|
|
23
|
+
expectedText?: string | null;
|
|
24
|
+
observedText?: string | null;
|
|
25
|
+
captureSource?: "live_page" | "error_fallback";
|
|
26
|
+
matchedCount?: number | null;
|
|
27
|
+
targetFound?: boolean | null;
|
|
28
|
+
visible?: boolean | null;
|
|
29
|
+
attached?: boolean | null;
|
|
30
|
+
enabled?: boolean | null;
|
|
31
|
+
testId?: string | null;
|
|
32
|
+
role?: string | null;
|
|
33
|
+
accessibleName?: string | null;
|
|
34
|
+
textContent?: string | null;
|
|
35
|
+
tagName?: string | null;
|
|
36
|
+
inputType?: string | null;
|
|
37
|
+
placeholder?: string | null;
|
|
38
|
+
ariaLabel?: string | null;
|
|
39
|
+
textAlternatives?: string[] | null;
|
|
40
|
+
matchedElements?: Array<{
|
|
41
|
+
index: number;
|
|
42
|
+
role: string | null;
|
|
43
|
+
accessibleName: string | null;
|
|
44
|
+
visible: boolean | null;
|
|
45
|
+
enabled: boolean | null;
|
|
46
|
+
text: string | null;
|
|
47
|
+
}> | null;
|
|
4
48
|
};
|
|
5
49
|
export type FailureFacts = {
|
|
6
50
|
title: string;
|
|
7
51
|
titlePath: string[];
|
|
52
|
+
projectName: string | null;
|
|
8
53
|
message: string;
|
|
54
|
+
firstErrorLine: string | null;
|
|
9
55
|
signal: DiagnosisSignal;
|
|
10
56
|
locator: string | null;
|
|
11
57
|
expected: string | null;
|
|
12
58
|
received: string | null;
|
|
13
59
|
timeoutMs: number | null;
|
|
60
|
+
timeoutBudgetMs: number | null;
|
|
14
61
|
lastUrl: string | null;
|
|
15
62
|
status: string;
|
|
63
|
+
file: string | null;
|
|
64
|
+
likelyFile: string | null;
|
|
65
|
+
likelyModule: string | null;
|
|
66
|
+
apiHint: string | null;
|
|
67
|
+
codeContext: CodeContextCapture | null;
|
|
68
|
+
domCapture: DomCapture | null;
|
|
16
69
|
};
|
|
17
|
-
export declare const collectFailureFacts: (playwrightJsonPath: string) => FailureFacts[];
|
|
18
|
-
export declare const parseFailureFacts: (title: string, titlePath: string[], message: string, status: string) => FailureFacts;
|
|
19
70
|
export declare const describeFailure: (failure: FailureFacts) => string;
|
|
71
|
+
export declare const parseFailureFacts: (title: string, titlePath: string[], message: string, status: string, file?: string | null, options?: {
|
|
72
|
+
projectName?: string | null;
|
|
73
|
+
timeoutBudgetMs?: number | null;
|
|
74
|
+
codeContext?: CodeContextCapture | null;
|
|
75
|
+
domCapture?: DomCapture | null;
|
|
76
|
+
errorLocation?: {
|
|
77
|
+
file?: string | null;
|
|
78
|
+
line?: number | null;
|
|
79
|
+
column?: number | null;
|
|
80
|
+
} | null;
|
|
81
|
+
errorSnippet?: string | null;
|
|
82
|
+
}) => FailureFacts;
|
|
83
|
+
export declare const collectFailureFacts: (playwrightJsonPath: string) => FailureFacts[];
|
|
20
84
|
export declare const buildDebugSummary: (failure: FailureFacts) => string;
|
|
21
85
|
export declare const buildSimilarityKey: (failure: FailureFacts) => string;
|
|
22
|
-
export declare const summarizeSignal: (signal: DiagnosisSignal) => "timeout while waiting for UI or network conditions" | "assertion mismatch between expected and rendered UI state" | "missing or changed locator" | "target element was not actionable" | "network or API failure" | "
|
|
86
|
+
export declare const summarizeSignal: (signal: DiagnosisSignal) => "timeout while waiting for UI or network conditions" | "assertion mismatch between expected and rendered UI state" | "missing or changed locator" | "target element was not actionable" | "network or API failure" | "runtime error thrown before the flow completed" | "browser or CI infrastructure failure" | "failure signal could not be classified cleanly";
|
|
23
87
|
export declare const buildQuickDiagnosis: (playwrightJsonPath: string) => QuickDiagnosis | null;
|
|
24
88
|
export {};
|