@testdino/playwright 1.0.4 → 1.0.6

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 CHANGED
@@ -2,21 +2,70 @@
2
2
  'use strict';
3
3
 
4
4
  var commander = require('commander');
5
- var chalk = require('chalk');
6
5
  var fs = require('fs');
7
6
  var path = require('path');
8
7
  var url = require('url');
9
8
  var jiti = require('jiti');
10
9
  var crypto = require('crypto');
11
10
  var os = require('os');
11
+ var chalk = require('chalk');
12
12
  var execa = require('execa');
13
13
 
14
14
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
15
15
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
16
 
17
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
18
17
  var jiti__default = /*#__PURE__*/_interopDefault(jiti);
18
+ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
19
+
20
+ // src/cli/errors.ts
21
+ var TestDinoError = class extends Error {
22
+ constructor(message) {
23
+ super(message);
24
+ this.name = "TestDinoError";
25
+ Error.captureStackTrace(this, this.constructor);
26
+ }
27
+ };
28
+ var TokenMissingError = class extends TestDinoError {
29
+ constructor() {
30
+ const message = `Token is required to run tests with TestDino
31
+
32
+ Provide token via:
33
+ \u2022 CLI flag: npx tdpw test --token <your-token>
34
+ \u2022 Environment: export TESTDINO_TOKEN=<your-token>
35
+ \u2022 Config file: Create testdino.config.ts with token
36
+
37
+ Get your token at: https://testdino.com/settings`;
38
+ super(message);
39
+ this.name = "TokenMissingError";
40
+ }
41
+ };
42
+ var ConfigSyntaxError = class extends TestDinoError {
43
+ constructor(configPath, originalError) {
44
+ const message = `Failed to load ${configPath}
19
45
 
46
+ ${originalError.message}
47
+
48
+ Fix the syntax error and try again.`;
49
+ super(message);
50
+ this.name = "ConfigSyntaxError";
51
+ }
52
+ };
53
+ var InvalidServerUrlError = class extends TestDinoError {
54
+ constructor(url) {
55
+ const message = `Invalid server URL: ${url}
56
+
57
+ Server URL must be a valid HTTP or HTTPS URL.
58
+
59
+ Examples:
60
+ \u2022 https://api.testdino.com
61
+ \u2022 https://api-v0.testdino.com
62
+ \u2022 https://global.testdino.com`;
63
+ super(message);
64
+ this.name = "InvalidServerUrlError";
65
+ }
66
+ };
67
+
68
+ // src/cli/config-loader.ts
20
69
  var CONFIG_FILENAMES = ["testdino.config.ts", "testdino.config.js"];
21
70
  var ConfigLoader = class {
22
71
  cwd;
@@ -35,10 +84,7 @@ var ConfigLoader = class {
35
84
  const config = this.loadConfigFile(configPath);
36
85
  return { config, configPath };
37
86
  } catch (error) {
38
- throw new Error(
39
- `Failed to load config file: ${configPath}
40
- ${error instanceof Error ? error.message : String(error)}`
41
- );
87
+ throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));
42
88
  }
43
89
  }
