reporting-labs 0.1.0 → 0.1.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/README.md +3 -1
- package/dist/reporter.d.ts +2 -0
- package/dist/reporter.js +35 -2
- package/dist/template.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,7 +231,9 @@ Ready-to-copy samples: [docs/ci/github-actions.yml](https://github.com/naveenani
|
|
|
231
231
|
|
|
232
232
|
## Good to know
|
|
233
233
|
|
|
234
|
-
- **Single file.** Screenshots and fonts are embedded, so `index.html` works from a mail attachment or a CI artifact. Videos and large files go to `./assets` next to it.
|
|
234
|
+
- **Single file.** Screenshots and fonts are embedded, so `index.html` works from a mail attachment or a CI artifact. Videos and large files go to `./assets` next to it, so keep the folder together when you move or share the report.
|
|
235
|
+
- **Re-running tests replaces the report.** The previous report stays intact until the new run finishes, then `index.html` and `assets/` are replaced. A report tab opened from an earlier run will lose its videos at that point; archive the folder if you need to keep it.
|
|
236
|
+
- **Video download.** Served over http (CI artifact viewer, a local server) the download link saves the file; opened as a plain file the browser opens the video in a new tab instead, where the player's menu offers Save.
|
|
235
237
|
- **Keyboard.** `j` / `k` next and previous test, `f` failed only, `/` search, `1`–`5` switch views, `Esc` close.
|
|
236
238
|
- **Print.** A print stylesheet is included for PDF export.
|
|
237
239
|
- **Themes.** Light and dark follow the OS; the toggle in the header remembers the choice.
|
package/dist/reporter.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export default class ReportingLabsReporter implements Reporter {
|
|
|
20
20
|
private pushOutput;
|
|
21
21
|
onBegin(config: FullConfig, suite: Suite): void;
|
|
22
22
|
onEnd(result: FullResult): Promise<void>;
|
|
23
|
+
/** Videos and traces are finalized asynchronously by the runner; wait until every file-backed attachment stops growing. */
|
|
24
|
+
private settleAttachmentFiles;
|
|
23
25
|
/** Runtime facts for the Environment card: Playwright, Node, OS, browsers, CI job, git commit. */
|
|
24
26
|
private collectEnv;
|
|
25
27
|
private toDataBlock;
|
package/dist/reporter.js
CHANGED
|
@@ -73,10 +73,15 @@ class ReportingLabsReporter {
|
|
|
73
73
|
const base = config.configFile ? path.dirname(config.configFile) : process.cwd();
|
|
74
74
|
this.outDir = path.resolve(base, this.options.outputFolder ?? 'reporting-labs');
|
|
75
75
|
this.assetsDir = path.join(this.outDir, 'assets');
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
// The previous report (and its assets) stays intact while the run is in progress;
|
|
77
|
+
// the folder is refreshed in onEnd, right before the new report is written.
|
|
78
|
+
fs.mkdirSync(this.outDir, { recursive: true });
|
|
78
79
|
}
|
|
79
80
|
async onEnd(result) {
|
|
81
|
+
await this.settleAttachmentFiles();
|
|
82
|
+
fs.rmSync(this.assetsDir, { recursive: true, force: true });
|
|
83
|
+
fs.mkdirSync(this.assetsDir, { recursive: true });
|
|
84
|
+
this.assetCounter = 0;
|
|
80
85
|
const tests = [];
|
|
81
86
|
const projects = new Set();
|
|
82
87
|
let workers = 0;
|
|
@@ -196,6 +201,34 @@ class ReportingLabsReporter {
|
|
|
196
201
|
}
|
|
197
202
|
}
|
|
198
203
|
// ---- helpers -------------------------------------------------------------
|
|
204
|
+
/** Videos and traces are finalized asynchronously by the runner; wait until every file-backed attachment stops growing. */
|
|
205
|
+
async settleAttachmentFiles() {
|
|
206
|
+
const paths = new Set();
|
|
207
|
+
for (const test of this.suite.allTests())
|
|
208
|
+
for (const r of test.results)
|
|
209
|
+
for (const a of r.attachments)
|
|
210
|
+
if (a.path)
|
|
211
|
+
paths.add(a.path);
|
|
212
|
+
const size = (p) => { try {
|
|
213
|
+
return fs.statSync(p).size;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return -1;
|
|
217
|
+
} };
|
|
218
|
+
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
|
|
219
|
+
for (const p of paths) {
|
|
220
|
+
let last = size(p);
|
|
221
|
+
for (let i = 0; i < 20; i++) { // up to ~5 s per file
|
|
222
|
+
if (last < 0)
|
|
223
|
+
break; // not on disk (yet); nothing to wait for
|
|
224
|
+
await sleep(250);
|
|
225
|
+
const now = size(p);
|
|
226
|
+
if (now === last && now > 0)
|
|
227
|
+
break;
|
|
228
|
+
last = now;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
199
232
|
/** Runtime facts for the Environment card: Playwright, Node, OS, browsers, CI job, git commit. */
|
|
200
233
|
collectEnv(base) {
|
|
201
234
|
const rows = [];
|
package/dist/template.js
CHANGED
|
@@ -612,6 +612,7 @@ html,body{-webkit-font-smoothing:antialiased}
|
|
|
612
612
|
.clu2 .who .sep{color:var(--line-2);margin:0 7px} .clu2 .who .ex{color:var(--ink-3)}
|
|
613
613
|
@media (max-width:640px){.attn2 .ow{display:none} .attn2 .pr{width:72px} .attn2 .pr small{display:none}}
|
|
614
614
|
/* ---------- run status, errors outside tests, snippets ---------- */
|
|
615
|
+
.att-err{padding:12px 14px;background:var(--fail-bg);color:var(--ink);border-radius:8px 8px 0 0;line-height:1.5} .att-err code{font:12px var(--mono);background:var(--surface);padding:1px 5px;border-radius:4px}
|
|
615
616
|
.runbanner{margin-bottom:14px;padding:10px 14px;border-radius:10px;background:var(--flaky-bg);color:var(--flaky-ink);border:1px solid color-mix(in srgb,var(--flaky) 40%,transparent)}
|
|
616
617
|
.note{padding:10px 14px;border-radius:8px;margin-bottom:10px;border:1px solid var(--line)} .note.ok{background:var(--pass-bg);color:var(--ink)} .note.warn{background:var(--flaky-bg);color:var(--flaky-ink)}
|
|
617
618
|
.badge.xfail{background:var(--flaky-bg);color:var(--flaky-ink)}
|
|
@@ -1319,7 +1320,9 @@ function renderDetail(t){
|
|
|
1319
1320
|
for(const a of imgs){ const m=a.name.match(/^(.*)-(expected|actual|diff)(\.\w+)?$/); if(m){ const set=cmp.get(m[1])||{}; set[m[2]]=a; cmp.set(m[1],set); } }
|
|
1320
1321
|
const plainImgs=imgs.filter(a=>!/-(expected|actual|diff)(\.\w+)?$/.test(a.name));
|
|
1321
1322
|
for(const [name,set] of cmp) if(set.expected&&set.actual) body.append(h('h4',{},'Visual comparison · '+name), compare(set)); else for(const k of Object.keys(set)) plainImgs.push(set[k]);
|
|
1322
|
-
if(vids.length){ body.append(h('h4',{},vids.length>1?'Videos':'Video'), h('div',{class:'vids'}, vids.map(a=>h('figure',{}
|
|
1323
|
+
if(vids.length){ body.append(h('h4',{},vids.length>1?'Videos':'Video'), h('div',{class:'vids'}, vids.map(a=>{ const fig=h('figure',{}); const v=h('video',{src:a.src,controls:'',preload:'metadata',playsinline:''});
|
|
1324
|
+
v.addEventListener('error',()=>{ const code=v.error&&v.error.code; const why=code===4?'The file is missing, or it is not a format this browser can play.':code===2?'The file could not be read.':'The file could not be decoded.'; v.replaceWith(h('div',{class:'att-err'}, h('b',{},'Video could not be loaded.'), ' '+why+' Expected at ', h('code',{},a.src), '. Note: re-running the tests replaces the assets folder, so a report opened from an earlier run loses its videos.')); });
|
|
1325
|
+
fig.append(v, h('figcaption',{}, a.name, a.size?h('span',{},' · '+kb(a.size)):null, ' · ', h('a',{href:a.src,download:'',target:'_blank',rel:'noopener',title:'Downloads when the report is served over http; opens in a new tab when opened as a file'},'download'))); return fig; }))); }
|
|
1323
1326
|
if(plainImgs.length){ body.append(h('h4',{},plainImgs.length>1?'Screenshots':'Screenshot'), h('div',{class:'att'}, plainImgs.map(a=>h('figure',{}, h('img',{src:a.src,alt:a.name,loading:'lazy',onclick:()=>lightbox(a.src)}), h('figcaption',{},a.name))))); }
|
|
1324
1327
|
if(traces.length){ body.append(h('h4',{},'Trace'), h('div',{class:'trace'}, traces.map(a=>h('div',{class:'trace-card'},
|
|
1325
1328
|
h('div',{}, h('b',{},a.name), a.size?h('span',{style:'color:var(--ink-3)'},' · '+kb(a.size)):null),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reporting-labs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "reportingLabs \u2013 beautiful, customizable single-file HTML test reports. One line of config. Playwright adapter included, more runners on the way.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"test-report",
|