@checkly/playwright-reporter 0.1.9 → 1.1.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/CHANGELOG.md +114 -0
- package/README.md +266 -0
- package/dist/index.d.ts +47 -202
- package/dist/index.js +2012 -650
- package/package.json +17 -15
package/dist/index.js
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
createChecklyReporter: () => createChecklyReporter,
|
|
34
|
+
default: () => index_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/extensions/checkly-upload.ts
|
|
39
|
+
var fs5 = __toESM(require("fs"));
|
|
40
|
+
var path4 = __toESM(require("path"));
|
|
41
|
+
|
|
42
|
+
// ../utils/src/ansi.ts
|
|
43
|
+
var ansiRegex = new RegExp(
|
|
44
|
+
[
|
|
45
|
+
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
|
|
46
|
+
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"
|
|
47
|
+
].join("|"),
|
|
48
|
+
"g"
|
|
49
|
+
);
|
|
50
|
+
|
|
1
51
|
// ../utils/src/asset-collector.ts
|
|
2
|
-
|
|
3
|
-
|
|
52
|
+
var fs = __toESM(require("fs"), 1);
|
|
53
|
+
var path = __toESM(require("path"), 1);
|
|
4
54
|
var AssetCollector = class {
|
|
5
55
|
constructor(testResultsDir) {
|
|
6
56
|
this.testResultsDir = testResultsDir;
|
|
@@ -234,15 +284,1034 @@ var AssetCollector = class {
|
|
|
234
284
|
}
|
|
235
285
|
};
|
|
236
286
|
|
|
287
|
+
// ../utils/src/ci-detector.ts
|
|
288
|
+
function detectCI() {
|
|
289
|
+
if (process.env.GITHUB_ACTIONS === "true") {
|
|
290
|
+
return { environment: "ci", ciProvider: "github-actions", repositoryId: process.env.GITHUB_REPOSITORY };
|
|
291
|
+
}
|
|
292
|
+
if (process.env.GITLAB_CI === "true") {
|
|
293
|
+
return { environment: "ci", ciProvider: "gitlab-ci", repositoryId: process.env.CI_PROJECT_PATH };
|
|
294
|
+
}
|
|
295
|
+
if (process.env.JENKINS_URL) {
|
|
296
|
+
return { environment: "ci", ciProvider: "jenkins", repositoryId: process.env.JOB_NAME };
|
|
297
|
+
}
|
|
298
|
+
if (process.env.CIRCLECI === "true") {
|
|
299
|
+
return { environment: "ci", ciProvider: "circleci", repositoryId: process.env.CIRCLE_PROJECT_REPONAME };
|
|
300
|
+
}
|
|
301
|
+
if (process.env.TRAVIS === "true") {
|
|
302
|
+
return { environment: "ci", ciProvider: "travis-ci", repositoryId: process.env.TRAVIS_REPO_SLUG };
|
|
303
|
+
}
|
|
304
|
+
if (process.env.TF_BUILD === "True") {
|
|
305
|
+
return { environment: "ci", ciProvider: "azure-devops", repositoryId: process.env.BUILD_REPOSITORY_NAME };
|
|
306
|
+
}
|
|
307
|
+
if (process.env.BITBUCKET_PIPELINE_UUID) {
|
|
308
|
+
return { environment: "ci", ciProvider: "bitbucket-pipelines", repositoryId: process.env.BITBUCKET_REPO_SLUG };
|
|
309
|
+
}
|
|
310
|
+
if (process.env.CI === "true" || process.env.CI === "1") {
|
|
311
|
+
return { environment: "ci", ciProvider: "unknown-ci" };
|
|
312
|
+
}
|
|
313
|
+
return { environment: "local", ciProvider: "local" };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ../utils/src/console-adapter.ts
|
|
317
|
+
var import_node_crypto = require("crypto");
|
|
318
|
+
function normalizeType(messageType) {
|
|
319
|
+
switch (messageType.toLowerCase()) {
|
|
320
|
+
case "debug":
|
|
321
|
+
return "debug";
|
|
322
|
+
case "error":
|
|
323
|
+
return "error";
|
|
324
|
+
case "info":
|
|
325
|
+
return "info";
|
|
326
|
+
case "warning":
|
|
327
|
+
case "warn":
|
|
328
|
+
return "warning";
|
|
329
|
+
default:
|
|
330
|
+
return "log";
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
function generateId(time, messageType, text, url) {
|
|
334
|
+
return (0, import_node_crypto.createHash)("sha256").update(`${time}-${messageType}-${text}-${url}`).digest("hex").substring(0, 16);
|
|
335
|
+
}
|
|
336
|
+
function toConsoleMessage(event) {
|
|
337
|
+
const url = event.location?.url || "";
|
|
338
|
+
return {
|
|
339
|
+
id: generateId(event.time, event.messageType, event.text, url),
|
|
340
|
+
location: {
|
|
341
|
+
url,
|
|
342
|
+
columnNumber: event.location?.columnNumber || 0,
|
|
343
|
+
lineNumber: event.location?.lineNumber || 0
|
|
344
|
+
},
|
|
345
|
+
text: event.text || "",
|
|
346
|
+
timestamp: event.time,
|
|
347
|
+
type: normalizeType(event.messageType)
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ../utils/src/git-info.ts
|
|
352
|
+
function getGitHubRepoInfo() {
|
|
353
|
+
const repository = process.env.GITHUB_REPOSITORY;
|
|
354
|
+
if (!repository) return void 0;
|
|
355
|
+
return {
|
|
356
|
+
repoUrl: `https://github.com/${repository}`,
|
|
357
|
+
commitId: process.env.GITHUB_SHA,
|
|
358
|
+
branchName: process.env.GITHUB_REF_NAME,
|
|
359
|
+
commitOwner: process.env.GITHUB_ACTOR,
|
|
360
|
+
commitMessage: process.env.GITHUB_EVENT_NAME
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ../utils/src/machine-id.ts
|
|
365
|
+
var import_node_crypto2 = require("crypto");
|
|
366
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
367
|
+
var os = __toESM(require("os"), 1);
|
|
368
|
+
var path2 = __toESM(require("path"), 1);
|
|
369
|
+
|
|
370
|
+
// ../utils/src/network-adapter.ts
|
|
371
|
+
var import_node_crypto3 = require("crypto");
|
|
372
|
+
function generateId2(url, method, startedAt) {
|
|
373
|
+
return (0, import_node_crypto3.createHash)("sha256").update(`${url}-${method}-${startedAt}`).digest("hex").substring(0, 16);
|
|
374
|
+
}
|
|
375
|
+
function extractDomain(url) {
|
|
376
|
+
try {
|
|
377
|
+
return new URL(url).hostname;
|
|
378
|
+
} catch {
|
|
379
|
+
return "";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
function headersArrayToRecord(headers) {
|
|
383
|
+
const record = {};
|
|
384
|
+
for (const { name, value } of headers) {
|
|
385
|
+
record[name.toLowerCase()] = value;
|
|
386
|
+
}
|
|
387
|
+
return record;
|
|
388
|
+
}
|
|
389
|
+
function isSuccessStatus(status) {
|
|
390
|
+
return status >= 200 && status < 400;
|
|
391
|
+
}
|
|
392
|
+
function determineResourceType(snapshot) {
|
|
393
|
+
if (snapshot._resourceType) {
|
|
394
|
+
return snapshot._resourceType;
|
|
395
|
+
}
|
|
396
|
+
if (snapshot._apiRequest) {
|
|
397
|
+
return "fetch";
|
|
398
|
+
}
|
|
399
|
+
return "other";
|
|
400
|
+
}
|
|
401
|
+
function toNetworkRequest(event) {
|
|
402
|
+
const { snapshot } = event;
|
|
403
|
+
const startedAt = new Date(snapshot.startedDateTime).getTime();
|
|
404
|
+
const time = Math.round(snapshot.time);
|
|
405
|
+
const finishedAt = startedAt + time;
|
|
406
|
+
const statusCode = snapshot.response.status;
|
|
407
|
+
const url = snapshot.request.url;
|
|
408
|
+
const method = snapshot.request.method;
|
|
409
|
+
return {
|
|
410
|
+
id: generateId2(url, method, startedAt),
|
|
411
|
+
url,
|
|
412
|
+
domain: extractDomain(url),
|
|
413
|
+
method,
|
|
414
|
+
resourceType: determineResourceType(snapshot),
|
|
415
|
+
statusCode,
|
|
416
|
+
statusText: snapshot.response.statusText || "",
|
|
417
|
+
start: startedAt,
|
|
418
|
+
startedAt,
|
|
419
|
+
finishedAt,
|
|
420
|
+
time,
|
|
421
|
+
hasFinished: true,
|
|
422
|
+
hasSucceeded: isSuccessStatus(statusCode),
|
|
423
|
+
requestHeaders: headersArrayToRecord(snapshot.request.headers || []),
|
|
424
|
+
responseHeaders: headersArrayToRecord(snapshot.response.headers || []),
|
|
425
|
+
transferBytes: snapshot.response._transferSize,
|
|
426
|
+
resourceBytes: snapshot.response.content?.size
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ../utils/src/trace-reader.ts
|
|
431
|
+
var fs3 = __toESM(require("fs"), 1);
|
|
432
|
+
|
|
433
|
+
// ../utils/src/zip-reader.ts
|
|
434
|
+
var import_node_util = require("util");
|
|
435
|
+
var zlib = __toESM(require("zlib"), 1);
|
|
436
|
+
var gunzip2 = (0, import_node_util.promisify)(zlib.gunzip);
|
|
437
|
+
var inflateRaw2 = (0, import_node_util.promisify)(zlib.inflateRaw);
|
|
438
|
+
function parseZipEntries(zipBuffer) {
|
|
439
|
+
const EOCD_SIG = 101010256;
|
|
440
|
+
let eocdOffset = -1;
|
|
441
|
+
for (let i = zipBuffer.length - 22; i >= 0; i--) {
|
|
442
|
+
if (zipBuffer.readUInt32LE(i) === EOCD_SIG) {
|
|
443
|
+
eocdOffset = i;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (eocdOffset === -1) {
|
|
448
|
+
return [];
|
|
449
|
+
}
|
|
450
|
+
const cdOffset = zipBuffer.readUInt32LE(eocdOffset + 16);
|
|
451
|
+
const cdEntries = zipBuffer.readUInt16LE(eocdOffset + 10);
|
|
452
|
+
const entries = [];
|
|
453
|
+
const CD_SIG = 33639248;
|
|
454
|
+
let offset = cdOffset;
|
|
455
|
+
for (let i = 0; i < cdEntries; i++) {
|
|
456
|
+
if (zipBuffer.readUInt32LE(offset) !== CD_SIG) {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
const compressionMethod = zipBuffer.readUInt16LE(offset + 10);
|
|
460
|
+
const compressedSize = zipBuffer.readUInt32LE(offset + 20);
|
|
461
|
+
const fileNameLength = zipBuffer.readUInt16LE(offset + 28);
|
|
462
|
+
const extraFieldLength = zipBuffer.readUInt16LE(offset + 30);
|
|
463
|
+
const commentLength = zipBuffer.readUInt16LE(offset + 32);
|
|
464
|
+
const localHeaderOffset = zipBuffer.readUInt32LE(offset + 42);
|
|
465
|
+
const fileName = zipBuffer.subarray(offset + 46, offset + 46 + fileNameLength).toString("utf-8");
|
|
466
|
+
entries.push({
|
|
467
|
+
fileName,
|
|
468
|
+
compressionMethod,
|
|
469
|
+
compressedSize,
|
|
470
|
+
localHeaderOffset
|
|
471
|
+
});
|
|
472
|
+
offset += 46 + fileNameLength + extraFieldLength + commentLength;
|
|
473
|
+
}
|
|
474
|
+
return entries;
|
|
475
|
+
}
|
|
476
|
+
async function readZipEntryContent(zipBuffer, entry) {
|
|
477
|
+
const LOCAL_SIG = 67324752;
|
|
478
|
+
if (zipBuffer.readUInt32LE(entry.localHeaderOffset) !== LOCAL_SIG) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
const localFileNameLength = zipBuffer.readUInt16LE(entry.localHeaderOffset + 26);
|
|
482
|
+
const localExtraLength = zipBuffer.readUInt16LE(entry.localHeaderOffset + 28);
|
|
483
|
+
const dataOffset = entry.localHeaderOffset + 30 + localFileNameLength + localExtraLength;
|
|
484
|
+
const compressedData = zipBuffer.subarray(dataOffset, dataOffset + entry.compressedSize);
|
|
485
|
+
let buffer;
|
|
486
|
+
if (entry.compressionMethod === 0) {
|
|
487
|
+
buffer = compressedData;
|
|
488
|
+
} else if (entry.compressionMethod === 8) {
|
|
489
|
+
buffer = await inflateRaw2(compressedData);
|
|
490
|
+
} else {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
if (buffer.length >= 2 && buffer[0] === 31 && buffer[1] === 139) {
|
|
494
|
+
const decompressed = await gunzip2(buffer);
|
|
495
|
+
return decompressed.toString("utf-8");
|
|
496
|
+
}
|
|
497
|
+
return buffer.toString("utf-8");
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ../utils/src/trace-reader.ts
|
|
501
|
+
var TraceReader = class {
|
|
502
|
+
constructor(tracePath) {
|
|
503
|
+
this.tracePath = tracePath;
|
|
504
|
+
}
|
|
505
|
+
zipBuffer = null;
|
|
506
|
+
traceEntries = [];
|
|
507
|
+
async open() {
|
|
508
|
+
if (!fs3.existsSync(this.tracePath)) {
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
try {
|
|
512
|
+
this.zipBuffer = fs3.readFileSync(this.tracePath);
|
|
513
|
+
const entries = parseZipEntries(this.zipBuffer);
|
|
514
|
+
this.traceEntries = entries.filter(
|
|
515
|
+
(e) => (/^\d+-trace\.trace$/.test(e.fileName) || /^\d+-trace\.network$/.test(e.fileName)) && !e.fileName.includes("/")
|
|
516
|
+
);
|
|
517
|
+
return this.traceEntries.length > 0;
|
|
518
|
+
} catch {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Extracts events matching a text filter.
|
|
524
|
+
*
|
|
525
|
+
* @param textFilter - Substring to match (e.g., '"type":"console"')
|
|
526
|
+
* @param adapter - Optional adapter to transform events
|
|
527
|
+
*/
|
|
528
|
+
async extractEvents(textFilter, adapter) {
|
|
529
|
+
if (!this.zipBuffer) {
|
|
530
|
+
throw new Error("TraceReader not opened. Call open() first.");
|
|
531
|
+
}
|
|
532
|
+
const results = [];
|
|
533
|
+
for (const traceEntry of this.traceEntries) {
|
|
534
|
+
const content = await readZipEntryContent(this.zipBuffer, traceEntry);
|
|
535
|
+
if (!content) continue;
|
|
536
|
+
for (const line of content.split("\n")) {
|
|
537
|
+
if (line.indexOf(textFilter) !== -1) {
|
|
538
|
+
try {
|
|
539
|
+
const event = JSON.parse(line);
|
|
540
|
+
results.push(adapter ? adapter(event) : event);
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (results.length > 0 && typeof results[0].time === "number") {
|
|
547
|
+
return results.sort((a, b) => a.time - b.time);
|
|
548
|
+
}
|
|
549
|
+
return results;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Extracts all events from the trace.
|
|
553
|
+
*/
|
|
554
|
+
async extractAllEvents(adapter) {
|
|
555
|
+
if (!this.zipBuffer) {
|
|
556
|
+
throw new Error("TraceReader not opened. Call open() first.");
|
|
557
|
+
}
|
|
558
|
+
const results = [];
|
|
559
|
+
for (const traceEntry of this.traceEntries) {
|
|
560
|
+
const content = await readZipEntryContent(this.zipBuffer, traceEntry);
|
|
561
|
+
if (!content) continue;
|
|
562
|
+
for (const line of content.split("\n")) {
|
|
563
|
+
if (line.trim()) {
|
|
564
|
+
try {
|
|
565
|
+
const event = JSON.parse(line);
|
|
566
|
+
results.push(adapter ? adapter(event) : event);
|
|
567
|
+
} catch {
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (results.length > 0 && typeof results[0].time === "number") {
|
|
573
|
+
return results.sort((a, b) => a.time - b.time);
|
|
574
|
+
}
|
|
575
|
+
return results;
|
|
576
|
+
}
|
|
577
|
+
listFiles() {
|
|
578
|
+
if (!this.zipBuffer) {
|
|
579
|
+
return [];
|
|
580
|
+
}
|
|
581
|
+
return parseZipEntries(this.zipBuffer).map((e) => e.fileName);
|
|
582
|
+
}
|
|
583
|
+
isOpen() {
|
|
584
|
+
return this.zipBuffer !== null;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
// ../utils/src/zipper.ts
|
|
589
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
590
|
+
var os2 = __toESM(require("os"), 1);
|
|
591
|
+
var path3 = __toESM(require("path"), 1);
|
|
592
|
+
|
|
593
|
+
// ../../node_modules/.pnpm/fflate@0.8.2/node_modules/fflate/esm/index.mjs
|
|
594
|
+
var import_module = require("module");
|
|
595
|
+
var require2 = (0, import_module.createRequire)("/");
|
|
596
|
+
var Worker;
|
|
597
|
+
try {
|
|
598
|
+
Worker = require2("worker_threads").Worker;
|
|
599
|
+
} catch (e) {
|
|
600
|
+
}
|
|
601
|
+
var u8 = Uint8Array;
|
|
602
|
+
var u16 = Uint16Array;
|
|
603
|
+
var i32 = Int32Array;
|
|
604
|
+
var fleb = new u8([
|
|
605
|
+
0,
|
|
606
|
+
0,
|
|
607
|
+
0,
|
|
608
|
+
0,
|
|
609
|
+
0,
|
|
610
|
+
0,
|
|
611
|
+
0,
|
|
612
|
+
0,
|
|
613
|
+
1,
|
|
614
|
+
1,
|
|
615
|
+
1,
|
|
616
|
+
1,
|
|
617
|
+
2,
|
|
618
|
+
2,
|
|
619
|
+
2,
|
|
620
|
+
2,
|
|
621
|
+
3,
|
|
622
|
+
3,
|
|
623
|
+
3,
|
|
624
|
+
3,
|
|
625
|
+
4,
|
|
626
|
+
4,
|
|
627
|
+
4,
|
|
628
|
+
4,
|
|
629
|
+
5,
|
|
630
|
+
5,
|
|
631
|
+
5,
|
|
632
|
+
5,
|
|
633
|
+
0,
|
|
634
|
+
/* unused */
|
|
635
|
+
0,
|
|
636
|
+
0,
|
|
637
|
+
/* impossible */
|
|
638
|
+
0
|
|
639
|
+
]);
|
|
640
|
+
var fdeb = new u8([
|
|
641
|
+
0,
|
|
642
|
+
0,
|
|
643
|
+
0,
|
|
644
|
+
0,
|
|
645
|
+
1,
|
|
646
|
+
1,
|
|
647
|
+
2,
|
|
648
|
+
2,
|
|
649
|
+
3,
|
|
650
|
+
3,
|
|
651
|
+
4,
|
|
652
|
+
4,
|
|
653
|
+
5,
|
|
654
|
+
5,
|
|
655
|
+
6,
|
|
656
|
+
6,
|
|
657
|
+
7,
|
|
658
|
+
7,
|
|
659
|
+
8,
|
|
660
|
+
8,
|
|
661
|
+
9,
|
|
662
|
+
9,
|
|
663
|
+
10,
|
|
664
|
+
10,
|
|
665
|
+
11,
|
|
666
|
+
11,
|
|
667
|
+
12,
|
|
668
|
+
12,
|
|
669
|
+
13,
|
|
670
|
+
13,
|
|
671
|
+
/* unused */
|
|
672
|
+
0,
|
|
673
|
+
0
|
|
674
|
+
]);
|
|
675
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
676
|
+
var freb = function(eb, start) {
|
|
677
|
+
var b = new u16(31);
|
|
678
|
+
for (var i = 0; i < 31; ++i) {
|
|
679
|
+
b[i] = start += 1 << eb[i - 1];
|
|
680
|
+
}
|
|
681
|
+
var r = new i32(b[30]);
|
|
682
|
+
for (var i = 1; i < 30; ++i) {
|
|
683
|
+
for (var j = b[i]; j < b[i + 1]; ++j) {
|
|
684
|
+
r[j] = j - b[i] << 5 | i;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return { b, r };
|
|
688
|
+
};
|
|
689
|
+
var _a = freb(fleb, 2);
|
|
690
|
+
var fl = _a.b;
|
|
691
|
+
var revfl = _a.r;
|
|
692
|
+
fl[28] = 258, revfl[258] = 28;
|
|
693
|
+
var _b = freb(fdeb, 0);
|
|
694
|
+
var fd = _b.b;
|
|
695
|
+
var revfd = _b.r;
|
|
696
|
+
var rev = new u16(32768);
|
|
697
|
+
for (i = 0; i < 32768; ++i) {
|
|
698
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
699
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
700
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
701
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
702
|
+
}
|
|
703
|
+
var x;
|
|
704
|
+
var i;
|
|
705
|
+
var hMap = (function(cd, mb, r) {
|
|
706
|
+
var s = cd.length;
|
|
707
|
+
var i = 0;
|
|
708
|
+
var l = new u16(mb);
|
|
709
|
+
for (; i < s; ++i) {
|
|
710
|
+
if (cd[i])
|
|
711
|
+
++l[cd[i] - 1];
|
|
712
|
+
}
|
|
713
|
+
var le = new u16(mb);
|
|
714
|
+
for (i = 1; i < mb; ++i) {
|
|
715
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
716
|
+
}
|
|
717
|
+
var co;
|
|
718
|
+
if (r) {
|
|
719
|
+
co = new u16(1 << mb);
|
|
720
|
+
var rvb = 15 - mb;
|
|
721
|
+
for (i = 0; i < s; ++i) {
|
|
722
|
+
if (cd[i]) {
|
|
723
|
+
var sv = i << 4 | cd[i];
|
|
724
|
+
var r_1 = mb - cd[i];
|
|
725
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
726
|
+
for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
|
|
727
|
+
co[rev[v] >> rvb] = sv;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
} else {
|
|
732
|
+
co = new u16(s);
|
|
733
|
+
for (i = 0; i < s; ++i) {
|
|
734
|
+
if (cd[i]) {
|
|
735
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return co;
|
|
740
|
+
});
|
|
741
|
+
var flt = new u8(288);
|
|
742
|
+
for (i = 0; i < 144; ++i)
|
|
743
|
+
flt[i] = 8;
|
|
744
|
+
var i;
|
|
745
|
+
for (i = 144; i < 256; ++i)
|
|
746
|
+
flt[i] = 9;
|
|
747
|
+
var i;
|
|
748
|
+
for (i = 256; i < 280; ++i)
|
|
749
|
+
flt[i] = 7;
|
|
750
|
+
var i;
|
|
751
|
+
for (i = 280; i < 288; ++i)
|
|
752
|
+
flt[i] = 8;
|
|
753
|
+
var i;
|
|
754
|
+
var fdt = new u8(32);
|
|
755
|
+
for (i = 0; i < 32; ++i)
|
|
756
|
+
fdt[i] = 5;
|
|
757
|
+
var i;
|
|
758
|
+
var flm = /* @__PURE__ */ hMap(flt, 9, 0);
|
|
759
|
+
var fdm = /* @__PURE__ */ hMap(fdt, 5, 0);
|
|
760
|
+
var shft = function(p) {
|
|
761
|
+
return (p + 7) / 8 | 0;
|
|
762
|
+
};
|
|
763
|
+
var slc = function(v, s, e) {
|
|
764
|
+
if (s == null || s < 0)
|
|
765
|
+
s = 0;
|
|
766
|
+
if (e == null || e > v.length)
|
|
767
|
+
e = v.length;
|
|
768
|
+
return new u8(v.subarray(s, e));
|
|
769
|
+
};
|
|
770
|
+
var ec = [
|
|
771
|
+
"unexpected EOF",
|
|
772
|
+
"invalid block type",
|
|
773
|
+
"invalid length/literal",
|
|
774
|
+
"invalid distance",
|
|
775
|
+
"stream finished",
|
|
776
|
+
"no stream handler",
|
|
777
|
+
,
|
|
778
|
+
"no callback",
|
|
779
|
+
"invalid UTF-8 data",
|
|
780
|
+
"extra field too long",
|
|
781
|
+
"date not in range 1980-2099",
|
|
782
|
+
"filename too long",
|
|
783
|
+
"stream finishing",
|
|
784
|
+
"invalid zip data"
|
|
785
|
+
// determined by unknown compression method
|
|
786
|
+
];
|
|
787
|
+
var err = function(ind, msg, nt) {
|
|
788
|
+
var e = new Error(msg || ec[ind]);
|
|
789
|
+
e.code = ind;
|
|
790
|
+
if (Error.captureStackTrace)
|
|
791
|
+
Error.captureStackTrace(e, err);
|
|
792
|
+
if (!nt)
|
|
793
|
+
throw e;
|
|
794
|
+
return e;
|
|
795
|
+
};
|
|
796
|
+
var wbits = function(d, p, v) {
|
|
797
|
+
v <<= p & 7;
|
|
798
|
+
var o = p / 8 | 0;
|
|
799
|
+
d[o] |= v;
|
|
800
|
+
d[o + 1] |= v >> 8;
|
|
801
|
+
};
|
|
802
|
+
var wbits16 = function(d, p, v) {
|
|
803
|
+
v <<= p & 7;
|
|
804
|
+
var o = p / 8 | 0;
|
|
805
|
+
d[o] |= v;
|
|
806
|
+
d[o + 1] |= v >> 8;
|
|
807
|
+
d[o + 2] |= v >> 16;
|
|
808
|
+
};
|
|
809
|
+
var hTree = function(d, mb) {
|
|
810
|
+
var t = [];
|
|
811
|
+
for (var i = 0; i < d.length; ++i) {
|
|
812
|
+
if (d[i])
|
|
813
|
+
t.push({ s: i, f: d[i] });
|
|
814
|
+
}
|
|
815
|
+
var s = t.length;
|
|
816
|
+
var t2 = t.slice();
|
|
817
|
+
if (!s)
|
|
818
|
+
return { t: et, l: 0 };
|
|
819
|
+
if (s == 1) {
|
|
820
|
+
var v = new u8(t[0].s + 1);
|
|
821
|
+
v[t[0].s] = 1;
|
|
822
|
+
return { t: v, l: 1 };
|
|
823
|
+
}
|
|
824
|
+
t.sort(function(a, b) {
|
|
825
|
+
return a.f - b.f;
|
|
826
|
+
});
|
|
827
|
+
t.push({ s: -1, f: 25001 });
|
|
828
|
+
var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
|
|
829
|
+
t[0] = { s: -1, f: l.f + r.f, l, r };
|
|
830
|
+
while (i1 != s - 1) {
|
|
831
|
+
l = t[t[i0].f < t[i2].f ? i0++ : i2++];
|
|
832
|
+
r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
|
|
833
|
+
t[i1++] = { s: -1, f: l.f + r.f, l, r };
|
|
834
|
+
}
|
|
835
|
+
var maxSym = t2[0].s;
|
|
836
|
+
for (var i = 1; i < s; ++i) {
|
|
837
|
+
if (t2[i].s > maxSym)
|
|
838
|
+
maxSym = t2[i].s;
|
|
839
|
+
}
|
|
840
|
+
var tr = new u16(maxSym + 1);
|
|
841
|
+
var mbt = ln(t[i1 - 1], tr, 0);
|
|
842
|
+
if (mbt > mb) {
|
|
843
|
+
var i = 0, dt = 0;
|
|
844
|
+
var lft = mbt - mb, cst = 1 << lft;
|
|
845
|
+
t2.sort(function(a, b) {
|
|
846
|
+
return tr[b.s] - tr[a.s] || a.f - b.f;
|
|
847
|
+
});
|
|
848
|
+
for (; i < s; ++i) {
|
|
849
|
+
var i2_1 = t2[i].s;
|
|
850
|
+
if (tr[i2_1] > mb) {
|
|
851
|
+
dt += cst - (1 << mbt - tr[i2_1]);
|
|
852
|
+
tr[i2_1] = mb;
|
|
853
|
+
} else
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
dt >>= lft;
|
|
857
|
+
while (dt > 0) {
|
|
858
|
+
var i2_2 = t2[i].s;
|
|
859
|
+
if (tr[i2_2] < mb)
|
|
860
|
+
dt -= 1 << mb - tr[i2_2]++ - 1;
|
|
861
|
+
else
|
|
862
|
+
++i;
|
|
863
|
+
}
|
|
864
|
+
for (; i >= 0 && dt; --i) {
|
|
865
|
+
var i2_3 = t2[i].s;
|
|
866
|
+
if (tr[i2_3] == mb) {
|
|
867
|
+
--tr[i2_3];
|
|
868
|
+
++dt;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
mbt = mb;
|
|
872
|
+
}
|
|
873
|
+
return { t: new u8(tr), l: mbt };
|
|
874
|
+
};
|
|
875
|
+
var ln = function(n, l, d) {
|
|
876
|
+
return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
|
|
877
|
+
};
|
|
878
|
+
var lc = function(c) {
|
|
879
|
+
var s = c.length;
|
|
880
|
+
while (s && !c[--s])
|
|
881
|
+
;
|
|
882
|
+
var cl = new u16(++s);
|
|
883
|
+
var cli = 0, cln = c[0], cls = 1;
|
|
884
|
+
var w = function(v) {
|
|
885
|
+
cl[cli++] = v;
|
|
886
|
+
};
|
|
887
|
+
for (var i = 1; i <= s; ++i) {
|
|
888
|
+
if (c[i] == cln && i != s)
|
|
889
|
+
++cls;
|
|
890
|
+
else {
|
|
891
|
+
if (!cln && cls > 2) {
|
|
892
|
+
for (; cls > 138; cls -= 138)
|
|
893
|
+
w(32754);
|
|
894
|
+
if (cls > 2) {
|
|
895
|
+
w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
|
|
896
|
+
cls = 0;
|
|
897
|
+
}
|
|
898
|
+
} else if (cls > 3) {
|
|
899
|
+
w(cln), --cls;
|
|
900
|
+
for (; cls > 6; cls -= 6)
|
|
901
|
+
w(8304);
|
|
902
|
+
if (cls > 2)
|
|
903
|
+
w(cls - 3 << 5 | 8208), cls = 0;
|
|
904
|
+
}
|
|
905
|
+
while (cls--)
|
|
906
|
+
w(cln);
|
|
907
|
+
cls = 1;
|
|
908
|
+
cln = c[i];
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return { c: cl.subarray(0, cli), n: s };
|
|
912
|
+
};
|
|
913
|
+
var clen = function(cf, cl) {
|
|
914
|
+
var l = 0;
|
|
915
|
+
for (var i = 0; i < cl.length; ++i)
|
|
916
|
+
l += cf[i] * cl[i];
|
|
917
|
+
return l;
|
|
918
|
+
};
|
|
919
|
+
var wfblk = function(out, pos, dat) {
|
|
920
|
+
var s = dat.length;
|
|
921
|
+
var o = shft(pos + 2);
|
|
922
|
+
out[o] = s & 255;
|
|
923
|
+
out[o + 1] = s >> 8;
|
|
924
|
+
out[o + 2] = out[o] ^ 255;
|
|
925
|
+
out[o + 3] = out[o + 1] ^ 255;
|
|
926
|
+
for (var i = 0; i < s; ++i)
|
|
927
|
+
out[o + i + 4] = dat[i];
|
|
928
|
+
return (o + 4 + s) * 8;
|
|
929
|
+
};
|
|
930
|
+
var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
|
|
931
|
+
wbits(out, p++, final);
|
|
932
|
+
++lf[256];
|
|
933
|
+
var _a2 = hTree(lf, 15), dlt = _a2.t, mlb = _a2.l;
|
|
934
|
+
var _b2 = hTree(df, 15), ddt = _b2.t, mdb = _b2.l;
|
|
935
|
+
var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
|
|
936
|
+
var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
|
|
937
|
+
var lcfreq = new u16(19);
|
|
938
|
+
for (var i = 0; i < lclt.length; ++i)
|
|
939
|
+
++lcfreq[lclt[i] & 31];
|
|
940
|
+
for (var i = 0; i < lcdt.length; ++i)
|
|
941
|
+
++lcfreq[lcdt[i] & 31];
|
|
942
|
+
var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
|
|
943
|
+
var nlcc = 19;
|
|
944
|
+
for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)
|
|
945
|
+
;
|
|
946
|
+
var flen = bl + 5 << 3;
|
|
947
|
+
var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
|
|
948
|
+
var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
|
|
949
|
+
if (bs >= 0 && flen <= ftlen && flen <= dtlen)
|
|
950
|
+
return wfblk(out, p, dat.subarray(bs, bs + bl));
|
|
951
|
+
var lm, ll, dm, dl;
|
|
952
|
+
wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
|
|
953
|
+
if (dtlen < ftlen) {
|
|
954
|
+
lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
|
|
955
|
+
var llm = hMap(lct, mlcb, 0);
|
|
956
|
+
wbits(out, p, nlc - 257);
|
|
957
|
+
wbits(out, p + 5, ndc - 1);
|
|
958
|
+
wbits(out, p + 10, nlcc - 4);
|
|
959
|
+
p += 14;
|
|
960
|
+
for (var i = 0; i < nlcc; ++i)
|
|
961
|
+
wbits(out, p + 3 * i, lct[clim[i]]);
|
|
962
|
+
p += 3 * nlcc;
|
|
963
|
+
var lcts = [lclt, lcdt];
|
|
964
|
+
for (var it = 0; it < 2; ++it) {
|
|
965
|
+
var clct = lcts[it];
|
|
966
|
+
for (var i = 0; i < clct.length; ++i) {
|
|
967
|
+
var len = clct[i] & 31;
|
|
968
|
+
wbits(out, p, llm[len]), p += lct[len];
|
|
969
|
+
if (len > 15)
|
|
970
|
+
wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
} else {
|
|
974
|
+
lm = flm, ll = flt, dm = fdm, dl = fdt;
|
|
975
|
+
}
|
|
976
|
+
for (var i = 0; i < li; ++i) {
|
|
977
|
+
var sym = syms[i];
|
|
978
|
+
if (sym > 255) {
|
|
979
|
+
var len = sym >> 18 & 31;
|
|
980
|
+
wbits16(out, p, lm[len + 257]), p += ll[len + 257];
|
|
981
|
+
if (len > 7)
|
|
982
|
+
wbits(out, p, sym >> 23 & 31), p += fleb[len];
|
|
983
|
+
var dst = sym & 31;
|
|
984
|
+
wbits16(out, p, dm[dst]), p += dl[dst];
|
|
985
|
+
if (dst > 3)
|
|
986
|
+
wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
|
|
987
|
+
} else {
|
|
988
|
+
wbits16(out, p, lm[sym]), p += ll[sym];
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
wbits16(out, p, lm[256]);
|
|
992
|
+
return p + ll[256];
|
|
993
|
+
};
|
|
994
|
+
var deo = /* @__PURE__ */ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
|
|
995
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
996
|
+
var dflt = function(dat, lvl, plvl, pre, post, st) {
|
|
997
|
+
var s = st.z || dat.length;
|
|
998
|
+
var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
|
|
999
|
+
var w = o.subarray(pre, o.length - post);
|
|
1000
|
+
var lst = st.l;
|
|
1001
|
+
var pos = (st.r || 0) & 7;
|
|
1002
|
+
if (lvl) {
|
|
1003
|
+
if (pos)
|
|
1004
|
+
w[0] = st.r >> 3;
|
|
1005
|
+
var opt = deo[lvl - 1];
|
|
1006
|
+
var n = opt >> 13, c = opt & 8191;
|
|
1007
|
+
var msk_1 = (1 << plvl) - 1;
|
|
1008
|
+
var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
|
|
1009
|
+
var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
|
|
1010
|
+
var hsh = function(i2) {
|
|
1011
|
+
return (dat[i2] ^ dat[i2 + 1] << bs1_1 ^ dat[i2 + 2] << bs2_1) & msk_1;
|
|
1012
|
+
};
|
|
1013
|
+
var syms = new i32(25e3);
|
|
1014
|
+
var lf = new u16(288), df = new u16(32);
|
|
1015
|
+
var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
|
|
1016
|
+
for (; i + 2 < s; ++i) {
|
|
1017
|
+
var hv = hsh(i);
|
|
1018
|
+
var imod = i & 32767, pimod = head[hv];
|
|
1019
|
+
prev[imod] = pimod;
|
|
1020
|
+
head[hv] = imod;
|
|
1021
|
+
if (wi <= i) {
|
|
1022
|
+
var rem = s - i;
|
|
1023
|
+
if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
|
|
1024
|
+
pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
1025
|
+
li = lc_1 = eb = 0, bs = i;
|
|
1026
|
+
for (var j = 0; j < 286; ++j)
|
|
1027
|
+
lf[j] = 0;
|
|
1028
|
+
for (var j = 0; j < 30; ++j)
|
|
1029
|
+
df[j] = 0;
|
|
1030
|
+
}
|
|
1031
|
+
var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
|
|
1032
|
+
if (rem > 2 && hv == hsh(i - dif)) {
|
|
1033
|
+
var maxn = Math.min(n, rem) - 1;
|
|
1034
|
+
var maxd = Math.min(32767, i);
|
|
1035
|
+
var ml = Math.min(258, rem);
|
|
1036
|
+
while (dif <= maxd && --ch_1 && imod != pimod) {
|
|
1037
|
+
if (dat[i + l] == dat[i + l - dif]) {
|
|
1038
|
+
var nl = 0;
|
|
1039
|
+
for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)
|
|
1040
|
+
;
|
|
1041
|
+
if (nl > l) {
|
|
1042
|
+
l = nl, d = dif;
|
|
1043
|
+
if (nl > maxn)
|
|
1044
|
+
break;
|
|
1045
|
+
var mmd = Math.min(dif, nl - 2);
|
|
1046
|
+
var md = 0;
|
|
1047
|
+
for (var j = 0; j < mmd; ++j) {
|
|
1048
|
+
var ti = i - dif + j & 32767;
|
|
1049
|
+
var pti = prev[ti];
|
|
1050
|
+
var cd = ti - pti & 32767;
|
|
1051
|
+
if (cd > md)
|
|
1052
|
+
md = cd, pimod = ti;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
imod = pimod, pimod = prev[imod];
|
|
1057
|
+
dif += imod - pimod & 32767;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
if (d) {
|
|
1061
|
+
syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
|
|
1062
|
+
var lin = revfl[l] & 31, din = revfd[d] & 31;
|
|
1063
|
+
eb += fleb[lin] + fdeb[din];
|
|
1064
|
+
++lf[257 + lin];
|
|
1065
|
+
++df[din];
|
|
1066
|
+
wi = i + l;
|
|
1067
|
+
++lc_1;
|
|
1068
|
+
} else {
|
|
1069
|
+
syms[li++] = dat[i];
|
|
1070
|
+
++lf[dat[i]];
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
for (i = Math.max(i, wi); i < s; ++i) {
|
|
1075
|
+
syms[li++] = dat[i];
|
|
1076
|
+
++lf[dat[i]];
|
|
1077
|
+
}
|
|
1078
|
+
pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);
|
|
1079
|
+
if (!lst) {
|
|
1080
|
+
st.r = pos & 7 | w[pos / 8 | 0] << 3;
|
|
1081
|
+
pos -= 7;
|
|
1082
|
+
st.h = head, st.p = prev, st.i = i, st.w = wi;
|
|
1083
|
+
}
|
|
1084
|
+
} else {
|
|
1085
|
+
for (var i = st.w || 0; i < s + lst; i += 65535) {
|
|
1086
|
+
var e = i + 65535;
|
|
1087
|
+
if (e >= s) {
|
|
1088
|
+
w[pos / 8 | 0] = lst;
|
|
1089
|
+
e = s;
|
|
1090
|
+
}
|
|
1091
|
+
pos = wfblk(w, pos + 1, dat.subarray(i, e));
|
|
1092
|
+
}
|
|
1093
|
+
st.i = s;
|
|
1094
|
+
}
|
|
1095
|
+
return slc(o, 0, pre + shft(pos) + post);
|
|
1096
|
+
};
|
|
1097
|
+
var crct = /* @__PURE__ */ (function() {
|
|
1098
|
+
var t = new Int32Array(256);
|
|
1099
|
+
for (var i = 0; i < 256; ++i) {
|
|
1100
|
+
var c = i, k = 9;
|
|
1101
|
+
while (--k)
|
|
1102
|
+
c = (c & 1 && -306674912) ^ c >>> 1;
|
|
1103
|
+
t[i] = c;
|
|
1104
|
+
}
|
|
1105
|
+
return t;
|
|
1106
|
+
})();
|
|
1107
|
+
var crc = function() {
|
|
1108
|
+
var c = -1;
|
|
1109
|
+
return {
|
|
1110
|
+
p: function(d) {
|
|
1111
|
+
var cr = c;
|
|
1112
|
+
for (var i = 0; i < d.length; ++i)
|
|
1113
|
+
cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8;
|
|
1114
|
+
c = cr;
|
|
1115
|
+
},
|
|
1116
|
+
d: function() {
|
|
1117
|
+
return ~c;
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
};
|
|
1121
|
+
var dopt = function(dat, opt, pre, post, st) {
|
|
1122
|
+
if (!st) {
|
|
1123
|
+
st = { l: 1 };
|
|
1124
|
+
if (opt.dictionary) {
|
|
1125
|
+
var dict = opt.dictionary.subarray(-32768);
|
|
1126
|
+
var newDat = new u8(dict.length + dat.length);
|
|
1127
|
+
newDat.set(dict);
|
|
1128
|
+
newDat.set(dat, dict.length);
|
|
1129
|
+
dat = newDat;
|
|
1130
|
+
st.w = dict.length;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
|
|
1134
|
+
};
|
|
1135
|
+
var mrg = function(a, b) {
|
|
1136
|
+
var o = {};
|
|
1137
|
+
for (var k in a)
|
|
1138
|
+
o[k] = a[k];
|
|
1139
|
+
for (var k in b)
|
|
1140
|
+
o[k] = b[k];
|
|
1141
|
+
return o;
|
|
1142
|
+
};
|
|
1143
|
+
var wbytes = function(d, b, v) {
|
|
1144
|
+
for (; v; ++b)
|
|
1145
|
+
d[b] = v, v >>>= 8;
|
|
1146
|
+
};
|
|
1147
|
+
function deflateSync(data, opts) {
|
|
1148
|
+
return dopt(data, opts || {}, 0, 0);
|
|
1149
|
+
}
|
|
1150
|
+
var fltn = function(d, p, t, o) {
|
|
1151
|
+
for (var k in d) {
|
|
1152
|
+
var val = d[k], n = p + k, op = o;
|
|
1153
|
+
if (Array.isArray(val))
|
|
1154
|
+
op = mrg(o, val[1]), val = val[0];
|
|
1155
|
+
if (val instanceof u8)
|
|
1156
|
+
t[n] = [val, op];
|
|
1157
|
+
else {
|
|
1158
|
+
t[n += "/"] = [new u8(0), op];
|
|
1159
|
+
fltn(val, n, t, o);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
var te = typeof TextEncoder != "undefined" && /* @__PURE__ */ new TextEncoder();
|
|
1164
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
1165
|
+
var tds = 0;
|
|
1166
|
+
try {
|
|
1167
|
+
td.decode(et, { stream: true });
|
|
1168
|
+
tds = 1;
|
|
1169
|
+
} catch (e) {
|
|
1170
|
+
}
|
|
1171
|
+
function strToU8(str, latin1) {
|
|
1172
|
+
if (latin1) {
|
|
1173
|
+
var ar_1 = new u8(str.length);
|
|
1174
|
+
for (var i = 0; i < str.length; ++i)
|
|
1175
|
+
ar_1[i] = str.charCodeAt(i);
|
|
1176
|
+
return ar_1;
|
|
1177
|
+
}
|
|
1178
|
+
if (te)
|
|
1179
|
+
return te.encode(str);
|
|
1180
|
+
var l = str.length;
|
|
1181
|
+
var ar = new u8(str.length + (str.length >> 1));
|
|
1182
|
+
var ai = 0;
|
|
1183
|
+
var w = function(v) {
|
|
1184
|
+
ar[ai++] = v;
|
|
1185
|
+
};
|
|
1186
|
+
for (var i = 0; i < l; ++i) {
|
|
1187
|
+
if (ai + 5 > ar.length) {
|
|
1188
|
+
var n = new u8(ai + 8 + (l - i << 1));
|
|
1189
|
+
n.set(ar);
|
|
1190
|
+
ar = n;
|
|
1191
|
+
}
|
|
1192
|
+
var c = str.charCodeAt(i);
|
|
1193
|
+
if (c < 128 || latin1)
|
|
1194
|
+
w(c);
|
|
1195
|
+
else if (c < 2048)
|
|
1196
|
+
w(192 | c >> 6), w(128 | c & 63);
|
|
1197
|
+
else if (c > 55295 && c < 57344)
|
|
1198
|
+
c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
1199
|
+
else
|
|
1200
|
+
w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
|
|
1201
|
+
}
|
|
1202
|
+
return slc(ar, 0, ai);
|
|
1203
|
+
}
|
|
1204
|
+
var exfl = function(ex) {
|
|
1205
|
+
var le = 0;
|
|
1206
|
+
if (ex) {
|
|
1207
|
+
for (var k in ex) {
|
|
1208
|
+
var l = ex[k].length;
|
|
1209
|
+
if (l > 65535)
|
|
1210
|
+
err(9);
|
|
1211
|
+
le += l + 4;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return le;
|
|
1215
|
+
};
|
|
1216
|
+
var wzh = function(d, b, f, fn, u, c, ce, co) {
|
|
1217
|
+
var fl2 = fn.length, ex = f.extra, col = co && co.length;
|
|
1218
|
+
var exl = exfl(ex);
|
|
1219
|
+
wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4;
|
|
1220
|
+
if (ce != null)
|
|
1221
|
+
d[b++] = 20, d[b++] = f.os;
|
|
1222
|
+
d[b] = 20, b += 2;
|
|
1223
|
+
d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8;
|
|
1224
|
+
d[b++] = f.compression & 255, d[b++] = f.compression >> 8;
|
|
1225
|
+
var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;
|
|
1226
|
+
if (y < 0 || y > 119)
|
|
1227
|
+
err(10);
|
|
1228
|
+
wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4;
|
|
1229
|
+
if (c != -1) {
|
|
1230
|
+
wbytes(d, b, f.crc);
|
|
1231
|
+
wbytes(d, b + 4, c < 0 ? -c - 2 : c);
|
|
1232
|
+
wbytes(d, b + 8, f.size);
|
|
1233
|
+
}
|
|
1234
|
+
wbytes(d, b + 12, fl2);
|
|
1235
|
+
wbytes(d, b + 14, exl), b += 16;
|
|
1236
|
+
if (ce != null) {
|
|
1237
|
+
wbytes(d, b, col);
|
|
1238
|
+
wbytes(d, b + 6, f.attrs);
|
|
1239
|
+
wbytes(d, b + 10, ce), b += 14;
|
|
1240
|
+
}
|
|
1241
|
+
d.set(fn, b);
|
|
1242
|
+
b += fl2;
|
|
1243
|
+
if (exl) {
|
|
1244
|
+
for (var k in ex) {
|
|
1245
|
+
var exf = ex[k], l = exf.length;
|
|
1246
|
+
wbytes(d, b, +k);
|
|
1247
|
+
wbytes(d, b + 2, l);
|
|
1248
|
+
d.set(exf, b + 4), b += 4 + l;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
if (col)
|
|
1252
|
+
d.set(co, b), b += col;
|
|
1253
|
+
return b;
|
|
1254
|
+
};
|
|
1255
|
+
var wzf = function(o, b, c, d, e) {
|
|
1256
|
+
wbytes(o, b, 101010256);
|
|
1257
|
+
wbytes(o, b + 8, c);
|
|
1258
|
+
wbytes(o, b + 10, c);
|
|
1259
|
+
wbytes(o, b + 12, d);
|
|
1260
|
+
wbytes(o, b + 16, e);
|
|
1261
|
+
};
|
|
1262
|
+
function zipSync(data, opts) {
|
|
1263
|
+
if (!opts)
|
|
1264
|
+
opts = {};
|
|
1265
|
+
var r = {};
|
|
1266
|
+
var files = [];
|
|
1267
|
+
fltn(data, "", r, opts);
|
|
1268
|
+
var o = 0;
|
|
1269
|
+
var tot = 0;
|
|
1270
|
+
for (var fn in r) {
|
|
1271
|
+
var _a2 = r[fn], file = _a2[0], p = _a2[1];
|
|
1272
|
+
var compression = p.level == 0 ? 0 : 8;
|
|
1273
|
+
var f = strToU8(fn), s = f.length;
|
|
1274
|
+
var com = p.comment, m = com && strToU8(com), ms = m && m.length;
|
|
1275
|
+
var exl = exfl(p.extra);
|
|
1276
|
+
if (s > 65535)
|
|
1277
|
+
err(11);
|
|
1278
|
+
var d = compression ? deflateSync(file, p) : file, l = d.length;
|
|
1279
|
+
var c = crc();
|
|
1280
|
+
c.p(file);
|
|
1281
|
+
files.push(mrg(p, {
|
|
1282
|
+
size: file.length,
|
|
1283
|
+
crc: c.d(),
|
|
1284
|
+
c: d,
|
|
1285
|
+
f,
|
|
1286
|
+
m,
|
|
1287
|
+
u: s != fn.length || m && com.length != ms,
|
|
1288
|
+
o,
|
|
1289
|
+
compression
|
|
1290
|
+
}));
|
|
1291
|
+
o += 30 + s + exl + l;
|
|
1292
|
+
tot += 76 + 2 * (s + exl) + (ms || 0) + l;
|
|
1293
|
+
}
|
|
1294
|
+
var out = new u8(tot + 22), oe = o, cdl = tot - o;
|
|
1295
|
+
for (var i = 0; i < files.length; ++i) {
|
|
1296
|
+
var f = files[i];
|
|
1297
|
+
wzh(out, f.o, f, f.f, f.u, f.c.length);
|
|
1298
|
+
var badd = 30 + f.f.length + exfl(f.extra);
|
|
1299
|
+
out.set(f.c, f.o + badd);
|
|
1300
|
+
wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);
|
|
1301
|
+
}
|
|
1302
|
+
wzf(out, o, files.length, cdl, oe);
|
|
1303
|
+
return out;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
237
1306
|
// ../utils/src/zipper.ts
|
|
238
|
-
import * as fs2 from "fs";
|
|
239
|
-
import * as os from "os";
|
|
240
|
-
import * as path2 from "path";
|
|
241
|
-
import { ZipArchive } from "archiver";
|
|
242
1307
|
var Zipper = class {
|
|
243
1308
|
outputPath;
|
|
1309
|
+
compressionLevel;
|
|
1310
|
+
onProgress;
|
|
244
1311
|
constructor(options) {
|
|
245
1312
|
this.outputPath = options.outputPath;
|
|
1313
|
+
this.compressionLevel = options.compressionLevel ?? 0;
|
|
1314
|
+
this.onProgress = options.onProgress;
|
|
246
1315
|
}
|
|
247
1316
|
/**
|
|
248
1317
|
* Creates a ZIP archive containing the JSON report and assets
|
|
@@ -251,76 +1320,105 @@ var Zipper = class {
|
|
|
251
1320
|
* @returns ZIP creation result with metadata
|
|
252
1321
|
*/
|
|
253
1322
|
async createZip(reportPath, assets) {
|
|
1323
|
+
if (!fs4.existsSync(reportPath)) {
|
|
1324
|
+
throw new Error(`Report file not found: ${reportPath}`);
|
|
1325
|
+
}
|
|
1326
|
+
const transformedReportPath = this.transformJsonReport(reportPath);
|
|
1327
|
+
const files = {};
|
|
1328
|
+
const totalEntries = assets.length + 1;
|
|
1329
|
+
let processedEntries = 0;
|
|
1330
|
+
const reportContent = fs4.readFileSync(transformedReportPath);
|
|
1331
|
+
files["output/playwright-test-report.json"] = new Uint8Array(reportContent);
|
|
1332
|
+
processedEntries++;
|
|
1333
|
+
this.onProgress?.({ processedEntries, totalEntries, currentFile: "output/playwright-test-report.json" });
|
|
1334
|
+
for (const asset of assets) {
|
|
1335
|
+
if (!fs4.existsSync(asset.sourcePath)) {
|
|
1336
|
+
console.warn(`[Checkly Reporter] Skipping missing asset: ${asset.sourcePath}`);
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
const content = fs4.readFileSync(asset.sourcePath);
|
|
1340
|
+
files[asset.archivePath] = new Uint8Array(content);
|
|
1341
|
+
processedEntries++;
|
|
1342
|
+
this.onProgress?.({ processedEntries, totalEntries, currentFile: asset.archivePath });
|
|
1343
|
+
}
|
|
1344
|
+
const zipData = zipSync(files, { level: this.compressionLevel });
|
|
1345
|
+
fs4.writeFileSync(this.outputPath, zipData);
|
|
1346
|
+
try {
|
|
1347
|
+
fs4.unlinkSync(transformedReportPath);
|
|
1348
|
+
} catch {
|
|
1349
|
+
}
|
|
1350
|
+
const entries = this.extractEntryOffsets(zipData);
|
|
1351
|
+
return {
|
|
1352
|
+
zipPath: this.outputPath,
|
|
1353
|
+
size: zipData.length,
|
|
1354
|
+
entryCount: entries.length,
|
|
1355
|
+
entries
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Extracts byte offsets for each entry from the ZIP data
|
|
1360
|
+
* Parses the central directory to get accurate offset information
|
|
1361
|
+
*/
|
|
1362
|
+
extractEntryOffsets(zipData) {
|
|
254
1363
|
const entries = [];
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
size: zipSize,
|
|
276
|
-
entryCount: entries.length,
|
|
277
|
-
entries
|
|
278
|
-
});
|
|
279
|
-
});
|
|
280
|
-
archive.on("error", (err) => {
|
|
281
|
-
reject(err);
|
|
282
|
-
});
|
|
283
|
-
output.on("error", (err) => {
|
|
284
|
-
reject(err);
|
|
285
|
-
});
|
|
286
|
-
archive.pipe(output);
|
|
287
|
-
if (!fs2.existsSync(reportPath)) {
|
|
288
|
-
reject(new Error(`Report file not found: ${reportPath}`));
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const transformedReportPath = this.transformJsonReport(reportPath);
|
|
292
|
-
archive.file(transformedReportPath, { name: "output/playwright-test-report.json" });
|
|
293
|
-
for (const asset of assets) {
|
|
294
|
-
if (!fs2.existsSync(asset.sourcePath)) {
|
|
295
|
-
console.warn(`[Checkly Reporter] Skipping missing asset: ${asset.sourcePath}`);
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
298
|
-
archive.file(asset.sourcePath, { name: asset.archivePath });
|
|
1364
|
+
const view = new DataView(zipData.buffer, zipData.byteOffset, zipData.byteLength);
|
|
1365
|
+
let eocdOffset = -1;
|
|
1366
|
+
for (let i = zipData.length - 22; i >= 0; i--) {
|
|
1367
|
+
if (view.getUint32(i, true) === 101010256) {
|
|
1368
|
+
eocdOffset = i;
|
|
1369
|
+
break;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (eocdOffset === -1) {
|
|
1373
|
+
console.warn("[Checkly Reporter] Could not find ZIP end of central directory");
|
|
1374
|
+
return entries;
|
|
1375
|
+
}
|
|
1376
|
+
let cdOffset = view.getUint32(eocdOffset + 16, true);
|
|
1377
|
+
const cdSize = view.getUint32(eocdOffset + 12, true);
|
|
1378
|
+
if (cdOffset === 4294967295 && eocdOffset >= 20) {
|
|
1379
|
+
const zip64LocatorOffset = eocdOffset - 20;
|
|
1380
|
+
if (view.getUint32(zip64LocatorOffset, true) === 117853008) {
|
|
1381
|
+
const zip64EocdOffset = Number(view.getBigUint64(zip64LocatorOffset + 8, true));
|
|
1382
|
+
if (view.getUint32(zip64EocdOffset, true) === 101075792) {
|
|
1383
|
+
cdOffset = Number(view.getBigUint64(zip64EocdOffset + 48, true));
|
|
299
1384
|
}
|
|
300
|
-
archive.finalize();
|
|
301
|
-
} catch (error) {
|
|
302
|
-
reject(error);
|
|
303
1385
|
}
|
|
304
|
-
}
|
|
1386
|
+
}
|
|
1387
|
+
let offset = cdOffset;
|
|
1388
|
+
const cdEnd = cdOffset + cdSize;
|
|
1389
|
+
while (offset < cdEnd && view.getUint32(offset, true) === 33639248) {
|
|
1390
|
+
const compressedSize = view.getUint32(offset + 20, true);
|
|
1391
|
+
const filenameLength = view.getUint16(offset + 28, true);
|
|
1392
|
+
const extraLength = view.getUint16(offset + 30, true);
|
|
1393
|
+
const commentLength = view.getUint16(offset + 32, true);
|
|
1394
|
+
const localHeaderOffset = view.getUint32(offset + 42, true);
|
|
1395
|
+
const filenameBytes = zipData.slice(offset + 46, offset + 46 + filenameLength);
|
|
1396
|
+
const filename = new TextDecoder().decode(filenameBytes);
|
|
1397
|
+
const localExtraLength = view.getUint16(localHeaderOffset + 28, true);
|
|
1398
|
+
const dataStart = localHeaderOffset + 30 + filenameLength + localExtraLength;
|
|
1399
|
+
const dataEnd = dataStart + compressedSize - 1;
|
|
1400
|
+
entries.push({
|
|
1401
|
+
name: filename.replace(/\\/g, "/"),
|
|
1402
|
+
start: dataStart,
|
|
1403
|
+
end: dataEnd >= dataStart ? dataEnd : dataStart
|
|
1404
|
+
});
|
|
1405
|
+
offset += 46 + filenameLength + extraLength + commentLength;
|
|
1406
|
+
}
|
|
1407
|
+
return entries;
|
|
305
1408
|
}
|
|
306
1409
|
/**
|
|
307
1410
|
* Transforms the JSON report to use relative paths for attachments
|
|
308
|
-
* This ensures the UI can map attachment paths to ZIP entries
|
|
309
|
-
* @param reportPath - Path to the original JSON report
|
|
310
|
-
* @returns Path to the transformed JSON report (in temp directory)
|
|
311
1411
|
*/
|
|
312
1412
|
transformJsonReport(reportPath) {
|
|
313
|
-
const reportContent =
|
|
1413
|
+
const reportContent = fs4.readFileSync(reportPath, "utf-8");
|
|
314
1414
|
const report = JSON.parse(reportContent);
|
|
315
1415
|
this.transformAttachmentPaths(report);
|
|
316
|
-
const tempReportPath =
|
|
317
|
-
|
|
1416
|
+
const tempReportPath = path3.join(os2.tmpdir(), `playwright-test-report-${Date.now()}.json`);
|
|
1417
|
+
fs4.writeFileSync(tempReportPath, JSON.stringify(report, null, 2));
|
|
318
1418
|
return tempReportPath;
|
|
319
1419
|
}
|
|
320
1420
|
/**
|
|
321
1421
|
* Recursively transforms attachment paths in the report structure
|
|
322
|
-
* Converts absolute paths to relative paths matching ZIP structure
|
|
323
|
-
* @param obj - Object to transform (mutated in place)
|
|
324
1422
|
*/
|
|
325
1423
|
transformAttachmentPaths(obj) {
|
|
326
1424
|
if (typeof obj !== "object" || obj === null) {
|
|
@@ -340,21 +1438,7 @@ var Zipper = class {
|
|
|
340
1438
|
Object.values(obj).forEach((value) => this.transformAttachmentPaths(value));
|
|
341
1439
|
}
|
|
342
1440
|
/**
|
|
343
|
-
* Normalizes attachment paths by extracting the relevant snapshot directory portion
|
|
344
|
-
* Supports Playwright's default and common custom snapshot directory patterns,
|
|
345
|
-
* as well as blob merge resource paths.
|
|
346
|
-
*
|
|
347
|
-
* Priority order (first match wins):
|
|
348
|
-
* 1. test-results/ (highest priority, existing behavior)
|
|
349
|
-
* 2. blob-reports/resources/ (blob merge extraction paths)
|
|
350
|
-
* 3. snapshots directories (Playwright default pattern)
|
|
351
|
-
* 4. __screenshots__/ (common custom pattern)
|
|
352
|
-
* 5. __snapshots__/ (common custom pattern)
|
|
353
|
-
* 6. screenshots/ (simple custom pattern)
|
|
354
|
-
* 7. snapshots/ (simple custom pattern)
|
|
355
|
-
*
|
|
356
|
-
* @param attachmentPath - Absolute or relative path to attachment
|
|
357
|
-
* @returns Normalized path starting from the matched directory, or original path if no match
|
|
1441
|
+
* Normalizes attachment paths by extracting the relevant snapshot directory portion
|
|
358
1442
|
*/
|
|
359
1443
|
normalizeAttachmentPath(attachmentPath) {
|
|
360
1444
|
const normalizedPath = attachmentPath.replace(/\\/g, "/");
|
|
@@ -391,17 +1475,11 @@ var Zipper = class {
|
|
|
391
1475
|
}
|
|
392
1476
|
};
|
|
393
1477
|
|
|
394
|
-
// src/
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
import * as path3 from "path";
|
|
398
|
-
import { dirname, join as join3 } from "path";
|
|
399
|
-
import { fileURLToPath } from "url";
|
|
400
|
-
|
|
401
|
-
// ../clients/src/checkly-client.ts
|
|
402
|
-
import axios from "axios";
|
|
1478
|
+
// src/api/client.ts
|
|
1479
|
+
var import_axios = __toESM(require("axios"));
|
|
1480
|
+
var import_form_data = __toESM(require("form-data"));
|
|
403
1481
|
|
|
404
|
-
//
|
|
1482
|
+
// src/api/errors.ts
|
|
405
1483
|
var ApiError = class extends Error {
|
|
406
1484
|
data;
|
|
407
1485
|
constructor(data, options) {
|
|
@@ -411,44 +1489,20 @@ var ApiError = class extends Error {
|
|
|
411
1489
|
}
|
|
412
1490
|
};
|
|
413
1491
|
var ValidationError = class extends ApiError {
|
|
414
|
-
constructor(data, options) {
|
|
415
|
-
super(data, options);
|
|
416
|
-
}
|
|
417
1492
|
};
|
|
418
1493
|
var UnauthorizedError = class extends ApiError {
|
|
419
|
-
constructor(data, options) {
|
|
420
|
-
super(data, options);
|
|
421
|
-
}
|
|
422
1494
|
};
|
|
423
1495
|
var ForbiddenError = class extends ApiError {
|
|
424
|
-
constructor(data, options) {
|
|
425
|
-
super(data, options);
|
|
426
|
-
}
|
|
427
1496
|
};
|
|
428
1497
|
var NotFoundError = class extends ApiError {
|
|
429
|
-
constructor(data, options) {
|
|
430
|
-
super(data, options);
|
|
431
|
-
}
|
|
432
1498
|
};
|
|
433
1499
|
var RequestTimeoutError = class extends ApiError {
|
|
434
|
-
constructor(data, options) {
|
|
435
|
-
super(data, options);
|
|
436
|
-
}
|
|
437
1500
|
};
|
|
438
1501
|
var ConflictError = class extends ApiError {
|
|
439
|
-
constructor(data, options) {
|
|
440
|
-
super(data, options);
|
|
441
|
-
}
|
|
442
1502
|
};
|
|
443
1503
|
var ServerError = class extends ApiError {
|
|
444
|
-
constructor(data, options) {
|
|
445
|
-
super(data, options);
|
|
446
|
-
}
|
|
447
1504
|
};
|
|
448
1505
|
var MiscellaneousError = class extends ApiError {
|
|
449
|
-
constructor(data, options) {
|
|
450
|
-
super(data, options);
|
|
451
|
-
}
|
|
452
1506
|
};
|
|
453
1507
|
var MissingResponseError = class extends Error {
|
|
454
1508
|
constructor(message, options) {
|
|
@@ -456,63 +1510,58 @@ var MissingResponseError = class extends Error {
|
|
|
456
1510
|
this.name = "MissingResponseError";
|
|
457
1511
|
}
|
|
458
1512
|
};
|
|
459
|
-
function parseErrorData(data,
|
|
460
|
-
if (!data)
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
1513
|
+
function parseErrorData(data, statusCode) {
|
|
1514
|
+
if (!data) return void 0;
|
|
1515
|
+
if (typeof data === "object" && data !== null) {
|
|
1516
|
+
const obj = data;
|
|
1517
|
+
if (obj.statusCode && obj.error && obj.message) {
|
|
1518
|
+
return {
|
|
1519
|
+
statusCode: obj.statusCode,
|
|
1520
|
+
error: obj.error,
|
|
1521
|
+
message: obj.message,
|
|
1522
|
+
errorCode: obj.errorCode
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
if (obj.error && obj.message) {
|
|
1526
|
+
return {
|
|
1527
|
+
statusCode,
|
|
1528
|
+
error: obj.error,
|
|
1529
|
+
message: obj.message,
|
|
1530
|
+
errorCode: obj.errorCode
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
if (obj.error) {
|
|
1534
|
+
return {
|
|
1535
|
+
statusCode,
|
|
1536
|
+
error: obj.error,
|
|
1537
|
+
message: obj.error
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
if (obj.message) {
|
|
1541
|
+
return {
|
|
1542
|
+
statusCode,
|
|
1543
|
+
error: obj.message,
|
|
1544
|
+
message: obj.message,
|
|
1545
|
+
errorCode: obj.errorCode
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
493
1548
|
}
|
|
494
1549
|
if (typeof data === "string") {
|
|
495
|
-
return {
|
|
496
|
-
statusCode: options.statusCode,
|
|
497
|
-
error: data,
|
|
498
|
-
message: data
|
|
499
|
-
};
|
|
1550
|
+
return { statusCode, error: data, message: data };
|
|
500
1551
|
}
|
|
501
1552
|
return void 0;
|
|
502
1553
|
}
|
|
503
|
-
function handleErrorResponse(
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const { status, data } = err.response;
|
|
508
|
-
const errorData = parseErrorData(data, { statusCode: status });
|
|
509
|
-
if (!errorData) {
|
|
510
|
-
throw new MiscellaneousError({
|
|
511
|
-
statusCode: status,
|
|
512
|
-
error: "Unknown error",
|
|
513
|
-
message: err.message || "An error occurred"
|
|
514
|
-
});
|
|
1554
|
+
function handleErrorResponse(err2) {
|
|
1555
|
+
const axiosError = err2;
|
|
1556
|
+
if (!axiosError.response) {
|
|
1557
|
+
throw new MissingResponseError(axiosError.message || "Network error");
|
|
515
1558
|
}
|
|
1559
|
+
const { status, data } = axiosError.response;
|
|
1560
|
+
const errorData = parseErrorData(data, status) ?? {
|
|
1561
|
+
statusCode: status,
|
|
1562
|
+
error: "Unknown error",
|
|
1563
|
+
message: axiosError.message || "An error occurred"
|
|
1564
|
+
};
|
|
516
1565
|
switch (status) {
|
|
517
1566
|
case 400:
|
|
518
1567
|
throw new ValidationError(errorData);
|
|
@@ -534,561 +1583,874 @@ function handleErrorResponse(err) {
|
|
|
534
1583
|
}
|
|
535
1584
|
}
|
|
536
1585
|
|
|
537
|
-
//
|
|
538
|
-
function
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
1586
|
+
// src/api/client.ts
|
|
1587
|
+
function createClient(options) {
|
|
1588
|
+
const http = import_axios.default.create({
|
|
1589
|
+
baseURL: options.baseUrl,
|
|
1590
|
+
timeout: 12e4,
|
|
1591
|
+
maxContentLength: Number.POSITIVE_INFINITY,
|
|
1592
|
+
maxBodyLength: Number.POSITIVE_INFINITY
|
|
1593
|
+
});
|
|
1594
|
+
http.interceptors.request.use((config) => {
|
|
543
1595
|
if (config.headers) {
|
|
544
|
-
config.headers.Authorization = `Bearer ${apiKey}`;
|
|
545
|
-
config.headers["x-checkly-account"] = accountId;
|
|
546
|
-
config.headers["
|
|
1596
|
+
config.headers.Authorization = `Bearer ${options.apiKey}`;
|
|
1597
|
+
config.headers["x-checkly-account"] = options.accountId;
|
|
1598
|
+
config.headers["x-checkly-reporter-version"] = options.telemetry.reporterVersion;
|
|
1599
|
+
config.headers["x-checkly-playwright-version"] = options.telemetry.playwrightVersion;
|
|
1600
|
+
config.headers["x-checkly-ci-provider"] = options.telemetry.ciProvider;
|
|
1601
|
+
config.headers["x-checkly-ci-environment"] = options.telemetry.ciEnvironment;
|
|
1602
|
+
config.headers["x-checkly-node-version"] = options.telemetry.nodeVersion;
|
|
547
1603
|
}
|
|
548
1604
|
return config;
|
|
1605
|
+
});
|
|
1606
|
+
http.interceptors.response.use(
|
|
1607
|
+
(response) => response,
|
|
1608
|
+
(error) => handleErrorResponse(error)
|
|
1609
|
+
);
|
|
1610
|
+
return {
|
|
1611
|
+
testSessions: {
|
|
1612
|
+
async create(request) {
|
|
1613
|
+
const response = await http.post("/next/test-sessions/create", request);
|
|
1614
|
+
return response.data;
|
|
1615
|
+
},
|
|
1616
|
+
async uploadAsset(testSessionId, testResultId, assets) {
|
|
1617
|
+
const form = new import_form_data.default();
|
|
1618
|
+
form.append("assets", assets, { filename: "assets.zip", contentType: "application/zip" });
|
|
1619
|
+
const response = await http.post(
|
|
1620
|
+
`/next/test-sessions/${testSessionId}/results/${testResultId}/assets`,
|
|
1621
|
+
form,
|
|
1622
|
+
{ headers: form.getHeaders() }
|
|
1623
|
+
);
|
|
1624
|
+
return response.data;
|
|
1625
|
+
},
|
|
1626
|
+
async updateResult(testSessionId, testResultId, request) {
|
|
1627
|
+
const response = await http.post(
|
|
1628
|
+
`/next/test-sessions/${testSessionId}/results/${testResultId}`,
|
|
1629
|
+
request
|
|
1630
|
+
);
|
|
1631
|
+
return response.data;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
549
1634
|
};
|
|
550
1635
|
}
|
|
551
|
-
function createResponseErrorInterceptor() {
|
|
552
|
-
return (error) => {
|
|
553
|
-
handleErrorResponse(error);
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
var ChecklyClient = class {
|
|
557
|
-
apiKey;
|
|
558
|
-
baseUrl;
|
|
559
|
-
accountId;
|
|
560
|
-
api;
|
|
561
|
-
constructor(options) {
|
|
562
|
-
this.accountId = options.accountId;
|
|
563
|
-
this.apiKey = options.apiKey;
|
|
564
|
-
this.baseUrl = options.baseUrl;
|
|
565
|
-
this.api = axios.create({
|
|
566
|
-
baseURL: this.baseUrl,
|
|
567
|
-
timeout: 12e4,
|
|
568
|
-
// 120 second timeout for large uploads
|
|
569
|
-
maxContentLength: Number.POSITIVE_INFINITY,
|
|
570
|
-
// Allow large payloads
|
|
571
|
-
maxBodyLength: Number.POSITIVE_INFINITY
|
|
572
|
-
// Allow large request bodies
|
|
573
|
-
});
|
|
574
|
-
this.api.interceptors.request.use(createRequestInterceptor(this.apiKey, this.accountId));
|
|
575
|
-
this.api.interceptors.response.use((response) => response, createResponseErrorInterceptor());
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* Gets the underlying axios instance
|
|
579
|
-
* Useful for creating resource-specific clients (e.g., TestResults)
|
|
580
|
-
*/
|
|
581
|
-
getAxiosInstance() {
|
|
582
|
-
return this.api;
|
|
583
|
-
}
|
|
584
|
-
};
|
|
585
1636
|
|
|
586
|
-
//
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
* Creates a new test session in Checkly
|
|
594
|
-
*
|
|
595
|
-
* @param request Test session creation request
|
|
596
|
-
* @returns Test session response with session ID and test result IDs
|
|
597
|
-
* @throws {ValidationError} If request data is invalid
|
|
598
|
-
* @throws {UnauthorizedError} If authentication fails
|
|
599
|
-
* @throws {ServerError} If server error occurs
|
|
600
|
-
*/
|
|
601
|
-
async createTestSession(request) {
|
|
602
|
-
const response = await this.api.post("/next/test-sessions/create", request);
|
|
603
|
-
return response.data;
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Step 1: Upload test result assets to S3
|
|
607
|
-
* Streams a ZIP file containing test assets (traces, videos, screenshots)
|
|
608
|
-
*
|
|
609
|
-
* @param testSessionId ID of the test session
|
|
610
|
-
* @param testResultId ID of the test result
|
|
611
|
-
* @param assets Buffer or ReadableStream of the ZIP file
|
|
612
|
-
* @returns Upload response with assetId, region, key, and url
|
|
613
|
-
* @throws {ValidationError} If assets are invalid
|
|
614
|
-
* @throws {UnauthorizedError} If authentication fails
|
|
615
|
-
* @throws {NotFoundError} If test session or result not found
|
|
616
|
-
* @throws {PayloadTooLargeError} If assets exceed 500MB
|
|
617
|
-
* @throws {ServerError} If S3 upload fails
|
|
618
|
-
*/
|
|
619
|
-
async uploadTestResultAsset(testSessionId, testResultId, assets) {
|
|
620
|
-
const form = new FormData();
|
|
621
|
-
form.append("assets", assets, {
|
|
622
|
-
filename: "assets.zip",
|
|
623
|
-
contentType: "application/zip"
|
|
624
|
-
});
|
|
625
|
-
const response = await this.api.post(
|
|
626
|
-
`/next/test-sessions/${testSessionId}/results/${testResultId}/assets`,
|
|
627
|
-
form,
|
|
628
|
-
{
|
|
629
|
-
headers: {
|
|
630
|
-
...form.getHeaders()
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
);
|
|
634
|
-
return response.data;
|
|
1637
|
+
// src/extensions/checkly-upload.ts
|
|
1638
|
+
function getPackageVersion() {
|
|
1639
|
+
try {
|
|
1640
|
+
const packageJson = JSON.parse(fs5.readFileSync(path4.join(__dirname, "..", "package.json"), "utf-8"));
|
|
1641
|
+
return packageJson.version;
|
|
1642
|
+
} catch {
|
|
1643
|
+
return "unknown";
|
|
635
1644
|
}
|
|
636
|
-
|
|
637
|
-
* Step 2: Update test result with status and optional asset reference
|
|
638
|
-
* Uses JSON payload for clean, easy-to-validate updates
|
|
639
|
-
*
|
|
640
|
-
* @param testSessionId ID of the test session
|
|
641
|
-
* @param testResultId ID of the test result to update
|
|
642
|
-
* @param request Test result update request (JSON)
|
|
643
|
-
* @returns Test result update response
|
|
644
|
-
* @throws {ValidationError} If request data is invalid
|
|
645
|
-
* @throws {UnauthorizedError} If authentication fails
|
|
646
|
-
* @throws {NotFoundError} If test session or result not found
|
|
647
|
-
* @throws {ServerError} If server error occurs
|
|
648
|
-
*/
|
|
649
|
-
async updateTestResult(testSessionId, testResultId, request) {
|
|
650
|
-
const response = await this.api.post(
|
|
651
|
-
`/next/test-sessions/${testSessionId}/results/${testResultId}`,
|
|
652
|
-
request
|
|
653
|
-
);
|
|
654
|
-
return response.data;
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
|
|
658
|
-
// src/reporter.ts
|
|
659
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
660
|
-
var __dirname = dirname(__filename);
|
|
661
|
-
var packageJson = JSON.parse(readFileSync3(join3(__dirname, "..", "package.json"), "utf-8"));
|
|
662
|
-
var pkgVersion = packageJson.version;
|
|
663
|
-
var pluralRules = new Intl.PluralRules("en-US");
|
|
664
|
-
var projectForms = {
|
|
665
|
-
zero: "Project",
|
|
666
|
-
one: "Project",
|
|
667
|
-
two: "Projects",
|
|
668
|
-
few: "Projects",
|
|
669
|
-
many: "Projects",
|
|
670
|
-
other: "Projects"
|
|
671
|
-
};
|
|
1645
|
+
}
|
|
672
1646
|
function getApiUrl(environment) {
|
|
673
|
-
const
|
|
1647
|
+
const urls = {
|
|
674
1648
|
local: "http://127.0.0.1:3000",
|
|
675
1649
|
development: "https://api-dev.checklyhq.com",
|
|
676
1650
|
staging: "https://api-test.checklyhq.com",
|
|
677
1651
|
production: "https://api.checklyhq.com"
|
|
678
1652
|
};
|
|
679
|
-
return
|
|
1653
|
+
return urls[environment];
|
|
680
1654
|
}
|
|
681
|
-
function getEnvironment(
|
|
682
|
-
const
|
|
683
|
-
const
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
if (!validEnvironments.includes(env)) {
|
|
687
|
-
console.warn(`[Checkly Reporter] Invalid environment "${env}", using "production"`);
|
|
1655
|
+
function getEnvironment() {
|
|
1656
|
+
const env = process.env.CHECKLY_ENV || "production";
|
|
1657
|
+
const valid = ["local", "development", "staging", "production"];
|
|
1658
|
+
if (!valid.includes(env)) {
|
|
1659
|
+
console.warn(`[Checkly] Invalid environment "${env}", using "production"`);
|
|
688
1660
|
return "production";
|
|
689
1661
|
}
|
|
690
1662
|
return env;
|
|
691
1663
|
}
|
|
692
|
-
function convertStepToJSON(step) {
|
|
693
|
-
return {
|
|
694
|
-
title: step.title,
|
|
695
|
-
duration: step.duration,
|
|
696
|
-
error: step.error,
|
|
697
|
-
steps: step.steps.length > 0 ? step.steps.map(convertStepToJSON) : void 0
|
|
698
|
-
};
|
|
699
|
-
}
|
|
700
1664
|
function getDirectoryName() {
|
|
701
1665
|
const cwd = process.cwd();
|
|
702
|
-
let
|
|
703
|
-
if (!
|
|
704
|
-
|
|
1666
|
+
let name = path4.basename(cwd);
|
|
1667
|
+
if (!name || name === "/" || name === ".") name = "playwright-tests";
|
|
1668
|
+
name = name.replace(/[<>:"|?*]/g, "-");
|
|
1669
|
+
if (name.length > 255) name = name.substring(0, 255);
|
|
1670
|
+
return name;
|
|
1671
|
+
}
|
|
1672
|
+
function checklyUpload(options = {}) {
|
|
1673
|
+
const apiKey = process.env.CHECKLY_API_KEY || options.apiKey;
|
|
1674
|
+
const accountId = process.env.CHECKLY_ACCOUNT_ID || options.accountId;
|
|
1675
|
+
const environment = getEnvironment();
|
|
1676
|
+
const baseUrl = getApiUrl(environment);
|
|
1677
|
+
const dryRun = options.dryRun ?? false;
|
|
1678
|
+
const ciInfo = detectCI();
|
|
1679
|
+
const reporterVersion = getPackageVersion();
|
|
1680
|
+
const canUpload = !dryRun && apiKey && accountId;
|
|
1681
|
+
let api;
|
|
1682
|
+
let testSession;
|
|
1683
|
+
let sessionCreationPromise;
|
|
1684
|
+
let startTime;
|
|
1685
|
+
let resolvedOutputDir;
|
|
1686
|
+
let assetCollector;
|
|
1687
|
+
let zipper;
|
|
1688
|
+
const testCounts = { passed: 0, failed: 0, flaky: 0 };
|
|
1689
|
+
const tracePathsMap = /* @__PURE__ */ new Map();
|
|
1690
|
+
const warningsMap = /* @__PURE__ */ new Map();
|
|
1691
|
+
const consoleMessagesMap = /* @__PURE__ */ new Map();
|
|
1692
|
+
const networkRequestsMap = /* @__PURE__ */ new Map();
|
|
1693
|
+
function resolveSessionName(ctx) {
|
|
1694
|
+
const { sessionName } = options;
|
|
1695
|
+
if (typeof sessionName === "function") return sessionName(ctx);
|
|
1696
|
+
if (typeof sessionName === "string") return sessionName;
|
|
1697
|
+
return `Playwright Test Session: ${ctx.directoryName}`;
|
|
705
1698
|
}
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1699
|
+
async function createSession(config, suite, log) {
|
|
1700
|
+
if (!api) return;
|
|
1701
|
+
try {
|
|
1702
|
+
const directoryName = getDirectoryName();
|
|
1703
|
+
const sessionName = resolveSessionName({ directoryName, config, suite });
|
|
1704
|
+
const repoInfo = getGitHubRepoInfo();
|
|
1705
|
+
log("\u{1F517} Creating test session", { name: sessionName, environment });
|
|
1706
|
+
testSession = await api.testSessions.create({
|
|
1707
|
+
name: sessionName,
|
|
1708
|
+
environment: process.env.NODE_ENV || "test",
|
|
1709
|
+
repoInfo,
|
|
1710
|
+
startedAt: startTime.getTime(),
|
|
1711
|
+
testResults: [{ name: directoryName }],
|
|
1712
|
+
provider: "PW_REPORTER"
|
|
1713
|
+
});
|
|
1714
|
+
log("\u2705 Session created", { id: testSession.testSessionId });
|
|
1715
|
+
} catch (err2) {
|
|
1716
|
+
console.error("[Checkly] Failed to create test session:", err2);
|
|
1717
|
+
}
|
|
709
1718
|
}
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
1719
|
+
function checkTraceAttachment(test, result) {
|
|
1720
|
+
const key = `${test.id}:${result.retry}`;
|
|
1721
|
+
const traceAttachment = result.attachments?.find((a) => a.name === "trace" || a.contentType === "application/zip");
|
|
1722
|
+
if (traceAttachment?.path) {
|
|
1723
|
+
tracePathsMap.set(key, traceAttachment.path);
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
const traceConfig = test.parent?.project()?.use?.trace;
|
|
1727
|
+
const traceMode = typeof traceConfig === "object" ? traceConfig.mode : traceConfig;
|
|
1728
|
+
if (!traceMode || traceMode === "off") return;
|
|
1729
|
+
const warnings = warningsMap.get(key) || [];
|
|
1730
|
+
warnings.push({ type: "trace-missing", message: `No trace found for trace mode "${traceMode}"` });
|
|
1731
|
+
warningsMap.set(key, warnings);
|
|
1732
|
+
}
|
|
1733
|
+
async function extractTraceData(key, tracePath) {
|
|
1734
|
+
const reader = new TraceReader(tracePath);
|
|
1735
|
+
if (!await reader.open()) return;
|
|
1736
|
+
const messages = await reader.extractEvents('"type":"console"', toConsoleMessage);
|
|
1737
|
+
if (messages.length > 0) consoleMessagesMap.set(key, messages);
|
|
1738
|
+
const requests = await reader.extractEvents('"type":"resource-snapshot"', toNetworkRequest);
|
|
1739
|
+
if (requests.length > 0) networkRequestsMap.set(key, requests);
|
|
1740
|
+
}
|
|
1741
|
+
async function extractDataFromTraces(log) {
|
|
1742
|
+
if (tracePathsMap.size === 0) return;
|
|
1743
|
+
log("\u{1F4E6} Extracting trace data", { traces: tracePathsMap.size });
|
|
1744
|
+
const extractions = Array.from(tracePathsMap.entries()).map(
|
|
1745
|
+
([key, tracePath]) => extractTraceData(key, tracePath).catch((err2) => {
|
|
1746
|
+
console.error(`[Checkly] Failed to extract trace data: ${err2}`);
|
|
1747
|
+
})
|
|
1748
|
+
);
|
|
1749
|
+
await Promise.all(extractions);
|
|
1750
|
+
}
|
|
1751
|
+
function buildChecklyExtensionData(key) {
|
|
1752
|
+
const warnings = warningsMap.get(key);
|
|
1753
|
+
const consoleMessages = consoleMessagesMap.get(key);
|
|
1754
|
+
const network = networkRequestsMap.get(key);
|
|
1755
|
+
if (!warnings?.length && !consoleMessages?.length && !network?.length) {
|
|
1756
|
+
return null;
|
|
1757
|
+
}
|
|
1758
|
+
return {
|
|
1759
|
+
...warnings?.length ? { warnings } : {},
|
|
1760
|
+
...consoleMessages?.length ? { console: consoleMessages } : {},
|
|
1761
|
+
...network?.length ? { network } : {}
|
|
741
1762
|
};
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
1763
|
+
}
|
|
1764
|
+
function injectDataIntoReport(report) {
|
|
1765
|
+
function processSuite(suite) {
|
|
1766
|
+
for (const spec of suite.specs) {
|
|
1767
|
+
for (const test of spec.tests) {
|
|
1768
|
+
for (const result of test.results) {
|
|
1769
|
+
const key = `${spec.id}:${result.retry}`;
|
|
1770
|
+
const checklyData = buildChecklyExtensionData(key);
|
|
1771
|
+
if (checklyData) {
|
|
1772
|
+
;
|
|
1773
|
+
result._checkly = checklyData;
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
suite.suites?.forEach(processSuite);
|
|
753
1779
|
}
|
|
1780
|
+
report.suites.forEach(processSuite);
|
|
754
1781
|
}
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1782
|
+
function calculateTiming(report) {
|
|
1783
|
+
const stats = report.stats;
|
|
1784
|
+
if (stats?.startTime && stats?.duration !== void 0) {
|
|
1785
|
+
const start = new Date(stats.startTime);
|
|
1786
|
+
const responseTime = Math.round(stats.duration);
|
|
1787
|
+
return {
|
|
1788
|
+
startedAt: start.toISOString(),
|
|
1789
|
+
stoppedAt: new Date(start.getTime() + responseTime).toISOString(),
|
|
1790
|
+
responseTime
|
|
1791
|
+
};
|
|
763
1792
|
}
|
|
764
|
-
|
|
765
|
-
|
|
1793
|
+
const now = Date.now();
|
|
1794
|
+
return {
|
|
1795
|
+
startedAt: startTime?.toISOString() ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1796
|
+
stoppedAt: new Date(now).toISOString(),
|
|
1797
|
+
responseTime: startTime ? Math.round(now - startTime.getTime()) : 0
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
async function uploadAssets(log, zipPath, zipSizeBytes) {
|
|
1801
|
+
if (!api || !testSession || zipSizeBytes === 0) return void 0;
|
|
1802
|
+
const firstResult = testSession.testResults[0];
|
|
1803
|
+
if (!firstResult) return void 0;
|
|
1804
|
+
log("\u{1F4E4} Uploading assets", { size: `${(zipSizeBytes / 1024).toFixed(1)}KB` });
|
|
1805
|
+
try {
|
|
1806
|
+
const assets = fs5.createReadStream(zipPath);
|
|
1807
|
+
const uploadResponse = await api.testSessions.uploadAsset(
|
|
1808
|
+
testSession.testSessionId,
|
|
1809
|
+
firstResult.testResultId,
|
|
1810
|
+
assets
|
|
1811
|
+
);
|
|
1812
|
+
log("\u2705 Assets uploaded", { assetId: uploadResponse.assetId });
|
|
1813
|
+
return uploadResponse.assetId;
|
|
1814
|
+
} catch (err2) {
|
|
1815
|
+
console.error("[Checkly] Asset upload failed:", err2);
|
|
1816
|
+
return void 0;
|
|
766
1817
|
}
|
|
767
|
-
return `Playwright Test Session: ${context.directoryName}`;
|
|
768
1818
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1819
|
+
async function uploadResults(log, report, zipPath, entries) {
|
|
1820
|
+
if (!api || !testSession || testSession.testResults.length === 0) return;
|
|
1821
|
+
try {
|
|
1822
|
+
const { failed, flaky } = testCounts;
|
|
1823
|
+
const overallStatus = failed > 0 ? "FAILED" : "PASSED";
|
|
1824
|
+
const isDegraded = failed === 0 && flaky > 0;
|
|
1825
|
+
const timing = calculateTiming(report);
|
|
1826
|
+
const zipSizeBytes = (await fs5.promises.stat(zipPath)).size;
|
|
1827
|
+
const assetId = await uploadAssets(log, zipPath, zipSizeBytes);
|
|
1828
|
+
const firstResult = testSession.testResults[0];
|
|
1829
|
+
log("\u{1F4DD} Updating test result", { status: overallStatus, isDegraded });
|
|
1830
|
+
await api.testSessions.updateResult(testSession.testSessionId, firstResult.testResultId, {
|
|
1831
|
+
status: overallStatus,
|
|
1832
|
+
assetEntries: assetId ? entries : void 0,
|
|
1833
|
+
isDegraded,
|
|
1834
|
+
...timing,
|
|
1835
|
+
metadata: { usageData: { s3PostTotalBytes: zipSizeBytes } }
|
|
1836
|
+
});
|
|
1837
|
+
} catch (err2) {
|
|
1838
|
+
console.error("[Checkly] Failed to upload results:", err2);
|
|
780
1839
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
1840
|
+
}
|
|
1841
|
+
return {
|
|
1842
|
+
name: "checkly-upload",
|
|
1843
|
+
onBegin: ({ config, suite, log }) => {
|
|
1844
|
+
startTime = /* @__PURE__ */ new Date();
|
|
1845
|
+
resolvedOutputDir = options.outputDir ?? config.projects[0]?.outputDir ?? "test-results";
|
|
1846
|
+
const zipPath = path4.join(resolvedOutputDir, "checkly-report.zip");
|
|
1847
|
+
assetCollector = new AssetCollector(resolvedOutputDir);
|
|
1848
|
+
zipper = new Zipper({ outputPath: zipPath });
|
|
1849
|
+
if (!canUpload) {
|
|
1850
|
+
if (!dryRun && (!apiKey || !accountId)) {
|
|
1851
|
+
log("\u26A0\uFE0F Skipping upload (missing API credentials)");
|
|
1852
|
+
}
|
|
789
1853
|
return;
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
1854
|
+
}
|
|
1855
|
+
api = createClient({
|
|
1856
|
+
apiKey,
|
|
1857
|
+
accountId,
|
|
1858
|
+
baseUrl,
|
|
1859
|
+
telemetry: {
|
|
1860
|
+
reporterVersion,
|
|
1861
|
+
playwrightVersion: config.version,
|
|
1862
|
+
ciProvider: ciInfo.ciProvider,
|
|
1863
|
+
ciEnvironment: ciInfo.environment,
|
|
1864
|
+
nodeVersion: process.version
|
|
801
1865
|
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1866
|
+
});
|
|
1867
|
+
sessionCreationPromise = createSession(config, suite, log);
|
|
1868
|
+
},
|
|
1869
|
+
onTestEnd: ({ test, result }) => {
|
|
1870
|
+
checkTraceAttachment(test, result);
|
|
1871
|
+
const outcome = test.outcome();
|
|
1872
|
+
const testIsComplete = result.retry === test.retries || outcome !== "unexpected";
|
|
1873
|
+
if (!testIsComplete) return;
|
|
1874
|
+
if (outcome === "flaky") {
|
|
1875
|
+
testCounts.flaky++;
|
|
1876
|
+
testCounts.passed++;
|
|
1877
|
+
} else if (result.status === "passed") {
|
|
1878
|
+
testCounts.passed++;
|
|
1879
|
+
} else if (result.status === "failed" || result.status === "timedOut") {
|
|
1880
|
+
testCounts.failed++;
|
|
1881
|
+
}
|
|
1882
|
+
},
|
|
1883
|
+
onEnd: async ({ report, log, addSummaryLine }) => {
|
|
1884
|
+
try {
|
|
1885
|
+
if (sessionCreationPromise) {
|
|
1886
|
+
await sessionCreationPromise;
|
|
813
1887
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
1888
|
+
await extractDataFromTraces(log);
|
|
1889
|
+
injectDataIntoReport(report);
|
|
1890
|
+
fs5.mkdirSync(resolvedOutputDir, { recursive: true });
|
|
1891
|
+
const tempReportPath = path4.join(resolvedOutputDir, `.checkly-report-${Date.now()}.json`);
|
|
1892
|
+
fs5.writeFileSync(tempReportPath, JSON.stringify(report, null, 2));
|
|
1893
|
+
const assets = await assetCollector.collectAssets(report);
|
|
1894
|
+
const zipResult = await zipper.createZip(tempReportPath, assets);
|
|
1895
|
+
log("\u{1F4E6} ZIP created", { path: zipResult.zipPath, size: `${(zipResult.size / 1024).toFixed(1)}KB` });
|
|
1896
|
+
if (api && testSession) {
|
|
1897
|
+
await uploadResults(log, report, zipResult.zipPath, zipResult.entries);
|
|
1898
|
+
if (!dryRun) {
|
|
1899
|
+
try {
|
|
1900
|
+
fs5.unlinkSync(zipResult.zipPath);
|
|
1901
|
+
} catch {
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
if (testSession.link) {
|
|
1905
|
+
addSummaryLine(`\u{1F517} Checkly Test Session: ${testSession.link}`);
|
|
1906
|
+
}
|
|
822
1907
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
warningType = "trace-retained-on-first-failure";
|
|
827
|
-
message = 'No trace retained because test passed. Trace mode is "retain-on-first-failure" which discards traces for passing tests.';
|
|
828
|
-
} else if (isRetry) {
|
|
829
|
-
warningType = "trace-retained-on-first-failure";
|
|
830
|
-
message = 'No trace for retries. Trace mode is "retain-on-first-failure" which only records the first run.';
|
|
831
|
-
} else {
|
|
832
|
-
warningType = "trace-missing";
|
|
833
|
-
message = 'Trace should exist but was not found. The test failed on first run with trace: "retain-on-first-failure".';
|
|
1908
|
+
try {
|
|
1909
|
+
fs5.unlinkSync(tempReportPath);
|
|
1910
|
+
} catch {
|
|
834
1911
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
message = 'Trace should exist but was not found. Trace mode is "on" which should always record traces.';
|
|
839
|
-
break;
|
|
840
|
-
default:
|
|
841
|
-
warningType = "trace-missing";
|
|
842
|
-
message = `No trace found. Trace mode "${traceMode}" may not be generating traces for this result.`;
|
|
1912
|
+
} catch (err2) {
|
|
1913
|
+
console.error("[Checkly] Error in onEnd:", err2);
|
|
1914
|
+
}
|
|
843
1915
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
// src/reporter.ts
|
|
1920
|
+
var import_node_fs = require("fs");
|
|
1921
|
+
var import_node_path = require("path");
|
|
1922
|
+
function getPackageVersion2() {
|
|
1923
|
+
try {
|
|
1924
|
+
const packageJson = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path.join)(__dirname, "..", "package.json"), "utf-8"));
|
|
1925
|
+
return packageJson.version;
|
|
1926
|
+
} catch {
|
|
1927
|
+
return "unknown";
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
var pluralRules = new Intl.PluralRules("en-US");
|
|
1931
|
+
var projectForms = {
|
|
1932
|
+
zero: "Project",
|
|
1933
|
+
one: "Project",
|
|
1934
|
+
two: "Projects",
|
|
1935
|
+
few: "Projects",
|
|
1936
|
+
many: "Projects",
|
|
1937
|
+
other: "Projects"
|
|
1938
|
+
};
|
|
1939
|
+
var BaseReporter = class {
|
|
1940
|
+
config;
|
|
1941
|
+
suite;
|
|
1942
|
+
startTime;
|
|
1943
|
+
options;
|
|
1944
|
+
verbose;
|
|
1945
|
+
globalErrors = [];
|
|
1946
|
+
tests = /* @__PURE__ */ new Map();
|
|
1947
|
+
expectedCount = 0;
|
|
1948
|
+
unexpectedCount = 0;
|
|
1949
|
+
flakyCount = 0;
|
|
1950
|
+
skippedCount = 0;
|
|
1951
|
+
_report = null;
|
|
1952
|
+
extensions = [];
|
|
1953
|
+
summaryLines = [];
|
|
1954
|
+
// Reconstructed projects for merge-reports scenarios
|
|
1955
|
+
reconstructedProjects = /* @__PURE__ */ new Map();
|
|
1956
|
+
constructor(options = {}) {
|
|
1957
|
+
this.options = options;
|
|
1958
|
+
this.verbose = options.verbose ?? process.env.CHECKLY_REPORTER_VERBOSE === "true";
|
|
1959
|
+
}
|
|
1960
|
+
use(extension) {
|
|
1961
|
+
this.extensions.push(extension);
|
|
1962
|
+
return this;
|
|
1963
|
+
}
|
|
1964
|
+
log(message, data) {
|
|
1965
|
+
if (!this.verbose) return;
|
|
1966
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().split("T")[1].slice(0, 12);
|
|
1967
|
+
const prefix = `[Checkly ${timestamp}]`;
|
|
1968
|
+
if (data && Object.keys(data).length > 0) {
|
|
1969
|
+
console.log(`${prefix} ${message}`, data);
|
|
1970
|
+
} else {
|
|
1971
|
+
console.log(`${prefix} ${message}`);
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
createExtensionLogger(extensionName) {
|
|
1975
|
+
return (message, data) => {
|
|
1976
|
+
this.log(`[${extensionName}] ${message}`, data);
|
|
1977
|
+
};
|
|
847
1978
|
}
|
|
848
|
-
/**
|
|
849
|
-
* Called once before running tests
|
|
850
|
-
* Creates test session in Checkly if credentials provided
|
|
851
|
-
*/
|
|
852
1979
|
onBegin(config, suite) {
|
|
1980
|
+
const deprecated = ["outputFile", "testResultsDir", "outputPath"];
|
|
1981
|
+
const opts = this.options;
|
|
1982
|
+
for (const key of deprecated) {
|
|
1983
|
+
if (key in opts && opts[key] !== void 0) {
|
|
1984
|
+
throw new Error(`[Checkly] "${key}" option is no longer supported. Use outputDir instead.`);
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
this.config = config;
|
|
1988
|
+
this.suite = suite;
|
|
853
1989
|
this.startTime = /* @__PURE__ */ new Date();
|
|
854
|
-
|
|
855
|
-
|
|
1990
|
+
this.tests.clear();
|
|
1991
|
+
this.globalErrors = [];
|
|
1992
|
+
this.expectedCount = 0;
|
|
1993
|
+
this.unexpectedCount = 0;
|
|
1994
|
+
this.flakyCount = 0;
|
|
1995
|
+
this.skippedCount = 0;
|
|
1996
|
+
this._report = null;
|
|
1997
|
+
this.reconstructedProjects.clear();
|
|
1998
|
+
this.reconstructProjectsIfNeeded();
|
|
1999
|
+
const testCount = this.countTests(suite);
|
|
2000
|
+
const projectNames = config.projects.length > 0 ? config.projects.map((p) => p.name).join(", ") : Array.from(this.reconstructedProjects.keys()).join(", ") || "default";
|
|
2001
|
+
this.log(`\u{1F3AC} Starting test run`, { tests: testCount, projects: projectNames, workers: config.workers });
|
|
2002
|
+
for (const ext of this.extensions) {
|
|
2003
|
+
ext.onBegin?.({ config, suite, log: this.createExtensionLogger(ext.name) });
|
|
856
2004
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
environment: process.env.NODE_ENV || "test",
|
|
872
|
-
repoInfo,
|
|
873
|
-
startedAt: this.startTime.getTime(),
|
|
874
|
-
// Required timestamp in milliseconds
|
|
875
|
-
testResults,
|
|
876
|
-
provider: "PW_REPORTER"
|
|
877
|
-
}).then((response) => {
|
|
878
|
-
this.testSession = response;
|
|
879
|
-
}).catch((error) => {
|
|
880
|
-
console.error("[Checkly Reporter] Failed to create test session:", error.message);
|
|
881
|
-
});
|
|
882
|
-
} catch (error) {
|
|
883
|
-
console.error("[Checkly Reporter] Error in onBegin:", error);
|
|
2005
|
+
}
|
|
2006
|
+
onTestBegin(test, result) {
|
|
2007
|
+
for (const ext of this.extensions) {
|
|
2008
|
+
ext.onTestBegin?.({ test, result, log: this.createExtensionLogger(ext.name) });
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
onStepBegin(test, result, step) {
|
|
2012
|
+
for (const ext of this.extensions) {
|
|
2013
|
+
ext.onStepBegin?.({ test, result, step, log: this.createExtensionLogger(ext.name) });
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
onStepEnd(test, result, step) {
|
|
2017
|
+
for (const ext of this.extensions) {
|
|
2018
|
+
ext.onStepEnd?.({ test, result, step, log: this.createExtensionLogger(ext.name) });
|
|
884
2019
|
}
|
|
885
2020
|
}
|
|
886
|
-
/**
|
|
887
|
-
* Called for each test when it completes
|
|
888
|
-
* Captures steps and warnings, tracks test results for final status calculation
|
|
889
|
-
*/
|
|
890
2021
|
onTestEnd(test, result) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
2022
|
+
const testId = test.id;
|
|
2023
|
+
let testData = this.tests.get(testId);
|
|
2024
|
+
if (!testData) {
|
|
2025
|
+
testData = { testCase: test, results: [] };
|
|
2026
|
+
this.tests.set(testId, testData);
|
|
2027
|
+
}
|
|
2028
|
+
testData.results.push(result);
|
|
2029
|
+
for (const ext of this.extensions) {
|
|
2030
|
+
ext.onTestEnd?.({ test, result, log: this.createExtensionLogger(ext.name) });
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
onStdOut(chunk, test, result) {
|
|
2034
|
+
for (const ext of this.extensions) {
|
|
2035
|
+
ext.onStdOut?.({ chunk, test, result, log: this.createExtensionLogger(ext.name) });
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
onStdErr(chunk, test, result) {
|
|
2039
|
+
for (const ext of this.extensions) {
|
|
2040
|
+
ext.onStdErr?.({ chunk, test, result, log: this.createExtensionLogger(ext.name) });
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
onError(error) {
|
|
2044
|
+
this.globalErrors.push(error);
|
|
2045
|
+
this.log(`\u{1F4A5} Global error`, { message: error.message?.slice(0, 100) });
|
|
2046
|
+
for (const ext of this.extensions) {
|
|
2047
|
+
ext.onError?.({ error, log: this.createExtensionLogger(ext.name) });
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
async onEnd(result) {
|
|
2051
|
+
for (const testData of this.tests.values()) {
|
|
2052
|
+
switch (testData.testCase.outcome()) {
|
|
2053
|
+
case "expected":
|
|
2054
|
+
this.expectedCount++;
|
|
2055
|
+
break;
|
|
2056
|
+
case "unexpected":
|
|
2057
|
+
this.unexpectedCount++;
|
|
2058
|
+
break;
|
|
2059
|
+
case "flaky":
|
|
2060
|
+
this.flakyCount++;
|
|
2061
|
+
break;
|
|
2062
|
+
case "skipped":
|
|
2063
|
+
this.skippedCount++;
|
|
2064
|
+
break;
|
|
896
2065
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
2066
|
+
}
|
|
2067
|
+
this._report = this.buildReport(result);
|
|
2068
|
+
this.log(`\u{1F3C1} Test run finished`, {
|
|
2069
|
+
status: result.status,
|
|
2070
|
+
duration: `${result.duration}ms`,
|
|
2071
|
+
passed: this.expectedCount,
|
|
2072
|
+
failed: this.unexpectedCount,
|
|
2073
|
+
flaky: this.flakyCount,
|
|
2074
|
+
skipped: this.skippedCount
|
|
2075
|
+
});
|
|
2076
|
+
const outputDir = this.options.outputDir;
|
|
2077
|
+
if (outputDir) {
|
|
2078
|
+
const fs6 = await import("fs");
|
|
2079
|
+
fs6.mkdirSync(outputDir, { recursive: true });
|
|
2080
|
+
const outputPath = `${outputDir}/checkly-report.json`;
|
|
2081
|
+
fs6.writeFileSync(outputPath, JSON.stringify(this._report, null, 2));
|
|
2082
|
+
this.log(`\u{1F4C4} Report saved`, { path: outputPath });
|
|
2083
|
+
}
|
|
2084
|
+
for (const ext of this.extensions) {
|
|
2085
|
+
await ext.onEnd?.({
|
|
2086
|
+
result,
|
|
2087
|
+
report: this._report,
|
|
2088
|
+
log: this.createExtensionLogger(ext.name),
|
|
2089
|
+
addSummaryLine: (line) => this.summaryLines.push(line)
|
|
2090
|
+
});
|
|
2091
|
+
}
|
|
2092
|
+
this.printSummary();
|
|
2093
|
+
}
|
|
2094
|
+
async onExit() {
|
|
2095
|
+
this.log(`\u{1F44B} Reporter exiting`);
|
|
2096
|
+
for (const ext of this.extensions) {
|
|
2097
|
+
await ext.onExit?.({ log: this.createExtensionLogger(ext.name) });
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
printsToStdio() {
|
|
2101
|
+
return false;
|
|
2102
|
+
}
|
|
2103
|
+
getReport() {
|
|
2104
|
+
if (this._report) return this._report;
|
|
2105
|
+
return this.buildReport({
|
|
2106
|
+
status: "passed",
|
|
2107
|
+
startTime: this.startTime,
|
|
2108
|
+
duration: Date.now() - this.startTime.getTime()
|
|
2109
|
+
});
|
|
2110
|
+
}
|
|
2111
|
+
buildReport(fullResult) {
|
|
2112
|
+
return {
|
|
2113
|
+
config: this.serializeConfig(),
|
|
2114
|
+
suites: this.serializeSuites(),
|
|
2115
|
+
errors: this.globalErrors.map((e) => this.serializeError(e, true)),
|
|
2116
|
+
stats: {
|
|
2117
|
+
startTime: this.startTime.toISOString(),
|
|
2118
|
+
duration: fullResult.duration,
|
|
2119
|
+
expected: this.expectedCount,
|
|
2120
|
+
unexpected: this.unexpectedCount,
|
|
2121
|
+
flaky: this.flakyCount,
|
|
2122
|
+
skipped: this.skippedCount
|
|
901
2123
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
reconstructProjectsIfNeeded() {
|
|
2127
|
+
if (this.config.projects.length > 0) {
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
this.log("\u{1F504} Detected merge-reports scenario (empty config.projects), reconstructing projects");
|
|
2131
|
+
for (const projectSuite of this.suite.suites) {
|
|
2132
|
+
const project = projectSuite.project();
|
|
2133
|
+
if (project) {
|
|
2134
|
+
const name = project.name || "default";
|
|
2135
|
+
if (!this.reconstructedProjects.has(name)) {
|
|
2136
|
+
this.reconstructedProjects.set(name, {
|
|
2137
|
+
id: name,
|
|
2138
|
+
name,
|
|
2139
|
+
testDir: project.testDir,
|
|
2140
|
+
outputDir: project.outputDir,
|
|
2141
|
+
timeout: project.timeout,
|
|
2142
|
+
retries: project.retries,
|
|
2143
|
+
repeatEach: project.repeatEach,
|
|
2144
|
+
metadata: project.metadata ?? {},
|
|
2145
|
+
testMatch: Array.isArray(project.testMatch) ? project.testMatch.map(String) : [String(project.testMatch)],
|
|
2146
|
+
testIgnore: Array.isArray(project.testIgnore) ? project.testIgnore.map(String) : [String(project.testIgnore)]
|
|
2147
|
+
});
|
|
911
2148
|
}
|
|
912
2149
|
}
|
|
913
|
-
} catch (error) {
|
|
914
|
-
console.error("[Checkly Reporter] Error in onTestEnd:", error);
|
|
915
2150
|
}
|
|
2151
|
+
if (this.reconstructedProjects.size === 0) {
|
|
2152
|
+
this.collectProjectsFromTests(this.suite);
|
|
2153
|
+
}
|
|
2154
|
+
this.log("\u{1F504} Reconstructed projects", {
|
|
2155
|
+
count: this.reconstructedProjects.size,
|
|
2156
|
+
names: Array.from(this.reconstructedProjects.keys())
|
|
2157
|
+
});
|
|
916
2158
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
2159
|
+
collectProjectsFromTests(suite) {
|
|
2160
|
+
for (const test of suite.allTests()) {
|
|
2161
|
+
const project = test.parent.project();
|
|
2162
|
+
const projectName = project?.name || "default";
|
|
2163
|
+
if (!this.reconstructedProjects.has(projectName)) {
|
|
2164
|
+
if (project) {
|
|
2165
|
+
this.reconstructedProjects.set(projectName, {
|
|
2166
|
+
id: projectName,
|
|
2167
|
+
name: projectName,
|
|
2168
|
+
testDir: project.testDir,
|
|
2169
|
+
outputDir: project.outputDir,
|
|
2170
|
+
timeout: project.timeout,
|
|
2171
|
+
retries: project.retries,
|
|
2172
|
+
repeatEach: project.repeatEach,
|
|
2173
|
+
metadata: project.metadata ?? {},
|
|
2174
|
+
testMatch: Array.isArray(project.testMatch) ? project.testMatch.map(String) : [String(project.testMatch)],
|
|
2175
|
+
testIgnore: Array.isArray(project.testIgnore) ? project.testIgnore.map(String) : [String(project.testIgnore)]
|
|
2176
|
+
});
|
|
2177
|
+
} else {
|
|
2178
|
+
this.reconstructedProjects.set(projectName, {
|
|
2179
|
+
id: projectName,
|
|
2180
|
+
name: projectName,
|
|
2181
|
+
testDir: "",
|
|
2182
|
+
outputDir: "",
|
|
2183
|
+
timeout: 0,
|
|
2184
|
+
retries: 0,
|
|
2185
|
+
repeatEach: 1,
|
|
2186
|
+
metadata: {},
|
|
2187
|
+
testMatch: [],
|
|
2188
|
+
testIgnore: []
|
|
2189
|
+
});
|
|
946
2190
|
}
|
|
947
2191
|
}
|
|
948
|
-
if (this.testResults && this.testSession?.link) {
|
|
949
|
-
this.printSummary(report, this.testSession);
|
|
950
|
-
}
|
|
951
|
-
} catch (error) {
|
|
952
|
-
console.error("[Checkly Reporter] ERROR creating report:", error);
|
|
953
2192
|
}
|
|
954
2193
|
}
|
|
955
|
-
|
|
956
|
-
const
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
2194
|
+
serializeConfig() {
|
|
2195
|
+
const c = this.config;
|
|
2196
|
+
const projects = c.projects.length > 0 ? c.projects.map((p) => this.serializeProject(p)) : Array.from(this.reconstructedProjects.values());
|
|
2197
|
+
return {
|
|
2198
|
+
rootDir: c.rootDir,
|
|
2199
|
+
configFile: c.configFile ?? void 0,
|
|
2200
|
+
version: c.version,
|
|
2201
|
+
workers: c.workers,
|
|
2202
|
+
fullyParallel: c.fullyParallel,
|
|
2203
|
+
forbidOnly: c.forbidOnly,
|
|
2204
|
+
globalTimeout: c.globalTimeout,
|
|
2205
|
+
maxFailures: c.maxFailures,
|
|
2206
|
+
metadata: c.metadata ?? {},
|
|
2207
|
+
projects,
|
|
2208
|
+
shard: c.shard ?? null,
|
|
2209
|
+
tags: c.tags ?? [],
|
|
2210
|
+
updateSourceMethod: c.updateSourceMethod,
|
|
2211
|
+
preserveOutput: c.preserveOutput,
|
|
2212
|
+
quiet: c.quiet,
|
|
2213
|
+
reportSlowTests: c.reportSlowTests ?? null,
|
|
2214
|
+
webServer: c.webServer ?? null,
|
|
2215
|
+
globalSetup: c.globalSetup ?? null,
|
|
2216
|
+
globalTeardown: c.globalTeardown ?? null,
|
|
2217
|
+
grep: c.grep,
|
|
2218
|
+
grepInvert: c.grepInvert,
|
|
2219
|
+
reporter: c.reporter,
|
|
2220
|
+
updateSnapshots: c.updateSnapshots
|
|
2221
|
+
};
|
|
963
2222
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
2223
|
+
serializeProject(p) {
|
|
2224
|
+
return {
|
|
2225
|
+
id: p.name,
|
|
2226
|
+
name: p.name,
|
|
2227
|
+
testDir: p.testDir,
|
|
2228
|
+
outputDir: p.outputDir,
|
|
2229
|
+
timeout: p.timeout,
|
|
2230
|
+
retries: p.retries,
|
|
2231
|
+
repeatEach: p.repeatEach,
|
|
2232
|
+
metadata: p.metadata ?? {},
|
|
2233
|
+
testMatch: Array.isArray(p.testMatch) ? p.testMatch.map(String) : [String(p.testMatch)],
|
|
2234
|
+
testIgnore: Array.isArray(p.testIgnore) ? p.testIgnore.map(String) : [String(p.testIgnore)]
|
|
2235
|
+
};
|
|
2236
|
+
}
|
|
2237
|
+
serializeSuites() {
|
|
2238
|
+
const fileSuites = /* @__PURE__ */ new Map();
|
|
2239
|
+
for (const projectSuite of this.suite.suites) {
|
|
2240
|
+
for (const fileSuite of projectSuite.suites) {
|
|
2241
|
+
const file = fileSuite.location?.file;
|
|
2242
|
+
if (!file) continue;
|
|
2243
|
+
const fileName = this.getFileName(file);
|
|
2244
|
+
const serialized = this.serializeSuite(fileSuite, fileName);
|
|
2245
|
+
if (!serialized) continue;
|
|
2246
|
+
const existing = fileSuites.get(file);
|
|
2247
|
+
if (existing) {
|
|
2248
|
+
this.mergeSuites(existing, serialized);
|
|
2249
|
+
} else {
|
|
2250
|
+
fileSuites.set(file, serialized);
|
|
988
2251
|
}
|
|
989
2252
|
}
|
|
990
|
-
};
|
|
991
|
-
for (const suite of report.suites) {
|
|
992
|
-
processSuite(suite);
|
|
993
2253
|
}
|
|
994
|
-
|
|
2254
|
+
return Array.from(fileSuites.values());
|
|
995
2255
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
if (testAny.projectName && !testAny.projectId) {
|
|
1011
|
-
testAny.projectId = testAny.projectName;
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
2256
|
+
serializeSuite(suite, fileName) {
|
|
2257
|
+
const allTests = suite.allTests();
|
|
2258
|
+
if (allTests.length === 0) return null;
|
|
2259
|
+
const childSuites = [];
|
|
2260
|
+
for (const child of suite.suites) {
|
|
2261
|
+
const serialized = this.serializeSuite(child, fileName);
|
|
2262
|
+
if (serialized) childSuites.push(serialized);
|
|
2263
|
+
}
|
|
2264
|
+
const specs = [];
|
|
2265
|
+
for (const test of suite.tests) {
|
|
2266
|
+
const testData = this.tests.get(test.id);
|
|
2267
|
+
if (testData) {
|
|
2268
|
+
specs.push(this.serializeSpec(testData));
|
|
1014
2269
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
2270
|
+
}
|
|
2271
|
+
return {
|
|
2272
|
+
title: suite.title || fileName,
|
|
2273
|
+
file: fileName,
|
|
2274
|
+
line: suite.location?.line ?? 0,
|
|
2275
|
+
column: suite.location?.column ?? 0,
|
|
2276
|
+
specs,
|
|
2277
|
+
suites: childSuites.length ? childSuites : void 0
|
|
2278
|
+
};
|
|
2279
|
+
}
|
|
2280
|
+
mergeSuites(to, from) {
|
|
2281
|
+
for (const fromSuite of from.suites || []) {
|
|
2282
|
+
const toSuite = to.suites?.find(
|
|
2283
|
+
(s) => s.title === fromSuite.title && s.line === fromSuite.line && s.column === fromSuite.column
|
|
2284
|
+
);
|
|
2285
|
+
if (toSuite) {
|
|
2286
|
+
this.mergeSuites(toSuite, fromSuite);
|
|
2287
|
+
} else {
|
|
2288
|
+
to.suites = to.suites ?? [];
|
|
2289
|
+
to.suites.push(fromSuite);
|
|
1019
2290
|
}
|
|
2291
|
+
}
|
|
2292
|
+
to.specs.push(...from.specs);
|
|
2293
|
+
}
|
|
2294
|
+
serializeSpec(data) {
|
|
2295
|
+
const { testCase } = data;
|
|
2296
|
+
const outcome = testCase.outcome();
|
|
2297
|
+
return {
|
|
2298
|
+
id: testCase.id,
|
|
2299
|
+
title: testCase.title,
|
|
2300
|
+
file: this.getFileName(testCase.location.file),
|
|
2301
|
+
line: testCase.location.line,
|
|
2302
|
+
column: testCase.location.column,
|
|
2303
|
+
tags: this.extractTags(testCase),
|
|
2304
|
+
ok: outcome === "expected" || outcome === "flaky" || outcome === "skipped",
|
|
2305
|
+
tests: [this.serializeTest(data)]
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
extractTags(testCase) {
|
|
2309
|
+
const runtimeTags = testCase.tags;
|
|
2310
|
+
if (runtimeTags && runtimeTags.length > 0) {
|
|
2311
|
+
return runtimeTags.map((t) => t.replace(/^@/, ""));
|
|
2312
|
+
}
|
|
2313
|
+
const titleTags = testCase.title.match(/@[\w-]+/g);
|
|
2314
|
+
return titleTags?.map((t) => t.replace(/^@/, "")) ?? [];
|
|
2315
|
+
}
|
|
2316
|
+
serializeTest(data) {
|
|
2317
|
+
const { testCase, results } = data;
|
|
2318
|
+
const projectName = this.getProjectName(testCase);
|
|
2319
|
+
return {
|
|
2320
|
+
projectId: projectName,
|
|
2321
|
+
projectName,
|
|
2322
|
+
timeout: testCase.timeout,
|
|
2323
|
+
expectedStatus: testCase.expectedStatus,
|
|
2324
|
+
annotations: this.serializeAnnotations(testCase.annotations),
|
|
2325
|
+
results: results.map((r) => this.serializeTestResult(r)),
|
|
2326
|
+
status: this.mapOutcome(testCase.outcome())
|
|
1020
2327
|
};
|
|
1021
|
-
|
|
1022
|
-
|
|
2328
|
+
}
|
|
2329
|
+
getProjectName(testCase) {
|
|
2330
|
+
const project = testCase.parent.project();
|
|
2331
|
+
if (project && typeof project.name === "string") {
|
|
2332
|
+
return project.name;
|
|
1023
2333
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
name
|
|
1029
|
-
}
|
|
2334
|
+
let current = testCase.parent;
|
|
2335
|
+
while (current) {
|
|
2336
|
+
const suiteProject = current.project();
|
|
2337
|
+
if (suiteProject && typeof suiteProject.name === "string") {
|
|
2338
|
+
return suiteProject.name;
|
|
2339
|
+
}
|
|
2340
|
+
current = current.parent;
|
|
1030
2341
|
}
|
|
2342
|
+
return "default";
|
|
1031
2343
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
2344
|
+
serializeTestResult(r) {
|
|
2345
|
+
return {
|
|
2346
|
+
workerIndex: r.workerIndex,
|
|
2347
|
+
parallelIndex: r.parallelIndex ?? 0,
|
|
2348
|
+
status: r.status,
|
|
2349
|
+
duration: r.duration,
|
|
2350
|
+
startTime: r.startTime.toISOString(),
|
|
2351
|
+
retry: r.retry,
|
|
2352
|
+
errors: r.errors.map((e) => this.serializeError(e, true)),
|
|
2353
|
+
error: r.error ? this.serializeError(r.error, false) : void 0,
|
|
2354
|
+
errorLocation: r.error?.location,
|
|
2355
|
+
stdout: r.stdout.map(
|
|
2356
|
+
(s) => typeof s === "string" ? { text: s } : Buffer.isBuffer(s) ? { buffer: s.toString("base64") } : s
|
|
2357
|
+
),
|
|
2358
|
+
stderr: r.stderr.map(
|
|
2359
|
+
(s) => typeof s === "string" ? { text: s } : Buffer.isBuffer(s) ? { buffer: s.toString("base64") } : s
|
|
2360
|
+
),
|
|
2361
|
+
attachments: r.attachments.map((a) => ({
|
|
2362
|
+
name: a.name,
|
|
2363
|
+
contentType: a.contentType,
|
|
2364
|
+
path: a.path,
|
|
2365
|
+
body: a.body ? a.body.toString("base64") : void 0
|
|
2366
|
+
})),
|
|
2367
|
+
steps: r.steps.map((s) => this.serializeStep(s)),
|
|
2368
|
+
annotations: this.serializeAnnotations(
|
|
2369
|
+
r.annotations ?? []
|
|
2370
|
+
)
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
serializeStep(step) {
|
|
2374
|
+
return {
|
|
2375
|
+
title: step.title,
|
|
2376
|
+
duration: step.duration,
|
|
2377
|
+
error: step.error ? this.serializeError(step.error, false) : void 0,
|
|
2378
|
+
steps: step.steps?.map((s) => this.serializeStep(s))
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2381
|
+
serializeError(error, includeContext) {
|
|
2382
|
+
if (error.value !== void 0) {
|
|
2383
|
+
return { message: error.value, value: error.value };
|
|
1038
2384
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const assets = fs3.createReadStream(zipPath);
|
|
1052
|
-
const uploadResponse = await this.testResults.uploadTestResultAsset(
|
|
1053
|
-
this.testSession.testSessionId,
|
|
1054
|
-
firstResult.testResultId,
|
|
1055
|
-
assets
|
|
1056
|
-
);
|
|
1057
|
-
assetId = uploadResponse.assetId;
|
|
1058
|
-
} catch (error) {
|
|
1059
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1060
|
-
console.error("[Checkly Reporter] Asset upload failed:", errorMessage);
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
await this.testResults.updateTestResult(this.testSession.testSessionId, firstResult.testResultId, {
|
|
1064
|
-
status: overallStatus,
|
|
1065
|
-
assetEntries: assetId ? entries : void 0,
|
|
1066
|
-
isDegraded,
|
|
1067
|
-
startedAt: this.startTime?.toISOString(),
|
|
1068
|
-
stoppedAt: endTime.toISOString(),
|
|
1069
|
-
responseTime,
|
|
1070
|
-
metadata: {
|
|
1071
|
-
usageData: {
|
|
1072
|
-
s3PostTotalBytes: zipSizeBytes
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
});
|
|
2385
|
+
let msg = error.message ?? "Unknown error";
|
|
2386
|
+
if (includeContext && !/^(\w+Error|Error):/.test(msg)) {
|
|
2387
|
+
msg = "Error: " + msg;
|
|
2388
|
+
}
|
|
2389
|
+
if (includeContext) {
|
|
2390
|
+
if (error.snippet) msg += "\n\n" + error.snippet;
|
|
2391
|
+
if (error.stack) {
|
|
2392
|
+
const frames = error.stack.split("\n").filter((l) => l.trim().startsWith("at "));
|
|
2393
|
+
if (frames.length) msg += "\n" + frames.join("\n");
|
|
2394
|
+
} else if (error.location) {
|
|
2395
|
+
msg += `
|
|
2396
|
+
at ${error.location.file}:${error.location.line}:${error.location.column}`;
|
|
1076
2397
|
}
|
|
1077
|
-
} catch (error) {
|
|
1078
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1079
|
-
console.error("[Checkly Reporter] Failed to upload results:", errorMessage);
|
|
1080
2398
|
}
|
|
2399
|
+
return {
|
|
2400
|
+
message: msg,
|
|
2401
|
+
location: error.location,
|
|
2402
|
+
stack: error.stack,
|
|
2403
|
+
snippet: error.snippet
|
|
2404
|
+
};
|
|
1081
2405
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
2406
|
+
serializeAnnotations(annotations) {
|
|
2407
|
+
return annotations.map((a) => ({ type: a.type, description: a.description, location: a.location }));
|
|
2408
|
+
}
|
|
2409
|
+
countTests(suite) {
|
|
2410
|
+
let count = suite.tests?.length ?? 0;
|
|
2411
|
+
for (const child of suite.suites ?? []) {
|
|
2412
|
+
count += this.countTests(child);
|
|
2413
|
+
}
|
|
2414
|
+
return count;
|
|
2415
|
+
}
|
|
2416
|
+
getFileName(filePath) {
|
|
2417
|
+
return filePath.split("/").pop() ?? filePath;
|
|
2418
|
+
}
|
|
2419
|
+
mapOutcome(outcome) {
|
|
2420
|
+
if (outcome === "expected" || outcome === "unexpected" || outcome === "flaky" || outcome === "skipped") {
|
|
2421
|
+
return outcome;
|
|
2422
|
+
}
|
|
2423
|
+
return "unexpected";
|
|
2424
|
+
}
|
|
2425
|
+
printSummary() {
|
|
2426
|
+
const pkgVersion = getPackageVersion2();
|
|
2427
|
+
const playwrightVersion = this.config.version;
|
|
2428
|
+
const projectNames = this.config.projects.length > 0 ? this.config.projects.map((p) => p.name).join(", ") : Array.from(this.reconstructedProjects.keys()).join(", ") || "default";
|
|
2429
|
+
const projectCount = this.config.projects.length > 0 ? this.config.projects.length : this.reconstructedProjects.size || 1;
|
|
2430
|
+
const rule = pluralRules.select(projectCount);
|
|
2431
|
+
console.log("\n======================================================\n");
|
|
2432
|
+
console.log(`\u{1F99D} Checkly reporter: ${pkgVersion}`);
|
|
2433
|
+
console.log(`\u{1F3AD} Playwright: ${playwrightVersion}`);
|
|
2434
|
+
console.log(`\u{1F4D4} ${projectForms[rule]}: ${projectNames}`);
|
|
2435
|
+
for (const line of this.summaryLines) {
|
|
2436
|
+
console.log(line);
|
|
2437
|
+
}
|
|
2438
|
+
console.log("\n======================================================");
|
|
1087
2439
|
}
|
|
1088
2440
|
};
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
2441
|
+
|
|
2442
|
+
// src/index.ts
|
|
2443
|
+
var ChecklyReporter = class extends BaseReporter {
|
|
2444
|
+
constructor(options = {}) {
|
|
2445
|
+
super(options);
|
|
2446
|
+
this.use(checklyUpload(options));
|
|
2447
|
+
}
|
|
1094
2448
|
};
|
|
2449
|
+
var index_default = ChecklyReporter;
|
|
2450
|
+
function createChecklyReporter(options = {}) {
|
|
2451
|
+
return ["@checkly/playwright-reporter", options];
|
|
2452
|
+
}
|
|
2453
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2454
|
+
0 && (module.exports = {
|
|
2455
|
+
createChecklyReporter
|
|
2456
|
+
});
|