reporting-labs 0.6.10 → 0.6.12
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 +35 -4
- package/dist/explain.d.ts +1 -1
- package/dist/explain.js +4 -0
- package/dist/pdf.d.ts +14 -0
- package/dist/pdf.js +149 -0
- package/dist/reporter.d.ts +14 -0
- package/dist/reporter.js +15 -0
- package/dist/template.html +335 -37
- package/dist/template.js +335 -37
- package/dist/types.d.ts +10 -0
- package/dist/wdio/env.d.ts +4 -0
- package/dist/wdio/env.js +62 -0
- package/dist/wdio/finalize.d.ts +39 -0
- package/dist/wdio/finalize.js +189 -0
- package/dist/wdio/index.d.ts +17 -0
- package/dist/wdio/index.js +22 -0
- package/dist/wdio/reporter.d.ts +67 -0
- package/dist/wdio/reporter.js +332 -0
- package/package.json +10 -1
package/dist/types.d.ts
CHANGED
|
@@ -17,6 +17,16 @@ export interface ReportingLabsOptions {
|
|
|
17
17
|
emitJson?: boolean;
|
|
18
18
|
/** File name of the JSON blob inside outputFolder. Default: "report.json" */
|
|
19
19
|
jsonFile?: string;
|
|
20
|
+
/** Also write a print-ready `report.pdf` next to the HTML, rendered by headless Chromium from the
|
|
21
|
+
* report's own PDF layout (executive summary, charts, failure analysis, the full test-case table and
|
|
22
|
+
* screenshots of failures). Printed by the Chromium that Playwright provides, else by an installed
|
|
23
|
+
* Chrome, Edge or Chromium, whichever browser the tests ran on (Firefox and WebKit runs included). Default: true — set `false` to skip,
|
|
24
|
+
* `{ file }` to rename, `{ chromePath }` to name the browser (or set CHROME_PATH). The report also has
|
|
25
|
+
* an "Export PDF" button. */
|
|
26
|
+
pdf?: boolean | {
|
|
27
|
+
file?: string;
|
|
28
|
+
chromePath?: string;
|
|
29
|
+
};
|
|
20
30
|
/** Inline screenshots as base64 (single file, opens anywhere). Default: true */
|
|
21
31
|
embedAttachments?: boolean;
|
|
22
32
|
/** Max size (bytes) of a single attachment to embed. Larger ones are copied as files. Default: 2 MB */
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ciRunLabel } from '../reporter';
|
|
2
|
+
import type { EnvRow } from '../types';
|
|
3
|
+
export { ciRunLabel };
|
|
4
|
+
export declare function collectEnv(base: string, extra: Record<string, string> | undefined, browsers: string[], workers: number, metadataBranch?: string): EnvRow[];
|
package/dist/wdio/env.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ciRunLabel = void 0;
|
|
37
|
+
exports.collectEnv = collectEnv;
|
|
38
|
+
/** Environment-card rows for the WDIO report, reusing the Playwright reporter's CI/git helpers. */
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const reporter_1 = require("../reporter");
|
|
41
|
+
Object.defineProperty(exports, "ciRunLabel", { enumerable: true, get: function () { return reporter_1.ciRunLabel; } });
|
|
42
|
+
function collectEnv(base, extra, browsers, workers, metadataBranch) {
|
|
43
|
+
const env = process.env;
|
|
44
|
+
const rows = [];
|
|
45
|
+
rows.push({ k: 'Node', v: process.version });
|
|
46
|
+
rows.push({ k: 'OS', v: `${os.type()} ${os.release()} (${os.arch()})` });
|
|
47
|
+
if (browsers.length)
|
|
48
|
+
rows.push({ k: 'Browsers', v: browsers.join(', ') });
|
|
49
|
+
if (workers > 1)
|
|
50
|
+
rows.push({ k: 'Workers', v: String(workers) });
|
|
51
|
+
const ci = (0, reporter_1.ciLink)(env);
|
|
52
|
+
if (ci)
|
|
53
|
+
rows.push({ k: 'CI', v: ci.name, href: ci.url });
|
|
54
|
+
const git = (0, reporter_1.gitInfo)(base, env);
|
|
55
|
+
if (git.sha)
|
|
56
|
+
rows.push({ k: 'Commit', v: `${git.sha.slice(0, 7)}${git.author ? ' · ' + git.author : ''}${git.subject ? ' · ' + git.subject : ''}`, href: git.url });
|
|
57
|
+
if (git.branch && !metadataBranch)
|
|
58
|
+
rows.push({ k: 'Branch', v: git.branch });
|
|
59
|
+
for (const [k, v] of Object.entries(extra || {}))
|
|
60
|
+
rows.push({ k, v: String(v), href: /^https?:\/\//.test(String(v)) ? String(v) : undefined });
|
|
61
|
+
return rows;
|
|
62
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface ReportingLabsCompleteOptions {
|
|
2
|
+
outputFolder?: string;
|
|
3
|
+
outputFile?: string;
|
|
4
|
+
jsonFile?: string;
|
|
5
|
+
emitJson?: boolean;
|
|
6
|
+
pdf?: boolean | {
|
|
7
|
+
file?: string;
|
|
8
|
+
chromePath?: string;
|
|
9
|
+
};
|
|
10
|
+
title?: string;
|
|
11
|
+
logo?: string;
|
|
12
|
+
accent?: string;
|
|
13
|
+
theme?: 'auto' | 'light' | 'dark';
|
|
14
|
+
palette?: 'lab' | 'ocean' | 'ember' | 'mono';
|
|
15
|
+
metadata?: Record<string, string>;
|
|
16
|
+
env?: Record<string, string>;
|
|
17
|
+
sections?: {
|
|
18
|
+
title: string;
|
|
19
|
+
html: string;
|
|
20
|
+
}[];
|
|
21
|
+
customCss?: string;
|
|
22
|
+
dimensions?: string[];
|
|
23
|
+
dimensionOrder?: Record<string, string[]>;
|
|
24
|
+
project?: unknown;
|
|
25
|
+
links?: Record<string, unknown>;
|
|
26
|
+
bdd?: boolean;
|
|
27
|
+
announce?: boolean;
|
|
28
|
+
history?: {
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
file?: string;
|
|
31
|
+
keep?: number;
|
|
32
|
+
};
|
|
33
|
+
maskKeys?: string[];
|
|
34
|
+
maskValues?: string[];
|
|
35
|
+
maskFromEnv?: boolean;
|
|
36
|
+
embedFonts?: boolean;
|
|
37
|
+
editorLinks?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export declare function reportingLabsComplete(options?: ReportingLabsCompleteOptions): Promise<string | undefined>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.reportingLabsComplete = reportingLabsComplete;
|
|
37
|
+
/**
|
|
38
|
+
* Combines the per-runner partials written by the WDIO reporter into the one report —
|
|
39
|
+
* index.html, report.json and (best-effort) report.pdf. Call it from `onComplete` in wdio.conf:
|
|
40
|
+
*
|
|
41
|
+
* import { reportingLabsComplete } from 'reporting-labs/wdio';
|
|
42
|
+
* export const config = {
|
|
43
|
+
* reporters: [[ReportingLabsWdioReporter, { outputFolder: 'reporting-labs' }]],
|
|
44
|
+
* async onComplete() { await reportingLabsComplete({ outputFolder: 'reporting-labs', title: 'My suite' }); },
|
|
45
|
+
* };
|
|
46
|
+
*/
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const template_1 = require("../template");
|
|
50
|
+
const mask_1 = require("../mask");
|
|
51
|
+
const pdf_1 = require("../pdf");
|
|
52
|
+
const env_1 = require("./env");
|
|
53
|
+
async function reportingLabsComplete(options = {}) {
|
|
54
|
+
const outputFolder = options.outputFolder || 'reporting-labs';
|
|
55
|
+
const partsDir = path.join(outputFolder, '.rl-wdio');
|
|
56
|
+
if (!fs.existsSync(partsDir))
|
|
57
|
+
return undefined;
|
|
58
|
+
const files = fs.readdirSync(partsDir).filter(f => f.endsWith('.json'));
|
|
59
|
+
if (!files.length)
|
|
60
|
+
return undefined;
|
|
61
|
+
const masker = (0, mask_1.makeMasker)(options.maskKeys || [], { knownValues: options.maskValues || [], fromEnv: options.maskFromEnv !== false });
|
|
62
|
+
const tests = [];
|
|
63
|
+
let startTime = Number.MAX_SAFE_INTEGER;
|
|
64
|
+
let endTime = 0;
|
|
65
|
+
let runStatus = 'passed';
|
|
66
|
+
const workers = files.length;
|
|
67
|
+
for (const f of files) {
|
|
68
|
+
let part;
|
|
69
|
+
try {
|
|
70
|
+
part = JSON.parse(fs.readFileSync(path.join(partsDir, f), 'utf8'));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (typeof part.startTime === 'number')
|
|
76
|
+
startTime = Math.min(startTime, part.startTime);
|
|
77
|
+
if (typeof part.endTime === 'number')
|
|
78
|
+
endTime = Math.max(endTime, part.endTime);
|
|
79
|
+
if (part.runStatus === 'failed')
|
|
80
|
+
runStatus = 'failed';
|
|
81
|
+
for (const t of part.tests || [])
|
|
82
|
+
tests.push(t);
|
|
83
|
+
}
|
|
84
|
+
if (startTime === Number.MAX_SAFE_INTEGER)
|
|
85
|
+
startTime = Date.now();
|
|
86
|
+
if (!endTime)
|
|
87
|
+
endTime = Date.now();
|
|
88
|
+
const stats = { passed: 0, failed: 0, skipped: 0, flaky: 0, timedOut: 0, interrupted: 0, total: tests.length };
|
|
89
|
+
for (const t of tests)
|
|
90
|
+
stats[t.outcome]++;
|
|
91
|
+
const projects = [...new Set(tests.map(t => t.project).filter(Boolean))];
|
|
92
|
+
const base = process.cwd();
|
|
93
|
+
const dims = (options.dimensions ?? ['priority', 'severity', 'feature', 'owner']).map(d => d.toLowerCase());
|
|
94
|
+
const histOn = options.history?.enabled ?? true;
|
|
95
|
+
const histFile = path.resolve(base, options.history?.file ?? 'reporting-labs.history.json');
|
|
96
|
+
let entries = [];
|
|
97
|
+
if (histOn) {
|
|
98
|
+
try {
|
|
99
|
+
entries = JSON.parse(fs.readFileSync(histFile, 'utf8'));
|
|
100
|
+
}
|
|
101
|
+
catch { /* first run */ }
|
|
102
|
+
}
|
|
103
|
+
const failedCount = stats.failed + stats.timedOut + stats.interrupted;
|
|
104
|
+
const code = (o) => o === 'passed' ? 'p' : o === 'flaky' ? 'k' : o === 'skipped' ? 's' : 'f';
|
|
105
|
+
const perTest = {};
|
|
106
|
+
for (const t of tests) {
|
|
107
|
+
const last = t.results[t.results.length - 1];
|
|
108
|
+
perTest[t.key] = [code(t.outcome), Math.round(last?.duration ?? t.duration)];
|
|
109
|
+
}
|
|
110
|
+
const current = {
|
|
111
|
+
time: startTime, duration: endTime - startTime,
|
|
112
|
+
passed: stats.passed, failed: failedCount, flaky: stats.flaky, skipped: stats.skipped, total: stats.total,
|
|
113
|
+
label: options.metadata?.build ?? (0, env_1.ciRunLabel)(process.env) ?? options.metadata?.branch, tests: perTest,
|
|
114
|
+
};
|
|
115
|
+
const history = [...entries, current].slice(-(options.history?.keep ?? 30));
|
|
116
|
+
if (histOn) {
|
|
117
|
+
try {
|
|
118
|
+
fs.writeFileSync(histFile, JSON.stringify(history, null, 1));
|
|
119
|
+
}
|
|
120
|
+
catch { /* read-only fs */ }
|
|
121
|
+
}
|
|
122
|
+
const metadata = Object.fromEntries(Object.entries(options.metadata ?? {}).map(([k, v]) => [k, masker.maskStr(String(v))]));
|
|
123
|
+
const bdd = options.bdd ?? tests.some(t => t.results.some(r => r.steps.some(st => /^(Given|When|Then|And|But)\b/.test(st.title))));
|
|
124
|
+
const data = {
|
|
125
|
+
title: masker.maskStr(options.title ?? 'Test report'),
|
|
126
|
+
generatedAt: Date.now(),
|
|
127
|
+
startTime,
|
|
128
|
+
duration: endTime - startTime,
|
|
129
|
+
metadata,
|
|
130
|
+
projects,
|
|
131
|
+
workers,
|
|
132
|
+
stats,
|
|
133
|
+
tests,
|
|
134
|
+
history,
|
|
135
|
+
bdd,
|
|
136
|
+
rootDir: base,
|
|
137
|
+
env: (0, env_1.collectEnv)(base, Object.fromEntries(Object.entries(options.env ?? {}).map(([k, v]) => [k, masker.maskStr(String(v))])), [...new Set(projects)], workers, options.metadata?.branch).map(r => ({ ...r, v: masker.maskStr(r.v) })),
|
|
138
|
+
runStatus,
|
|
139
|
+
globalErrors: [],
|
|
140
|
+
globalOutput: [],
|
|
141
|
+
options: {
|
|
142
|
+
logo: options.logo,
|
|
143
|
+
accent: options.accent,
|
|
144
|
+
theme: options.theme ?? 'auto',
|
|
145
|
+
palette: options.palette ?? 'lab',
|
|
146
|
+
embedFonts: options.embedFonts ?? true,
|
|
147
|
+
sections: options.sections ?? [],
|
|
148
|
+
widgets: { runStrip: true, outcome: true, attention: true, dimensions: true, timeline: true, durations: true, tags: true, slowest: true, projects: true, flaky: true, environment: true, skipped: true },
|
|
149
|
+
dimensions: dims,
|
|
150
|
+
dimensionOrder: {
|
|
151
|
+
priority: ['P0', 'P1', 'P2', 'P3', 'P4'],
|
|
152
|
+
severity: ['blocker', 'critical', 'major', 'high', 'medium', 'normal', 'minor', 'low', 'trivial'],
|
|
153
|
+
...(options.dimensionOrder ?? {}),
|
|
154
|
+
},
|
|
155
|
+
project: options.project,
|
|
156
|
+
links: Object.fromEntries(Object.entries(options.links ?? {}).map(([k, v]) => [k.toLowerCase(), typeof v === 'string' ? v : v.url])),
|
|
157
|
+
customCss: options.customCss ?? '',
|
|
158
|
+
editorLinks: options.editorLinks ?? !process.env.CI,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
fs.mkdirSync(outputFolder, { recursive: true });
|
|
162
|
+
const htmlFile = path.join(outputFolder, options.outputFile ?? 'index.html');
|
|
163
|
+
fs.writeFileSync(htmlFile, (0, template_1.renderHtml)(data), 'utf8');
|
|
164
|
+
if (options.emitJson !== false)
|
|
165
|
+
fs.writeFileSync(path.join(outputFolder, options.jsonFile ?? 'report.json'), JSON.stringify(data), 'utf8');
|
|
166
|
+
// tidy the partials
|
|
167
|
+
try {
|
|
168
|
+
fs.rmSync(partsDir, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
catch { /* leave them */ }
|
|
171
|
+
if (options.announce !== false) {
|
|
172
|
+
console.log(`\n reporting-labs: report written to ${path.relative(process.cwd(), htmlFile)}`);
|
|
173
|
+
}
|
|
174
|
+
if (options.pdf !== false)
|
|
175
|
+
await writePdf(htmlFile, outputFolder, options);
|
|
176
|
+
if (options.announce !== false)
|
|
177
|
+
console.log('');
|
|
178
|
+
return htmlFile;
|
|
179
|
+
}
|
|
180
|
+
/** report.pdf next to the HTML; see writeReportPdf for which browser prints it (an installed Chrome or
|
|
181
|
+
* Edge when the project has no Playwright). Never fails the run. */
|
|
182
|
+
async function writePdf(htmlFile, outputFolder, options) {
|
|
183
|
+
const pdfOpt = typeof options.pdf === 'object' ? options.pdf : {};
|
|
184
|
+
const pdfFile = path.join(outputFolder, pdfOpt.file || 'report.pdf');
|
|
185
|
+
const r = await (0, pdf_1.writeReportPdf)(htmlFile, pdfFile, pdfOpt.chromePath);
|
|
186
|
+
if (options.announce === false)
|
|
187
|
+
return;
|
|
188
|
+
console.log(r.ok ? ` reporting-labs: PDF written to ${path.relative(process.cwd(), pdfFile)}` : ` reporting-labs: PDF skipped — ${r.reason}`);
|
|
189
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reportingLabs for WebdriverIO.
|
|
3
|
+
*
|
|
4
|
+
* // wdio.conf.ts
|
|
5
|
+
* import ReportingLabsReporter, { reportingLabsComplete } from 'reporting-labs/wdio';
|
|
6
|
+
*
|
|
7
|
+
* export const config = {
|
|
8
|
+
* reporters: [[ReportingLabsReporter, { outputFolder: 'reporting-labs' }]],
|
|
9
|
+
* async onComplete() { await reportingLabsComplete({ outputFolder: 'reporting-labs', title: 'My suite' }); },
|
|
10
|
+
* };
|
|
11
|
+
*/
|
|
12
|
+
import ReportingLabsWdioReporter from './reporter';
|
|
13
|
+
export { ReportingLabsWdioReporter };
|
|
14
|
+
export type { ReportingLabsWdioOptions } from './reporter';
|
|
15
|
+
export { reportingLabsComplete } from './finalize';
|
|
16
|
+
export type { ReportingLabsCompleteOptions } from './finalize';
|
|
17
|
+
export default ReportingLabsWdioReporter;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.reportingLabsComplete = exports.ReportingLabsWdioReporter = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* reportingLabs for WebdriverIO.
|
|
9
|
+
*
|
|
10
|
+
* // wdio.conf.ts
|
|
11
|
+
* import ReportingLabsReporter, { reportingLabsComplete } from 'reporting-labs/wdio';
|
|
12
|
+
*
|
|
13
|
+
* export const config = {
|
|
14
|
+
* reporters: [[ReportingLabsReporter, { outputFolder: 'reporting-labs' }]],
|
|
15
|
+
* async onComplete() { await reportingLabsComplete({ outputFolder: 'reporting-labs', title: 'My suite' }); },
|
|
16
|
+
* };
|
|
17
|
+
*/
|
|
18
|
+
const reporter_1 = __importDefault(require("./reporter"));
|
|
19
|
+
exports.ReportingLabsWdioReporter = reporter_1.default;
|
|
20
|
+
var finalize_1 = require("./finalize");
|
|
21
|
+
Object.defineProperty(exports, "reportingLabsComplete", { enumerable: true, get: function () { return finalize_1.reportingLabsComplete; } });
|
|
22
|
+
exports.default = reporter_1.default;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reportingLabs reporter for WebdriverIO.
|
|
3
|
+
*
|
|
4
|
+
* WDIO drives a reporter by emitting lifecycle events onto it and reading `isSynchronised`, so this
|
|
5
|
+
* class is a plain EventEmitter — it needs no `@wdio/reporter` at runtime and stays CommonJS, which
|
|
6
|
+
* loads on every Node version. One instance runs per runner (per spec / worker); it collects that
|
|
7
|
+
* runner's suites, tests, WebDriver-command steps, errors and (on failure) a screenshot, then writes
|
|
8
|
+
* a partial JSON. `reportingLabsComplete()` (a one-line `onComplete` hook) combines every partial into
|
|
9
|
+
* the one report — the same index.html, report.json and report.pdf the Playwright reporter produces.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here touches the Playwright reporter; it only reuses the shared, pure helpers.
|
|
12
|
+
*/
|
|
13
|
+
import { EventEmitter } from 'node:events';
|
|
14
|
+
declare const META_KEYS: string[];
|
|
15
|
+
export interface ReportingLabsWdioOptions {
|
|
16
|
+
outputFolder?: string;
|
|
17
|
+
title?: string;
|
|
18
|
+
screenshot?: 'on-failure' | 'always' | 'off';
|
|
19
|
+
maskKeys?: string[];
|
|
20
|
+
maskValues?: string[];
|
|
21
|
+
maskFromEnv?: boolean;
|
|
22
|
+
[k: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
export default class ReportingLabsWdioReporter extends EventEmitter {
|
|
25
|
+
options: ReportingLabsWdioOptions;
|
|
26
|
+
outputStream: {
|
|
27
|
+
write: (_c: unknown) => boolean;
|
|
28
|
+
};
|
|
29
|
+
private masker;
|
|
30
|
+
private startTime;
|
|
31
|
+
private suiteStack;
|
|
32
|
+
private rlTests;
|
|
33
|
+
private specs;
|
|
34
|
+
private cur?;
|
|
35
|
+
private elTypes;
|
|
36
|
+
private cid;
|
|
37
|
+
private capsName;
|
|
38
|
+
private runStatus;
|
|
39
|
+
private pending;
|
|
40
|
+
private endInfo?;
|
|
41
|
+
private written;
|
|
42
|
+
constructor(options?: ReportingLabsWdioOptions);
|
|
43
|
+
/** WDIO polls this before tearing a worker down; we hold it open until the partial is written. */
|
|
44
|
+
get isSynchronised(): boolean;
|
|
45
|
+
write(_content: unknown): void;
|
|
46
|
+
private safe;
|
|
47
|
+
private onRunnerStart;
|
|
48
|
+
private onSuiteStart;
|
|
49
|
+
private onSuiteEnd;
|
|
50
|
+
private onTestStart;
|
|
51
|
+
private onBeforeCommand;
|
|
52
|
+
private onAfterCommand;
|
|
53
|
+
private endTest;
|
|
54
|
+
/** Best-effort screenshot of the live session on failure. Async — gated by isSynchronised so the
|
|
55
|
+
* partial is written only once it resolves. */
|
|
56
|
+
private maybeShot;
|
|
57
|
+
private toError;
|
|
58
|
+
private onRunnerEnd;
|
|
59
|
+
private tryWrite;
|
|
60
|
+
private rel;
|
|
61
|
+
}
|
|
62
|
+
/** Pull meta (priority/severity/owner/...) from WDIO tags like `@priority:P1`, `@P1`, `@critical`. */
|
|
63
|
+
export declare function metaFromTags(tags: string[], dims: string[]): {
|
|
64
|
+
meta: Record<string, string>;
|
|
65
|
+
clean: string[];
|
|
66
|
+
};
|
|
67
|
+
export { META_KEYS };
|