@testdino/playwright 1.0.10 → 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.d.mts CHANGED
@@ -489,6 +489,10 @@ declare class QuotaExceededError extends TestDinoServerError {
489
489
  resetDate?: string;
490
490
  canPartialSubmit: boolean;
491
491
  allowedCount: number;
492
+ projectName?: string;
493
+ projectLimit?: number;
494
+ projectUsed?: number;
495
+ projectBorrowed?: number;
492
496
  };
493
497
  constructor(message: string, details: {
494
498
  planName: string;
@@ -499,6 +503,10 @@ declare class QuotaExceededError extends TestDinoServerError {
499
503
  resetDate?: string;
500
504
  canPartialSubmit: boolean;
501
505
  allowedCount: number;
506
+ projectName?: string;
507
+ projectLimit?: number;
508
+ projectUsed?: number;
509
+ projectBorrowed?: number;
502
510
  });
503
511
  }
504
512
  /**
@@ -833,6 +841,7 @@ declare class TestdinoReporter implements Reporter {
833
841
  private sigtermHandler?;
834
842
  private isShuttingDown;
835
843
  private quotaExceeded;
844
+ private pendingQuotaError;
836
845
  private sessionId;
837
846
  private artifactUploader;
838
847
  private artifactsEnabled;
package/dist/index.d.ts CHANGED
@@ -489,6 +489,10 @@ declare class QuotaExceededError extends TestDinoServerError {
489
489
  resetDate?: string;
490
490
  canPartialSubmit: boolean;
491
491
  allowedCount: number;
492
+ projectName?: string;
493
+ projectLimit?: number;
494
+ projectUsed?: number;
495
+ projectBorrowed?: number;
492
496
  };
493
497
  constructor(message: string, details: {
494
498
  planName: string;
@@ -499,6 +503,10 @@ declare class QuotaExceededError extends TestDinoServerError {
499
503
  resetDate?: string;
500
504
  canPartialSubmit: boolean;
501
505
  allowedCount: number;
506
+ projectName?: string;
507
+ projectLimit?: number;
508
+ projectUsed?: number;
509
+ projectBorrowed?: number;
502
510
  });
503
511
  }
504
512
  /**
@@ -833,6 +841,7 @@ declare class TestdinoReporter implements Reporter {
833
841
  private sigtermHandler?;
834
842
  private isShuttingDown;
835
843
  private quotaExceeded;
844
+ private pendingQuotaError;
836
845
  private sessionId;
837
846
  private artifactUploader;
838
847
  private artifactsEnabled;
package/dist/index.js CHANGED
@@ -306,7 +306,11 @@ var WebSocketClient = class {
306
306
  total: Number(details.total) || 0,
307
307
  resetDate: details.resetDate?.toString(),
308
308
  canPartialSubmit: Boolean(details.canPartialSubmit),
309
- 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
310
314
  })
311
315
  );
312
316
  } else if (errorCode === "QUOTA_EXHAUSTED" && errorObj.details && typeof errorObj.details === "object") {
@@ -458,6 +462,14 @@ var HttpClient = class {
458
462
  await this.client.post("/events", { events });
459
463
  return;
460
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
+ }
461
473
  lastError = new Error(this.getErrorMessage(error));
462
474
  if (attempt < this.options.maxRetries - 1) {
463
475
  const delay = this.options.retryDelay * Math.pow(2, attempt);
@@ -2393,6 +2405,7 @@ var TestdinoReporter = class {
2393
2405
  isShuttingDown = false;
2394
2406
  // Quota tracking
2395
2407
  quotaExceeded = false;
2408
+ pendingQuotaError = null;
2396
2409
  // Session ID from HTTP auth, passed to WebSocket for session reuse
2397
2410
  sessionId = null;
2398
2411
  // Artifact upload
@@ -2555,7 +2568,7 @@ var TestdinoReporter = class {
2555
2568
  if (!this.quotaExceeded) {
2556
2569
  this.quotaExceeded = true;
2557
2570
  this.initFailed = true;
2558
- this.printQuotaError(error);
2571
+ this.pendingQuotaError = error;
2559
2572
  }
2560
2573
  } else {
2561
2574
  this.log.error(`WebSocket error: ${error.message}`);
@@ -2595,7 +2608,7 @@ var TestdinoReporter = class {
2595
2608
  this.initFailed = true;
2596
2609
  if (error instanceof Error && "code" in error && isQuotaError(error)) {
2597
2610
  this.quotaExceeded = true;
2598
- this.printQuotaError(error);
2611
+ this.pendingQuotaError = error;
2599
2612
  } else if (errorMessage.includes("Authentication failed") || errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
2600
2613
  this.printConfigurationError("Authentication failed - Invalid or expired token", [
2601
2614
  "Verify your token is correct",
@@ -2819,6 +2832,9 @@ var TestdinoReporter = class {
2819
2832
  if (this.pendingTestEndPromises.size > 0) {
2820
2833
  await Promise.allSettled(Array.from(this.pendingTestEndPromises));
2821
2834
  }
2835
+ if (this.pendingQuotaError) {
2836
+ this.printQuotaError(this.pendingQuotaError);
2837
+ }
2822
2838
  this.log.success("Tests completed (quota limit reached; not streamed to TestDino)");
2823
2839
  this.wsClient?.close();
2824
2840
  this.removeSignalHandlers();
@@ -2907,8 +2923,15 @@ var TestdinoReporter = class {
2907
2923
  this.log.success("All events sent (HTTP fallback)");
2908
2924
  delivered = true;
2909
2925
  } catch (httpError) {
2910
- const httpErrorMessage = httpError instanceof Error ? httpError.message : String(httpError);
2911
- 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
+ }
2912
2935
  }
2913
2936
  } else if (!delivered) {
2914
2937
  this.log.warn("Server did not acknowledge run:end in time, events may be pending");
@@ -3215,45 +3238,75 @@ var TestdinoReporter = class {
3215
3238
  const details = errorData.details;
3216
3239
  const planName = details?.planName || "Unknown";
3217
3240
  const resetDate = details?.resetDate;
3218
- let message = "Execution quota exceeded";
3219
- message += `
3220
-
3221
- Current Plan: ${planName}`;
3222
- if (errorData.code === "QUOTA_EXHAUSTED") {
3223
- message += `
3224
- Monthly Limit: ${details.totalLimit || "Unknown"} executions`;
3225
- message += `
3226
- Used: ${details.used || "Unknown"} executions`;
3227
- if (resetDate) {
3228
- message += `
3229
- Limit Resets: ${new Date(resetDate).toLocaleDateString()}`;
3230
- }
3231
- } 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") {
3232
3249
  const exceeded = details;
3233
- message += `
3234
- Monthly Limit: ${exceeded.total || "Unknown"} executions`;
3235
- message += `
3236
- Used: ${exceeded.used || "Unknown"} executions`;
3237
- const remaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);
3238
- message += `
3239
- Remaining: ${remaining} executions`;
3240
- message += `
3241
- Tests in this run: ${exceeded.totalTests || "Unknown"}`;
3242
- if (resetDate) {
3243
- message += `
3244
- 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
+ );
3245
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}`);
3246
3306
  }
3247
3307
  console.error("");
3248
- console.error(border);
3249
- console.error(" \u274C TestDino Execution Limit Reached");
3250
- console.error(border);
3251
- console.error(` ${message}`);
3252
- console.error("");
3253
- console.error(" Solutions:");
3254
- console.error(" 1. Upgrade your plan to increase monthly limit");
3255
- console.error(" 2. Wait for monthly limit reset");
3256
- 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");
3257
3310
  console.error(border);
3258
3311
  console.error("");
3259
3312
  }