44
90
  /**
@@ -90,8 +136,7 @@ ${error instanceof Error ? error.message : String(error)}`
90
136
  const resolvedPath = typeof resolved === "string" ? resolved : url.fileURLToPath(resolved);
91
137
  loaded = jitiLoader(resolvedPath);
92
138
  } catch (error) {
93
- throw new Error(`Syntax error in config file:
94
- ${error instanceof Error ? error.message : String(error)}`);
139
+ throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);
95
140
  }
96
141
  let config;
97
142
  if (loaded && typeof loaded === "object" && "__esModule" in loaded) {
@@ -108,8 +153,7 @@ ${error instanceof Error ? error.message : String(error)}`);
108
153
  try {
109
154
  config = config();
110
155
  } catch (error) {
111
- throw new Error(`Error executing config function:
112
- ${error instanceof Error ? error.message : String(error)}`);
156
+ throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);
113
157
  }
114
158
  if (config instanceof Promise) {
115
159
  throw new Error("Async config functions are not supported");
@@ -147,10 +191,7 @@ var ConfigDetector = class {
147
191
  configPath
148
192
  };
149
193
  } catch (error) {
150
- throw new Error(
151
- `Failed to load Playwright config: ${configPath}
152
- ${error instanceof Error ? error.message : String(error)}`
153
- );
194
+ throw new ConfigSyntaxError(configPath, error instanceof Error ? error : new Error(String(error)));
154
195
  }
155
196
  }
156
197
  /**
@@ -183,8 +224,7 @@ ${error instanceof Error ? error.message : String(error)}`
183
224
  const resolvedPath = typeof resolved === "string" ? resolved : url.fileURLToPath(resolved);
184
225
  loaded = jitiLoader(resolvedPath);
185
226
  } catch (error) {
186
- throw new Error(`Syntax error in Playwright config:
187
- ${error instanceof Error ? error.message : String(error)}`);
227
+ throw new Error(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);
188
228
  }
189
229
  let config;
190
230
  if (loaded && typeof loaded === "object" && "__esModule" in loaded) {
@@ -198,10 +238,7 @@ ${error instanceof Error ? error.message : String(error)}`);
198
238
  try {
199
239
  config = config();
200
240
  } catch (error) {
201
- throw new Error(
202
- `Error executing Playwright config function:
203
- ${error instanceof Error ? error.message : String(error)}`
204
- );
241
+ throw new Error(`Error executing config function: ${error instanceof Error ? error.message : String(error)}`);
205
242
  }
206
243
  }
207
244
  if (!config || typeof config !== "object") {
@@ -280,12 +317,6 @@ ${error instanceof Error ? error.message : String(error)}`
280
317
  return config;
281
318
  }
282
319
  };
283
- var ConfigValidationError = class extends Error {
284
- constructor(message) {
285
- super(message);
286
- this.name = "ConfigValidationError";
287
- }
288
- };
289
320
  var ConfigMerger = class _ConfigMerger {
290
321
  static DEFAULT_SERVER_URL = "https://api.testdino.com";
291
322
  /**
@@ -329,27 +360,14 @@ var ConfigMerger = class _ConfigMerger {
329
360
  * Validate merged configuration
330
361
  */
