@testdino/playwright 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +58 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +58 -7
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +274 -15
- package/dist/index.d.ts +274 -15
- package/dist/index.js +617 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +610 -65
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -2
package/dist/cli/index.js
CHANGED
|
@@ -314,6 +314,41 @@ var ConfigDetector = class {
|
|
|
314
314
|
if ("debug" in options && typeof options.debug === "boolean") {
|
|
315
315
|
config.debug = options.debug;
|
|
316
316
|
}
|
|
317
|
+
if ("coverage" in options && typeof options.coverage === "object" && options.coverage !== null) {
|
|
318
|
+
config.coverage = this.extractCoverageConfig(options.coverage);
|
|
319
|
+
}
|
|
320
|
+
return config;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Extract and validate CoverageConfig from reporter options
|
|
324
|
+
*/
|
|
325
|
+
extractCoverageConfig(raw) {
|
|
326
|
+
const config = {
|
|
327
|
+
enabled: typeof raw.enabled === "boolean" ? raw.enabled : false
|
|
328
|
+
};
|
|
329
|
+
if (Array.isArray(raw.projects)) {
|
|
330
|
+
config.projects = raw.projects.filter((p) => typeof p === "string");
|
|
331
|
+
}
|
|
332
|
+
if (typeof raw.localReport === "boolean") {
|
|
333
|
+
config.localReport = raw.localReport;
|
|
334
|
+
}
|
|
335
|
+
if (typeof raw.localReportDir === "string") {
|
|
336
|
+
config.localReportDir = raw.localReportDir;
|
|
337
|
+
}
|
|
338
|
+
if (Array.isArray(raw.include)) {
|
|
339
|
+
config.include = raw.include.filter((p) => typeof p === "string");
|
|
340
|
+
}
|
|
341
|
+
if (Array.isArray(raw.exclude)) {
|
|
342
|
+
config.exclude = raw.exclude.filter((p) => typeof p === "string");
|
|
343
|
+
}
|
|
344
|
+
if (typeof raw.thresholds === "object" && raw.thresholds !== null) {
|
|
345
|
+
const t = raw.thresholds;
|
|
346
|
+
config.thresholds = {};
|
|
347
|
+
if (typeof t.statements === "number") config.thresholds.statements = t.statements;
|
|
348
|
+
if (typeof t.branches === "number") config.thresholds.branches = t.branches;
|
|
349
|
+
if (typeof t.functions === "number") config.thresholds.functions = t.functions;
|
|
350
|
+
if (typeof t.lines === "number") config.thresholds.lines = t.lines;
|
|
351
|
+
}
|
|
317
352
|
return config;
|
|
318
353
|
}
|
|
319
354
|
};
|
|
@@ -334,16 +369,30 @@ var ConfigMerger = class _ConfigMerger {
|
|
|
334
369
|
const ciRunId = this.selectValue(cliOptions.ciRunId, testdinoConfig.ciRunId, playwrightConfig.ciRunId) || this.generateCiRunId();
|
|
335
370
|
const debug = this.selectValue(cliOptions.debug, testdinoConfig.debug, playwrightConfig.debug, env.debug) ?? false;
|
|
336
371
|
const artifacts = cliOptions.noArtifacts === true ? false : this.selectValue(testdinoConfig.artifacts, playwrightConfig.artifacts) ?? true;
|
|
372
|
+
const coverage = this.mergeCoverageConfig(cliOptions.coverage, testdinoConfig.coverage, playwrightConfig.coverage);
|
|
337
373
|
const mergedConfig = {
|
|
338
374
|
token,
|
|
339
375
|
serverUrl,
|
|
340
376
|
ciRunId,
|
|
341
377
|
debug,
|
|
342
|
-
artifacts
|
|
378
|
+
artifacts,
|
|
379
|
+
...coverage ? { coverage } : {}
|
|
343
380
|
};
|
|
344
381
|
this.validate(mergedConfig);
|
|
345
382
|
return mergedConfig;
|
|
346
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Merge coverage configuration from CLI flag and config files.
|
|
386
|
+
* CLI --coverage only toggles enabled; other fields come from config files.
|
|
387
|
+
*/
|
|
388
|
+
mergeCoverageConfig(cliCoverage, testdinoCoverage, playwrightCoverage) {
|
|
389
|
+
const baseConfig = testdinoCoverage ?? playwrightCoverage;
|
|
390
|
+
if (!baseConfig && cliCoverage === void 0) return void 0;
|
|
391
|
+
if (cliCoverage !== void 0) {
|
|
392
|
+
return { ...baseConfig || { enabled: false }, enabled: cliCoverage };
|
|
393
|
+
}
|
|
394
|
+
return baseConfig;
|
|
395
|
+
}
|
|
347
396
|
/**
|
|
348
397
|
* Select first non-undefined value from arguments
|
|
349
398
|
*/
|
|
@@ -399,7 +448,7 @@ var ConfigMerger = class _ConfigMerger {
|
|
|
399
448
|
};
|
|
400
449
|
|
|
401
450
|
// src/cli/arg-filter.ts
|
|
402
|
-
var TESTDINO_FLAGS = ["--token", "-t", "--ci-run-id", "--server-url", "--debug", "--no-artifacts"];
|
|
451
|
+
var TESTDINO_FLAGS = ["--token", "-t", "--ci-run-id", "--server-url", "--debug", "--no-artifacts", "--coverage"];
|
|
403
452
|
var FLAGS_WITH_VALUES = ["--token", "-t", "--ci-run-id", "--server-url"];
|
|
404
453
|
var ArgFilter = class {
|
|
405
454
|
/**
|
|
@@ -668,13 +717,15 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
668
717
|
};
|
|
669
718
|
process.on("exit", this.exitHandler);
|
|
670
719
|
this.sigintHandler = () => {
|
|
671
|
-
this.
|
|
672
|
-
|
|
720
|
+
if (this.sigintHandler) {
|
|
721
|
+
process.removeListener("SIGINT", this.sigintHandler);
|
|
722
|
+
}
|
|
673
723
|
};
|
|
674
724
|
process.on("SIGINT", this.sigintHandler);
|
|
675
725
|
this.sigtermHandler = () => {
|
|
676
|
-
this.
|
|
677
|
-
|
|
726
|
+
if (this.sigtermHandler) {
|
|
727
|
+
process.removeListener("SIGTERM", this.sigtermHandler);
|
|
728
|
+
}
|
|
678
729
|
};
|
|
679
730
|
process.on("SIGTERM", this.sigtermHandler);
|
|
680
731
|
this.uncaughtExceptionHandler = (error) => {
|
|
@@ -839,7 +890,7 @@ function getVersion() {
|
|
|
839
890
|
var logger2 = new Logger(isDebugEnabled());
|
|
840
891
|
function buildProgram() {
|
|
841
892
|
const program = new commander.Command().name("tdpw").description("Run Playwright tests with TestDino reporting").version(getVersion(), "-v, --version", "Output the current version").helpOption("-h, --help", "Display help for command");
|
|
842
|
-
program.command("test").description("Run Playwright tests with TestDino reporter").option("-t, --token <token>", "TestDino authentication token").option("--ci-run-id <id>", "CI run ID for grouping test runs").option("--server-url <url>", "TestDino server URL").option("--debug", "Enable debug logging").option("--no-artifacts", "Disable artifact uploads (screenshots, videos, traces)").allowUnknownOption().allowExcessArguments().action(async (options, command) => {
|
|
893
|
+
program.command("test").description("Run Playwright tests with TestDino reporter").option("-t, --token <token>", "TestDino authentication token").option("--ci-run-id <id>", "CI run ID for grouping test runs").option("--server-url <url>", "TestDino server URL").option("--debug", "Enable debug logging").option("--no-artifacts", "Disable artifact uploads (screenshots, videos, traces)").option("--coverage", "Enable code coverage collection").allowUnknownOption().allowExcessArguments().action(async (options, command) => {
|
|
843
894
|
if (options.debug) {
|
|
844
895
|
logger2.setDebug(true);
|
|
845
896
|
}
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/errors.ts","../../src/cli/config-loader.ts","../../src/cli/config-detector.ts","../../src/cli/config-merger.ts","../../src/cli/arg-filter.ts","../../src/utils/index.ts","../../src/cli/logger.ts","../../src/cli/temp-config.ts","../../src/cli/playwright-spawner.ts","../../src/cli/commands/test.ts","../../src/cli/index.ts"],"names":["join","existsSync","statSync","dirname","jiti","fileURLToPath","randomUUID","chalk","logger","writeFileSync","unlinkSync","tmpdir","execa","__filename","__dirname","readFileSync","Command"],"mappings":";;;;;;;;;;;;;;;;;;;;AAQO,IAAM,aAAA,GAAN,cAA4B,KAAA,CAAM;AAAA,EACvC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,eAAA;AACZ,IAAA,KAAA,CAAM,iBAAA,CAAkB,IAAA,EAAM,IAAA,CAAK,WAAW,CAAA;AAAA,EAChD;AACF,CAAA;AAKO,IAAM,iBAAA,GAAN,cAAgC,aAAA,CAAc;AAAA,EACnD,WAAA,GAAc;AACZ,IAAA,MAAM,OAAA,GAAU,CAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA,gDAAA,CAAA;AAShB,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AAAA,EACd;AACF,CAAA;AAKO,IAAM,iBAAA,GAAN,cAAgC,aAAA,CAAc;AAAA,EACnD,WAAA,CAAY,YAAoB,aAAA,EAAsB;AACpD,IAAA,MAAM,OAAA,GAAU,kBAAkB,UAAU;;AAAA,EAE9C,cAAc,OAAO;;AAAA,mCAAA,CAAA;AAInB,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,mBAAA;AAAA,EACd;AACF,CAAA;AAqCO,IAAM,qBAAA,GAAN,cAAoC,aAAA,CAAc;AAAA,EACvD,YAAY,GAAA,EAAa;AACvB,IAAA,MAAM,OAAA,GAAU,uBAAuB,GAAG;;AAAA;;AAAA;AAAA;AAAA;AAAA,oCAAA,CAAA;AAS1C,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AAAA,EACd;AACF,CAAA;;;ACxFA,IAAM,gBAAA,GAAmB,CAAC,oBAAA,EAAsB,oBAAoB,CAAA;AAa7D,IAAM,eAAN,MAAmB;AAAA,EAChB,GAAA;AAAA,EAER,WAAA,CAAY,GAAA,GAAc,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvC,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAA,GAAkC;AACtC,IAAA,MAAM,UAAA,GAAa,KAAK,cAAA,EAAe;AAEvC,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,OAAO,EAAE,MAAA,EAAQ,EAAC,EAAE;AAAA,IACtB;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,cAAA,CAAe,UAAU,CAAA;AAC7C,MAAA,OAAO,EAAE,QAAQ,UAAA,EAAW;AAAA,IAC9B,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,iBAAA,CAAkB,UAAA,EAAY,KAAA,YAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,IACnG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAA,GAAqC;AAC3C,IAAA,IAAI,aAAa,IAAA,CAAK,GAAA;AAEtB,IAAA,OAAO,IAAA,EAAM;AAEX,MAAA,KAAA,MAAW,YAAY,gBAAA,EAAkB;AACvC,QAAA,MAAM,UAAA,GAAaA,SAAA,CAAK,UAAA,EAAY,QAAQ,CAAA;AAC5C,QAAA,IAAIC,aAAA,CAAW,UAAU,CAAA,EAAG;AAC1B,UAAA,OAAO,UAAA;AAAA,QACT;AAAA,MACF;AAGA,MAAA,MAAM,MAAA,GAASD,SAAA,CAAK,UAAA,EAAY,MAAM,CAAA;AACtC,MAAA,IAAIC,cAAW,MAAM,CAAA,IAAKC,YAAS,MAAM,CAAA,CAAE,aAAY,EAAG;AAExD,QAAA,KAAA,MAAW,YAAY,gBAAA,EAAkB;AACvC,UAAA,MAAM,UAAA,GAAaF,SAAA,CAAK,UAAA,EAAY,QAAQ,CAAA;AAC5C,UAAA,IAAIC,aAAA,CAAW,UAAU,CAAA,EAAG;AAC1B,YAAA,OAAO,UAAA;AAAA,UACT;AAAA,QACF;AAEA,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,SAAA,GAAYE,aAAQ,UAAU,CAAA;AAGpC,MAAA,IAAI,cAAc,UAAA,EAAY;AAC5B,QAAA;AAAA,MACF;AAEA,MAAA,UAAA,GAAa,SAAA;AAAA,IACf;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,UAAA,EAAuC;AAC5D,IAAA,MAAM,UAAA,GAAaC,qBAAA,CAAKD,YAAA,CAAQ,UAAU,CAAA,EAAG;AAAA,MAC3C,cAAA,EAAgB,IAAA;AAAA,MAChB,KAAA,EAAO,KAAA;AAAA,MACP,UAAA,EAAY,CAAC,KAAA,EAAO,KAAK;AAAA,KAC1B,CAAA;AAED,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AAEF,MAAA,MAAM,WAAW,UAAA,CAAW,UAAA,CAAW,YAAY,EAAE,GAAA,EAAK,MAAM,CAAA;AAChE,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,UAAU,CAAA,CAAE,CAAA;AAAA,MAChE;AAEA,MAAA,MAAM,eAAe,OAAO,QAAA,KAAa,QAAA,GAAW,QAAA,GAAWE,kBAAc,QAAQ,CAAA;AACrF,MAAA,MAAA,GAAS,WAAW,YAAY,CAAA;AAAA,IAClC,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IAC3F;AAIA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,gBAAgB,MAAA,EAAQ;AAClE,MAAA,MAAA,GAAU,MAAA,CAAmC,OAAA;AAAA,IAC/C,WAAW,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,aAAa,MAAA,EAAQ;AAEtE,MAAA,MAAA,GAAU,MAAA,CAAmC,OAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,MAAA;AAAA,IACX;AAGA,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,MAAA,OAAO,EAAC;AAAA,IACV;AAGA,IAAA,IAAI,OAAO,WAAW,UAAA,EAAY;AAChC,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,MAAA,EAAO;AAAA,MAClB,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,MAC9G;AAGA,MAAA,IAAI,kBAAkB,OAAA,EAAS;AAC7B,QAAA,MAAM,IAAI,MAAM,0CAA0C,CAAA;AAAA,MAC5D;AAGA,MAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,MAAA,EAAW;AAC3C,QAAA,OAAO,EAAC;AAAA,MACV;AAAA,IACF;AAGA,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAU;AACxC,MAAA,MAAM,IAAI,MAAM,0BAA0B,CAAA;AAAA,IAC5C;AAEA,IAAA,OAAO,UAAU,EAAC;AAAA,EACpB;AACF,CAAA;ACrJA,IAAM,2BAAA,GAA8B,CAAC,sBAAA,EAAwB,sBAAsB,CAAA;AACnF,IAAM,uBAAA,GAA0B,CAAC,sBAAA,EAAwB,qBAAA,EAAuB,kBAAkB,CAAA;AA+B3F,IAAM,iBAAN,MAAqB;AAAA,EAClB,GAAA;AAAA,EAER,WAAA,CAAY,GAAA,GAAc,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvC,IAAA,IAAA,CAAK,GAAA,GAAM,GAAA;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAA,GAAyC;AAC7C,IAAA,MAAM,UAAA,GAAa,KAAK,oBAAA,EAAqB;AAE7C,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,OAAO,EAAE,aAAa,KAAA,EAAM;AAAA,IAC9B;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,oBAAA,CAAqB,UAAU,CAAA;AACnD,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,uBAAA,CAAwB,MAAM,CAAA;AAElD,MAAA,OAAO;AAAA,QACL,GAAG,MAAA;AAAA,QACH;AAAA,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,iBAAA,CAAkB,UAAA,EAAY,KAAA,YAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,IACnG;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAA,GAA2C;AACjD,IAAA,KAAA,MAAW,YAAY,2BAAA,EAA6B;AAClD,MAAA,MAAM,UAAA,GAAaL,SAAAA,CAAK,IAAA,CAAK,GAAA,EAAK,QAAQ,CAAA;AAC1C,MAAA,IAAIC,aAAAA,CAAW,UAAU,CAAA,EAAG;AAC1B,QAAA,OAAO,UAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAAqB,UAAA,EAAsC;AACjE,IAAA,MAAM,UAAA,GAAaG,qBAAAA,CAAKD,YAAAA,CAAQ,UAAU,CAAA,EAAG;AAAA,MAC3C,cAAA,EAAgB,IAAA;AAAA,MAChB,KAAA,EAAO,KAAA;AAAA,MACP,UAAA,EAAY,CAAC,KAAA,EAAO,KAAK;AAAA,KAC1B,CAAA;AAED,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI;AACF,MAAA,MAAM,WAAW,UAAA,CAAW,UAAA,CAAW,YAAY,EAAE,GAAA,EAAK,MAAM,CAAA;AAChE,MAAA,IAAI,CAAC,QAAA,EAAU;AACb,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qCAAA,EAAwC,UAAU,CAAA,CAAE,CAAA;AAAA,MACtE;AAEA,MAAA,MAAM,eAAe,OAAO,QAAA,KAAa,QAAA,GAAW,QAAA,GAAWE,kBAAc,QAAQ,CAAA;AACrF,MAAA,MAAA,GAAS,WAAW,YAAY,CAAA;AAAA,IAClC,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,cAAA,EAAiB,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,IAC3F;AAGA,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,gBAAgB,MAAA,EAAQ;AAClE,MAAA,MAAA,GAAU,MAAA,CAAmC,OAAA;AAAA,IAC/C,WAAW,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,aAAa,MAAA,EAAQ;AACtE,MAAA,MAAA,GAAU,MAAA,CAAmC,OAAA;AAAA,IAC/C,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,MAAA;AAAA,IACX;AAGA,IAAA,IAAI,OAAO,WAAW,UAAA,EAAY;AAChC,MAAA,IAAI;AACF,QAAA,MAAA,GAAS,MAAA,EAAO;AAAA,MAClB,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAAA,MAC9G;AAAA,IACF;AAGA,IAAA,IAAI,CAAC,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,EAAU;AACzC,MAAA,MAAM,IAAI,MAAM,qCAAqC,CAAA;AAAA,IACvD;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAAwB,MAAA,EAAqE;AACnG,IAAA,MAAM,EAAE,UAAS,GAAI,MAAA;AAErB,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,OAAO,EAAE,aAAa,KAAA,EAAM;AAAA,IAC9B;AAGA,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,IAAI,IAAA,CAAK,kBAAA,CAAmB,QAAQ,CAAA,EAAG;AACrC,QAAA,OAAO,EAAE,WAAA,EAAa,IAAA,EAAM,OAAA,EAAS,EAAC,EAAE;AAAA,MAC1C;AACA,MAAA,OAAO,EAAE,aAAa,KAAA,EAAM;AAAA,IAC9B;AAGA,IAAA,IAAI,MAAM,OAAA,CAAQ,QAAQ,CAAA,IAAK,QAAA,CAAS,SAAS,CAAA,EAAG;AAElD,MAAA,IAAI,OAAO,QAAA,CAAS,CAAC,CAAA,KAAM,QAAA,EAAU;AACnC,QAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAA;AACxB,QAAA,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA,EAAG;AACjC,UAAA,OAAO;AAAA,YACL,WAAA,EAAa,IAAA;AAAA,YACb,OAAA,EAAS,IAAA,CAAK,cAAA,CAAe,OAAO;AAAA,WACtC;AAAA,QACF;AAAA,MAGF;AAGA,MAAA,KAAA,MAAW,QAAQ,QAAA,EAAU;AAC3B,QAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,UAAA,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA,EAAG;AACjC,YAAA,OAAO,EAAE,WAAA,EAAa,IAAA,EAAM,OAAA,EAAS,EAAC,EAAE;AAAA,UAC1C;AAAA,QACF,WAAW,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,IAAK,IAAA,CAAK,SAAS,CAAA,EAAG;AACjD,UAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,IAAA;AACxB,UAAA,IAAI,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAA,EAAG;AACjC,YAAA,OAAO;AAAA,cACL,WAAA,EAAa,IAAA;AAAA,cACb,OAAA,EAAS,IAAA,CAAK,cAAA,CAAe,OAAO;AAAA,aACtC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAO,EAAE,aAAa,KAAA,EAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,IAAA,EAAuB;AAChD,IAAA,OAAO,uBAAA,CAAwB,KAAK,CAAC,YAAA,KAAiB,SAAS,YAAA,IAAgB,IAAA,CAAK,QAAA,CAAS,YAAY,CAAC,CAAA;AAAA,EAC5G;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,OAAA,EAAmD;AACxE,IAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AAC3C,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,MAAM,SAAyB,EAAC;AAEhC,IAAA,IAAI,OAAA,IAAW,OAAA,IAAW,OAAO,OAAA,CAAQ,UAAU,QAAA,EAAU;AAC3D,MAAA,MAAA,CAAO,QAAQ,OAAA,CAAQ,KAAA;AAAA,IACzB;AAEA,IAAA,IAAI,WAAA,IAAe,OAAA,IAAW,OAAO,OAAA,CAAQ,cAAc,QAAA,EAAU;AACnE,MAAA,MAAA,CAAO,YAAY,OAAA,CAAQ,SAAA;AAAA,IAC7B;AAEA,IAAA,IAAI,SAAA,IAAa,OAAA,IAAW,OAAO,OAAA,CAAQ,YAAY,QAAA,EAAU;AAC/D,MAAA,MAAA,CAAO,UAAU,OAAA,CAAQ,OAAA;AAAA,IAC3B;AAEA,IAAA,IAAI,OAAA,IAAW,OAAA,IAAW,OAAO,OAAA,CAAQ,UAAU,SAAA,EAAW;AAC5D,MAAA,MAAA,CAAO,QAAQ,OAAA,CAAQ,KAAA;AAAA,IACzB;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAA;AC1MO,IAAM,YAAA,GAAN,MAAM,aAAA,CAAa;AAAA,EACxB,OAAwB,kBAAA,GAAqB,0BAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU7C,MAAM,OAAA,EAAsC;AAC1C,IAAA,MAAM,EAAE,GAAA,GAAM,EAAC,EAAG,gBAAA,GAAmB,EAAC,EAAG,cAAA,GAAiB,EAAC,EAAG,UAAA,GAAa,IAAG,GAAI,OAAA;AAGlF,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,WAAA,CAAY,UAAA,CAAW,KAAA,EAAO,eAAe,KAAA,EAAO,gBAAA,CAAiB,KAAA,EAAO,GAAA,CAAI,KAAK,CAAA;AAGxG,IAAA,MAAM,SAAA,GACJ,IAAA,CAAK,WAAA,CAAY,UAAA,CAAW,SAAA,EAAW,cAAA,CAAe,SAAA,EAAW,gBAAA,CAAiB,SAAA,EAAW,GAAA,CAAI,SAAS,CAAA,IAC1G,aAAA,CAAa,kBAAA;AAGf,IAAA,MAAM,OAAA,GACJ,IAAA,CAAK,WAAA,CAAY,UAAA,CAAW,OAAA,EAAS,cAAA,CAAe,OAAA,EAAS,gBAAA,CAAiB,OAAO,CAAA,IAAK,IAAA,CAAK,eAAA,EAAgB;AAGjH,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,WAAA,CAAY,UAAA,CAAW,KAAA,EAAO,cAAA,CAAe,KAAA,EAAO,gBAAA,CAAiB,KAAA,EAAO,GAAA,CAAI,KAAK,CAAA,IAAK,KAAA;AAI7G,IAAA,MAAM,SAAA,GACJ,UAAA,CAAW,WAAA,KAAgB,IAAA,GACvB,KAAA,GACC,IAAA,CAAK,WAAA,CAAY,cAAA,CAAe,SAAA,EAAW,gBAAA,CAAiB,SAAS,CAAA,IAAK,IAAA;AAEjF,IAAA,MAAM,YAAA,GAA6B;AAAA,MACjC,KAAA;AAAA,MACA,SAAA;AAAA,MACA,OAAA;AAAA,MACA,KAAA;AAAA,MACA;AAAA,KACF;AAGA,IAAA,IAAA,CAAK,SAAS,YAAY,CAAA;AAE1B,IAAA,OAAO,YAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAkB,MAAA,EAA0C;AAClE,IAAA,OAAO,OAAO,IAAA,CAAK,CAAC,UAAU,KAAA,KAAU,MAAA,IAAa,UAAU,IAAI,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAA,GAA0B;AAChC,IAAA,OAAO,CAAA,IAAA,EAAOC,mBAAY,CAAA,CAAA;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAS,MAAA,EAA4B;AAE3C,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,IAAS,OAAO,MAAA,CAAO,KAAA,KAAU,QAAA,IAAY,MAAA,CAAO,KAAA,CAAM,IAAA,EAAK,CAAE,MAAA,KAAW,CAAA,EAAG;AACzF,MAAA,MAAM,IAAI,iBAAA,EAAkB;AAAA,IAC9B;AAGA,IAAA,IAAI,OAAO,SAAA,EAAW;AACpB,MAAA,IAAI,OAAO,OAAO,SAAA,KAAc,QAAA,IAAY,CAAC,IAAA,CAAK,UAAA,CAAW,MAAA,CAAO,SAAS,CAAA,EAAG;AAC9E,QAAA,MAAM,IAAI,qBAAA,CAAsB,MAAA,CAAO,SAAS,CAAA;AAAA,MAClD;AAAA,IACF;AAAA,EAIF;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAW,SAAA,EAA4B;AAC7C,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,SAAS,CAAA;AAC7B,MAAA,OAAO,GAAA,CAAI,QAAA,KAAa,OAAA,IAAW,GAAA,CAAI,QAAA,KAAa,QAAA;AAAA,IACtD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,YAAA,GAAwC;AAC7C,IAAA,MAAM,SAAkC,EAAC;AAEzC,IAAA,IAAI,OAAA,CAAQ,IAAI,cAAA,EAAgB;AAC9B,MAAA,MAAA,CAAO,KAAA,GAAQ,QAAQ,GAAA,CAAI,cAAA;AAAA,IAC7B;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAI,mBAAA,EAAqB;AACnC,MAAA,MAAA,CAAO,SAAA,GAAY,QAAQ,GAAA,CAAI,mBAAA;AAAA,IACjC;AAEA,IAAA,IAAI,OAAA,CAAQ,IAAI,cAAA,EAAgB;AAC9B,MAAA,MAAA,CAAO,QAAQ,OAAA,CAAQ,GAAA,CAAI,mBAAmB,MAAA,IAAU,OAAA,CAAQ,IAAI,cAAA,KAAmB,GAAA;AAAA,IACzF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AACF,CAAA;;;ACpIA,IAAM,iBAAiB,CAAC,SAAA,EAAW,MAAM,aAAA,EAAe,cAAA,EAAgB,WAAW,gBAAgB,CAAA;AAKnG,IAAM,iBAAA,GAAoB,CAAC,SAAA,EAAW,IAAA,EAAM,eAAe,cAAc,CAAA;AAKlE,IAAM,YAAN,MAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrB,OAAO,IAAA,EAA0B;AAC/B,IAAA,MAAM,SAAmB,EAAC;AAC1B,IAAA,IAAI,QAAA,GAAW,KAAA;AAEf,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,QAAQ,CAAA,EAAA,EAAK;AACpC,MAAA,MAAM,GAAA,GAAM,KAAK,CAAC,CAAA;AAGlB,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,QAAA,GAAW,KAAA;AACX,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,IAAA,CAAK,cAAA,CAAe,GAAG,CAAA,EAAG;AAE5B,QAAA,IAAI,IAAA,CAAK,gBAAgB,GAAG,CAAA,IAAK,CAAC,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AAEnD,UAAA,QAAA,GAAW,IAAA;AAAA,QACb;AAEA,QAAA;AAAA,MACF;AAGA,MAAA,IAAI,IAAA,CAAK,wBAAA,CAAyB,GAAG,CAAA,EAAG;AAEtC,QAAA;AAAA,MACF;AAGA,MAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AAAA,IACjB;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,GAAA,EAAsB;AAE3C,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AACjC,IAAA,OAAO,cAAA,CAAe,SAAS,QAAQ,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKQ,yBAAyB,GAAA,EAAsB;AACrD,IAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AACtB,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AACjC,IAAA,OAAO,cAAA,CAAe,SAAS,QAAQ,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,GAAA,EAAsB;AAC5C,IAAA,MAAM,QAAA,GAAW,GAAA,CAAI,KAAA,CAAM,GAAG,EAAE,CAAC,CAAA;AACjC,IAAA,OAAO,iBAAA,CAAkB,SAAS,QAAQ,CAAA;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,gBAAA,GAA6B;AAClC,IAAA,OAAO,CAAC,GAAG,cAAc,CAAA;AAAA,EAC3B;AACF,CAAA;;;ACnFO,SAAS,cAAA,GAA0B;AACxC,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,cAAA,KAAmB,MAAA,IAAU,OAAA,CAAQ,IAAI,cAAA,KAAmB,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,KAAA,KAAU,MAAA;AAC9G;;;ACMO,IAAM,SAAN,MAAa;AAAA,EACV,YAAA;AAAA,EAER,WAAA,CAAY,eAAe,KAAA,EAAO;AAChC,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAAA,EAAwB;AAC/B,IAAA,IAAA,CAAK,YAAA,GAAe,OAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,KAAA,CAAM,SAAiB,KAAA,EAAqB;AAC1C,IAAA,OAAA,CAAQ,KAAA,CAAMC,uBAAM,GAAA,CAAI;AAAA,cAAA,EAAc,OAAO,EAAE,CAAC,CAAA;AAEhD,IAAA,IAAI,KAAA,IAAS,KAAK,YAAA,EAAc;AAC9B,MAAA,OAAA,CAAQ,KAAA,CAAMA,sBAAA,CAAM,GAAA,CAAI,gBAAgB,CAAC,CAAA;AACzC,MAAA,OAAA,CAAQ,MAAMA,sBAAA,CAAM,GAAA,CAAI,MAAM,KAAA,IAAS,KAAA,CAAM,OAAO,CAAC,CAAA;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAAA,EAAuB;AAC1B,IAAA,OAAA,CAAQ,KAAKA,sBAAA,CAAM,MAAA,CAAO,CAAA,uBAAA,EAAgB,OAAO,EAAE,CAAC,CAAA;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAAA,EAAuB;AAC1B,IAAA,OAAA,CAAQ,IAAIA,sBAAA,CAAM,IAAA,CAAK,CAAA,cAAA,EAAO,OAAO,EAAE,CAAC,CAAA;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,OAAA,EAAuB;AAC7B,IAAA,OAAA,CAAQ,IAAIA,sBAAA,CAAM,KAAA,CAAM,CAAA,OAAA,EAAK,OAAO,EAAE,CAAC,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,EAAuB;AAC3B,IAAA,IAAI,KAAK,YAAA,EAAc;AACrB,MAAA,OAAA,CAAQ,IAAIA,sBAAA,CAAM,GAAA,CAAI,CAAA,QAAA,EAAW,OAAO,EAAE,CAAC,CAAA;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAA,GAAgB;AACd,IAAA,OAAA,CAAQ,GAAA,EAAI;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,KAAA,EAAqB;AAC3B,IAAA,OAAA,CAAQ,GAAA,CAAIA,sBAAA,CAAM,IAAA,CAAK,IAAA,CAAK;AAAA,EAAK,KAAK,EAAE,CAAC,CAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,IAAA,EAAoB;AAC3B,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,SAAA,EAAO,IAAI,CAAA,CAAE,CAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,IAAA,EAAoB;AACvB,IAAA,OAAA,CAAQ,IAAIA,sBAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,IAAI,EAAE,CAAC,CAAA;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,KAAA,EAAsB;AAChC,IAAA,IAAI,IAAA,CAAK,YAAA,IAAgB,KAAA,CAAM,KAAA,EAAO;AACpC,MAAA,OAAO,KAAA,CAAM,KAAA;AAAA,IACf;AACA,IAAA,OAAO,KAAA,CAAM,OAAA;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,OAAA,EAAuB;AAC5B,IAAA,OAAA,CAAQ,GAAA;AAAA,MACNA,uBAAM,IAAA,CAAK;AAAA;AAAA;AAAA,SAAA,EAGXA,sBAAA,CAAM,KAAK,qBAAqB,CAAC,KAAK,OAAA,CAAQ,MAAA,CAAO,EAAE,CAAC,CAAA;AAAA,SAAA,EACxDA,sBAAA,CAAM,GAAA,CAAI,sBAAsB,CAAC,CAAA;AAAA;AAAA;AAAA,CAGtC;AAAA,KACG;AAAA,EACF;AACF,CAAA;AAKsB,IAAI,MAAA,CAAO,cAAA,EAAgB;;;ACzH1C,IAAM,oBAAN,MAAwB;AAAA,EACrB,SAAA,uBAA6B,GAAA,EAAI;AAAA,EACjC,yBAAA,GAA4B,KAAA;AAAA,EAC5B,WAAA;AAAA,EACA,aAAA;AAAA,EACA,cAAA;AAAA,EACA,wBAAA;AAAA,EACA,yBAAA;AAAA,EACA,MAAA;AAAA,EAER,YAAYC,OAAAA,EAAiB;AAC3B,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA,IAAU,IAAI,MAAA,EAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,MAAA,EAAsC;AAC3C,IAAA,MAAM,QAAA,GAAW,KAAK,gBAAA,EAAiB;AAEvC,IAAA,IAAI;AAEF,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,SAAA,CAAU,MAAA,EAAQ,MAAM,CAAC,CAAA;AACjD,MAAAC,gBAAA,CAAc,QAAA,EAAU,YAAY,OAAO,CAAA;AAG3C,MAAA,IAAA,CAAK,SAAA,CAAU,IAAI,QAAQ,CAAA;AAG3B,MAAA,IAAI,CAAC,KAAK,yBAAA,EAA2B;AACnC,QAAA,IAAA,CAAK,uBAAA,EAAwB;AAC7B,QAAA,IAAA,CAAK,yBAAA,GAA4B,IAAA;AAAA,MACnC;AAEA,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,QAAA;AAAA,QACN;AAAA,OACF;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,sCAAsC,QAAQ;AAAA,EAAK,iBAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,OAC3G;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,QAAA,EAAwB;AAC9B,IAAA,IAAI;AACF,MAAA,IAAIR,aAAAA,CAAW,QAAQ,CAAA,EAAG;AACxB,QAAAS,aAAA,CAAW,QAAQ,CAAA;AAAA,MACrB;AACA,MAAA,IAAA,CAAK,SAAA,CAAU,OAAO,QAAQ,CAAA;AAAA,IAChC,CAAA,CAAA,MAAQ;AAEN,MAAA,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,CAAA,6BAAA,EAAgC,QAAQ,CAAA,CAAE,CAAA;AAAA,IAC7D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAA,GAAmB;AACjB,IAAA,KAAA,MAAW,QAAA,IAAY,KAAK,SAAA,EAAW;AACrC,MAAA,IAAA,CAAK,QAAQ,QAAQ,CAAA;AAAA,IACvB;AACA,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAA,GAAuB;AACrB,IAAA,IAAI,KAAK,WAAA,EAAa;AACpB,MAAA,OAAA,CAAQ,cAAA,CAAe,MAAA,EAAQ,IAAA,CAAK,WAAW,CAAA;AAAA,IACjD;AACA,IAAA,IAAI,KAAK,aAAA,EAAe;AACtB,MAAA,OAAA,CAAQ,cAAA,CAAe,QAAA,EAAU,IAAA,CAAK,aAAa,CAAA;AAAA,IACrD;AACA,IAAA,IAAI,KAAK,cAAA,EAAgB;AACvB,MAAA,OAAA,CAAQ,cAAA,CAAe,SAAA,EAAW,IAAA,CAAK,cAAc,CAAA;AAAA,IACvD;AACA,IAAA,IAAI,KAAK,wBAAA,EAA0B;AACjC,MAAA,OAAA,CAAQ,cAAA,CAAe,mBAAA,EAAqB,IAAA,CAAK,wBAAwB,CAAA;AAAA,IAC3E;AACA,IAAA,IAAI,KAAK,yBAAA,EAA2B;AAClC,MAAA,OAAA,CAAQ,cAAA,CAAe,oBAAA,EAAsB,IAAA,CAAK,yBAAyB,CAAA;AAAA,IAC7E;AACA,IAAA,IAAA,CAAK,yBAAA,GAA4B,KAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAA,GAA2B;AACjC,IAAA,MAAM,QAAA,GAAW,CAAA,gBAAA,EAAmBJ,iBAAAA,EAAY,CAAA,KAAA,CAAA;AAChD,IAAA,OAAON,SAAAA,CAAKW,SAAA,EAAO,EAAG,QAAQ,CAAA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKQ,uBAAA,GAAgC;AAEtC,IAAA,IAAA,CAAK,cAAc,MAAM;AACvB,MAAA,IAAA,CAAK,UAAA,EAAW;AAAA,IAClB,CAAA;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,MAAA,EAAQ,IAAA,CAAK,WAAW,CAAA;AAGnC,IAAA,IAAA,CAAK,gBAAgB,MAAM;AACzB,MAAA,IAAA,CAAK,UAAA,EAAW;AAChB,MAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAClB,CAAA;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,QAAA,EAAU,IAAA,CAAK,aAAa,CAAA;AAGvC,IAAA,IAAA,CAAK,iBAAiB,MAAM;AAC1B,MAAA,IAAA,CAAK,UAAA,EAAW;AAChB,MAAA,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAClB,CAAA;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,SAAA,EAAW,IAAA,CAAK,cAAc,CAAA;AAGzC,IAAA,IAAA,CAAK,wBAAA,GAA2B,CAAC,KAAA,KAAiB;AAChD,MAAA,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,oBAAA,EAAsB,KAAK,CAAA;AAC7C,MAAA,IAAA,CAAK,UAAA,EAAW;AAChB,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB,CAAA;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,mBAAA,EAAqB,IAAA,CAAK,wBAAwB,CAAA;AAG7D,IAAA,IAAA,CAAK,yBAAA,GAA4B,CAAC,MAAA,KAAoB;AACpD,MAAA,IAAA,CAAK,OAAO,KAAA,CAAM,qBAAA,EAAuB,MAAA,YAAkB,KAAA,GAAQ,SAAS,MAAS,CAAA;AACrF,MAAA,IAAA,CAAK,UAAA,EAAW;AAChB,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB,CAAA;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,oBAAA,EAAsB,IAAA,CAAK,yBAAyB,CAAA;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAAyB;AACvB,IAAA,OAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA;AAAA,EAClC;AACF,CAAA;ACvIO,IAAM,oBAAN,MAAwB;AAAA,EACrB,MAAA;AAAA,EAER,YAAYH,OAAAA,EAAiB;AAC3B,IAAA,IAAA,CAAK,MAAA,GAASA,OAAAA,IAAU,IAAI,MAAA,EAAO;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,MAAM,OAAA,EAAiE;AAC3E,IAAA,MAAM,EAAE,MAAM,cAAA,EAAgB,MAAA,EAAQ,MAAM,OAAA,CAAQ,GAAA,IAAM,GAAI,OAAA;AAE9D,IAAA,IAAI;AAEF,MAAA,MAAM,GAAA,GAAM;AAAA,QACV,GAAG,OAAA,CAAQ,GAAA;AAAA,QACX,wBAAA,EAA0B,cAAA;AAAA,QAC1B,gBAAgB,MAAA,CAAO,KAAA;AAAA,QACvB,qBAAqB,MAAA,CAAO,SAAA;AAAA,QAC5B,oBAAoB,MAAA,CAAO,OAAA;AAAA,QAC3B,cAAA,EAAgB,MAAA,CAAO,KAAA,GAAQ,MAAA,GAAS;AAAA,OAC1C;AAGA,MAAA,MAAM,iBAAiB,CAAC,YAAA,EAAc,QAAQ,YAAA,EAAc,sBAAA,EAAwB,GAAG,IAAI,CAAA;AAG3F,MAAA,MAAM,MAAA,GAAS,MAAMI,WAAA,CAAM,KAAA,EAAO,cAAA,EAAgB;AAAA,QAChD,KAAA,EAAO,SAAA;AAAA;AAAA,QACP,GAAA;AAAA,QACA,GAAA;AAAA,QACA,MAAA,EAAQ;AAAA;AAAA,OACT,CAAA;AAED,MAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,CAAA;AAEpC,MAAA,OAAO;AAAA,QACL,QAAA;AAAA,QACA,SAAS,QAAA,KAAa;AAAA,OACxB;AAAA,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,OAAO,IAAA,CAAK,iBAAiB,KAAK,CAAA;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,KAAA,EAAuC;AAC9D,IAAA,MAAM,UAAA,GAAa,KAAA;AAGnB,IAAA,IAAI,UAAA,CAAW,SAAS,QAAA,EAAU;AAChC,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,4BAA4B,CAAA;AAC9C,MAAA,IAAA,CAAK,OAAO,OAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,sDAAsD,CAAA;AACvE,MAAA,IAAA,CAAK,OAAO,OAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,wBAAwB,CAAA;AAC5C,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,iCAAiC,CAAA;AAClD,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,wBAAwB,CAAA;AACzC,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,CAAA;AAAA,QACV,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAGA,IAAA,IAAI,UAAA,CAAW,SAAS,QAAA,EAAU;AAChC,MAAA,IAAA,CAAK,MAAA,CAAO,MAAM,mDAAmD,CAAA;AACrE,MAAA,IAAA,CAAK,OAAO,OAAA,EAAQ;AACpB,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,8CAA8C,CAAA;AAC/D,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,CAAA;AAAA,QACV,OAAA,EAAS;AAAA,OACX;AAAA,IACF;AAGA,IAAA,IAAA,CAAK,MAAA,CAAO,MAAM,4BAA4B,CAAA;AAC9C,IAAA,IAAA,CAAK,OAAO,OAAA,EAAQ;AACpB,IAAA,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,OAAA,EAAU,UAAA,CAAW,WAAW,MAAA,CAAO,KAAK,CAAC,CAAA,CAAE,CAAA;AAChE,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,CAAA;AAAA,MACV,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AACF,CAAA;;;ACrGO,IAAM,cAAN,MAAkB;AAAA,EACf,YAAA;AAAA,EACA,cAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AAAA,EAER,YACE,YAAA,EACA,cAAA,EACA,cACA,SAAA,EACA,iBAAA,EACA,mBACAJ,OAAAA,EACA;AACA,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA,IAAgB,IAAI,YAAA,EAAa;AACrD,IAAA,IAAA,CAAK,cAAA,GAAiB,cAAA,IAAkB,IAAI,cAAA,EAAe;AAC3D,IAAA,IAAA,CAAK,YAAA,GAAe,YAAA,IAAgB,IAAI,YAAA,EAAa;AACrD,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA,IAAa,IAAI,SAAA,EAAU;AAC5C,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA,IAAqB,IAAI,iBAAA,CAAkBA,OAAM,CAAA;AAC1E,IAAA,IAAA,CAAK,iBAAA,GAAoB,iBAAA,IAAqB,IAAI,iBAAA,CAAkBA,OAAM,CAAA;AAAA,EAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,CAAQ,OAAA,EAAqB,IAAA,EAAgD;AACjF,IAAA,IAAI,cAAA;AAEJ,IAAA,IAAI;AAEF,MAAA,MAAM,oBAAA,GAAuB,MAAM,IAAA,CAAK,YAAA,CAAa,IAAA,EAAK;AAG1D,MAAA,MAAM,sBAAA,GAAyB,MAAM,IAAA,CAAK,cAAA,CAAe,MAAA,EAAO;AAGhE,MAAA,MAAM,SAAA,GAAY,aAAa,YAAA,EAAa;AAG5C,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM;AAAA,QAC3C,GAAA,EAAK,SAAA;AAAA,QACL,kBAAkB,sBAAA,CAAuB,OAAA;AAAA,QACzC,gBAAgB,oBAAA,CAAqB,MAAA;AAAA,QACrC,UAAA,EAAY;AAAA,OACb,CAAA;AAGD,MAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,YAAY,CAAA;AACjE,MAAA,cAAA,GAAiB,cAAA,CAAe,IAAA;AAGhC,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,IAAI,CAAA;AAG/C,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,iBAAA,CAAkB,KAAA,CAAM;AAAA,QAChD,IAAA,EAAM,YAAA;AAAA,QACN,cAAA;AAAA,QACA,MAAA,EAAQ;AAAA,OACT,CAAA;AAED,MAAA,OAAO,MAAA;AAAA,IACT,CAAA,SAAE;AAEA,MAAA,IAAI,cAAA,EAAgB;AAClB,QAAA,IAAA,CAAK,iBAAA,CAAkB,QAAQ,cAAc,CAAA;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF,CAAA;;;AC7EA,IAAMK,YAAA,GAAaR,iBAAAA,CAAc,0PAAe,CAAA;AAChD,IAAMS,WAAA,GAAYX,aAAQU,YAAU,CAAA;AAKpC,SAAS,UAAA,GAAqB;AAC5B,EAAA,IAAI;AAEF,IAAA,MAAM,WAAA,GAAcb,SAAAA,CAAKc,WAAA,EAAW,oBAAoB,CAAA;AACxD,IAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAMC,eAAA,CAAa,WAAA,EAAa,OAAO,CAAC,CAAA;AACjE,IAAA,OAAO,WAAA,CAAY,OAAA;AAAA,EACrB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,OAAA;AAAA,EACT;AACF;AAGA,IAAMP,OAAAA,GAAS,IAAI,MAAA,CAAO,cAAA,EAAgB,CAAA;AAK1C,SAAS,YAAA,GAAwB;AAC/B,EAAA,MAAM,UAAU,IAAIQ,iBAAA,GACjB,IAAA,CAAK,MAAM,EACX,WAAA,CAAY,8CAA8C,CAAA,CAC1D,OAAA,CAAQ,YAAW,EAAG,eAAA,EAAiB,4BAA4B,CAAA,CACnE,UAAA,CAAW,cAAc,0BAA0B,CAAA;AAGtD,EAAA,OAAA,CACG,OAAA,CAAQ,MAAM,CAAA,CACd,WAAA,CAAY,6CAA6C,CAAA,CACzD,MAAA,CAAO,qBAAA,EAAuB,+BAA+B,CAAA,CAC7D,MAAA,CAAO,kBAAA,EAAoB,kCAAkC,EAC7D,MAAA,CAAO,oBAAA,EAAsB,qBAAqB,CAAA,CAClD,MAAA,CAAO,SAAA,EAAW,sBAAsB,CAAA,CACxC,OAAO,gBAAA,EAAkB,wDAAwD,CAAA,CACjF,kBAAA,GACA,oBAAA,EAAqB,CACrB,MAAA,CAAO,OAAO,SAAS,OAAA,KAAY;AAElC,IAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,MAAAR,OAAAA,CAAO,SAAS,IAAI,CAAA;AAAA,IACtB;AAEA,IAAA,IAAI;AAEF,MAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,EAAC;AAG9B,MAAA,MAAM,WAAA,GAAc,IAAI,WAAA,EAAY;AACpC,MAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,OAAA,CAAQ,SAAS,IAAI,CAAA;AAGtD,MAAA,OAAA,CAAQ,IAAA,CAAK,OAAO,QAAQ,CAAA;AAAA,IAC9B,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,aAAA,EAAe;AAElC,QAAAA,OAAAA,CAAO,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AAAA,MAC5B,CAAA,MAAO;AACL,QAAAA,OAAAA,CAAO,KAAA;AAAA,UACL,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AAAA,UACrD,KAAA,YAAiB,QAAQ,KAAA,GAAQ;AAAA,SACnC;AAAA,MACF;AAEA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAAA,EACF,CAAC,CAAA;AAEH,EAAA,OAAO,OAAA;AACT;AAKA,eAAe,IAAA,GAAsB;AACnC,EAAA,IAAI;AACF,IAAAA,OAAAA,CAAO,MAAA,CAAO,UAAA,EAAY,CAAA;AAE1B,IAAA,MAAM,UAAU,YAAA,EAAa;AAC7B,IAAA,MAAM,OAAA,CAAQ,UAAA,CAAW,OAAA,CAAQ,IAAI,CAAA;AAAA,EACvC,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,iBAAiB,aAAA,EAAe;AAClC,MAAAA,OAAAA,CAAO,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AAAA,IAC5B,CAAA,MAAO;AACL,MAAAA,OAAAA,CAAO,KAAA,CAAM,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAA,EAAG,KAAA,YAAiB,KAAA,GAAQ,KAAA,GAAQ,MAAS,CAAA;AAAA,IACjH;AAEA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF;AAGA,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,KAAA,KAAU;AACtB,EAAAA,QAAO,KAAA,CAAM,kBAAA,EAAoB,KAAA,YAAiB,KAAA,GAAQ,QAAQ,MAAS,CAAA;AAC3E,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAChB,CAAC,CAAA","file":"index.js","sourcesContent":["/**\n * Custom error classes for TestDino CLI\n * Provides clear, actionable error messages with suggestions\n */\n\n/**\n * Base class for all TestDino CLI errors\n */\nexport class TestDinoError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'TestDinoError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when authentication token is missing\n */\nexport class TokenMissingError extends TestDinoError {\n constructor() {\n const message = `Token is required to run tests with TestDino\n\nProvide token via:\n • CLI flag: npx tdpw test --token <your-token>\n • Environment: export TESTDINO_TOKEN=<your-token>\n • Config file: Create testdino.config.ts with token\n\nGet your token at: https://testdino.com/settings`;\n\n super(message);\n this.name = 'TokenMissingError';\n }\n}\n\n/**\n * Error thrown when config file has syntax errors\n */\nexport class ConfigSyntaxError extends TestDinoError {\n constructor(configPath: string, originalError: Error) {\n const message = `Failed to load ${configPath}\n\n${originalError.message}\n\nFix the syntax error and try again.`;\n\n super(message);\n this.name = 'ConfigSyntaxError';\n }\n}\n\n/**\n * Error thrown when Playwright is not installed\n */\nexport class PlaywrightNotInstalledError extends TestDinoError {\n constructor() {\n const message = `Playwright is not installed\n\nInstall Playwright:\n npm install -D @playwright/test\n\nThen run:\n npx playwright install`;\n\n super(message);\n this.name = 'PlaywrightNotInstalledError';\n }\n}\n\n/**\n * Error thrown when config file cannot be found\n */\nexport class ConfigNotFoundError extends TestDinoError {\n constructor(configPath: string) {\n const message = `Config file not found: ${configPath}\n\nMake sure the file exists and is readable.`;\n\n super(message);\n this.name = 'ConfigNotFoundError';\n }\n}\n\n/**\n * Error thrown when server URL is invalid\n */\nexport class InvalidServerUrlError extends TestDinoError {\n constructor(url: string) {\n const message = `Invalid server URL: ${url}\n\nServer URL must be a valid HTTP or HTTPS URL.\n\nExamples:\n • https://api.testdino.com\n • https://api-v0.testdino.com\n • https://global.testdino.com`;\n\n super(message);\n this.name = 'InvalidServerUrlError';\n }\n}\n\n/**\n * Error thrown when Playwright execution fails\n */\nexport class PlaywrightExecutionError extends TestDinoError {\n constructor(exitCode: number, message?: string) {\n const errorMessage = message\n ? `Playwright execution failed: ${message}`\n : `Playwright execution failed with exit code ${exitCode}`;\n\n super(errorMessage);\n this.name = 'PlaywrightExecutionError';\n }\n}\n\n/**\n * Error thrown when permission is denied\n */\nexport class PermissionDeniedError extends TestDinoError {\n constructor(path: string) {\n const message = `Permission denied: ${path}\n\nCheck file permissions and try again.`;\n\n super(message);\n this.name = 'PermissionDeniedError';\n }\n}\n","/**\n * Config file loader for TestDino CLI\n * Searches for testdino.config.[ts|js] up the directory tree\n */\n\nimport { existsSync, statSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport jiti from 'jiti';\nimport type { ConfigFileContent } from './types.js';\nimport { ConfigSyntaxError } from './errors.js';\n\nconst CONFIG_FILENAMES = ['testdino.config.ts', 'testdino.config.js'];\n\n/**\n * Result of config loading\n */\nexport interface ConfigLoadResult {\n config: ConfigFileContent;\n configPath?: string;\n}\n\n/**\n * Config loader class\n */\nexport class ConfigLoader {\n private cwd: string;\n\n constructor(cwd: string = process.cwd()) {\n this.cwd = cwd;\n }\n\n /**\n * Load config file from current directory or parent directories\n */\n async load(): Promise<ConfigLoadResult> {\n const configPath = this.findConfigFile();\n\n if (!configPath) {\n return { config: {} };\n }\n\n try {\n const config = this.loadConfigFile(configPath);\n return { config, configPath };\n } catch (error) {\n throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Find config file by searching up directory tree\n * Stops at .git directory\n */\n private findConfigFile(): string | undefined {\n let currentDir = this.cwd;\n\n while (true) {\n // Check for config files in current directory\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n\n // Check if we've reached .git directory\n const gitDir = join(currentDir, '.git');\n if (existsSync(gitDir) && statSync(gitDir).isDirectory()) {\n // Check one more time in the git root directory\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n // Stop at git root\n break;\n }\n\n // Move to parent directory\n const parentDir = dirname(currentDir);\n\n // Stop if we've reached the root\n if (parentDir === currentDir) {\n break;\n }\n\n currentDir = parentDir;\n }\n\n return undefined;\n }\n\n /**\n * Load and parse config file using jiti\n */\n private loadConfigFile(configPath: string): ConfigFileContent {\n const jitiLoader = jiti(dirname(configPath), {\n interopDefault: true,\n cache: false,\n extensions: ['.ts', '.js'],\n });\n\n let loaded: unknown;\n try {\n // Use jiti's esmResolve to handle both ESM and CommonJS\n const resolved = jitiLoader.esmResolve(configPath, { try: true });\n if (!resolved) {\n throw new Error(`Could not resolve config file: ${configPath}`);\n }\n\n const resolvedPath = typeof resolved === 'string' ? resolved : fileURLToPath(resolved);\n loaded = jitiLoader(resolvedPath);\n } catch (error) {\n throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Extract config from default export or direct export\n // Handle __esModule pattern from jiti\n let config: unknown;\n if (loaded && typeof loaded === 'object' && '__esModule' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else if (loaded && typeof loaded === 'object' && 'default' in loaded) {\n // Handle case where jiti returns { default: value } without __esModule\n config = (loaded as Record<string, unknown>).default;\n } else {\n config = loaded;\n }\n\n // Handle null/undefined from default export\n if (config === null || config === undefined) {\n return {};\n }\n\n // Handle function configs\n if (typeof config === 'function') {\n try {\n config = config();\n } catch (error) {\n throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Don't support async configs\n if (config instanceof Promise) {\n throw new Error('Async config functions are not supported');\n }\n\n // Handle null/undefined from function\n if (config === null || config === undefined) {\n return {};\n }\n }\n\n // Validate config structure\n if (config && typeof config !== 'object') {\n throw new Error('Config must be an object');\n }\n\n return config ?? {};\n }\n}\n","/**\n * Config detector for TestDino CLI\n * Detects and extracts TestdinoReporter configuration from playwright.config.[ts|js]\n */\n\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport jiti from 'jiti';\nimport type { TestdinoConfig } from '../types/index.js';\nimport { ConfigSyntaxError } from './errors.js';\n\nconst PLAYWRIGHT_CONFIG_FILENAMES = ['playwright.config.ts', 'playwright.config.js'];\nconst TESTDINO_REPORTER_NAMES = ['@testdino/playwright', 'testdino-playwright', 'TestdinoReporter'];\n\n/**\n * Result of config detection\n */\nexport interface ConfigDetectionResult {\n hasReporter: boolean;\n options?: TestdinoConfig;\n configPath?: string;\n}\n\n/**\n * Playwright config structure (simplified)\n */\ninterface PlaywrightConfig {\n reporter?: ReporterConfig;\n [key: string]: unknown;\n}\n\n/**\n * Reporter configuration can be:\n * - string: 'html'\n * - [string]: ['html']\n * - [string, options]: ['html', { outputDir: 'report' }]\n * - Array of above\n */\ntype ReporterConfig = string | [string, Record<string, unknown>?] | Array<string | [string, Record<string, unknown>?]>;\n\n/**\n * Config detector class\n */\nexport class ConfigDetector {\n private cwd: string;\n\n constructor(cwd: string = process.cwd()) {\n this.cwd = cwd;\n }\n\n /**\n * Detect TestdinoReporter in Playwright config\n */\n async detect(): Promise<ConfigDetectionResult> {\n const configPath = this.findPlaywrightConfig();\n\n if (!configPath) {\n return { hasReporter: false };\n }\n\n try {\n const config = this.loadPlaywrightConfig(configPath);\n const result = this.extractTestdinoReporter(config);\n\n return {\n ...result,\n configPath,\n };\n } catch (error) {\n throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Find playwright.config.[ts|js] in current directory\n */\n private findPlaywrightConfig(): string | undefined {\n for (const filename of PLAYWRIGHT_CONFIG_FILENAMES) {\n const configPath = join(this.cwd, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return undefined;\n }\n\n /**\n * Load and parse Playwright config using jiti\n */\n private loadPlaywrightConfig(configPath: string): PlaywrightConfig {\n const jitiLoader = jiti(dirname(configPath), {\n interopDefault: true,\n cache: false,\n extensions: ['.ts', '.js'],\n });\n\n let loaded: unknown;\n try {\n const resolved = jitiLoader.esmResolve(configPath, { try: true });\n if (!resolved) {\n throw new Error(`Could not resolve Playwright config: ${configPath}`);\n }\n\n const resolvedPath = typeof resolved === 'string' ? resolved : fileURLToPath(resolved);\n loaded = jitiLoader(resolvedPath);\n } catch (error) {\n throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Extract config from default export or direct export\n let config: unknown;\n if (loaded && typeof loaded === 'object' && '__esModule' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else if (loaded && typeof loaded === 'object' && 'default' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else {\n config = loaded;\n }\n\n // Handle function configs (Playwright supports this)\n if (typeof config === 'function') {\n try {\n config = config();\n } catch (error) {\n throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Validate config structure\n if (!config || typeof config !== 'object') {\n throw new Error('Playwright config must be an object');\n }\n\n return config as PlaywrightConfig;\n }\n\n /**\n * Extract TestdinoReporter configuration from Playwright config\n */\n private extractTestdinoReporter(config: PlaywrightConfig): Omit<ConfigDetectionResult, 'configPath'> {\n const { reporter } = config;\n\n if (!reporter) {\n return { hasReporter: false };\n }\n\n // Handle single reporter as string\n if (typeof reporter === 'string') {\n if (this.isTestdinoReporter(reporter)) {\n return { hasReporter: true, options: {} };\n }\n return { hasReporter: false };\n }\n\n // Handle single reporter as tuple [name, options]\n if (Array.isArray(reporter) && reporter.length > 0) {\n // Check if it's a single reporter tuple: ['reporter-name', { options }]\n if (typeof reporter[0] === 'string') {\n const [name, options] = reporter as [string, Record<string, unknown>?];\n if (this.isTestdinoReporter(name)) {\n return {\n hasReporter: true,\n options: this.extractOptions(options),\n };\n }\n // If first element is string but not TestDino, might be array of reporters\n // Fall through to array handling\n }\n\n // Handle array of reporters\n for (const item of reporter) {\n if (typeof item === 'string') {\n if (this.isTestdinoReporter(item)) {\n return { hasReporter: true, options: {} };\n }\n } else if (Array.isArray(item) && item.length > 0) {\n const [name, options] = item as [string, Record<string, unknown>?];\n if (this.isTestdinoReporter(name)) {\n return {\n hasReporter: true,\n options: this.extractOptions(options),\n };\n }\n }\n }\n }\n\n return { hasReporter: false };\n }\n\n /**\n * Check if reporter name matches TestdinoReporter\n */\n private isTestdinoReporter(name: string): boolean {\n return TESTDINO_REPORTER_NAMES.some((testdinoName) => name === testdinoName || name.includes(testdinoName));\n }\n\n /**\n * Extract and validate TestdinoConfig options\n */\n private extractOptions(options?: Record<string, unknown>): TestdinoConfig {\n if (!options || typeof options !== 'object') {\n return {};\n }\n\n const config: TestdinoConfig = {};\n\n if ('token' in options && typeof options.token === 'string') {\n config.token = options.token;\n }\n\n if ('serverUrl' in options && typeof options.serverUrl === 'string') {\n config.serverUrl = options.serverUrl;\n }\n\n if ('ciRunId' in options && typeof options.ciRunId === 'string') {\n config.ciRunId = options.ciRunId;\n }\n\n if ('debug' in options && typeof options.debug === 'boolean') {\n config.debug = options.debug;\n }\n\n return config;\n }\n}\n","/**\n * Config merger for TestDino CLI\n * Merges configuration from multiple sources with proper precedence\n */\n\nimport { randomUUID } from 'crypto';\nimport type { CliOptions, MergedConfig, ConfigFileContent } from './types.js';\nimport type { TestdinoConfig } from '../types/index.js';\nimport { TokenMissingError, InvalidServerUrlError } from './errors.js';\n\n/**\n * Config sources for merging\n */\nexport interface ConfigSources {\n env?: Partial<TestdinoConfig>;\n playwrightConfig?: TestdinoConfig;\n testdinoConfig?: ConfigFileContent;\n cliOptions?: CliOptions;\n}\n\n/**\n * Config merger class\n * Merges configs with priority: CLI > testdino.config > playwright.config > env vars\n */\nexport class ConfigMerger {\n private static readonly DEFAULT_SERVER_URL = 'https://api.testdino.com';\n\n /**\n * Merge configurations from all sources\n * Priority (highest to lowest):\n * 1. CLI flags\n * 2. testdino.config.[ts|js]\n * 3. playwright.config reporter options\n * 4. Environment variables\n */\n merge(sources: ConfigSources): MergedConfig {\n const { env = {}, playwrightConfig = {}, testdinoConfig = {}, cliOptions = {} } = sources;\n\n // Merge token (required field)\n const token = this.selectValue(cliOptions.token, testdinoConfig.token, playwrightConfig.token, env.token);\n\n // Merge serverUrl with default fallback\n const serverUrl =\n this.selectValue(cliOptions.serverUrl, testdinoConfig.serverUrl, playwrightConfig.serverUrl, env.serverUrl) ||\n ConfigMerger.DEFAULT_SERVER_URL;\n\n // Merge ciRunId (auto-generate if not provided)\n const ciRunId =\n this.selectValue(cliOptions.ciRunId, testdinoConfig.ciRunId, playwrightConfig.ciRunId) || this.generateCiRunId();\n\n // Merge debug flag (default to false)\n const debug = this.selectValue(cliOptions.debug, testdinoConfig.debug, playwrightConfig.debug, env.debug) ?? false;\n\n // Merge artifacts flag (default to true)\n // CLI --no-artifacts sets noArtifacts=true, which means artifacts=false\n const artifacts =\n cliOptions.noArtifacts === true\n ? false\n : (this.selectValue(testdinoConfig.artifacts, playwrightConfig.artifacts) ?? true);\n\n const mergedConfig: MergedConfig = {\n token,\n serverUrl,\n ciRunId,\n debug,\n artifacts,\n };\n\n // Validate the merged config\n this.validate(mergedConfig);\n\n return mergedConfig;\n }\n\n /**\n * Select first non-undefined value from arguments\n */\n private selectValue<T>(...values: (T | undefined)[]): T | undefined {\n return values.find((value) => value !== undefined && value !== null);\n }\n\n /**\n * Generate a unique CI run ID\n */\n private generateCiRunId(): string {\n return `run-${randomUUID()}`;\n }\n\n /**\n * Validate merged configuration\n */\n private validate(config: MergedConfig): void {\n // Token is required - throw specific error\n if (!config.token || typeof config.token !== 'string' || config.token.trim().length === 0) {\n throw new TokenMissingError();\n }\n\n // ServerUrl must be valid if provided - throw specific error\n if (config.serverUrl) {\n if (typeof config.serverUrl !== 'string' || !this.isValidUrl(config.serverUrl)) {\n throw new InvalidServerUrlError(config.serverUrl);\n }\n }\n\n // Note: ciRunId and debug validations removed as they are handled internally\n // and don't need user-facing error messages\n }\n\n /**\n * Check if string is a valid URL\n */\n private isValidUrl(urlString: string): boolean {\n try {\n const url = new URL(urlString);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n }\n\n /**\n * Get environment variables as config\n */\n static getEnvConfig(): Partial<TestdinoConfig> {\n const config: Partial<TestdinoConfig> = {};\n\n if (process.env.TESTDINO_TOKEN) {\n config.token = process.env.TESTDINO_TOKEN;\n }\n\n if (process.env.TESTDINO_SERVER_URL) {\n config.serverUrl = process.env.TESTDINO_SERVER_URL;\n }\n\n if (process.env.TESTDINO_DEBUG) {\n config.debug = process.env.TESTDINO_DEBUG === 'true' || process.env.TESTDINO_DEBUG === '1';\n }\n\n return config;\n }\n}\n","/**\n * Argument filter for TestDino CLI\n * Filters out TestDino-specific flags from arguments before passing to Playwright\n */\n\n/**\n * TestDino-specific flags that should be removed before passing to Playwright\n */\nconst TESTDINO_FLAGS = ['--token', '-t', '--ci-run-id', '--server-url', '--debug', '--no-artifacts'];\n\n/**\n * Flags that take a value (not boolean flags)\n */\nconst FLAGS_WITH_VALUES = ['--token', '-t', '--ci-run-id', '--server-url'];\n\n/**\n * Argument filter class\n */\nexport class ArgFilter {\n /**\n * Filter TestDino-specific arguments from the argument list\n * Removes both flags and their values\n *\n * @param args - Raw command line arguments\n * @returns Filtered arguments safe to pass to Playwright\n */\n filter(args: string[]): string[] {\n const result: string[] = [];\n let skipNext = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n // Skip this arg if previous flag indicated we should\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n // Check if this is a TestDino flag\n if (this.isTestdinoFlag(arg)) {\n // Check if it's a flag with value (not using = syntax)\n if (this.isFlagWithValue(arg) && !arg.includes('=')) {\n // Skip the next argument (the value)\n skipNext = true;\n }\n // Skip this flag\n continue;\n }\n\n // Check if this is a TestDino flag with = syntax (e.g., --token=value)\n if (this.isTestdinoFlagWithEquals(arg)) {\n // Skip this entire argument\n continue;\n }\n\n // Keep this argument\n result.push(arg);\n }\n\n return result;\n }\n\n /**\n * Check if argument is a TestDino flag\n */\n private isTestdinoFlag(arg: string): boolean {\n // Extract flag name (before = if present)\n const flagName = arg.split('=')[0];\n return TESTDINO_FLAGS.includes(flagName);\n }\n\n /**\n * Check if argument is a TestDino flag with = syntax\n */\n private isTestdinoFlagWithEquals(arg: string): boolean {\n if (!arg.includes('=')) {\n return false;\n }\n const flagName = arg.split('=')[0];\n return TESTDINO_FLAGS.includes(flagName);\n }\n\n /**\n * Check if flag takes a value\n */\n private isFlagWithValue(arg: string): boolean {\n const flagName = arg.split('=')[0];\n return FLAGS_WITH_VALUES.includes(flagName);\n }\n\n /**\n * Get list of TestDino flags (for reference/testing)\n */\n static getTestdinoFlags(): string[] {\n return [...TESTDINO_FLAGS];\n }\n}\n","/**\n * Shared utility functions\n */\n\n/**\n * Sleep utility for retry delays\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Check if debug mode is enabled (standardized check)\n */\nexport function isDebugEnabled(): boolean {\n return process.env.TESTDINO_DEBUG === 'true' || process.env.TESTDINO_DEBUG === '1' || process.env.DEBUG === 'true';\n}\n","/**\n * CLI logger with colors and formatting\n * Provides consistent, user-friendly output\n */\n\nimport chalk from 'chalk';\nimport { isDebugEnabled } from '../utils/index.js';\n\n/**\n * Log levels\n */\nexport enum LogLevel {\n ERROR = 'error',\n WARN = 'warn',\n INFO = 'info',\n SUCCESS = 'success',\n DEBUG = 'debug',\n}\n\n/**\n * CLI Logger class\n */\nexport class Logger {\n private debugEnabled: boolean;\n\n constructor(debugEnabled = false) {\n this.debugEnabled = debugEnabled;\n }\n\n /**\n * Enable or disable debug logging\n */\n setDebug(enabled: boolean): void {\n this.debugEnabled = enabled;\n }\n\n /**\n * Log error message\n */\n error(message: string, error?: Error): void {\n console.error(chalk.red(`\\n✖ Error: ${message}`));\n\n if (error && this.debugEnabled) {\n console.error(chalk.dim('\\nStack trace:'));\n console.error(chalk.dim(error.stack || error.message));\n }\n }\n\n /**\n * Log warning message\n */\n warn(message: string): void {\n console.warn(chalk.yellow(`⚠️ Warning: ${message}`));\n }\n\n /**\n * Log info message\n */\n info(message: string): void {\n console.log(chalk.blue(`ℹ️ ${message}`));\n }\n\n /**\n * Log success message\n */\n success(message: string): void {\n console.log(chalk.green(`✓ ${message}`));\n }\n\n /**\n * Log debug message (only if debug is enabled)\n */\n debug(message: string): void {\n if (this.debugEnabled) {\n console.log(chalk.dim(`[DEBUG] ${message}`));\n }\n }\n\n /**\n * Log a blank line\n */\n newline(): void {\n console.log();\n }\n\n /**\n * Log a section header\n */\n section(title: string): void {\n console.log(chalk.bold.cyan(`\\n${title}`));\n }\n\n /**\n * Log a list item\n */\n listItem(text: string): void {\n console.log(` • ${text}`);\n }\n\n /**\n * Log code/command\n */\n code(text: string): void {\n console.log(chalk.gray(` ${text}`));\n }\n\n /**\n * Format error for display\n */\n formatError(error: Error): string {\n if (this.debugEnabled && error.stack) {\n return error.stack;\n }\n return error.message;\n }\n\n /**\n * Log TestDino CLI banner\n */\n banner(version: string): void {\n console.log(\n chalk.cyan(`\n╔═══════════════════════════════════════════════════════════╗\n║ ║\n║ ${chalk.bold('TestDino Playwright')} v${version.padEnd(36)}║\n║ ${chalk.dim('https://testdino.com')} ║\n║ ║\n╚═══════════════════════════════════════════════════════════╝\n`)\n );\n }\n}\n\n/**\n * Default logger instance\n */\nexport const logger = new Logger(isDebugEnabled());\n","/**\n * Temp config file manager for TestDino CLI\n * Creates and manages temporary configuration files\n */\n\nimport { writeFileSync, unlinkSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { tmpdir } from 'os';\nimport { randomUUID } from 'crypto';\nimport type { MergedConfig, TempConfigInfo } from './types.js';\nimport { Logger } from './logger.js';\n\n/**\n * Temp config manager class\n */\nexport class TempConfigManager {\n private tempFiles: Set<string> = new Set();\n private cleanupHandlersRegistered = false;\n private exitHandler?: () => void;\n private sigintHandler?: () => void;\n private sigtermHandler?: () => void;\n private uncaughtExceptionHandler?: (error: Error) => void;\n private unhandledRejectionHandler?: (reason: unknown) => void;\n private logger: Logger;\n\n constructor(logger?: Logger) {\n this.logger = logger ?? new Logger();\n }\n\n /**\n * Create a temporary config file with the merged configuration\n * @param config - Merged configuration to write\n * @returns Temp config info with path and config\n */\n create(config: MergedConfig): TempConfigInfo {\n const tempPath = this.generateTempPath();\n\n try {\n // Write config as JSON to temp file\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(tempPath, configJson, 'utf-8');\n\n // Track this file for cleanup\n this.tempFiles.add(tempPath);\n\n // Register cleanup handlers on first file creation\n if (!this.cleanupHandlersRegistered) {\n this.registerCleanupHandlers();\n this.cleanupHandlersRegistered = true;\n }\n\n return {\n path: tempPath,\n config,\n };\n } catch (error) {\n throw new Error(\n `Failed to create temp config file: ${tempPath}\\n${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Clean up a specific temp config file\n * @param tempPath - Path to temp file to clean up\n */\n cleanup(tempPath: string): void {\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath);\n }\n this.tempFiles.delete(tempPath);\n } catch {\n // Log error but don't throw - cleanup should be best-effort\n this.logger.warn(`Failed to cleanup temp file: ${tempPath}`);\n }\n }\n\n /**\n * Clean up all tracked temp files\n */\n cleanupAll(): void {\n for (const tempPath of this.tempFiles) {\n this.cleanup(tempPath);\n }\n this.tempFiles.clear();\n }\n\n /**\n * Remove all event handlers (for testing)\n */\n removeHandlers(): void {\n if (this.exitHandler) {\n process.removeListener('exit', this.exitHandler);\n }\n if (this.sigintHandler) {\n process.removeListener('SIGINT', this.sigintHandler);\n }\n if (this.sigtermHandler) {\n process.removeListener('SIGTERM', this.sigtermHandler);\n }\n if (this.uncaughtExceptionHandler) {\n process.removeListener('uncaughtException', this.uncaughtExceptionHandler);\n }\n if (this.unhandledRejectionHandler) {\n process.removeListener('unhandledRejection', this.unhandledRejectionHandler);\n }\n this.cleanupHandlersRegistered = false;\n }\n\n /**\n * Generate unique temp file path\n */\n private generateTempPath(): string {\n const filename = `testdino-config-${randomUUID()}.json`;\n return join(tmpdir(), filename);\n }\n\n /**\n * Register cleanup handlers for process exit and signals\n */\n private registerCleanupHandlers(): void {\n // Normal exit\n this.exitHandler = () => {\n this.cleanupAll();\n };\n process.on('exit', this.exitHandler);\n\n // SIGINT (Ctrl+C)\n this.sigintHandler = () => {\n this.cleanupAll();\n process.exit(130); // Standard exit code for SIGINT\n };\n process.on('SIGINT', this.sigintHandler);\n\n // SIGTERM\n this.sigtermHandler = () => {\n this.cleanupAll();\n process.exit(143); // Standard exit code for SIGTERM\n };\n process.on('SIGTERM', this.sigtermHandler);\n\n // Uncaught exceptions\n this.uncaughtExceptionHandler = (error: Error) => {\n this.logger.error('Uncaught exception', error);\n this.cleanupAll();\n process.exit(1);\n };\n process.on('uncaughtException', this.uncaughtExceptionHandler);\n\n // Unhandled promise rejections\n this.unhandledRejectionHandler = (reason: unknown) => {\n this.logger.error('Unhandled rejection', reason instanceof Error ? reason : undefined);\n this.cleanupAll();\n process.exit(1);\n };\n process.on('unhandledRejection', this.unhandledRejectionHandler);\n }\n\n /**\n * Get list of tracked temp files (for testing)\n */\n getTempFiles(): string[] {\n return Array.from(this.tempFiles);\n }\n}\n","/**\n * Playwright spawner for TestDino CLI\n * Spawns Playwright test process with TestDino configuration\n */\n\nimport { execa, type ExecaError } from 'execa';\nimport type { MergedConfig } from './types.js';\nimport { Logger } from './logger.js';\n\n/**\n * Spawn options\n */\nexport interface PlaywrightSpawnOptions {\n args: string[];\n tempConfigPath: string;\n config: MergedConfig;\n cwd?: string;\n}\n\n/**\n * Spawn result\n */\nexport interface PlaywrightSpawnResult {\n exitCode: number;\n success: boolean;\n}\n\n/**\n * Playwright spawner class\n */\nexport class PlaywrightSpawner {\n private logger: Logger;\n\n constructor(logger?: Logger) {\n this.logger = logger ?? new Logger();\n }\n\n /**\n * Spawn Playwright test process\n * @param options - Spawn options\n * @returns Spawn result with exit code\n */\n async spawn(options: PlaywrightSpawnOptions): Promise<PlaywrightSpawnResult> {\n const { args, tempConfigPath, config, cwd = process.cwd() } = options;\n\n try {\n // Build environment variables\n const env = {\n ...process.env,\n TESTDINO_CLI_CONFIG_PATH: tempConfigPath,\n TESTDINO_TOKEN: config.token,\n TESTDINO_SERVER_URL: config.serverUrl,\n TESTDINO_CI_RUN_ID: config.ciRunId,\n TESTDINO_DEBUG: config.debug ? 'true' : 'false',\n };\n\n // Build Playwright arguments with injected reporter\n const playwrightArgs = ['playwright', 'test', '--reporter', '@testdino/playwright', ...args];\n\n // Spawn Playwright with execa\n const result = await execa('npx', playwrightArgs, {\n stdio: 'inherit', // Forward stdout/stderr in real-time\n cwd,\n env,\n reject: false, // Don't throw on non-zero exit codes\n });\n\n const exitCode = result.exitCode ?? 0;\n\n return {\n exitCode,\n success: exitCode === 0,\n };\n } catch (error) {\n // Handle spawn errors (e.g., Playwright not installed, npx not found)\n return this.handleSpawnError(error);\n }\n }\n\n /**\n * Handle spawn errors\n */\n private handleSpawnError(error: unknown): PlaywrightSpawnResult {\n const execaError = error as ExecaError;\n\n // Check if it's a command not found error\n if (execaError.code === 'ENOENT') {\n this.logger.error('Failed to spawn Playwright');\n this.logger.newline();\n this.logger.info('Playwright is not installed or npx is not available.');\n this.logger.newline();\n this.logger.section('To install Playwright:');\n this.logger.code('npm install -D @playwright/test');\n this.logger.code('npx playwright install');\n return {\n exitCode: 1,\n success: false,\n };\n }\n\n // Check if it's a permission error\n if (execaError.code === 'EACCES') {\n this.logger.error('Permission denied when trying to spawn Playwright');\n this.logger.newline();\n this.logger.info('Please check file permissions and try again.');\n return {\n exitCode: 1,\n success: false,\n };\n }\n\n // Generic error\n this.logger.error('Failed to spawn Playwright');\n this.logger.newline();\n this.logger.info(`Error: ${execaError.message || String(error)}`);\n return {\n exitCode: 1,\n success: false,\n };\n }\n}\n","/**\n * Test command for TestDino CLI\n * Orchestrates all CLI components to run Playwright tests with TestDino reporter\n */\n\nimport { ConfigLoader } from '../config-loader.js';\nimport { ConfigDetector } from '../config-detector.js';\nimport { ConfigMerger } from '../config-merger.js';\nimport { ArgFilter } from '../arg-filter.js';\nimport { TempConfigManager } from '../temp-config.js';\nimport { PlaywrightSpawner } from '../playwright-spawner.js';\nimport { Logger } from '../logger.js';\nimport type { CliOptions } from '../types.js';\nimport type { PlaywrightSpawnResult } from '../playwright-spawner.js';\n\n/**\n * Test command class\n * Orchestrates the full flow of running Playwright tests with TestDino\n */\nexport class TestCommand {\n private configLoader: ConfigLoader;\n private configDetector: ConfigDetector;\n private configMerger: ConfigMerger;\n private argFilter: ArgFilter;\n private tempConfigManager: TempConfigManager;\n private playwrightSpawner: PlaywrightSpawner;\n\n constructor(\n configLoader?: ConfigLoader,\n configDetector?: ConfigDetector,\n configMerger?: ConfigMerger,\n argFilter?: ArgFilter,\n tempConfigManager?: TempConfigManager,\n playwrightSpawner?: PlaywrightSpawner,\n logger?: Logger\n ) {\n this.configLoader = configLoader || new ConfigLoader();\n this.configDetector = configDetector || new ConfigDetector();\n this.configMerger = configMerger || new ConfigMerger();\n this.argFilter = argFilter || new ArgFilter();\n this.tempConfigManager = tempConfigManager || new TempConfigManager(logger);\n this.playwrightSpawner = playwrightSpawner || new PlaywrightSpawner(logger);\n }\n\n /**\n * Execute the test command\n * @param options - CLI options from commander\n * @param args - Remaining arguments to pass to Playwright\n * @returns Spawn result with exit code\n */\n async execute(options: CliOptions, args: string[]): Promise<PlaywrightSpawnResult> {\n let tempConfigPath: string | undefined;\n\n try {\n // 1. Load testdino.config.[ts|js]\n const testdinoConfigResult = await this.configLoader.load();\n\n // 2. Detect playwright.config.[ts|js] and TestdinoReporter\n const playwrightConfigResult = await this.configDetector.detect();\n\n // 3. Get environment variables\n const envConfig = ConfigMerger.getEnvConfig();\n\n // 4. Merge all configs with proper priority\n const mergedConfig = this.configMerger.merge({\n env: envConfig,\n playwrightConfig: playwrightConfigResult.options,\n testdinoConfig: testdinoConfigResult.config,\n cliOptions: options,\n });\n\n // 5. Create temp config file\n const tempConfigInfo = this.tempConfigManager.create(mergedConfig);\n tempConfigPath = tempConfigInfo.path;\n\n // 6. Filter TestDino-specific arguments\n const filteredArgs = this.argFilter.filter(args);\n\n // 7. Spawn Playwright with filtered args and config\n const result = await this.playwrightSpawner.spawn({\n args: filteredArgs,\n tempConfigPath,\n config: mergedConfig,\n });\n\n return result;\n } finally {\n // 8. Always cleanup temp config file\n if (tempConfigPath) {\n this.tempConfigManager.cleanup(tempConfigPath);\n }\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * TestDino Playwright CLI\n * Main entry point for the tdpw command\n */\n\nimport { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { TestCommand } from './commands/test.js';\nimport { Logger } from './logger.js';\nimport { TestDinoError } from './errors.js';\nimport { isDebugEnabled } from '../utils/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Get package version\n */\nfunction getVersion(): string {\n try {\n // In built dist, package.json is two levels up\n const packagePath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return packageJson.version;\n } catch {\n return '0.0.0';\n }\n}\n\n// Logger instance created at program start, debug enabled via env vars initially\nconst logger = new Logger(isDebugEnabled());\n\n/**\n * Build the CLI program\n */\nfunction buildProgram(): Command {\n const program = new Command()\n .name('tdpw')\n .description('Run Playwright tests with TestDino reporting')\n .version(getVersion(), '-v, --version', 'Output the current version')\n .helpOption('-h, --help', 'Display help for command');\n\n // Test command\n program\n .command('test')\n .description('Run Playwright tests with TestDino reporter')\n .option('-t, --token <token>', 'TestDino authentication token')\n .option('--ci-run-id <id>', 'CI run ID for grouping test runs')\n .option('--server-url <url>', 'TestDino server URL')\n .option('--debug', 'Enable debug logging')\n .option('--no-artifacts', 'Disable artifact uploads (screenshots, videos, traces)')\n .allowUnknownOption()\n .allowExcessArguments()\n .action(async (options, command) => {\n // Update logger debug state based on CLI option\n if (options.debug) {\n logger.setDebug(true);\n }\n\n try {\n // Get remaining arguments (everything after 'test')\n const args = command.args || [];\n\n // Create and execute test command\n const testCommand = new TestCommand();\n const result = await testCommand.execute(options, args);\n\n // Exit with Playwright's exit code\n process.exit(result.exitCode);\n } catch (error) {\n if (error instanceof TestDinoError) {\n // Custom errors have well-formatted messages\n logger.error(error.message);\n } else {\n logger.error(\n error instanceof Error ? error.message : String(error),\n error instanceof Error ? error : undefined\n );\n }\n\n process.exit(1);\n }\n });\n\n return program;\n}\n\n/**\n * Main CLI entry point\n */\nasync function main(): Promise<void> {\n try {\n logger.banner(getVersion());\n\n const program = buildProgram();\n await program.parseAsync(process.argv);\n } catch (error) {\n if (error instanceof TestDinoError) {\n logger.error(error.message);\n } else {\n logger.error(error instanceof Error ? error.message : String(error), error instanceof Error ? error : undefined);\n }\n\n process.exit(1);\n }\n}\n\n// Run CLI\nmain().catch((error) => {\n logger.error('Unexpected error', error instanceof Error ? error : undefined);\n process.exit(1);\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/errors.ts","../../src/cli/config-loader.ts","../../src/cli/config-detector.ts","../../src/cli/config-merger.ts","../../src/cli/arg-filter.ts","../../src/utils/index.ts","../../src/cli/logger.ts","../../src/cli/temp-config.ts","../../src/cli/playwright-spawner.ts","../../src/cli/commands/test.ts","../../src/cli/index.ts"],"names":["join","existsSync","statSync","dirname","jiti","fileURLToPath","randomUUID","chalk","logger","writeFileSync","unlinkSync","tmpdir","execa","__filename","__dirname","readFileSync","Command"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Custom error classes for TestDino CLI\n * Provides clear, actionable error messages with suggestions\n */\n\n/**\n * Base class for all TestDino CLI errors\n */\nexport class TestDinoError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'TestDinoError';\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when authentication token is missing\n */\nexport class TokenMissingError extends TestDinoError {\n constructor() {\n const message = `Token is required to run tests with TestDino\n\nProvide token via:\n • CLI flag: npx tdpw test --token <your-token>\n • Environment: export TESTDINO_TOKEN=<your-token>\n • Config file: Create testdino.config.ts with token\n\nGet your token at: https://testdino.com/settings`;\n\n super(message);\n this.name = 'TokenMissingError';\n }\n}\n\n/**\n * Error thrown when config file has syntax errors\n */\nexport class ConfigSyntaxError extends TestDinoError {\n constructor(configPath: string, originalError: Error) {\n const message = `Failed to load ${configPath}\n\n${originalError.message}\n\nFix the syntax error and try again.`;\n\n super(message);\n this.name = 'ConfigSyntaxError';\n }\n}\n\n/**\n * Error thrown when Playwright is not installed\n */\nexport class PlaywrightNotInstalledError extends TestDinoError {\n constructor() {\n const message = `Playwright is not installed\n\nInstall Playwright:\n npm install -D @playwright/test\n\nThen run:\n npx playwright install`;\n\n super(message);\n this.name = 'PlaywrightNotInstalledError';\n }\n}\n\n/**\n * Error thrown when config file cannot be found\n */\nexport class ConfigNotFoundError extends TestDinoError {\n constructor(configPath: string) {\n const message = `Config file not found: ${configPath}\n\nMake sure the file exists and is readable.`;\n\n super(message);\n this.name = 'ConfigNotFoundError';\n }\n}\n\n/**\n * Error thrown when server URL is invalid\n */\nexport class InvalidServerUrlError extends TestDinoError {\n constructor(url: string) {\n const message = `Invalid server URL: ${url}\n\nServer URL must be a valid HTTP or HTTPS URL.\n\nExamples:\n • https://api.testdino.com\n • https://api-v0.testdino.com\n • https://global.testdino.com`;\n\n super(message);\n this.name = 'InvalidServerUrlError';\n }\n}\n\n/**\n * Error thrown when Playwright execution fails\n */\nexport class PlaywrightExecutionError extends TestDinoError {\n constructor(exitCode: number, message?: string) {\n const errorMessage = message\n ? `Playwright execution failed: ${message}`\n : `Playwright execution failed with exit code ${exitCode}`;\n\n super(errorMessage);\n this.name = 'PlaywrightExecutionError';\n }\n}\n\n/**\n * Error thrown when permission is denied\n */\nexport class PermissionDeniedError extends TestDinoError {\n constructor(path: string) {\n const message = `Permission denied: ${path}\n\nCheck file permissions and try again.`;\n\n super(message);\n this.name = 'PermissionDeniedError';\n }\n}\n","/**\n * Config file loader for TestDino CLI\n * Searches for testdino.config.[ts|js] up the directory tree\n */\n\nimport { existsSync, statSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport jiti from 'jiti';\nimport type { ConfigFileContent } from './types.js';\nimport { ConfigSyntaxError } from './errors.js';\n\nconst CONFIG_FILENAMES = ['testdino.config.ts', 'testdino.config.js'];\n\n/**\n * Result of config loading\n */\nexport interface ConfigLoadResult {\n config: ConfigFileContent;\n configPath?: string;\n}\n\n/**\n * Config loader class\n */\nexport class ConfigLoader {\n private cwd: string;\n\n constructor(cwd: string = process.cwd()) {\n this.cwd = cwd;\n }\n\n /**\n * Load config file from current directory or parent directories\n */\n async load(): Promise<ConfigLoadResult> {\n const configPath = this.findConfigFile();\n\n if (!configPath) {\n return { config: {} };\n }\n\n try {\n const config = this.loadConfigFile(configPath);\n return { config, configPath };\n } catch (error) {\n throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Find config file by searching up directory tree\n * Stops at .git directory\n */\n private findConfigFile(): string | undefined {\n let currentDir = this.cwd;\n\n while (true) {\n // Check for config files in current directory\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n\n // Check if we've reached .git directory\n const gitDir = join(currentDir, '.git');\n if (existsSync(gitDir) && statSync(gitDir).isDirectory()) {\n // Check one more time in the git root directory\n for (const filename of CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n // Stop at git root\n break;\n }\n\n // Move to parent directory\n const parentDir = dirname(currentDir);\n\n // Stop if we've reached the root\n if (parentDir === currentDir) {\n break;\n }\n\n currentDir = parentDir;\n }\n\n return undefined;\n }\n\n /**\n * Load and parse config file using jiti\n */\n private loadConfigFile(configPath: string): ConfigFileContent {\n const jitiLoader = jiti(dirname(configPath), {\n interopDefault: true,\n cache: false,\n extensions: ['.ts', '.js'],\n });\n\n let loaded: unknown;\n try {\n // Use jiti's esmResolve to handle both ESM and CommonJS\n const resolved = jitiLoader.esmResolve(configPath, { try: true });\n if (!resolved) {\n throw new Error(`Could not resolve config file: ${configPath}`);\n }\n\n const resolvedPath = typeof resolved === 'string' ? resolved : fileURLToPath(resolved);\n loaded = jitiLoader(resolvedPath);\n } catch (error) {\n throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Extract config from default export or direct export\n // Handle __esModule pattern from jiti\n let config: unknown;\n if (loaded && typeof loaded === 'object' && '__esModule' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else if (loaded && typeof loaded === 'object' && 'default' in loaded) {\n // Handle case where jiti returns { default: value } without __esModule\n config = (loaded as Record<string, unknown>).default;\n } else {\n config = loaded;\n }\n\n // Handle null/undefined from default export\n if (config === null || config === undefined) {\n return {};\n }\n\n // Handle function configs\n if (typeof config === 'function') {\n try {\n config = config();\n } catch (error) {\n throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Don't support async configs\n if (config instanceof Promise) {\n throw new Error('Async config functions are not supported');\n }\n\n // Handle null/undefined from function\n if (config === null || config === undefined) {\n return {};\n }\n }\n\n // Validate config structure\n if (config && typeof config !== 'object') {\n throw new Error('Config must be an object');\n }\n\n return config ?? {};\n }\n}\n","/**\n * Config detector for TestDino CLI\n * Detects and extracts TestdinoReporter configuration from playwright.config.[ts|js]\n */\n\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport jiti from 'jiti';\nimport type { TestdinoConfig } from '../types/index.js';\nimport type { CoverageConfig } from '../code-coverage/types.js';\nimport { ConfigSyntaxError } from './errors.js';\n\nconst PLAYWRIGHT_CONFIG_FILENAMES = ['playwright.config.ts', 'playwright.config.js'];\nconst TESTDINO_REPORTER_NAMES = ['@testdino/playwright', 'testdino-playwright', 'TestdinoReporter'];\n\n/**\n * Result of config detection\n */\nexport interface ConfigDetectionResult {\n hasReporter: boolean;\n options?: TestdinoConfig;\n configPath?: string;\n}\n\n/**\n * Playwright config structure (simplified)\n */\ninterface PlaywrightConfig {\n reporter?: ReporterConfig;\n [key: string]: unknown;\n}\n\n/**\n * Reporter configuration can be:\n * - string: 'html'\n * - [string]: ['html']\n * - [string, options]: ['html', { outputDir: 'report' }]\n * - Array of above\n */\ntype ReporterConfig = string | [string, Record<string, unknown>?] | Array<string | [string, Record<string, unknown>?]>;\n\n/**\n * Config detector class\n */\nexport class ConfigDetector {\n private cwd: string;\n\n constructor(cwd: string = process.cwd()) {\n this.cwd = cwd;\n }\n\n /**\n * Detect TestdinoReporter in Playwright config\n */\n async detect(): Promise<ConfigDetectionResult> {\n const configPath = this.findPlaywrightConfig();\n\n if (!configPath) {\n return { hasReporter: false };\n }\n\n try {\n const config = this.loadPlaywrightConfig(configPath);\n const result = this.extractTestdinoReporter(config);\n\n return {\n ...result,\n configPath,\n };\n } catch (error) {\n throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Find playwright.config.[ts|js] in current directory\n */\n private findPlaywrightConfig(): string | undefined {\n for (const filename of PLAYWRIGHT_CONFIG_FILENAMES) {\n const configPath = join(this.cwd, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n return undefined;\n }\n\n /**\n * Load and parse Playwright config using jiti\n */\n private loadPlaywrightConfig(configPath: string): PlaywrightConfig {\n const jitiLoader = jiti(dirname(configPath), {\n interopDefault: true,\n cache: false,\n extensions: ['.ts', '.js'],\n });\n\n let loaded: unknown;\n try {\n const resolved = jitiLoader.esmResolve(configPath, { try: true });\n if (!resolved) {\n throw new Error(`Could not resolve Playwright config: ${configPath}`);\n }\n\n const resolvedPath = typeof resolved === 'string' ? resolved : fileURLToPath(resolved);\n loaded = jitiLoader(resolvedPath);\n } catch (error) {\n throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);\n }\n\n // Extract config from default export or direct export\n let config: unknown;\n if (loaded && typeof loaded === 'object' && '__esModule' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else if (loaded && typeof loaded === 'object' && 'default' in loaded) {\n config = (loaded as Record<string, unknown>).default;\n } else {\n config = loaded;\n }\n\n // Handle function configs (Playwright supports this)\n if (typeof config === 'function') {\n try {\n config = config();\n } catch (error) {\n throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n // Validate config structure\n if (!config || typeof config !== 'object') {\n throw new Error('Playwright config must be an object');\n }\n\n return config as PlaywrightConfig;\n }\n\n /**\n * Extract TestdinoReporter configuration from Playwright config\n */\n private extractTestdinoReporter(config: PlaywrightConfig): Omit<ConfigDetectionResult, 'configPath'> {\n const { reporter } = config;\n\n if (!reporter) {\n return { hasReporter: false };\n }\n\n // Handle single reporter as string\n if (typeof reporter === 'string') {\n if (this.isTestdinoReporter(reporter)) {\n return { hasReporter: true, options: {} };\n }\n return { hasReporter: false };\n }\n\n // Handle single reporter as tuple [name, options]\n if (Array.isArray(reporter) && reporter.length > 0) {\n // Check if it's a single reporter tuple: ['reporter-name', { options }]\n if (typeof reporter[0] === 'string') {\n const [name, options] = reporter as [string, Record<string, unknown>?];\n if (this.isTestdinoReporter(name)) {\n return {\n hasReporter: true,\n options: this.extractOptions(options),\n };\n }\n // If first element is string but not TestDino, might be array of reporters\n // Fall through to array handling\n }\n\n // Handle array of reporters\n for (const item of reporter) {\n if (typeof item === 'string') {\n if (this.isTestdinoReporter(item)) {\n return { hasReporter: true, options: {} };\n }\n } else if (Array.isArray(item) && item.length > 0) {\n const [name, options] = item as [string, Record<string, unknown>?];\n if (this.isTestdinoReporter(name)) {\n return {\n hasReporter: true,\n options: this.extractOptions(options),\n };\n }\n }\n }\n }\n\n return { hasReporter: false };\n }\n\n /**\n * Check if reporter name matches TestdinoReporter\n */\n private isTestdinoReporter(name: string): boolean {\n return TESTDINO_REPORTER_NAMES.some((testdinoName) => name === testdinoName || name.includes(testdinoName));\n }\n\n /**\n * Extract and validate TestdinoConfig options\n */\n private extractOptions(options?: Record<string, unknown>): TestdinoConfig {\n if (!options || typeof options !== 'object') {\n return {};\n }\n\n const config: TestdinoConfig = {};\n\n if ('token' in options && typeof options.token === 'string') {\n config.token = options.token;\n }\n\n if ('serverUrl' in options && typeof options.serverUrl === 'string') {\n config.serverUrl = options.serverUrl;\n }\n\n if ('ciRunId' in options && typeof options.ciRunId === 'string') {\n config.ciRunId = options.ciRunId;\n }\n\n if ('debug' in options && typeof options.debug === 'boolean') {\n config.debug = options.debug;\n }\n\n if ('coverage' in options && typeof options.coverage === 'object' && options.coverage !== null) {\n config.coverage = this.extractCoverageConfig(options.coverage as Record<string, unknown>);\n }\n\n return config;\n }\n\n /**\n * Extract and validate CoverageConfig from reporter options\n */\n private extractCoverageConfig(raw: Record<string, unknown>): CoverageConfig {\n const config: CoverageConfig = {\n enabled: typeof raw.enabled === 'boolean' ? raw.enabled : false,\n };\n\n if (Array.isArray(raw.projects)) {\n config.projects = raw.projects.filter((p): p is string => typeof p === 'string');\n }\n\n if (typeof raw.localReport === 'boolean') {\n config.localReport = raw.localReport;\n }\n\n if (typeof raw.localReportDir === 'string') {\n config.localReportDir = raw.localReportDir;\n }\n\n if (Array.isArray(raw.include)) {\n config.include = raw.include.filter((p): p is string => typeof p === 'string');\n }\n\n if (Array.isArray(raw.exclude)) {\n config.exclude = raw.exclude.filter((p): p is string => typeof p === 'string');\n }\n\n if (typeof raw.thresholds === 'object' && raw.thresholds !== null) {\n const t = raw.thresholds as Record<string, unknown>;\n config.thresholds = {};\n if (typeof t.statements === 'number') config.thresholds.statements = t.statements;\n if (typeof t.branches === 'number') config.thresholds.branches = t.branches;\n if (typeof t.functions === 'number') config.thresholds.functions = t.functions;\n if (typeof t.lines === 'number') config.thresholds.lines = t.lines;\n }\n\n return config;\n }\n}\n","/**\n * Config merger for TestDino CLI\n * Merges configuration from multiple sources with proper precedence\n */\n\nimport { randomUUID } from 'crypto';\nimport type { CliOptions, MergedConfig, ConfigFileContent } from './types.js';\nimport type { TestdinoConfig } from '../types/index.js';\nimport type { CoverageConfig } from '../code-coverage/types.js';\nimport { TokenMissingError, InvalidServerUrlError } from './errors.js';\n\n/**\n * Config sources for merging\n */\nexport interface ConfigSources {\n env?: Partial<TestdinoConfig>;\n playwrightConfig?: TestdinoConfig;\n testdinoConfig?: ConfigFileContent;\n cliOptions?: CliOptions;\n}\n\n/**\n * Config merger class\n * Merges configs with priority: CLI > testdino.config > playwright.config > env vars\n */\nexport class ConfigMerger {\n private static readonly DEFAULT_SERVER_URL = 'https://api.testdino.com';\n\n /**\n * Merge configurations from all sources\n * Priority (highest to lowest):\n * 1. CLI flags\n * 2. testdino.config.[ts|js]\n * 3. playwright.config reporter options\n * 4. Environment variables\n */\n merge(sources: ConfigSources): MergedConfig {\n const { env = {}, playwrightConfig = {}, testdinoConfig = {}, cliOptions = {} } = sources;\n\n // Merge token (required field)\n const token = this.selectValue(cliOptions.token, testdinoConfig.token, playwrightConfig.token, env.token);\n\n // Merge serverUrl with default fallback\n const serverUrl =\n this.selectValue(cliOptions.serverUrl, testdinoConfig.serverUrl, playwrightConfig.serverUrl, env.serverUrl) ||\n ConfigMerger.DEFAULT_SERVER_URL;\n\n // Merge ciRunId (auto-generate if not provided)\n const ciRunId =\n this.selectValue(cliOptions.ciRunId, testdinoConfig.ciRunId, playwrightConfig.ciRunId) || this.generateCiRunId();\n\n // Merge debug flag (default to false)\n const debug = this.selectValue(cliOptions.debug, testdinoConfig.debug, playwrightConfig.debug, env.debug) ?? false;\n\n // Merge artifacts flag (default to true)\n // CLI --no-artifacts sets noArtifacts=true, which means artifacts=false\n const artifacts =\n cliOptions.noArtifacts === true\n ? false\n : (this.selectValue(testdinoConfig.artifacts, playwrightConfig.artifacts) ?? true);\n\n // Merge coverage configuration\n // CLI --coverage only toggles enabled; other fields come from config files\n const coverage = this.mergeCoverageConfig(cliOptions.coverage, testdinoConfig.coverage, playwrightConfig.coverage);\n\n const mergedConfig: MergedConfig = {\n token,\n serverUrl,\n ciRunId,\n debug,\n artifacts,\n ...(coverage ? { coverage } : {}),\n };\n\n // Validate the merged config\n this.validate(mergedConfig);\n\n return mergedConfig;\n }\n\n /**\n * Merge coverage configuration from CLI flag and config files.\n * CLI --coverage only toggles enabled; other fields come from config files.\n */\n private mergeCoverageConfig(\n cliCoverage: boolean | undefined,\n testdinoCoverage: CoverageConfig | undefined,\n playwrightCoverage: CoverageConfig | undefined\n ): CoverageConfig | undefined {\n const baseConfig = testdinoCoverage ?? playwrightCoverage;\n\n if (!baseConfig && cliCoverage === undefined) return undefined;\n\n if (cliCoverage !== undefined) {\n return { ...(baseConfig || { enabled: false }), enabled: cliCoverage };\n }\n\n return baseConfig;\n }\n\n /**\n * Select first non-undefined value from arguments\n */\n private selectValue<T>(...values: (T | undefined)[]): T | undefined {\n return values.find((value) => value !== undefined && value !== null);\n }\n\n /**\n * Generate a unique CI run ID\n */\n private generateCiRunId(): string {\n return `run-${randomUUID()}`;\n }\n\n /**\n * Validate merged configuration\n */\n private validate(config: MergedConfig): void {\n // Token is required - throw specific error\n if (!config.token || typeof config.token !== 'string' || config.token.trim().length === 0) {\n throw new TokenMissingError();\n }\n\n // ServerUrl must be valid if provided - throw specific error\n if (config.serverUrl) {\n if (typeof config.serverUrl !== 'string' || !this.isValidUrl(config.serverUrl)) {\n throw new InvalidServerUrlError(config.serverUrl);\n }\n }\n\n // Note: ciRunId and debug validations removed as they are handled internally\n // and don't need user-facing error messages\n }\n\n /**\n * Check if string is a valid URL\n */\n private isValidUrl(urlString: string): boolean {\n try {\n const url = new URL(urlString);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch {\n return false;\n }\n }\n\n /**\n * Get environment variables as config\n */\n static getEnvConfig(): Partial<TestdinoConfig> {\n const config: Partial<TestdinoConfig> = {};\n\n if (process.env.TESTDINO_TOKEN) {\n config.token = process.env.TESTDINO_TOKEN;\n }\n\n if (process.env.TESTDINO_SERVER_URL) {\n config.serverUrl = process.env.TESTDINO_SERVER_URL;\n }\n\n if (process.env.TESTDINO_DEBUG) {\n config.debug = process.env.TESTDINO_DEBUG === 'true' || process.env.TESTDINO_DEBUG === '1';\n }\n\n return config;\n }\n}\n","/**\n * Argument filter for TestDino CLI\n * Filters out TestDino-specific flags from arguments before passing to Playwright\n */\n\n/**\n * TestDino-specific flags that should be removed before passing to Playwright\n */\nconst TESTDINO_FLAGS = ['--token', '-t', '--ci-run-id', '--server-url', '--debug', '--no-artifacts', '--coverage'];\n\n/**\n * Flags that take a value (not boolean flags)\n */\nconst FLAGS_WITH_VALUES = ['--token', '-t', '--ci-run-id', '--server-url'];\n\n/**\n * Argument filter class\n */\nexport class ArgFilter {\n /**\n * Filter TestDino-specific arguments from the argument list\n * Removes both flags and their values\n *\n * @param args - Raw command line arguments\n * @returns Filtered arguments safe to pass to Playwright\n */\n filter(args: string[]): string[] {\n const result: string[] = [];\n let skipNext = false;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n // Skip this arg if previous flag indicated we should\n if (skipNext) {\n skipNext = false;\n continue;\n }\n\n // Check if this is a TestDino flag\n if (this.isTestdinoFlag(arg)) {\n // Check if it's a flag with value (not using = syntax)\n if (this.isFlagWithValue(arg) && !arg.includes('=')) {\n // Skip the next argument (the value)\n skipNext = true;\n }\n // Skip this flag\n continue;\n }\n\n // Check if this is a TestDino flag with = syntax (e.g., --token=value)\n if (this.isTestdinoFlagWithEquals(arg)) {\n // Skip this entire argument\n continue;\n }\n\n // Keep this argument\n result.push(arg);\n }\n\n return result;\n }\n\n /**\n * Check if argument is a TestDino flag\n */\n private isTestdinoFlag(arg: string): boolean {\n // Extract flag name (before = if present)\n const flagName = arg.split('=')[0];\n return TESTDINO_FLAGS.includes(flagName);\n }\n\n /**\n * Check if argument is a TestDino flag with = syntax\n */\n private isTestdinoFlagWithEquals(arg: string): boolean {\n if (!arg.includes('=')) {\n return false;\n }\n const flagName = arg.split('=')[0];\n return TESTDINO_FLAGS.includes(flagName);\n }\n\n /**\n * Check if flag takes a value\n */\n private isFlagWithValue(arg: string): boolean {\n const flagName = arg.split('=')[0];\n return FLAGS_WITH_VALUES.includes(flagName);\n }\n\n /**\n * Get list of TestDino flags (for reference/testing)\n */\n static getTestdinoFlags(): string[] {\n return [...TESTDINO_FLAGS];\n }\n}\n","/**\n * Shared utility functions\n */\n\nimport { relative } from 'path';\n\n/**\n * Normalize file path to repo-root-relative.\n * Ensures consistent paths across different machines and shards.\n */\nexport function normalizePath(filePath: string, rootDir?: string): string {\n if (rootDir && filePath.startsWith(rootDir)) {\n return relative(rootDir, filePath);\n }\n return filePath;\n}\n\n/**\n * Sleep utility for retry delays\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Check if debug mode is enabled (standardized check)\n */\nexport function isDebugEnabled(): boolean {\n return process.env.TESTDINO_DEBUG === 'true' || process.env.TESTDINO_DEBUG === '1' || process.env.DEBUG === 'true';\n}\n","/**\n * CLI logger with colors and formatting\n * Provides consistent, user-friendly output\n */\n\nimport chalk from 'chalk';\nimport { isDebugEnabled } from '../utils/index.js';\n\n/**\n * Log levels\n */\nexport enum LogLevel {\n ERROR = 'error',\n WARN = 'warn',\n INFO = 'info',\n SUCCESS = 'success',\n DEBUG = 'debug',\n}\n\n/**\n * CLI Logger class\n */\nexport class Logger {\n private debugEnabled: boolean;\n\n constructor(debugEnabled = false) {\n this.debugEnabled = debugEnabled;\n }\n\n /**\n * Enable or disable debug logging\n */\n setDebug(enabled: boolean): void {\n this.debugEnabled = enabled;\n }\n\n /**\n * Log error message\n */\n error(message: string, error?: Error): void {\n console.error(chalk.red(`\\n✖ Error: ${message}`));\n\n if (error && this.debugEnabled) {\n console.error(chalk.dim('\\nStack trace:'));\n console.error(chalk.dim(error.stack || error.message));\n }\n }\n\n /**\n * Log warning message\n */\n warn(message: string): void {\n console.warn(chalk.yellow(`⚠️ Warning: ${message}`));\n }\n\n /**\n * Log info message\n */\n info(message: string): void {\n console.log(chalk.blue(`ℹ️ ${message}`));\n }\n\n /**\n * Log success message\n */\n success(message: string): void {\n console.log(chalk.green(`✓ ${message}`));\n }\n\n /**\n * Log debug message (only if debug is enabled)\n */\n debug(message: string): void {\n if (this.debugEnabled) {\n console.log(chalk.dim(`[DEBUG] ${message}`));\n }\n }\n\n /**\n * Log a blank line\n */\n newline(): void {\n console.log();\n }\n\n /**\n * Log a section header\n */\n section(title: string): void {\n console.log(chalk.bold.cyan(`\\n${title}`));\n }\n\n /**\n * Log a list item\n */\n listItem(text: string): void {\n console.log(` • ${text}`);\n }\n\n /**\n * Log code/command\n */\n code(text: string): void {\n console.log(chalk.gray(` ${text}`));\n }\n\n /**\n * Format error for display\n */\n formatError(error: Error): string {\n if (this.debugEnabled && error.stack) {\n return error.stack;\n }\n return error.message;\n }\n\n /**\n * Log TestDino CLI banner\n */\n banner(version: string): void {\n console.log(\n chalk.cyan(`\n╔═══════════════════════════════════════════════════════════╗\n║ ║\n║ ${chalk.bold('TestDino Playwright')} v${version.padEnd(36)}║\n║ ${chalk.dim('https://testdino.com')} ║\n║ ║\n╚═══════════════════════════════════════════════════════════╝\n`)\n );\n }\n}\n\n/**\n * Default logger instance\n */\nexport const logger = new Logger(isDebugEnabled());\n","/**\n * Temp config file manager for TestDino CLI\n * Creates and manages temporary configuration files\n */\n\nimport { writeFileSync, unlinkSync, existsSync } from 'fs';\nimport { join } from 'path';\nimport { tmpdir } from 'os';\nimport { randomUUID } from 'crypto';\nimport type { MergedConfig, TempConfigInfo } from './types.js';\nimport { Logger } from './logger.js';\n\n/**\n * Temp config manager class\n */\nexport class TempConfigManager {\n private tempFiles: Set<string> = new Set();\n private cleanupHandlersRegistered = false;\n private exitHandler?: () => void;\n private sigintHandler?: () => void;\n private sigtermHandler?: () => void;\n private uncaughtExceptionHandler?: (error: Error) => void;\n private unhandledRejectionHandler?: (reason: unknown) => void;\n private logger: Logger;\n\n constructor(logger?: Logger) {\n this.logger = logger ?? new Logger();\n }\n\n /**\n * Create a temporary config file with the merged configuration\n * @param config - Merged configuration to write\n * @returns Temp config info with path and config\n */\n create(config: MergedConfig): TempConfigInfo {\n const tempPath = this.generateTempPath();\n\n try {\n // Write config as JSON to temp file\n const configJson = JSON.stringify(config, null, 2);\n writeFileSync(tempPath, configJson, 'utf-8');\n\n // Track this file for cleanup\n this.tempFiles.add(tempPath);\n\n // Register cleanup handlers on first file creation\n if (!this.cleanupHandlersRegistered) {\n this.registerCleanupHandlers();\n this.cleanupHandlersRegistered = true;\n }\n\n return {\n path: tempPath,\n config,\n };\n } catch (error) {\n throw new Error(\n `Failed to create temp config file: ${tempPath}\\n${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * Clean up a specific temp config file\n * @param tempPath - Path to temp file to clean up\n */\n cleanup(tempPath: string): void {\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath);\n }\n this.tempFiles.delete(tempPath);\n } catch {\n // Log error but don't throw - cleanup should be best-effort\n this.logger.warn(`Failed to cleanup temp file: ${tempPath}`);\n }\n }\n\n /**\n * Clean up all tracked temp files\n */\n cleanupAll(): void {\n for (const tempPath of this.tempFiles) {\n this.cleanup(tempPath);\n }\n this.tempFiles.clear();\n }\n\n /**\n * Remove all event handlers (for testing)\n */\n removeHandlers(): void {\n if (this.exitHandler) {\n process.removeListener('exit', this.exitHandler);\n }\n if (this.sigintHandler) {\n process.removeListener('SIGINT', this.sigintHandler);\n }\n if (this.sigtermHandler) {\n process.removeListener('SIGTERM', this.sigtermHandler);\n }\n if (this.uncaughtExceptionHandler) {\n process.removeListener('uncaughtException', this.uncaughtExceptionHandler);\n }\n if (this.unhandledRejectionHandler) {\n process.removeListener('unhandledRejection', this.unhandledRejectionHandler);\n }\n this.cleanupHandlersRegistered = false;\n }\n\n /**\n * Generate unique temp file path\n */\n private generateTempPath(): string {\n const filename = `testdino-config-${randomUUID()}.json`;\n return join(tmpdir(), filename);\n }\n\n /**\n * Register cleanup handlers for process exit and signals\n */\n private registerCleanupHandlers(): void {\n // Normal exit\n this.exitHandler = () => {\n this.cleanupAll();\n };\n process.on('exit', this.exitHandler);\n\n // SIGINT (Ctrl+C)\n this.sigintHandler = () => {\n // Remove handler to prevent duplicate calls on repeated Ctrl+C\n if (this.sigintHandler) {\n process.removeListener('SIGINT', this.sigintHandler);\n }\n // Don't call cleanupAll() or process.exit() here.\n // Let the spawned Playwright process handle the signal and exit naturally.\n // The reporter needs time to send the run:end event with status='interrupted'.\n // Cleanup will happen in TestCommand's finally block after the child exits.\n };\n process.on('SIGINT', this.sigintHandler);\n\n // SIGTERM\n this.sigtermHandler = () => {\n // Remove handler to prevent duplicate calls\n if (this.sigtermHandler) {\n process.removeListener('SIGTERM', this.sigtermHandler);\n }\n // Don't call cleanupAll() or process.exit() - same reasoning as SIGINT\n };\n process.on('SIGTERM', this.sigtermHandler);\n\n // Uncaught exceptions\n this.uncaughtExceptionHandler = (error: Error) => {\n this.logger.error('Uncaught exception', error);\n this.cleanupAll();\n process.exit(1);\n };\n process.on('uncaughtException', this.uncaughtExceptionHandler);\n\n // Unhandled promise rejections\n this.unhandledRejectionHandler = (reason: unknown) => {\n this.logger.error('Unhandled rejection', reason instanceof Error ? reason : undefined);\n this.cleanupAll();\n process.exit(1);\n };\n process.on('unhandledRejection', this.unhandledRejectionHandler);\n }\n\n /**\n * Get list of tracked temp files (for testing)\n */\n getTempFiles(): string[] {\n return Array.from(this.tempFiles);\n }\n}\n","/**\n * Playwright spawner for TestDino CLI\n * Spawns Playwright test process with TestDino configuration\n */\n\nimport { execa, type ExecaError } from 'execa';\nimport type { MergedConfig } from './types.js';\nimport { Logger } from './logger.js';\n\n/**\n * Spawn options\n */\nexport interface PlaywrightSpawnOptions {\n args: string[];\n tempConfigPath: string;\n config: MergedConfig;\n cwd?: string;\n}\n\n/**\n * Spawn result\n */\nexport interface PlaywrightSpawnResult {\n exitCode: number;\n success: boolean;\n}\n\n/**\n * Playwright spawner class\n */\nexport class PlaywrightSpawner {\n private logger: Logger;\n\n constructor(logger?: Logger) {\n this.logger = logger ?? new Logger();\n }\n\n /**\n * Spawn Playwright test process\n * @param options - Spawn options\n * @returns Spawn result with exit code\n */\n async spawn(options: PlaywrightSpawnOptions): Promise<PlaywrightSpawnResult> {\n const { args, tempConfigPath, config, cwd = process.cwd() } = options;\n\n try {\n // Build environment variables\n const env = {\n ...process.env,\n TESTDINO_CLI_CONFIG_PATH: tempConfigPath,\n TESTDINO_TOKEN: config.token,\n TESTDINO_SERVER_URL: config.serverUrl,\n TESTDINO_CI_RUN_ID: config.ciRunId,\n TESTDINO_DEBUG: config.debug ? 'true' : 'false',\n };\n\n // Build Playwright arguments with injected reporter\n const playwrightArgs = ['playwright', 'test', '--reporter', '@testdino/playwright', ...args];\n\n // Spawn Playwright with execa\n const result = await execa('npx', playwrightArgs, {\n stdio: 'inherit', // Forward stdout/stderr in real-time\n cwd,\n env,\n reject: false, // Don't throw on non-zero exit codes\n });\n\n const exitCode = result.exitCode ?? 0;\n\n return {\n exitCode,\n success: exitCode === 0,\n };\n } catch (error) {\n // Handle spawn errors (e.g., Playwright not installed, npx not found)\n return this.handleSpawnError(error);\n }\n }\n\n /**\n * Handle spawn errors\n */\n private handleSpawnError(error: unknown): PlaywrightSpawnResult {\n const execaError = error as ExecaError;\n\n // Check if it's a command not found error\n if (execaError.code === 'ENOENT') {\n this.logger.error('Failed to spawn Playwright');\n this.logger.newline();\n this.logger.info('Playwright is not installed or npx is not available.');\n this.logger.newline();\n this.logger.section('To install Playwright:');\n this.logger.code('npm install -D @playwright/test');\n this.logger.code('npx playwright install');\n return {\n exitCode: 1,\n success: false,\n };\n }\n\n // Check if it's a permission error\n if (execaError.code === 'EACCES') {\n this.logger.error('Permission denied when trying to spawn Playwright');\n this.logger.newline();\n this.logger.info('Please check file permissions and try again.');\n return {\n exitCode: 1,\n success: false,\n };\n }\n\n // Generic error\n this.logger.error('Failed to spawn Playwright');\n this.logger.newline();\n this.logger.info(`Error: ${execaError.message || String(error)}`);\n return {\n exitCode: 1,\n success: false,\n };\n }\n}\n","/**\n * Test command for TestDino CLI\n * Orchestrates all CLI components to run Playwright tests with TestDino reporter\n */\n\nimport { ConfigLoader } from '../config-loader.js';\nimport { ConfigDetector } from '../config-detector.js';\nimport { ConfigMerger } from '../config-merger.js';\nimport { ArgFilter } from '../arg-filter.js';\nimport { TempConfigManager } from '../temp-config.js';\nimport { PlaywrightSpawner } from '../playwright-spawner.js';\nimport { Logger } from '../logger.js';\nimport type { CliOptions } from '../types.js';\nimport type { PlaywrightSpawnResult } from '../playwright-spawner.js';\n\n/**\n * Test command class\n * Orchestrates the full flow of running Playwright tests with TestDino\n */\nexport class TestCommand {\n private configLoader: ConfigLoader;\n private configDetector: ConfigDetector;\n private configMerger: ConfigMerger;\n private argFilter: ArgFilter;\n private tempConfigManager: TempConfigManager;\n private playwrightSpawner: PlaywrightSpawner;\n\n constructor(\n configLoader?: ConfigLoader,\n configDetector?: ConfigDetector,\n configMerger?: ConfigMerger,\n argFilter?: ArgFilter,\n tempConfigManager?: TempConfigManager,\n playwrightSpawner?: PlaywrightSpawner,\n logger?: Logger\n ) {\n this.configLoader = configLoader || new ConfigLoader();\n this.configDetector = configDetector || new ConfigDetector();\n this.configMerger = configMerger || new ConfigMerger();\n this.argFilter = argFilter || new ArgFilter();\n this.tempConfigManager = tempConfigManager || new TempConfigManager(logger);\n this.playwrightSpawner = playwrightSpawner || new PlaywrightSpawner(logger);\n }\n\n /**\n * Execute the test command\n * @param options - CLI options from commander\n * @param args - Remaining arguments to pass to Playwright\n * @returns Spawn result with exit code\n */\n async execute(options: CliOptions, args: string[]): Promise<PlaywrightSpawnResult> {\n let tempConfigPath: string | undefined;\n\n try {\n // 1. Load testdino.config.[ts|js]\n const testdinoConfigResult = await this.configLoader.load();\n\n // 2. Detect playwright.config.[ts|js] and TestdinoReporter\n const playwrightConfigResult = await this.configDetector.detect();\n\n // 3. Get environment variables\n const envConfig = ConfigMerger.getEnvConfig();\n\n // 4. Merge all configs with proper priority\n const mergedConfig = this.configMerger.merge({\n env: envConfig,\n playwrightConfig: playwrightConfigResult.options,\n testdinoConfig: testdinoConfigResult.config,\n cliOptions: options,\n });\n\n // 5. Create temp config file\n const tempConfigInfo = this.tempConfigManager.create(mergedConfig);\n tempConfigPath = tempConfigInfo.path;\n\n // 6. Filter TestDino-specific arguments\n const filteredArgs = this.argFilter.filter(args);\n\n // 7. Spawn Playwright with filtered args and config\n const result = await this.playwrightSpawner.spawn({\n args: filteredArgs,\n tempConfigPath,\n config: mergedConfig,\n });\n\n return result;\n } finally {\n // 8. Always cleanup temp config file\n if (tempConfigPath) {\n this.tempConfigManager.cleanup(tempConfigPath);\n }\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * TestDino Playwright CLI\n * Main entry point for the tdpw command\n */\n\nimport { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport { TestCommand } from './commands/test.js';\nimport { Logger } from './logger.js';\nimport { TestDinoError } from './errors.js';\nimport { isDebugEnabled } from '../utils/index.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Get package version\n */\nfunction getVersion(): string {\n try {\n // In built dist, package.json is two levels up\n const packagePath = join(__dirname, '../../package.json');\n const packageJson = JSON.parse(readFileSync(packagePath, 'utf-8'));\n return packageJson.version;\n } catch {\n return '0.0.0';\n }\n}\n\n// Logger instance created at program start, debug enabled via env vars initially\nconst logger = new Logger(isDebugEnabled());\n\n/**\n * Build the CLI program\n */\nfunction buildProgram(): Command {\n const program = new Command()\n .name('tdpw')\n .description('Run Playwright tests with TestDino reporting')\n .version(getVersion(), '-v, --version', 'Output the current version')\n .helpOption('-h, --help', 'Display help for command');\n\n // Test command\n program\n .command('test')\n .description('Run Playwright tests with TestDino reporter')\n .option('-t, --token <token>', 'TestDino authentication token')\n .option('--ci-run-id <id>', 'CI run ID for grouping test runs')\n .option('--server-url <url>', 'TestDino server URL')\n .option('--debug', 'Enable debug logging')\n .option('--no-artifacts', 'Disable artifact uploads (screenshots, videos, traces)')\n .option('--coverage', 'Enable code coverage collection')\n .allowUnknownOption()\n .allowExcessArguments()\n .action(async (options, command) => {\n // Update logger debug state based on CLI option\n if (options.debug) {\n logger.setDebug(true);\n }\n\n try {\n // Get remaining arguments (everything after 'test')\n const args = command.args || [];\n\n // Create and execute test command\n const testCommand = new TestCommand();\n const result = await testCommand.execute(options, args);\n\n // Exit with Playwright's exit code\n process.exit(result.exitCode);\n } catch (error) {\n if (error instanceof TestDinoError) {\n // Custom errors have well-formatted messages\n logger.error(error.message);\n } else {\n logger.error(\n error instanceof Error ? error.message : String(error),\n error instanceof Error ? error : undefined\n );\n }\n\n process.exit(1);\n }\n });\n\n return program;\n}\n\n/**\n * Main CLI entry point\n */\nasync function main(): Promise<void> {\n try {\n logger.banner(getVersion());\n\n const program = buildProgram();\n await program.parseAsync(process.argv);\n } catch (error) {\n if (error instanceof TestDinoError) {\n logger.error(error.message);\n } else {\n logger.error(error instanceof Error ? error.message : String(error), error instanceof Error ? error : undefined);\n }\n\n process.exit(1);\n }\n}\n\n// Run CLI\nmain().catch((error) => {\n logger.error('Unexpected error', error instanceof Error ? error : undefined);\n process.exit(1);\n});\n"]}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -306,6 +306,41 @@ var ConfigDetector = class {
|
|
|
306
306
|
if ("debug" in options && typeof options.debug === "boolean") {
|
|
307
307
|
config.debug = options.debug;
|
|
308
308
|
}
|
|
309
|
+
if ("coverage" in options && typeof options.coverage === "object" && options.coverage !== null) {
|
|
310
|
+
config.coverage = this.extractCoverageConfig(options.coverage);
|
|
311
|
+
}
|
|
312
|
+
return config;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Extract and validate CoverageConfig from reporter options
|
|
316
|
+
*/
|
|
317
|
+
extractCoverageConfig(raw) {
|
|
318
|
+
const config = {
|
|
319
|
+
enabled: typeof raw.enabled === "boolean" ? raw.enabled : false
|
|
320
|
+
};
|
|
321
|
+
if (Array.isArray(raw.projects)) {
|
|
322
|
+
config.projects = raw.projects.filter((p) => typeof p === "string");
|
|
323
|
+
}
|
|
324
|
+
if (typeof raw.localReport === "boolean") {
|
|
325
|
+
config.localReport = raw.localReport;
|
|
326
|
+
}
|
|
327
|
+
if (typeof raw.localReportDir === "string") {
|
|
328
|
+
config.localReportDir = raw.localReportDir;
|
|
329
|
+
}
|
|
330
|
+
if (Array.isArray(raw.include)) {
|
|
331
|
+
config.include = raw.include.filter((p) => typeof p === "string");
|
|
332
|
+
}
|
|
333
|
+
if (Array.isArray(raw.exclude)) {
|
|
334
|
+
config.exclude = raw.exclude.filter((p) => typeof p === "string");
|
|
335
|
+
}
|
|
336
|
+
if (typeof raw.thresholds === "object" && raw.thresholds !== null) {
|
|
337
|
+
const t = raw.thresholds;
|
|
338
|
+
config.thresholds = {};
|
|
339
|
+
if (typeof t.statements === "number") config.thresholds.statements = t.statements;
|
|
340
|
+
if (typeof t.branches === "number") config.thresholds.branches = t.branches;
|
|
341
|
+
if (typeof t.functions === "number") config.thresholds.functions = t.functions;
|
|
342
|
+
if (typeof t.lines === "number") config.thresholds.lines = t.lines;
|
|
343
|
+
}
|
|
309
344
|
return config;
|
|
310
345
|
}
|
|
311
346
|
};
|
|
@@ -326,16 +361,30 @@ var ConfigMerger = class _ConfigMerger {
|
|
|
326
361
|
const ciRunId = this.selectValue(cliOptions.ciRunId, testdinoConfig.ciRunId, playwrightConfig.ciRunId) || this.generateCiRunId();
|
|
327
362
|
const debug = this.selectValue(cliOptions.debug, testdinoConfig.debug, playwrightConfig.debug, env.debug) ?? false;
|
|
328
363
|
const artifacts = cliOptions.noArtifacts === true ? false : this.selectValue(testdinoConfig.artifacts, playwrightConfig.artifacts) ?? true;
|
|
364
|
+
const coverage = this.mergeCoverageConfig(cliOptions.coverage, testdinoConfig.coverage, playwrightConfig.coverage);
|
|
329
365
|
const mergedConfig = {
|
|
330
366
|
token,
|
|
331
367
|
serverUrl,
|
|
332
368
|
ciRunId,
|
|
333
369
|
debug,
|
|
334
|
-
artifacts
|
|
370
|
+
artifacts,
|
|
371
|
+
...coverage ? { coverage } : {}
|
|
335
372
|
};
|
|
336
373
|
this.validate(mergedConfig);
|
|
337
374
|
return mergedConfig;
|
|
338
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* Merge coverage configuration from CLI flag and config files.
|
|
378
|
+
* CLI --coverage only toggles enabled; other fields come from config files.
|
|
379
|
+
*/
|
|
380
|
+
mergeCoverageConfig(cliCoverage, testdinoCoverage, playwrightCoverage) {
|
|
381
|
+
const baseConfig = testdinoCoverage ?? playwrightCoverage;
|
|
382
|
+
if (!baseConfig && cliCoverage === void 0) return void 0;
|
|
383
|
+
if (cliCoverage !== void 0) {
|
|
384
|
+
return { ...baseConfig || { enabled: false }, enabled: cliCoverage };
|
|
385
|
+
}
|
|
386
|
+
return baseConfig;
|
|
387
|
+
}
|
|
339
388
|
/**
|
|
340
389
|
* Select first non-undefined value from arguments
|
|
341
390
|
*/
|
|
@@ -391,7 +440,7 @@ var ConfigMerger = class _ConfigMerger {
|
|
|
391
440
|
};
|
|
392
441
|
|
|
393
442
|
// src/cli/arg-filter.ts
|
|
394
|
-
var TESTDINO_FLAGS = ["--token", "-t", "--ci-run-id", "--server-url", "--debug", "--no-artifacts"];
|
|
443
|
+
var TESTDINO_FLAGS = ["--token", "-t", "--ci-run-id", "--server-url", "--debug", "--no-artifacts", "--coverage"];
|
|
395
444
|
var FLAGS_WITH_VALUES = ["--token", "-t", "--ci-run-id", "--server-url"];
|
|
396
445
|
var ArgFilter = class {
|
|
397
446
|
/**
|
|
@@ -660,13 +709,15 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
660
709
|
};
|
|
661
710
|
process.on("exit", this.exitHandler);
|
|
662
711
|
this.sigintHandler = () => {
|
|
663
|
-
this.
|
|
664
|
-
|
|
712
|
+
if (this.sigintHandler) {
|
|
713
|
+
process.removeListener("SIGINT", this.sigintHandler);
|
|
714
|
+
}
|
|
665
715
|
};
|
|
666
716
|
process.on("SIGINT", this.sigintHandler);
|
|
667
717
|
this.sigtermHandler = () => {
|
|
668
|
-
this.
|
|
669
|
-
|
|
718
|
+
if (this.sigtermHandler) {
|
|
719
|
+
process.removeListener("SIGTERM", this.sigtermHandler);
|
|
720
|
+
}
|
|
670
721
|
};
|
|
671
722
|
process.on("SIGTERM", this.sigtermHandler);
|
|
672
723
|
this.uncaughtExceptionHandler = (error) => {
|
|
@@ -831,7 +882,7 @@ function getVersion() {
|
|
|
831
882
|
var logger2 = new Logger(isDebugEnabled());
|
|
832
883
|
function buildProgram() {
|
|
833
884
|
const program = new Command().name("tdpw").description("Run Playwright tests with TestDino reporting").version(getVersion(), "-v, --version", "Output the current version").helpOption("-h, --help", "Display help for command");
|
|
834
|
-
program.command("test").description("Run Playwright tests with TestDino reporter").option("-t, --token <token>", "TestDino authentication token").option("--ci-run-id <id>", "CI run ID for grouping test runs").option("--server-url <url>", "TestDino server URL").option("--debug", "Enable debug logging").option("--no-artifacts", "Disable artifact uploads (screenshots, videos, traces)").allowUnknownOption().allowExcessArguments().action(async (options, command) => {
|
|
885
|
+
program.command("test").description("Run Playwright tests with TestDino reporter").option("-t, --token <token>", "TestDino authentication token").option("--ci-run-id <id>", "CI run ID for grouping test runs").option("--server-url <url>", "TestDino server URL").option("--debug", "Enable debug logging").option("--no-artifacts", "Disable artifact uploads (screenshots, videos, traces)").option("--coverage", "Enable code coverage collection").allowUnknownOption().allowExcessArguments().action(async (options, command) => {
|
|
835
886
|
if (options.debug) {
|
|
836
887
|
logger2.setDebug(true);
|
|
837
888
|
}
|