@testdino/playwright 1.0.9 → 1.0.11

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/index.js CHANGED
@@ -1,37 +1,48 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var crypto = require('crypto');
6
- var fs = require('fs');
7
- var WebSocket = require('ws');
8
- var axios = require('axios');
9
- var path = require('path');
10
- var promises = require('fs/promises');
11
- var execa = require('execa');
12
- var os = require('os');
13
- var process$1 = require('process');
14
- var istanbulCoverage = require('istanbul-lib-coverage');
15
- var picomatch = require('picomatch');
16
- var istanbulLibReport = require('istanbul-lib-report');
17
- var istanbulReports = require('istanbul-reports');
18
- var test$1 = require('@playwright/test');
19
- var chalk = require('chalk');
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
29
 
21
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ coverageFixtures: () => coverageFixtures,
34
+ default: () => TestdinoReporter,
35
+ expect: () => import_test.expect,
36
+ test: () => test
37
+ });
38
+ module.exports = __toCommonJS(src_exports);
22
39
 
23
- var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
24
- var axios__default = /*#__PURE__*/_interopDefault(axios);
25
- var istanbulCoverage__default = /*#__PURE__*/_interopDefault(istanbulCoverage);
26
- var picomatch__default = /*#__PURE__*/_interopDefault(picomatch);
27
- var chalk__default = /*#__PURE__*/_interopDefault(chalk);
40
+ // src/reporter/index.ts
41
+ var import_crypto2 = require("crypto");
42
+ var import_fs2 = require("fs");
28
43
 
29
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
30
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
31
- }) : x)(function(x) {
32
- if (typeof require !== "undefined") return require.apply(this, arguments);
33
- throw Error('Dynamic require of "' + x + '" is not supported');
34
- });
44
+ // src/streaming/websocket.ts
45
+ var import_ws = __toESM(require("ws"));
35
46
 
36
47
  // src/reporter/errors.ts