331
362
  validate(config) {
332
- const errors = [];
333
363
  if (!config.token || typeof config.token !== "string" || config.token.trim().length === 0) {
334
- errors.push("Token is required and must be a non-empty string");
364
+ throw new TokenMissingError();
335
365
  }
336
366
  if (config.serverUrl) {
337
- if (typeof config.serverUrl !== "string") {
338
- errors.push("Server URL must be a string");
339
- } else if (!this.isValidUrl(config.serverUrl)) {
340
- errors.push("Server URL must be a valid HTTP/HTTPS URL");
367
+ if (typeof config.serverUrl !== "string" || !this.isValidUrl(config.serverUrl)) {
368
+ throw new InvalidServerUrlError(config.serverUrl);
341
369
  }
342
370
  }
343
- if (config.ciRunId && typeof config.ciRunId !== "string") {
344
- errors.push("CI run ID must be a string");
345
- }
346
- if (config.debug !== void 0 && typeof config.debug !== "boolean") {
347
- errors.push("Debug flag must be a boolean");
348
- }
349
- if (errors.length > 0) {
350
- throw new ConfigValidationError(`Configuration validation failed:
351
- ${errors.map((e) => ` - ${e}`).join("\n")}`);
352
- }
353
371
  }
354
372
  /**
355
373
  * Check if string is a valid URL
@@ -444,6 +462,114 @@ var ArgFilter = class {
444
462
  return [...TESTDINO_FLAGS];
445
463
  }
446
464
  };
465
+
466
+ // src/utils/index.ts
467
+ function isDebugEnabled() {
468
+ return process.env.TESTDINO_DEBUG === "true" || process.env.TESTDINO_DEBUG === "1" || process.env.DEBUG === "true";
469
+ }
470
+
471
+ // src/cli/logger.ts
472
+ var Logger = class {
473
+ debugEnabled;
474
+ constructor(debugEnabled = false) {
475
+ this.debugEnabled = debugEnabled;
476
+ }
477
+ /**
478
+ * Enable or disable debug logging
479
+ */
480
+ setDebug(enabled) {
481
+ this.debugEnabled = enabled;
482
+ }
483
+ /**
484
+ * Log error message
485
+ */
486
+ error(message, error) {
487
+ console.error(chalk__default.default.red(`
488
+ \u2716 Error: ${message}`));
489
+ if (error && this.debugEnabled) {
490
+ console.error(chalk__default.default.dim("\nStack trace:"));
491
+ console.error(chalk__default.default.dim(error.stack || error.message));
492
+ }
493
+ }
494
+ /**
495
+ * Log warning message
496
+ */
497
+ warn(message) {
498
+ console.warn(chalk__default.default.yellow(`\u26A0\uFE0F Warning: ${message}`));
499
+ }
500
+ /**
501
+ * Log info message
502
+ */
503
+ info(message) {
504
+ console.log(chalk__default.default.blue(`\u2139\uFE0F ${message}`));
505
+ }
506
+ /**
507
+ * Log success message
508
+ */
509
+ success(message) {
510
+ console.log(chalk__default.default.green(`\u2713 ${message}`));
511
+ }
512
+ /**
513
+ * Log debug message (only if debug is enabled)
514
+ */
515
+ debug(message) {
516
+ if (this.debugEnabled) {
517
+ console.log(chalk__default.default.dim(`[DEBUG] ${message}`));
518
+ }
519
+ }
520
+ /**
521
+ * Log a blank line
522
+ */
523
+ newline() {
524
+ console.log();
525
+ }
526
+ /**
527
+ * Log a section header
528
+ */
529
+ section(title) {
530
+ console.log(chalk__default.default.bold.cyan(`
531
+ ${title}`));
532
+ }
533
+ /**
534
+ * Log a list item
535
+ */
536
+ listItem(text) {
537
+ console.log(` \u2022 ${text}`);
538
+ }
539
+ /**
540
+ * Log code/command
541
+ */
542
+ code(text) {
543
+ console.log(chalk__default.default.gray(` ${text}`));
544
+ }
545
+ /**
546
+ * Format error for display
547
+ */
548
+ formatError(error) {
549
+ if (this.debugEnabled && error.stack) {
550
+ return error.stack;
551
+ }
552
+ return error.message;
553
+ }
554
+ /**
555
+ * Log TestDino CLI banner
556
+ */
557
+ banner(version) {
558
+ console.log(
559
+ chalk__default.default.cyan(`
560
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
561
+ \u2551 \u2551
562
+ \u2551 ${chalk__default.default.bold("TestDino Playwright")} v${version.padEnd(36)}\u2551
563
+ \u2551 ${chalk__default.default.dim("https://testdino.com")} \u2551
564
+ \u2551 \u2551
565
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
566
+ `)
567
+ );
568
+ }
569
+ };
570
+ new Logger(isDebugEnabled());
571
+
572
+ // src/cli/temp-config.ts
447
573
  var TempConfigManager = class {
448
574
  tempFiles = /* @__PURE__ */ new Set();
449
575
  cleanupHandlersRegistered = false;
@@ -452,6 +578,10 @@ var TempConfigManager = class {
452
578
  sigtermHandler;
453
579
  uncaughtExceptionHandler;
454
580
  unhandledRejectionHandler;
581
+ logger;
582
+ constructor(logger3) {
583
+ this.logger = logger3 ?? new Logger();
584
+ }
455
585
  /**
456
586
  * Create a temporary config file with the merged configuration
457
587
  * @param config - Merged configuration to write
@@ -489,7 +619,7 @@ ${error instanceof Error ? error.message : String(error)}`
489
619
  }
490
620
  this.tempFiles.delete(tempPath);
491
621
  } catch {
492
- console.warn(`\u26A0\uFE0F TestDino: Failed to cleanup temp file: ${tempPath}`);
622
+ this.logger.warn(`Failed to cleanup temp file: ${tempPath}`);
493
623
  }
494
624
  }
495
625
  /**
@@ -548,13 +678,13 @@ ${error instanceof Error ? error.message : String(error)}`
548
678
  };
549
679
  process.on("SIGTERM", this.sigtermHandler);
550
680
  this.uncaughtExceptionHandler = (error) => {
551
- console.error("Uncaught exception:", error);
681
+ this.logger.error("Uncaught exception", error);
552
682
  this.cleanupAll();
553
683
  process.exit(1);
554
684
  };
555
685
  process.on("uncaughtException", this.uncaughtExceptionHandler);
556
686
  this.unhandledRejectionHandler = (reason) => {
557
- console.error("Unhandled rejection:", reason);
687
+ this.logger.error("Unhandled rejection", reason instanceof Error ? reason : void 0);
558
688
  this.cleanupAll();
559
689
  process.exit(1);
560
690
  };
@@ -568,6 +698,10 @@ ${error instanceof Error ? error.message : String(error)}`
568
698
  }
569
699
  };
570
700
  var PlaywrightSpawner = class {
701
+ logger;
702
+ constructor(logger3) {
703
+ this.logger = logger3 ?? new Logger();
704
+ }
571
705
  /**
572
706
  * Spawn Playwright test process
573
707
  * @param options - Spawn options
@@ -608,33 +742,30 @@ var PlaywrightSpawner = class {
608
742
  handleSpawnError(error) {
609
743
  const execaError = error;
610
744
  if (execaError.code === "ENOENT") {
611
- console.error("\u274C TestDino: Failed to spawn Playwright");
612
- console.error("");
613
- console.error("Playwright is not installed or npx is not available.");
614
- console.error("");
615
- console.error("To install Playwright:");
616
- console.error(" npm install -D @playwright/test");
617
- console.error(" npx playwright install");
618
- console.error("");
745
+ this.logger.error("Failed to spawn Playwright");
746
+ this.logger.newline();
747
+ this.logger.info("Playwright is not installed or npx is not available.");
748
+ this.logger.newline();
749
+ this.logger.section("To install Playwright:");
750
+ this.logger.code("npm install -D @playwright/test");
751
+ this.logger.code("npx playwright install");
619
752
  return {
620
753
  exitCode: 1,
621
754
  success: false
622
755
  };
623
756
  }
624
757
  if (execaError.code === "EACCES") {
625
- console.error("\u274C TestDino: Permission denied when trying to spawn Playwright");
626
- console.error("");
627
- console.error("Please check file permissions and try again.");
628
- console.error("");
758
+ this.logger.error("Permission denied when trying to spawn Playwright");
759
+ this.logger.newline();
760
+ this.logger.info("Please check file permissions and try again.");
629
761
  return {
630
762
  exitCode: 1,
631
763
  success: false
632
764
  };
633
765
  }
634
- console.error("\u274C TestDino: Failed to spawn Playwright");
635
- console.error("");
636
- console.error("Error:", execaError.message || String(error));
637
- console.error("");
766
+ this.logger.error("Failed to spawn Playwright");
767
+ this.logger.newline();
768
+ this.logger.info(`Error: ${execaError.message || String(error)}`);
638
769
  return {
639
770
  exitCode: 1,
640
771
  success: false
@@ -650,13 +781,13 @@ var TestCommand = class {
650
781
  argFilter;
651
782
  tempConfigManager;
652
783
  playwrightSpawner;
653
- constructor(configLoader, configDetector, configMerger, argFilter, tempConfigManager, playwrightSpawner) {
784
+ constructor(configLoader, configDetector, configMerger, argFilter, tempConfigManager, playwrightSpawner, logger3) {
654
785
  this.configLoader = configLoader || new ConfigLoader();
655
786
  this.configDetector = configDetector || new ConfigDetector();
656
787
  this.configMerger = configMerger || new ConfigMerger();
657
788
  this.argFilter = argFilter || new ArgFilter();
658
- this.tempConfigManager = tempConfigManager || new TempConfigManager();
659
- this.playwrightSpawner = playwrightSpawner || new PlaywrightSpawner();
789
+ this.tempConfigManager = tempConfigManager || new TempConfigManager(logger3);
790
+ this.playwrightSpawner = playwrightSpawner || new PlaywrightSpawner(logger3);
660
791
  }
661
792
  /**
662
793
  * Execute the test command
@@ -705,32 +836,26 @@ function getVersion() {
705
836
  return "0.0.0";
706
837
  }
707
838
  }
708
- function printBanner() {
709
- const version = getVersion();
710
- console.log(
711
- chalk__default.default.cyan(`
712
- \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
713
- \u2551 \u2551
714
- \u2551 ${chalk__default.default.bold("TestDino Playwright")} v${version.padEnd(36)}\u2551
715
- \u2551 ${chalk__default.default.dim("https://testdino.com")} \u2551
716
- \u2551 \u2551
717
- \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
718
- `)
719
- );
720
- }
839
+ var logger2 = new Logger(isDebugEnabled());
721
840
  function buildProgram() {
722
841
  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");
723
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) => {
843
+ if (options.debug) {
844
+ logger2.setDebug(true);
845
+ }
724
846
  try {
725
847
  const args = command.args || [];
726
848
  const testCommand = new TestCommand();
727
849
  const result = await testCommand.execute(options, args);
728
850
  process.exit(result.exitCode);
729
851
  } catch (error) {
730
- console.error(chalk__default.default.red("\n\u2716 Unexpected error:"), error instanceof Error ? error.message : String(error));
731
- if (options.debug) {
732
- console.error(chalk__default.default.dim("\nStack trace:"));
733
- console.error(error);
852
+ if (error instanceof TestDinoError) {
853
+ logger2.error(error.message);
854
+ } else {
855
+ logger2.error(
856
+ error instanceof Error ? error.message : String(error),
857
+ error instanceof Error ? error : void 0
858
+ );
734
859
  }
735
860
  process.exit(1);
736
861
  }
@@ -739,20 +864,20 @@ function buildProgram() {
739
864
  }
740
865
  async function main() {
741
866
  try {
742
- printBanner();
867
+ logger2.banner(getVersion());
743
868
  const program = buildProgram();
744
869
  await program.parseAsync(process.argv);
745
870
  } catch (error) {
746
- console.error(chalk__default.default.red("\n\u2716 Error:"), error instanceof Error ? error.message : String(error));
747
- if (process.env.DEBUG || process.env.TESTDINO_DEBUG) {
748
- console.error(chalk__default.default.dim("\nStack trace:"));
749
- console.error(error);
871
+ if (error instanceof TestDinoError) {
872
+ logger2.error(error.message);
873
+ } else {
874
+ logger2.error(error instanceof Error ? error.message : String(error), error instanceof Error ? error : void 0);
750
875
  }
751
876
  process.exit(1);
752
877
  }
753
878
  }
754
879
  main().catch((error) => {
755
- console.error(chalk__default.default.red("Unexpected error:"), error);
880
+ logger2.error("Unexpected error", error instanceof Error ? error : void 0);
756
881
  process.exit(1);
757
882
  });
758
883
  //# sourceMappingURL=index.js.map