@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.mjs CHANGED
@@ -274,7 +274,11 @@ var WebSocketClient = class {
274
274
  total: Number(details.total) || 0,
275
275
  resetDate: details.resetDate?.toString(),
276
276
  canPartialSubmit: Boolean(details.canPartialSubmit),
277
- allowedCount: Number(details.allowedCount) || 0
277
+ allowedCount: Number(details.allowedCount) || 0,
278
+ projectName: details.projectName?.toString(),
279
+ projectLimit: details.projectLimit != null ? Number(details.projectLimit) : void 0,
280
+ projectUsed: details.projectUsed != null ? Number(details.projectUsed) : void 0,
281
+ projectBorrowed: details.projectBorrowed != null ? Number(details.projectBorrowed) : void 0
278
282
  })
279
283
  );
280
284
  } else if (errorCode === "QUOTA_EXHAUSTED" && errorObj.details && typeof errorObj.details === "object") {
@@ -426,6 +430,14 @@ var HttpClient = class {
426
430
  await this.client.post("/events", { events });
427
431
  return;
428
432
  } catch (error) {
433
+ if (axios.isAxiosError(error) && error.response?.status === 402) {
434
+ const data = error.response.data;
435
+ const details = data?.details;
436
+ if (data?.error === "QUOTA_EXCEEDED" && details) {
437
+ throw new QuotaExceededError(data.message || "Quota exceeded", details);
438
+ }
439
+ throw new QuotaExhaustedError(data?.message || "Quota exceeded", details);
440
+ }
429
441
  lastError = new Error(this.getErrorMessage(error));
430
442
  if (attempt < this.options.maxRetries - 1) {
431
443
  const delay = this.options.retryDelay * Math.pow(2, attempt);
@@ -2361,6 +2373,7 @@ var TestdinoReporter = class {
2361
2373
  isShuttingDown = false;
2362
2374
  // Quota tracking
2363
2375
  quotaExceeded = false;
2376
+ pendingQuotaError = null;
2364
2377
  // Session ID from HTTP auth, passed to WebSocket for session reuse
2365
2378
  sessionId = null;
2366
2379
  // Artifact upload
@@ -2523,7 +2536,7 @@ var TestdinoReporter = class {
2523
2536
  if (!this.quotaExceeded) {
2524
2537
  this.quotaExceeded = true;
2525
2538
  this.initFailed = true;
2526
- this.printQuotaError(error);
2539
+ this.pendingQuotaError = error;
2527
2540
  }
2528
2541
  } else {
2529
2542
  this.log.error(`WebSocket error: ${error.message}`);
@@ -2563,7 +2576,7 @@ var TestdinoReporter = class {
2563
2576
  this.initFailed = true;
2564
2577
  if (error instanceof Error && "code" in error && isQuotaError(error)) {
2565
2578
  this.quotaExceeded = true;
2566
- this.printQuotaError(error);
2579
+ this.pendingQuotaError = error;
2567
2580
  } else if (errorMessage.includes("Authentication failed") || errorMessage.includes("401") || errorMessage.includes("Unauthorized")) {
2568
2581
  this.printConfigurationError("Authentication failed - Invalid or expired token", [
2569
2582
  "Verify your token is correct",
@@ -2787,6 +2800,9 @@ var TestdinoReporter = class {
2787
2800
  if (this.pendingTestEndPromises.size > 0) {
2788
2801
  await Promise.allSettled(Array.from(this.pendingTestEndPromises));
2789
2802
  }
2803
+ if (this.pendingQuotaError) {
2804
+ this.printQuotaError(this.pendingQuotaError);
2805
+ }
2790
2806
  this.log.success("Tests completed (quota limit reached; not streamed to TestDino)");
2791
2807
  this.wsClient?.close();
2792
2808
  this.removeSignalHandlers();
@@ -2875,8 +2891,15 @@ var TestdinoReporter = class {
2875
2891
  this.log.success("All events sent (HTTP fallback)");
2876
2892
  delivered = true;
2877
2893
  } catch (httpError) {
2878
- const httpErrorMessage = httpError instanceof Error ? httpError.message : String(httpError);
2879
- this.log.error(`HTTP fallback also failed: ${httpErrorMessage}`);
2894
+ const isQuota = isQuotaError(httpError) || httpError instanceof Error && "code" in httpError && (httpError.code === "QUOTA_EXCEEDED" || httpError.code === "QUOTA_EXHAUSTED");
2895
+ if (isQuota) {
2896
+ this.quotaExceeded = true;
2897
+ this.pendingQuotaError = httpError;
2898
+ this.printQuotaError(httpError);
2899
+ } else {
2900
+ const httpErrorMessage = httpError instanceof Error ? httpError.message : String(httpError);
2901
+ this.log.error(`HTTP fallback also failed: ${httpErrorMessage}`);
2902
+ }
2880
2903
  }
2881
2904
  } else if (!delivered) {
2882
2905
  this.log.warn("Server did not acknowledge run:end in time, events may be pending");
@@ -3183,45 +3206,75 @@ var TestdinoReporter = class {
3183
3206
  const details = errorData.details;
3184
3207
  const planName = details?.planName || "Unknown";
3185
3208
  const resetDate = details?.resetDate;
3186
- let message = "Execution quota exceeded";
3187
- message += `
3188
-
3189
- Current Plan: ${planName}`;
3190
- if (errorData.code === "QUOTA_EXHAUSTED") {
3191
- message += `
3192
- Monthly Limit: ${details.totalLimit || "Unknown"} executions`;
3193
- message += `
3194
- Used: ${details.used || "Unknown"} executions`;
3195
- if (resetDate) {
3196
- message += `
3197
- Limit Resets: ${new Date(resetDate).toLocaleDateString()}`;
3198
- }
3199
- } else if (errorData.code === "QUOTA_EXCEEDED") {
3209
+ const formattedResetDate = resetDate ? new Date(resetDate).toLocaleDateString("en-US", {
3210
+ day: "2-digit",
3211
+ month: "short",
3212
+ year: "numeric"
3213
+ }) : void 0;
3214
+ console.error("");
3215
+ console.error(border);
3216
+ if (errorData.code === "QUOTA_EXCEEDED") {
3200
3217
  const exceeded = details;
3201
- message += `
3202
- Monthly Limit: ${exceeded.total || "Unknown"} executions`;
3203
- message += `
3204
- Used: ${exceeded.used || "Unknown"} executions`;
3205
- const remaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);
3206
- message += `
3207
- Remaining: ${remaining} executions`;
3208
- message += `
3209
- Tests in this run: ${exceeded.totalTests || "Unknown"}`;
3210
- if (resetDate) {
3211
- message += `
3212
- Limit Resets: ${new Date(resetDate).toLocaleDateString()}`;
3218
+ const orgRemaining = (exceeded.total ?? 0) - (exceeded.used ?? 0);
3219
+ const effectiveLimit = (exceeded.projectLimit ?? 0) + (exceeded.projectBorrowed ?? 0);
3220
+ console.error(" \u274C TestDino Project Execution Limit Reached");
3221
+ console.error(border);
3222
+ console.error("");
3223
+ console.error(" The test case limit allocated to this project has been exceeded.");
3224
+ console.error("");
3225
+ console.error(" Project Usage:");
3226
+ if (exceeded.projectName) {
3227
+ console.error(` Project: ${exceeded.projectName}`);
3228
+ }
3229
+ if (exceeded.projectLimit != null) {
3230
+ console.error(
3231
+ ` Limit: ${effectiveLimit} test cases${exceeded.projectBorrowed ? ` (${exceeded.projectLimit} allocated + ${exceeded.projectBorrowed} borrowed)` : ""}`
3232
+ );
3213
3233
  }
3234
+ if (exceeded.projectUsed != null) {
3235
+ console.error(` Used: ${exceeded.projectUsed}`);
3236
+ }
3237
+ console.error(` This run: ${exceeded.totalTests || "Unknown"} test cases`);
3238
+ console.error(" Status: Project quota exhausted");
3239
+ console.error("");
3240
+ console.error(" Organization Usage:");
3241
+ console.error(` Plan: ${planName} (${exceeded.total || "Unknown"} test cases / month)`);
3242
+ console.error(` Used: ${exceeded.used || "Unknown"}`);
3243
+ console.error(` Remaining: ${orgRemaining}`);
3244
+ if (orgRemaining > 0) {
3245
+ console.error("");
3246
+ console.error(" Note:");
3247
+ console.error(` Your organization still has ${orgRemaining} test cases available,`);
3248
+ console.error(" but they are not allocated to this project.");
3249
+ }
3250
+ console.error("");
3251
+ console.error(" Solutions:");
3252
+ console.error(" 1. Allocate more test case quota to this project in");
3253
+ console.error(" Settings \u2192 Billing & Usage \u2192 Test Limits");
3254
+ console.error(" 2. Enable Auto Allocation to automatically distribute");
3255
+ console.error(" remaining organization quota");
3256
+ } else if (errorData.code === "QUOTA_EXHAUSTED") {
3257
+ console.error(" \u274C TestDino Organization Execution Limit Reached");
3258
+ console.error(border);
3259
+ console.error("");
3260
+ console.error(" Your organization has exhausted its monthly test case limit.");
3261
+ console.error("");
3262
+ console.error(" Organization Usage:");
3263
+ console.error(` Plan: ${planName} (${details.totalLimit || "Unknown"} test cases / month)`);
3264
+ console.error(` Used: ${details.used || "Unknown"}`);
3265
+ console.error(" Remaining: 0");
3266
+ console.error("");
3267
+ console.error(" Solutions:");
3268
+ console.error(" 1. Upgrade your plan to increase monthly test case limit");
3269
+ }
3270
+ if (formattedResetDate) {
3271
+ console.error("");
3272
+ console.error(" Monthly Reset:");
3273
+ console.error(` ${formattedResetDate}`);
3214
3274
  }
3215
3275
  console.error("");
3216
- console.error(border);
3217
- console.error(" \u274C TestDino Execution Limit Reached");
3218
- console.error(border);
3219
- console.error(` ${message}`);
3220
- console.error("");
3221
- console.error(" Solutions:");
3222
- console.error(" 1. Upgrade your plan to increase monthly limit");
3223
- console.error(" 2. Wait for monthly limit reset");
3224
- console.error(" 3. Visit https://testdino.com/pricing for plan options");
3276
+ console.error(" Docs: https://docs.testdino.com/platform/billing-and-usage/test-limits");
3277
+ console.error(" Pricing: https://testdino.com/pricing");
3225
3278
  console.error(border);
3226
3279
  console.error("");
3227
3280
  }