37
48
  var TestDinoServerError = class extends Error {
@@ -103,7 +114,7 @@ var WebSocketClient = class {
103
114
  * Passes sessionId from HTTP auth so the server reuses the existing session.
104
115
  */
105
116
  async connect() {
106
- if (this.isConnecting || this.ws?.readyState === WebSocket__default.default.OPEN) {
117
+ if (this.isConnecting || this.ws?.readyState === import_ws.default.OPEN) {
107
118
  return;
108
119
  }
109
120
  this.isConnecting = true;
@@ -113,7 +124,7 @@ var WebSocketClient = class {
113
124
  if (this.options.sessionId) {
114
125
  wsUrl += `&sessionId=${this.options.sessionId}`;
115
126
  }
116
- this.ws = new WebSocket__default.default(wsUrl);
127
+ this.ws = new import_ws.default(wsUrl);
117
128
  let serverReady = false;
118
129
  const handshakeTimeout = setTimeout(() => {
119
130
  if (!serverReady) {
@@ -177,7 +188,7 @@ var WebSocketClient = class {
177
188
  * Send event through WebSocket
178
189
  */
179
190
  async send(event) {
180
- if (!this.ws || this.ws.readyState !== WebSocket__default.default.OPEN) {
191
+ if (!this.ws || this.ws.readyState !== import_ws.default.OPEN) {
181
192
  throw new Error("WebSocket is not connected");
182
193
  }
183
194
  return new Promise((resolve, reject) => {
@@ -195,7 +206,7 @@ var WebSocketClient = class {
195
206
  * Note: Uses Promise.all intentionally - if one send fails, connection is broken
196
207
  */
197
208
  async sendBatch(events) {
198
- if (!this.ws || this.ws.readyState !== WebSocket__default.default.OPEN) {
209
+ if (!this.ws || this.ws.readyState !== import_ws.default.OPEN) {
199
210
  throw new Error("WebSocket is not connected");
200
211
  }
201
212
  await Promise.all(events.map((event) => this.send(event)));
@@ -205,7 +216,7 @@ var WebSocketClient = class {
205
216
  * Use this for critical events like run:end where delivery must be confirmed
206
217
  */
207
218
  async sendAndWaitForAck(event, timeout = this.ackTimeout) {
208
- if (!this.ws || this.ws.readyState !== WebSocket__default.default.OPEN) {
219
+ if (!this.ws || this.ws.readyState !== import_ws.default.OPEN) {
209
220
  throw new Error("WebSocket is not connected");
210
221
  }
211
222
  const sequence = event.sequence;
@@ -234,7 +245,7 @@ var WebSocketClient = class {
234
245
  * Check if WebSocket is connected
235
246
  */
236
247
  isConnected() {
237
- return this.ws?.readyState === WebSocket__default.default.OPEN;
248
+ return this.ws?.readyState === import_ws.default.OPEN;
238
249
  }
239
250
  /**
240
251
  * Close WebSocket connection
@@ -295,7 +306,11 @@ var WebSocketClient = class {
295
306
  total: Number(details.total) || 0,
296
307
  resetDate: details.resetDate?.toString(),
297
308
  canPartialSubmit: Boolean(details.canPartialSubmit),
298
- allowedCount: Number(details.allowedCount) || 0
309
+ allowedCount: Number(details.allowedCount) || 0,
310
+ projectName: details.projectName?.toString(),
311
+ projectLimit: details.projectLimit != null ? Number(details.projectLimit) : void 0,
312
+ projectUsed: details.projectUsed != null ? Number(details.projectUsed) : void 0,
313
+ projectBorrowed: details.projectBorrowed != null ? Number(details.projectBorrowed) : void 0
299
314
  })
300
315
  );
301
316
  } else if (errorCode === "QUOTA_EXHAUSTED" && errorObj.details && typeof errorObj.details === "object") {
@@ -369,7 +384,7 @@ var WebSocketClient = class {
369
384
  startPing() {
370
385
  this.stopPing();
371
386
  this.pingInterval = setInterval(() => {
372
- if (this.ws?.readyState === WebSocket__default.default.OPEN) {
387
+ if (this.ws?.readyState === import_ws.default.OPEN) {
373
388
  this.ws.ping();
374
389
  }
375
390
  }, 3e4);
@@ -384,9 +399,15 @@ var WebSocketClient = class {
384
399
  }
385
400
  }
386
401
  };
402
+
403
+ // src/streaming/http.ts
404
+ var import_axios = __toESM(require("axios"));
405
+
406
+ // src/utils/index.ts
407
+ var import_path = require("path");
387
408
  function normalizePath(filePath, rootDir) {
388
409
  if (rootDir && filePath.startsWith(rootDir)) {
389
- return path.relative(rootDir, filePath);
410
+ return (0, import_path.relative)(rootDir, filePath);
390
411
  }
391
412
  return filePath;
392
413
  }
@@ -407,7 +428,7 @@ var HttpClient = class {
407
428
  retryDelay: 1e3,
408
429
  ...options
409
430
  };
410
- this.client = axios__default.default.create({
431
+ this.client = import_axios.default.create({
411
432
  baseURL: this.options.serverUrl,
412
433
  headers: {
413
434
  "Content-Type": "application/json",
@@ -424,7 +445,7 @@ var HttpClient = class {
424
445
  const response = await this.client.post("/auth");
425
446
  return response.data;
426
447
  } catch (error) {
427
- if (axios__default.default.isAxiosError(error) && error.response?.status === 402) {
448
+ if (import_axios.default.isAxiosError(error) && error.response?.status === 402) {
428
449
  const quotaError = error.response.data;
429
450
  throw new QuotaExhaustedError(quotaError.message, quotaError.details);
430
451
  }
@@ -441,6 +462,14 @@ var HttpClient = class {
441
462
  await this.client.post("/events", { events });
442
463
  return;
443
464
  } catch (error) {
465
+ if (import_axios.default.isAxiosError(error) && error.response?.status === 402) {
466
+ const data = error.response.data;
467
+ const details = data?.details;
468
+ if (data?.error === "QUOTA_EXCEEDED" && details) {
469
+ throw new QuotaExceededError(data.message || "Quota exceeded", details);
470
+ }
471
+ throw new QuotaExhaustedError(data?.message || "Quota exceeded", details);
472
+ }
444
473
  lastError = new Error(this.getErrorMessage(error));
445
474
  if (attempt < this.options.maxRetries - 1) {
446
475
  const delay = this.options.retryDelay * Math.pow(2, attempt);
@@ -460,7 +489,7 @@ var HttpClient = class {
460
489
  * Extract error message from various error types
461
490
  */
462
491
  getErrorMessage(error) {
463
- if (axios__default.default.isAxiosError(error)) {
492
+ if (import_axios.default.isAxiosError(error)) {
464
493
  return error.response?.data?.message || error.message;
465
494
  }
466
495
  if (error instanceof Error) {
@@ -552,6 +581,9 @@ var EventBuffer = class {
552
581
  }
553
582
  };
554
583
 
584
+ // src/metadata/git.ts
585
+ var import_promises = require("fs/promises");
586
+
555
587
  // src/metadata/base.ts
556
588
  var BaseMetadataCollector = class {
557
589
  name;
@@ -637,6 +669,16 @@ var BaseMetadataCollector = class {
637
669
  };
638
670
 
639
671
  // src/metadata/git.ts
672
+ var execaPromise = null;
673
+ async function getExeca() {
674
+ if (!execaPromise) {
675
+ execaPromise = import("execa").then((m) => m.execa).catch((error) => {
676
+ console.error("Failed to import execa:", error.message);
677
+ throw new Error("Failed to load execa. Ensure execa is installed: npm install execa");
678
+ });
679
+ }
680
+ return execaPromise;
681
+ }
640
682
  var GitMetadataCollector = class extends BaseMetadataCollector {
641
683
  options;
642
684
  constructor(options = {}) {
@@ -729,7 +771,8 @@ var GitMetadataCollector = class extends BaseMetadataCollector {
729
771
  const isCI = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true";
730
772
  if (!isCI) return;
731
773
  try {
732
- await execa.execa("git", ["config", "--global", "--add", "safe.directory", this.options.cwd], {
774
+ const execa = await getExeca();
775
+ await execa("git", ["config", "--global", "--add", "safe.directory", this.options.cwd], {
733
776
  timeout: this.options.timeout,
734
777
  reject: true
735
778
  });
@@ -744,7 +787,7 @@ var GitMetadataCollector = class extends BaseMetadataCollector {
744
787
  if (!eventPath) return void 0;
745
788
  try {
746
789
  const content = await this.withTimeout(
747
- promises.readFile(eventPath, "utf-8"),
790
+ (0, import_promises.readFile)(eventPath, "utf-8"),
748
791
  this.options.timeout,
749
792
  "GitHub event file read"
750
793
  );
@@ -1028,8 +1071,9 @@ var GitMetadataCollector = class extends BaseMetadataCollector {
1028
1071
  * Execute git command with timeout
1029
1072
  */
1030
1073
  async execGit(args) {
1074
+ const execa = await getExeca();
1031
1075
  const { stdout } = await this.withTimeout(
1032
- execa.execa("git", args, {
1076
+ execa("git", args, {
1033
1077
  cwd: this.options.cwd,
1034
1078
  timeout: this.options.timeout,
1035
1079
  reject: true
@@ -1040,6 +1084,9 @@ var GitMetadataCollector = class extends BaseMetadataCollector {
1040
1084
  return stdout.trim();
1041
1085
  }
1042
1086
  };
1087
+
1088
+ // src/metadata/ci.ts
1089
+ var import_os = require("os");
1043
1090
  var CIMetadataCollector = class extends BaseMetadataCollector {
1044
1091
  constructor(_options = {}) {
1045
1092
  super("ci");
@@ -1117,9 +1164,9 @@ var CIMetadataCollector = class extends BaseMetadataCollector {
1117
1164
  collectEnvironment() {
1118
1165
  try {
1119
1166
  return {
1120
- name: os.type(),
1167
+ name: (0, import_os.type)(),
1121
1168
  type: process.platform,
1122
- os: `${os.type()} ${os.release()}`,
1169
+ os: `${(0, import_os.type)()} ${(0, import_os.release)()}`,
1123
1170
  node: process.version
1124
1171
  };
1125
1172
  } catch {
@@ -1127,6 +1174,10 @@ var CIMetadataCollector = class extends BaseMetadataCollector {
1127
1174
  }
1128
1175
  }
1129
1176
  };
1177
+
1178
+ // src/metadata/system.ts
1179
+ var import_os2 = require("os");
1180
+ var import_process = require("process");
1130
1181
  var SystemMetadataCollector = class extends BaseMetadataCollector {
1131
1182
  constructor(_options = {}) {
1132
1183
  super("system");
@@ -1161,11 +1212,11 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1161
1212
  let platformName = "unknown";
1162
1213
  let releaseVersion = "unknown";
1163
1214
  try {
1164
- platformName = os.platform();
1215
+ platformName = (0, import_os2.platform)();
1165
1216
  } catch {
1166
1217
  }
1167
1218
  try {
1168
- releaseVersion = os.release();
1219
+ releaseVersion = (0, import_os2.release)();
1169
1220
  } catch {
1170
1221
  }
1171
1222
  return `${platformName} ${releaseVersion}`;
@@ -1176,7 +1227,7 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1176
1227
  */
1177
1228
  getCpuInfo() {
1178
1229
  try {
1179
- const cpuList = os.cpus();
1230
+ const cpuList = (0, import_os2.cpus)();
1180
1231
  if (cpuList.length === 0) {
1181
1232
  return "unknown";
1182
1233
  }
@@ -1193,7 +1244,7 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1193
1244
  */
1194
1245
  getMemoryInfo() {
1195
1246
  try {
1196
- const totalBytes = os.totalmem();
1247
+ const totalBytes = (0, import_os2.totalmem)();
1197
1248
  const totalGB = totalBytes / (1024 * 1024 * 1024);
1198
1249
  return `${totalGB.toFixed(1)} GB`;
1199
1250
  } catch {
@@ -1206,7 +1257,7 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1206
1257
  */
1207
1258
  getNodeVersion() {
1208
1259
  try {
1209
- return process$1.version;
1260
+ return import_process.version;
1210
1261
  } catch {
1211
1262
  return "unknown";
1212
1263
  }
@@ -1217,7 +1268,7 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1217
1268
  */
1218
1269
  getPlatform() {
1219
1270
  try {
1220
- return os.platform();
1271
+ return (0, import_os2.platform)();
1221
1272
  } catch {
1222
1273
  return "unknown";
1223
1274
  }
@@ -1228,12 +1279,15 @@ var SystemMetadataCollector = class extends BaseMetadataCollector {
1228
1279
  */
1229
1280
  getHostname() {
1230
1281
  try {
1231
- return os.hostname();
1282
+ return (0, import_os2.hostname)();
1232
1283
  } catch {
1233
1284
  return "unknown";
1234
1285
  }
1235
1286
  }
1236
1287
  };
1288
+
1289
+ // src/metadata/playwright.ts
1290
+ var import_promises2 = require("fs/promises");
1237
1291
  var PlaywrightMetadataCollector = class extends BaseMetadataCollector {
1238
1292
  options;
1239
1293
  constructor(options = {}) {
@@ -1283,7 +1337,7 @@ var PlaywrightMetadataCollector = class extends BaseMetadataCollector {
1283
1337
  return void 0;
1284
1338
  }
1285
1339
  const packageJsonContent = await this.withTimeout(
1286
- promises.readFile(packageJsonPath, "utf-8"),
1340
+ (0, import_promises2.readFile)(packageJsonPath, "utf-8"),
1287
1341
  this.options.timeout,
1288
1342
  "Playwright package.json read"
1289
1343
  );
@@ -1302,7 +1356,7 @@ var PlaywrightMetadataCollector = class extends BaseMetadataCollector {
1302
1356
  */
1303
1357
  resolvePlaywrightPackageJson() {
1304
1358
  try {
1305
- return __require.resolve("@playwright/test/package.json");
1359
+ return require.resolve("@playwright/test/package.json");
1306
1360
  } catch {
1307
1361
  return void 0;
1308
1362
  }
@@ -1706,6 +1760,9 @@ function createMetadataCollector(playwrightConfig, playwrightSuite) {
1706
1760
  );
1707
1761
  return aggregator;
1708
1762
  }
1763
+
1764
+ // src/uploads/sas-token-client.ts
1765
+ var import_axios2 = __toESM(require("axios"));
1709
1766
  var SASTokenClient = class {
1710
1767
  client;
1711
1768
  options;
@@ -1715,7 +1772,7 @@ var SASTokenClient = class {
1715
1772
  retryDelay: 1e3,
1716
1773
  ...options
1717
1774
  };
1718
- this.client = axios__default.default.create({
1775
+ this.client = import_axios2.default.create({
1719
1776
  baseURL: this.options.serverUrl,
1720
1777
  headers: {
1721
1778
  "Content-Type": "application/json",
@@ -1757,7 +1814,7 @@ var SASTokenClient = class {
1757
1814
  * Extract error message from various error types
1758
1815
  */
1759
1816
  getErrorMessage(error) {
1760
- if (axios__default.default.isAxiosError(error)) {
1817
+ if (import_axios2.default.isAxiosError(error)) {
1761
1818
  if (error.response?.status === 401) {
1762
1819
  return "Invalid API key for artifact uploads";
1763
1820
  }
@@ -1775,6 +1832,11 @@ var SASTokenClient = class {
1775
1832
  return String(error);
1776
1833
  }
1777
1834
  };
1835
+
1836
+ // src/uploads/artifact-uploader.ts
1837
+ var import_fs = require("fs");
1838
+ var import_path2 = require("path");
1839
+ var import_axios3 = __toESM(require("axios"));
1778
1840
  var ArtifactUploader = class {
1779
1841
  sasToken;
1780
1842
  options;
@@ -1795,9 +1857,9 @@ var ArtifactUploader = class {
1795
1857
  */
1796
1858
  async uploadFile(attachment, testId) {
1797
1859
  const startTime = Date.now();
1798
- const fileName = path.basename(attachment.path);
1860
+ const fileName = (0, import_path2.basename)(attachment.path);
1799
1861
  try {
1800
- const stats = fs.statSync(attachment.path);
1862
+ const stats = (0, import_fs.statSync)(attachment.path);
1801
1863
  const fileSize = stats.size;
1802
1864
  if (fileSize > this.sasToken.maxSize) {
1803
1865
  return {
@@ -1808,7 +1870,7 @@ var ArtifactUploader = class {
1808
1870
  duration: Date.now() - startTime
1809
1871
  };
1810
1872
  }
1811
- const extension = path.extname(fileName).slice(1).toLowerCase();
1873
+ const extension = (0, import_path2.extname)(fileName).slice(1).toLowerCase();
1812
1874
  const allowedTypes = this.sasToken.allowedFileTypes;
1813
1875
  if (allowedTypes.length > 0 && !allowedTypes.includes(extension)) {
1814
1876
  return {
@@ -1918,9 +1980,9 @@ var ArtifactUploader = class {
1918
1980
  * Perform actual file upload to Azure
1919
1981
  */
1920
1982
  async doUpload(filePath, uploadUrl, contentType) {
1921
- const fileStream = fs.createReadStream(filePath);
1922
- const stats = fs.statSync(filePath);
1923
- await axios__default.default.put(uploadUrl, fileStream, {
1983
+ const fileStream = (0, import_fs.createReadStream)(filePath);
1984
+ const stats = (0, import_fs.statSync)(filePath);
1985
+ await import_axios3.default.put(uploadUrl, fileStream, {
1924
1986
  headers: {
1925
1987
  "Content-Type": contentType,
1926
1988
  "Content-Length": stats.size,
@@ -1946,6 +2008,10 @@ var ArtifactUploader = class {
1946
2008
  return this.sasToken.uniqueId;
1947
2009
  }
1948
2010
  };
2011
+
2012
+ // src/code-coverage/merger.ts
2013
+ var import_istanbul_lib_coverage = __toESM(require("istanbul-lib-coverage"));
2014
+ var import_picomatch = __toESM(require("picomatch"));
1949
2015
  function toIstanbulMapData(map) {
1950
2016
  return map;
1951
2017
  }
@@ -1953,7 +2019,7 @@ function fromIstanbulMapData(data) {
1953
2019
  return data;
1954
2020
  }
1955
2021
  var CoverageMerger = class {
1956
- coverageMap = istanbulCoverage__default.default.createCoverageMap({});
2022
+ coverageMap = import_istanbul_lib_coverage.default.createCoverageMap({});
1957
2023
  hasData = false;
1958
2024
  includePatterns;
1959
2025
  excludePatterns;
@@ -1991,8 +2057,8 @@ var CoverageMerger = class {
1991
2057
  const hasInclude = this.includePatterns && this.includePatterns.length > 0;
1992
2058
  const hasExclude = this.excludePatterns && this.excludePatterns.length > 0;
1993
2059
  if (!hasInclude && !hasExclude) return coverageMap;
1994
- const isExcluded = hasExclude ? picomatch__default.default(this.excludePatterns) : void 0;
1995
- const isIncluded = hasInclude ? picomatch__default.default(this.includePatterns) : void 0;
2060
+ const isExcluded = hasExclude ? (0, import_picomatch.default)(this.excludePatterns) : void 0;
2061
+ const isIncluded = hasInclude ? (0, import_picomatch.default)(this.includePatterns) : void 0;
1996
2062
  const filtered = {};
1997
2063
  for (const [filePath, fileCoverage] of Object.entries(coverageMap)) {
1998
2064
  if (isExcluded && isExcluded(filePath)) {
@@ -2062,6 +2128,9 @@ function extractMetric(metric) {
2062
2128
  pct: metric.pct
2063
2129
  };
2064
2130
  }
2131
+
2132
+ // src/code-coverage/compact.ts
2133
+ var import_crypto = require("crypto");
2065
2134
  function extractCompactCounts(coverageMapJSON, gitRoot) {
2066
2135
  const files = {};
2067
2136
  let fileCount = 0;
@@ -2097,14 +2166,19 @@ function computeShapeHash(fileCoverage) {
2097
2166
  b: countBranchPaths(branchMap),
2098
2167
  bp: Object.values(branchMap).map((b) => (b.locations || []).length)
2099
2168
  };
2100
- return crypto.createHash("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 12);
2169
+ return (0, import_crypto.createHash)("sha256").update(JSON.stringify(shape)).digest("hex").slice(0, 12);
2101
2170
  }
2171
+
2172
+ // src/code-coverage/html-report.ts
2173
+ var import_istanbul_lib_report = require("istanbul-lib-report");
2174
+ var import_istanbul_reports = require("istanbul-reports");
2175
+ var import_promises3 = require("fs/promises");
2102
2176
  async function generateIstanbulHtmlReport(coverageMerger, options) {
2103
- await promises.rm(options.outputDir, { recursive: true, force: true }).catch(() => {
2177
+ await (0, import_promises3.rm)(options.outputDir, { recursive: true, force: true }).catch(() => {
2104
2178
  });
2105
- await promises.mkdir(options.outputDir, { recursive: true });
2179
+ await (0, import_promises3.mkdir)(options.outputDir, { recursive: true });
2106
2180
  const coverageMap = coverageMerger.getRawCoverageMap();
2107
- const context = istanbulLibReport.createContext({
2181
+ const context = (0, import_istanbul_lib_report.createContext)({
2108
2182
  dir: options.outputDir,
2109
2183
  watermarks: {
2110
2184
  statements: [50, 80],
@@ -2114,13 +2188,16 @@ async function generateIstanbulHtmlReport(coverageMerger, options) {
2114
2188
  },
2115
2189
  coverageMap
2116
2190
  });
2117
- const reporter = istanbulReports.create("html", {
2191
+ const reporter = (0, import_istanbul_reports.create)("html", {
2118
2192
  skipEmpty: false,
2119
2193
  subdir: ""
2120
2194
  });
2121
2195
  reporter.execute(context);
2122
2196
  return `${options.outputDir}/index.html`;
2123
2197
  }
2198
+
2199
+ // src/code-coverage/fixtures.ts
2200
+ var import_test = require("@playwright/test");
2124
2201
  var COVERAGE_EXTRACT_TIMEOUT_MS = 3e4;
2125
2202
  async function extractCoverageFromPage(page, timeoutMs = COVERAGE_EXTRACT_TIMEOUT_MS) {
2126
2203
  return Promise.race([
@@ -2149,9 +2226,30 @@ var coverageFixtures = {
2149
2226
  { auto: true }
2150
2227
  ]
2151
2228
  };
2152
- var test = test$1.test.extend(
2229
+ var test = import_test.test.extend(
2153
2230
  coverageFixtures
2154
2231
  );
2232
+
2233
+ // src/reporter/log.ts
2234
+ var chalkPromise = null;
2235
+ async function getChalk() {
2236
+ if (!chalkPromise) {
2237
+ chalkPromise = import("chalk").then((m) => m.default).catch((error) => {
2238
+ console.warn("\u26A0\uFE0F TestDino: Failed to load chalk, using plain text output");
2239
+ console.debug("Chalk import error:", error.message);
2240
+ return {
2241
+ green: (s) => s,
2242
+ yellow: (s) => s,
2243
+ red: (s) => s,
2244
+ blue: (s) => s,
2245
+ cyan: (s) => s,
2246
+ dim: (s) => s,
2247
+ bold: (s) => s
2248
+ };
2249
+ });
2250
+ }
2251
+ return chalkPromise;
2252
+ }
2155
2253
  function stripAnsi(str) {
2156
2254
  return str.replace(/\u001b\[[0-9;]*m/g, "");
2157
2255
  }
@@ -2180,20 +2278,20 @@ function shortenPath(filePath) {
2180
2278
  const parts = filePath.split("/");
2181
2279
  return parts.length > 2 ? parts.slice(-2).join("/") : filePath;
2182
2280
  }
2183
- function colorPct(pct) {
2184
- const color = pct >= 80 ? chalk__default.default.green : pct >= 50 ? chalk__default.default.yellow : chalk__default.default.red;
2281
+ function colorPct(pct, chalk) {
2282
+ const color = pct >= 80 ? chalk.green : pct >= 50 ? chalk.yellow : chalk.red;
2185
2283
  return color(pct === 100 ? "100%" : `${pct.toFixed(1)}%`);
2186
2284
  }
2187
- function printCoverageTable(event) {
2285
+ function printCoverageTableWithChalk(event, chalk) {
2188
2286
  const { summary, files } = event;
2189
- const row = (content) => ` ${chalk__default.default.dim("\u2502")} ${content}`;
2287
+ const row = (content) => ` ${chalk.dim("\u2502")} ${content}`;
2190
2288
  const nameW = 30;
2191
2289
  const colW = 10;
2192
- console.log(row(`${chalk__default.default.bold("Coverage")} ${chalk__default.default.dim(`${files.length} files`)}`));
2290
+ console.log(row(`${chalk.bold("Coverage")} ${chalk.dim(`${files.length} files`)}`));
2193
2291
  console.log(row(""));
2194
2292
  console.log(
2195
2293
  row(
2196
- ` ${chalk__default.default.dim(`${pad("File", nameW)}${padStart("Stmts", colW)}${padStart("Branch", colW)}${padStart("Funcs", colW)}${padStart("Lines", colW)}`)}`
2294
+ ` ${chalk.dim(`${pad("File", nameW)}${padStart("Stmts", colW)}${padStart("Branch", colW)}${padStart("Funcs", colW)}${padStart("Lines", colW)}`)}`
2197
2295
  )
2198
2296
  );
2199
2297
  for (const file of files) {
@@ -2201,67 +2299,67 @@ function printCoverageTable(event) {
2201
2299
  const short = name.length > nameW ? name.slice(0, nameW - 1) + "~" : name;
2202
2300
  console.log(
2203
2301
  row(
2204
- ` ${pad(short, nameW)}` + padStart(colorPct(file.statements.pct), colW) + padStart(colorPct(file.branches.pct), colW) + padStart(colorPct(file.functions.pct), colW) + padStart(colorPct(file.lines.pct), colW)
2302
+ ` ${pad(short, nameW)}` + padStart(colorPct(file.statements.pct, chalk), colW) + padStart(colorPct(file.branches.pct, chalk), colW) + padStart(colorPct(file.functions.pct, chalk), colW) + padStart(colorPct(file.lines.pct, chalk), colW)
2205
2303
  )
2206
2304
  );
2207
2305
  }
2208
- console.log(row(` ${chalk__default.default.dim("\u2500".repeat(nameW + colW * 4))}`));
2306
+ console.log(row(` ${chalk.dim("\u2500".repeat(nameW + colW * 4))}`));
2209
2307
  console.log(
2210
2308
  row(
2211
- ` ${chalk__default.default.bold(pad("All files", nameW))}` + padStart(colorPct(summary.statements.pct), colW) + padStart(colorPct(summary.branches.pct), colW) + padStart(colorPct(summary.functions.pct), colW) + padStart(colorPct(summary.lines.pct), colW)
2309
+ ` ${chalk.bold(pad("All files", nameW))}` + padStart(colorPct(summary.statements.pct, chalk), colW) + padStart(colorPct(summary.branches.pct, chalk), colW) + padStart(colorPct(summary.functions.pct, chalk), colW) + padStart(colorPct(summary.lines.pct, chalk), colW)
2212
2310
  )
2213
2311
  );
2214
2312
  }
2215
- function printRunSummary(result, streamingSuccess, data) {
2313
+ function printRunSummaryWithChalk(result, streamingSuccess, data, chalk) {
2216
2314
  const W = 72;
2217
- const topBorder = ` ${chalk__default.default.dim(`\u250C${"\u2500".repeat(W)}\u2510`)}`;
2218
- const bottomBorder = ` ${chalk__default.default.dim(`\u2514${"\u2500".repeat(W)}\u2518`)}`;
2219
- const divider = ` ${chalk__default.default.dim(`\u251C${"\u2500".repeat(W)}\u2524`)}`;
2220
- const row = (content) => ` ${chalk__default.default.dim("\u2502")} ${content}`;
2315
+ const topBorder = ` ${chalk.dim(`\u250C${"\u2500".repeat(W)}\u2510`)}`;
2316
+ const bottomBorder = ` ${chalk.dim(`\u2514${"\u2500".repeat(W)}\u2518`)}`;
2317
+ const divider = ` ${chalk.dim(`\u251C${"\u2500".repeat(W)}\u2524`)}`;
2318
+ const row = (content) => ` ${chalk.dim("\u2502")} ${content}`;
2221
2319
  console.log("");
2222
2320
  console.log(topBorder);
2223
- console.log(row(chalk__default.default.bold("TestDino Run Summary")));
2321
+ console.log(row(chalk.bold("TestDino Run Summary")));
2224
2322
  console.log(divider);
2225
- console.log(row(`${chalk__default.default.dim("Run")} ${data.runId}`));
2323
+ console.log(row(`${chalk.dim("Run")} ${data.runId}`));
2226
2324
  const git = data.runMetadata?.git;
2227
2325
  if (git?.branch || git?.commit?.hash) {
2228
- const branch = git.branch ? chalk__default.default.cyan(git.branch) : "";
2229
- const sha = git.commit?.hash ? chalk__default.default.dim(git.commit.hash.slice(0, 7)) : "";
2230
- const sep = branch && sha ? ` ${chalk__default.default.dim("@")} ` : "";
2231
- const msg = git.commit?.message ? ` ${chalk__default.default.dim(git.commit.message.split("\n")[0].slice(0, 50))}` : "";
2232
- console.log(row(`${chalk__default.default.dim("Git")} ${branch}${sep}${sha}${msg}`));
2326
+ const branch = git.branch ? chalk.cyan(git.branch) : "";
2327
+ const sha = git.commit?.hash ? chalk.dim(git.commit.hash.slice(0, 7)) : "";
2328
+ const sep = branch && sha ? ` ${chalk.dim("@")} ` : "";
2329
+ const msg = git.commit?.message ? ` ${chalk.dim(git.commit.message.split("\n")[0].slice(0, 50))}` : "";
2330
+ console.log(row(`${chalk.dim("Git")} ${branch}${sep}${sha}${msg}`));
2233
2331
  }
2234
2332
  console.log(divider);
2235
- const statusColor = result.status === "passed" ? chalk__default.default.green : result.status === "failed" ? chalk__default.default.red : chalk__default.default.yellow;
2333
+ const statusColor = result.status === "passed" ? chalk.green : result.status === "failed" ? chalk.red : chalk.yellow;
2236
2334
  const statusLabel = result.status === "timedout" ? "timed out" : result.status;
2237
2335
  console.log(
2238
2336
  row(
2239
- `${chalk__default.default.bold("Tests")} ${statusColor(statusLabel.toUpperCase())} ${chalk__default.default.dim(formatDuration(result.duration))}`
2337
+ `${chalk.bold("Tests")} ${statusColor(statusLabel.toUpperCase())} ${chalk.dim(formatDuration(result.duration))}`
2240
2338
  )
2241
2339
  );
2242
2340
  const counts = [];
2243
- if (data.testCounts.passed > 0) counts.push(chalk__default.default.green(`${data.testCounts.passed} passed`));
2244
- if (data.testCounts.failed > 0) counts.push(chalk__default.default.red(`${data.testCounts.failed} failed`));
2245
- if (data.testCounts.flaky > 0) counts.push(chalk__default.default.yellow(`${data.testCounts.flaky} flaky`));
2246
- if (data.testCounts.skipped > 0) counts.push(chalk__default.default.dim(`${data.testCounts.skipped} skipped`));
2247
- if (data.testCounts.timedOut > 0) counts.push(chalk__default.default.red(`${data.testCounts.timedOut} timed out`));
2248
- if (data.testCounts.interrupted > 0) counts.push(chalk__default.default.yellow(`${data.testCounts.interrupted} interrupted`));
2249
- const retriedStr = data.testCounts.retried > 0 ? ` ${chalk__default.default.dim(`(${data.testCounts.retried} retries)`)}` : "";
2250
- console.log(row(` ${counts.join(chalk__default.default.dim(" \xB7 "))} ${chalk__default.default.dim(`of ${data.totalTests}`)}${retriedStr}`));
2341
+ if (data.testCounts.passed > 0) counts.push(chalk.green(`${data.testCounts.passed} passed`));
2342
+ if (data.testCounts.failed > 0) counts.push(chalk.red(`${data.testCounts.failed} failed`));
2343
+ if (data.testCounts.flaky > 0) counts.push(chalk.yellow(`${data.testCounts.flaky} flaky`));
2344
+ if (data.testCounts.skipped > 0) counts.push(chalk.dim(`${data.testCounts.skipped} skipped`));
2345
+ if (data.testCounts.timedOut > 0) counts.push(chalk.red(`${data.testCounts.timedOut} timed out`));
2346
+ if (data.testCounts.interrupted > 0) counts.push(chalk.yellow(`${data.testCounts.interrupted} interrupted`));
2347
+ const retriedStr = data.testCounts.retried > 0 ? ` ${chalk.dim(`(${data.testCounts.retried} retries)`)}` : "";
2348
+ console.log(row(` ${counts.join(chalk.dim(" \xB7 "))} ${chalk.dim(`of ${data.totalTests}`)}${retriedStr}`));
2251
2349
  console.log(divider);
2252
2350
  const shardStr = data.shardInfo ? `${data.shardInfo.current}/${data.shardInfo.total}` : "\u2014";
2253
2351
  console.log(
2254
2352
  row(
2255
- `${pad(`${chalk__default.default.dim("Workers")} ${data.workerCount > 0 ? data.workerCount : "\u2014"}`, 28)}${pad(`${chalk__default.default.dim("Shard")} ${shardStr}`, 28)}${chalk__default.default.dim("Projects")} ${data.projectNames.size > 0 ? Array.from(data.projectNames).join(", ") : "\u2014"}`
2353
+ `${pad(`${chalk.dim("Workers")} ${data.workerCount > 0 ? data.workerCount : "\u2014"}`, 28)}${pad(`${chalk.dim("Shard")} ${shardStr}`, 28)}${chalk.dim("Projects")} ${data.projectNames.size > 0 ? Array.from(data.projectNames).join(", ") : "\u2014"}`
2256
2354
  )
2257
2355
  );
2258
2356
  console.log(divider);
2259
2357
  const transport = data.useHttpFallback ? "HTTP" : "WebSocket";
2260
- const streamIcon = streamingSuccess ? chalk__default.default.green("sent") : chalk__default.default.red("failed");
2261
- console.log(row(`${chalk__default.default.bold("Stream")} ${streamIcon} ${chalk__default.default.dim(`via ${transport}`)}`));
2358
+ const streamIcon = streamingSuccess ? chalk.green("sent") : chalk.red("failed");
2359
+ console.log(row(`${chalk.bold("Stream")} ${streamIcon} ${chalk.dim(`via ${transport}`)}`));
2262
2360
  if (data.lastCoverageEvent) {
2263
2361
  console.log(divider);
2264
- printCoverageTable(data.lastCoverageEvent);
2362
+ printCoverageTableWithChalk(data.lastCoverageEvent, chalk);
2265
2363
  }
2266
2364
  console.log(bottomBorder);
2267
2365
  console.log("");
@@ -2276,8 +2374,14 @@ var createReporterLog = (options) => ({
2276
2374
  console.log(`\u{1F50D} TestDino: ${msg}`);
2277
2375
  }
2278
2376
  },
2279
- printRunSummary,
2280
- printCoverageTable
2377
+ printRunSummary: async (result, streamingSuccess, data) => {
2378
+ const chalk = await getChalk();
2379
+ printRunSummaryWithChalk(result, streamingSuccess, data, chalk);
2380
+ },
2381
+ printCoverageTable: async (event) => {
2382
+ const chalk = await getChalk();
2383
+ printCoverageTableWithChalk(event, chalk);
2384
+ }
2281
2385
  });
2282
2386
 
2283
2387
  // src/reporter/index.ts
@@ -2301,6 +2405,7 @@ var TestdinoReporter = class {
2301
2405
  isShuttingDown = false;
2302
2406
  // Quota tracking
2303
2407
  quotaExceeded = false;
2408
+ pendingQuotaError = null;
2304
2409
  // Session ID from HTTP auth, passed to WebSocket for session reuse
2305
2410
  sessionId = null;
2306
2411
  // Artifact upload
@@ -2330,7 +2435,7 @@ var TestdinoReporter = class {
2330
2435
  constructor(config = {}) {
2331
2436
  const cliConfig = this.loadCliConfig();
2332
2437
  this.config = { ...config, ...cliConfig };
2333
- this.runId = crypto.randomUUID();
2438
+ this.runId = (0, import_crypto2.randomUUID)();
2334
2439
  this.log = createReporterLog({ debug: this.config.debug ?? false });
2335
2440
  this.coverageEnabled = this.config.coverage?.enabled ?? false;
2336
2441
  if (this.coverageEnabled) {
@@ -2360,10 +2465,10 @@ var TestdinoReporter = class {
2360
2465
  return {};
2361
2466
  }
2362
2467
  try {
2363
- if (!fs.existsSync(cliConfigPath)) {
2468
+ if (!(0, import_fs2.existsSync)(cliConfigPath)) {
2364
2469
  return {};
2365
2470
  }
2366
- const configContent = fs.readFileSync(cliConfigPath, "utf-8");
2471
+ const configContent = (0, import_fs2.readFileSync)(cliConfigPath, "utf-8");
2367
2472
  const cliConfig = JSON.parse(configContent);
2368
2473
  const mappedConfig = {};
2369
2474
  if (cliConfig.token !== void 0 && typeof cliConfig.token === "string") {
@@ -2463,7 +2568,7 @@ var TestdinoReporter = class {
2463
2568
  if (!this.quotaExceeded) {
2464
2569
  this.quotaExceeded = true;
2465
2570
  this.initFailed = true;
2466
- this.printQuotaError(error);
2571
+ this.pendingQuotaError = error;
2467
2572
  }
2468
2573
  } else {
2469
2574
  this.log.error(`WebSocket error: ${error.message}`);
@@ -2503,7 +2608,7 @@ var TestdinoReporter = class {
2503
2608
  this.initFailed = true;
2504
2609
  if (error instanceof Error && "code" in error && isQuotaError(error)) {
2505
2610
  this.quotaExceeded = true;
2506
- this.printQuotaError(error);
2611
+ this.pendingQuotaError = error;
2507
2612
  } else if (errorMessage.includes("Authentication failed") || errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
2508
2613
  this.printConfigurationError("Authentication failed - Invalid or expired token", [
2509
2614
  "Verify your token is correct",
@@ -2727,6 +2832,9 @@ var TestdinoReporter = class {
2727
2832
  if (this.pendingTestEndPromises.size > 0) {
2728
2833
  await Promise.allSettled(Array.from(this.pendingTestEndPromises));
2729
2834
  }
2835
+ if (this.pendingQuotaError) {
2836
+ this.printQuotaError(this.pendingQuotaError);
2837
+ }
2730
2838
  this.log.success("Tests completed (quota limit reached; not streamed to TestDino)");
2731
2839
  this.wsClient?.close();
2732
2840
  this.removeSignalHandlers();
@@ -2815,8 +2923,15 @@ var TestdinoReporter = class {
2815
2923
  this.log.success("All events sent (HTTP fallback)");
2816
2924
  delivered = true;
2817
2925
  } catch (httpError) {
2818
- const httpErrorMessage = httpError instanceof Error ? httpError.message : String(httpError);
2819
- this.log.error(`HTTP fallback also failed: ${httpErrorMessage}`);
2926
+ const isQuota = isQuotaError(httpError) || httpError instanceof Error && "code" in httpError && (httpError.code === "QUOTA_EXCEEDED" || httpError.code === "QUOTA_EXHAUSTED");
2927
+ if (isQuota) {
2928
+ this.quotaExceeded = true;
2929
+ this.pendingQuotaError = httpError;
2930
+ this.printQuotaError(httpError);
2931
+ } else {
2932
+ const httpErrorMessage = httpError instanceof Error ? httpError.message : String(httpError);
2933
+ this.log.error(`HTTP fallback also failed: ${httpErrorMessage}`);
2934
+ }
2820
2935
  }
2821
2936
  } else if (!delivered) {
2822
2937
  this.log.warn("Server did not acknowledge run:end in time, events may be pending");
@@ -2836,7 +2951,7 @@ var TestdinoReporter = class {
2836
2951
  useHttpFallback: this.useHttpFallback,
2837
2952
  lastCoverageEvent: this.lastCoverageEvent
2838
2953
  };
2839
- this.log.printRunSummary(result, delivered, summaryData);
2954
+ await this.log.printRunSummary(result, delivered, summaryData);
2840
2955
  if (this.coverageThresholdFailed && this.lastCoverageEvent) {
2841
2956
  const failures = this.checkCoverageThresholds(this.lastCoverageEvent.summary);
2842
2957
  this.log.error("Coverage thresholds not met:");
@@ -3123,45 +3238,75 @@ var TestdinoReporter = class {
3123
3238
  const details = errorData.details;
3124
3239
  const planName = details?.planName || "Unknown";
3125
3240
  const resetDate = details?.resetDate;
3126
- let message = "Execution quota exceeded";
3127
- message += `
3128
-
3129
- Current Plan: ${planName}`;
3130
- if (errorData.code === "QUOTA_EXHAUSTED") {
3131
- message += `
3132
- Monthly Limit: ${details.totalLimit || "Unknown"} executions`;
3133
- message += `
3134
- Used: ${details.used || "Unknown"} executions`;
3135
- if (resetDate) {
3136
- message += `
3137
- Limit Resets: ${new Date(resetDate).toLocaleDateString()}`;
3138
- }
3139
- } else if (errorData.code === "QUOTA_EXCEEDED") {
3241
+ const formattedResetDate = resetDate ? new Date(resetDate).toLocaleDateString("en-US", {
3242
+ day: "2-digit",
3243
+ month: "short",
3244
+ year: "numeric"
3245
+ }) : void 0;
3246
+ console.error("");
3247
+ console.error(border);
3248
+ if (errorData.code === "QUOTA_EXCEEDED") {
3140
3249
  const exceeded = details;
3141
- message += `
3142
- Monthly Limit: ${exceeded.total || "Unknown"} executions`;
3143
- message += `
3144
- Used: ${exceeded.used || "Unknown"} executions`;
3145
- const remaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);
3146
- message += `
3147
- Remaining: ${remaining} executions`;
3148
- message += `
3149
- Tests in this run: ${exceeded.totalTests || "Unknown"}`;
3150
- if (resetDate) {
3151
- message += `
3152
- Limit Resets: ${new Date(resetDate).toLocaleDateString()}`;
3250
+ const orgRemaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);
3251
+ const effectiveLimit = (exceeded.projectLimit ?? 0) + (exceeded.projectBorrowed ?? 0);
3252
+ console.error(" \u274C TestDino Project Execution Limit Reached");
3253
+ console.error(border);
3254
+ console.error("");
3255
+ console.error(" The test case limit allocated to this project has been exceeded.");
3256
+ console.error("");
3257
+ console.error(" Project Usage:");
3258
+ if (exceeded.projectName) {
3259
+ console.error(` Project: ${exceeded.projectName}`);
3260
+ }
3261
+ if (exceeded.projectLimit != null) {
3262
+ console.error(
3263
+ ` Limit: ${effectiveLimit} test cases${exceeded.projectBorrowed ? ` (${exceeded.projectLimit} allocated + ${exceeded.projectBorrowed} borrowed)` : ""}`
3264
+ );
3153
3265
  }
3266
+ if (exceeded.projectUsed != null) {
3267
+ console.error(` Used: ${exceeded.projectUsed}`);
3268
+ }
3269
+ console.error(` This run: ${exceeded.totalTests || "Unknown"} test cases`);
3270
+ console.error(" Status: Project quota exhausted");
3271
+ console.error("");
3272
+ console.error(" Organization Usage:");
3273
+ console.error(` Plan: ${planName} (${exceeded.total || "Unknown"} test cases / month)`);
3274
+ console.error(` Used: ${exceeded.used || "Unknown"}`);
3275
+ console.error(` Remaining: ${orgRemaining}`);
3276
+ if (orgRemaining > 0) {
3277
+ console.error("");
3278
+ console.error(" Note:");
3279
+ console.error(` Your organization still has ${orgRemaining} test cases available,`);
3280
+ console.error(" but they are not allocated to this project.");
3281
+ }
3282
+ console.error("");
3283
+ console.error(" Solutions:");
3284
+ console.error(" 1. Allocate more test case quota to this project in");
3285
+ console.error(" Settings \u2192 Billing & Usage \u2192 Test Limits");
3286
+ console.error(" 2. Enable Auto Allocation to automatically distribute");
3287
+ console.error(" remaining organization quota");
3288
+ } else if (errorData.code === "QUOTA_EXHAUSTED") {
3289
+ console.error(" \u274C TestDino Organization Execution Limit Reached");
3290
+ console.error(border);
3291
+ console.error("");
3292
+ console.error(" Your organization has exhausted its monthly test case limit.");
3293
+ console.error("");
3294
+ console.error(" Organization Usage:");
3295
+ console.error(` Plan: ${planName} (${details.totalLimit || "Unknown"} test cases / month)`);
3296
+ console.error(` Used: ${details.used || "Unknown"}`);
3297
+ console.error(" Remaining: 0");
3298
+ console.error("");
3299
+ console.error(" Solutions:");
3300
+ console.error(" 1. Upgrade your plan to increase monthly test case limit");
3301
+ }
3302
+ if (formattedResetDate) {
3303
+ console.error("");
3304
+ console.error(" Monthly Reset:");
3305
+ console.error(` ${formattedResetDate}`);
3154
3306
  }
3155
3307
  console.error("");
3156
- console.error(border);
3157
- console.error(" \u274C TestDino Execution Limit Reached");
3158
- console.error(border);
3159
- console.error(` ${message}`);
3160
- console.error("");
3161
- console.error(" Solutions:");
3162
- console.error(" 1. Upgrade your plan to increase monthly limit");
3163
- console.error(" 2. Wait for monthly limit reset");
3164
- console.error(" 3. Visit https://testdino.com/pricing for plan options");
3308
+ console.error(" Docs: https://docs.testdino.com/platform/billing-and-usage/test-limits");
3309
+ console.error(" Pricing: https://testdino.com/pricing");
3165
3310
  console.error(border);
3166
3311
  console.error("");
3167
3312
  }
@@ -3541,13 +3686,10 @@ var TestdinoReporter = class {
3541
3686
  return failures;
3542
3687
  }
3543
3688
  };
3544
-
3545
- Object.defineProperty(exports, "expect", {
3546
- enumerable: true,
3547
- get: function () { return test$1.expect; }
3689
+ // Annotate the CommonJS export names for ESM import in node:
3690
+ 0 && (module.exports = {
3691
+ coverageFixtures,
3692
+ expect,
3693
+ test
3548
3694
  });
3549
- exports.coverageFixtures = coverageFixtures;
3550
- exports.default = TestdinoReporter;
3551
- exports.test = test;
3552
- //# sourceMappingURL=index.js.map
3553
3695
  //# sourceMappingURL=index.js.map