testlens-playwright-reporter 0.3.1 → 0.3.3

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.
Files changed (4) hide show
  1. package/index.js +127 -8
  2. package/index.ts +123 -13
  3. package/lib/index.js +119 -12
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -1,5 +1,3 @@
1
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
2
-
3
1
  const { randomUUID } = require('crypto');
4
2
  const os = require('os');
5
3
  const path = require('path');
@@ -97,6 +95,7 @@ class TestLensReporter {
97
95
  this.runMetadata = this.initializeRunMetadata();
98
96
  this.specMap = new Map();
99
97
  this.testMap = new Map();
98
+ this.runCreationFailed = false; // Track if run creation failed due to limits
100
99
  }
101
100
 
102
101
  initializeRunMetadata() {
@@ -164,6 +163,9 @@ class TestLensReporter {
164
163
  }
165
164
 
166
165
  async onTestBegin(test, result) {
166
+ // Log which test is starting
167
+ console.log(`\n▶️ Running test: ${test.title}`);
168
+
167
169
  const specPath = test.location.file;
168
170
  const specKey = `${specPath}-${test.parent.title}`;
169
171
 
@@ -496,24 +498,108 @@ class TestLensReporter {
496
498
  }
497
499
 
498
500
  async sendToApi(payload) {
501
+ // Skip sending if run creation already failed
502
+ if (this.runCreationFailed && payload.type !== 'runStart') {
503
+ return false;
504
+ }
505
+
499
506
  try {
500
507
  const response = await this.axiosInstance.post('', payload, {
501
508
  headers: {
502
509
  'X-API-Key': this.config.apiKey
503
510
  }
504
511
  });
512
+ if (this.config.enableRealTimeStream) {
513
+ console.log(`✅ Sent ${payload.type} event to TestLens (HTTP ${response.status})`);
514
+ }
515
+ return true;
505
516
  } catch (error) {
506
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
507
- message: error?.message || 'Unknown error',
508
- status: error?.response?.status,
509
- data: error?.response?.data
510
- });
517
+ const errorData = error?.response?.data;
518
+ const status = error?.response?.status;
511
519
 
520
+ // Check for limit exceeded (403)
521
+ if (status === 403 && errorData?.error === 'limit_exceeded') {
522
+ // Set flag to skip subsequent events
523
+ if (payload.type === 'runStart' && errorData?.limit_type === 'test_runs') {
524
+ this.runCreationFailed = true;
525
+ }
526
+
527
+ console.error('\n' + '='.repeat(80));
528
+ if (errorData?.limit_type === 'test_cases') {
529
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
530
+ } else if (errorData?.limit_type === 'test_runs') {
531
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
532
+ } else {
533
+ console.error('❌ TESTLENS ERROR: Plan Limit Reached');
534
+ }
535
+ console.error('='.repeat(80));
536
+ console.error('');
537
+ console.error(errorData?.message || 'You have reached your plan limit.');
538
+ console.error('');
539
+ console.error(`Current usage: ${errorData?.current_usage || 'N/A'} / ${errorData?.limit || 'N/A'}`);
540
+ console.error('');
541
+ console.error('To continue, please upgrade your plan.');
542
+ console.error('Contact: support@alternative-path.com');
543
+ console.error('');
544
+ console.error('='.repeat(80));
545
+ console.error('');
546
+ return false; // Don't log the full error object for limit errors
547
+ }
548
+
549
+ // Check for trial expiration, subscription errors, or limit errors (401)
550
+ if (status === 401) {
551
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
552
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
553
+ console.error('\n' + '='.repeat(80));
554
+
555
+ if (errorData?.error === 'test_cases_limit_reached') {
556
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
557
+ } else if (errorData?.error === 'test_runs_limit_reached') {
558
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
559
+ } else {
560
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
561
+ }
562
+
563
+ console.error('='.repeat(80));
564
+ console.error('');
565
+ console.error(errorData?.message || 'Your trial period has expired.');
566
+ console.error('');
567
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
568
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
569
+ console.error('');
570
+ if (errorData?.trial_end_date) {
571
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
572
+ console.error('');
573
+ }
574
+ console.error('='.repeat(80));
575
+ console.error('');
576
+ } else {
577
+ console.error(`❌ Authentication failed: ${errorData?.error || 'Invalid API key'}`);
578
+ }
579
+ } else if (status !== 403) {
580
+ // Log other errors (but not 403 which we handled above)
581
+ console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
582
+ message: error?.message || 'Unknown error',
583
+ status: status,
584
+ statusText: error?.response?.statusText,
585
+ data: errorData,
586
+ code: error?.code,
587
+ url: error?.config?.url,
588
+ method: error?.config?.method
589
+ });
590
+ }
591
+
592
+ return false; // Return false on error
512
593
  // Don't throw error to avoid breaking test execution
513
594
  }
514
595
  }
515
596
 
516
597
  async processArtifacts(testId, result) {
598
+ // Skip artifact processing if run creation failed
599
+ if (this.runCreationFailed) {
600
+ return;
601
+ }
602
+
517
603
  const attachments = result.attachments;
518
604
 
519
605
  // Process artifacts with controlled async handling to ensure uploads complete
@@ -740,7 +826,7 @@ class TestLensReporter {
740
826
  remoteUrl
741
827
  };
742
828
  } catch (error) {
743
- console.warn('Could not collect Git information:', error.message);
829
+ // Silently skip git information if not in a git repository
744
830
  return null;
745
831
  }
746
832
  }
@@ -863,6 +949,39 @@ class TestLensReporter {
863
949
  throw new Error(`Upload confirmation failed: ${confirmResponse.data.error || 'Unknown error'}`);
864
950
  }
865
951
  } catch (error) {
952
+ // Check for trial expiration, subscription errors, or limit errors
953
+ if (error?.response?.status === 401) {
954
+ const errorData = error?.response?.data;
955
+
956
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
957
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
958
+ console.error('\\n' + '='.repeat(80));
959
+
960
+ if (errorData?.error === 'test_cases_limit_reached') {
961
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
962
+ } else if (errorData?.error === 'test_runs_limit_reached') {
963
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
964
+ } else {
965
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
966
+ }
967
+
968
+ console.error('='.repeat(80));
969
+ console.error('');
970
+ console.error(errorData?.message || 'Your trial period has expired.');
971
+ console.error('');
972
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
973
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
974
+ console.error('');
975
+ if (errorData?.trial_end_date) {
976
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
977
+ console.error('');
978
+ }
979
+ console.error('='.repeat(80));
980
+ console.error('');
981
+ return null;
982
+ }
983
+ }
984
+
866
985
  // Better error messages for common issues
867
986
  let errorMsg = error.message;
868
987
 
package/index.ts CHANGED
@@ -1,5 +1,3 @@
1
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
2
-
3
1
  import { randomUUID } from 'crypto';
4
2
  import * as os from 'os';
5
3
  import * as path from 'path';
@@ -178,6 +176,7 @@ export class TestLensReporter implements Reporter {
178
176
  private runMetadata: RunMetadata;
179
177
  private specMap: Map<string, SpecData>;
180
178
  private testMap: Map<string, TestData>;
179
+ private runCreationFailed: boolean = false; // Track if run creation failed due to limits
181
180
 
182
181
  constructor(options: TestLensReporterOptions) {
183
182
  this.config = {
@@ -259,6 +258,7 @@ export class TestLensReporter implements Reporter {
259
258
  this.runMetadata = this.initializeRunMetadata();
260
259
  this.specMap = new Map<string, SpecData>();
261
260
  this.testMap = new Map<string, TestData>();
261
+ this.runCreationFailed = false;
262
262
  }
263
263
 
264
264
  private initializeRunMetadata(): RunMetadata {
@@ -335,6 +335,9 @@ export class TestLensReporter implements Reporter {
335
335
  }
336
336
 
337
337
  async onTestBegin(test: TestCase, result: TestResult): Promise<void> {
338
+ // Log which test is starting
339
+ console.log(`\n▶️ Running test: ${test.title}`);
340
+
338
341
  const specPath = test.location.file;
339
342
  const specKey = `${specPath}-${test.parent.title}`;
340
343
 
@@ -671,8 +674,12 @@ export class TestLensReporter implements Reporter {
671
674
  }
672
675
 
673
676
  private async sendToApi(payload: any): Promise<void> {
677
+ // Skip sending if run creation already failed
678
+ if (this.runCreationFailed && payload.type !== 'runStart') {
679
+ return;
680
+ }
681
+
674
682
  try {
675
- console.log(`📤 Sending ${payload.type} event to ${this.config.apiEndpoint}`);
676
683
  const response = await this.axiosInstance.post('', payload, {
677
684
  headers: {
678
685
  'X-API-Key': this.config.apiKey
@@ -682,21 +689,91 @@ export class TestLensReporter implements Reporter {
682
689
  console.log(`✅ Sent ${payload.type} event to TestLens (HTTP ${response.status})`);
683
690
  }
684
691
  } catch (error: any) {
685
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
686
- message: error?.message || 'Unknown error',
687
- status: error?.response?.status,
688
- statusText: error?.response?.statusText,
689
- data: error?.response?.data,
690
- code: error?.code,
691
- url: error?.config?.url,
692
- method: error?.config?.method
693
- });
692
+ const errorData = error?.response?.data;
693
+ const status = error?.response?.status;
694
+
695
+ // Check for limit exceeded (403)
696
+ if (status === 403 && errorData?.error === 'limit_exceeded') {
697
+ // Set flag to skip subsequent events
698
+ if (payload.type === 'runStart' && errorData?.limit_type === 'test_runs') {
699
+ this.runCreationFailed = true;
700
+ }
701
+
702
+ console.error('\n' + '='.repeat(80));
703
+ if (errorData?.limit_type === 'test_cases') {
704
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
705
+ } else if (errorData?.limit_type === 'test_runs') {
706
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
707
+ } else {
708
+ console.error('❌ TESTLENS ERROR: Plan Limit Reached');
709
+ }
710
+ console.error('='.repeat(80));
711
+ console.error('');
712
+ console.error(errorData?.message || 'You have reached your plan limit.');
713
+ console.error('');
714
+ console.error(`Current usage: ${errorData?.current_usage || 'N/A'} / ${errorData?.limit || 'N/A'}`);
715
+ console.error('');
716
+ console.error('To continue, please upgrade your plan.');
717
+ console.error('Contact: support@alternative-path.com');
718
+ console.error('');
719
+ console.error('='.repeat(80));
720
+ console.error('');
721
+ return; // Don't log the full error object for limit errors
722
+ }
723
+
724
+ // Check for trial expiration, subscription errors, or limit errors (401)
725
+ if (status === 401) {
726
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
727
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
728
+ console.error('\n' + '='.repeat(80));
729
+
730
+ if (errorData?.error === 'test_cases_limit_reached') {
731
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
732
+ } else if (errorData?.error === 'test_runs_limit_reached') {
733
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
734
+ } else {
735
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
736
+ }
737
+
738
+ console.error('='.repeat(80));
739
+ console.error('');
740
+ console.error(errorData?.message || 'Your trial period has expired.');
741
+ console.error('');
742
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
743
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
744
+ console.error('');
745
+ if (errorData?.trial_end_date) {
746
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
747
+ console.error('');
748
+ }
749
+ console.error('='.repeat(80));
750
+ console.error('');
751
+ } else {
752
+ console.error(`❌ Authentication failed: ${errorData?.error || 'Invalid API key'}`);
753
+ }
754
+ } else if (status !== 403) {
755
+ // Log other errors (but not 403 which we handled above)
756
+ console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
757
+ message: error?.message || 'Unknown error',
758
+ status: status,
759
+ statusText: error?.response?.statusText,
760
+ data: errorData,
761
+ code: error?.code,
762
+ url: error?.config?.url,
763
+ method: error?.config?.method
764
+ });
765
+ }
694
766
 
695
767
  // Don't throw error to avoid breaking test execution
696
768
  }
697
769
  }
698
770
 
699
771
  private async processArtifacts(testId: string, result: TestResult): Promise<void> {
772
+ // Skip artifact processing if run creation failed
773
+ if (this.runCreationFailed) {
774
+ return;
775
+ }
776
+
700
777
  const attachments = result.attachments;
701
778
 
702
779
  for (const attachment of attachments) {
@@ -919,7 +996,7 @@ export class TestLensReporter implements Reporter {
919
996
  remoteUrl
920
997
  };
921
998
  } catch (error: any) {
922
- console.warn('Could not collect Git information:', error.message);
999
+ // Silently skip git information if not in a git repository
923
1000
  return null;
924
1001
  }
925
1002
  }
@@ -1040,6 +1117,39 @@ export class TestLensReporter implements Reporter {
1040
1117
  throw new Error(`Upload confirmation failed: ${confirmResponse.data.error || 'Unknown error'}`);
1041
1118
  }
1042
1119
  } catch (error: any) {
1120
+ // Check for trial expiration, subscription errors, or limit errors
1121
+ if (error?.response?.status === 401) {
1122
+ const errorData = error?.response?.data;
1123
+
1124
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
1125
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
1126
+ console.error('\\n' + '='.repeat(80));
1127
+
1128
+ if (errorData?.error === 'test_cases_limit_reached') {
1129
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
1130
+ } else if (errorData?.error === 'test_runs_limit_reached') {
1131
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
1132
+ } else {
1133
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
1134
+ }
1135
+
1136
+ console.error('='.repeat(80));
1137
+ console.error('');
1138
+ console.error(errorData?.message || 'Your trial period has expired.');
1139
+ console.error('');
1140
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
1141
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
1142
+ console.error('');
1143
+ if (errorData?.trial_end_date) {
1144
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
1145
+ console.error('');
1146
+ }
1147
+ console.error('='.repeat(80));
1148
+ console.error('');
1149
+ return null;
1150
+ }
1151
+ }
1152
+
1043
1153
  // Better error messages for common issues
1044
1154
  let errorMsg = error.message;
1045
1155
 
package/lib/index.js CHANGED
@@ -37,7 +37,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.TestLensReporter = void 0;
40
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
41
40
  const crypto_1 = require("crypto");
42
41
  const os = __importStar(require("os"));
43
42
  const path = __importStar(require("path"));
@@ -57,6 +56,7 @@ async function getMime() {
57
56
  }
58
57
  class TestLensReporter {
59
58
  constructor(options) {
59
+ this.runCreationFailed = false; // Track if run creation failed due to limits
60
60
  this.config = {
61
61
  apiEndpoint: options.apiEndpoint || 'https://testlens.qa-path.com/api/v1/webhook/playwright',
62
62
  apiKey: options.apiKey, // API key must come from config file
@@ -126,6 +126,7 @@ class TestLensReporter {
126
126
  this.runMetadata = this.initializeRunMetadata();
127
127
  this.specMap = new Map();
128
128
  this.testMap = new Map();
129
+ this.runCreationFailed = false;
129
130
  }
130
131
  initializeRunMetadata() {
131
132
  return {
@@ -196,6 +197,8 @@ class TestLensReporter {
196
197
  });
197
198
  }
198
199
  async onTestBegin(test, result) {
200
+ // Log which test is starting
201
+ console.log(`\n▶️ Running test: ${test.title}`);
199
202
  const specPath = test.location.file;
200
203
  const specKey = `${specPath}-${test.parent.title}`;
201
204
  // Create or update spec data
@@ -491,8 +494,11 @@ class TestLensReporter {
491
494
  console.log(`🎯 Results: ${passedTests} passed, ${failedTests} failed (${timedOutTests} timeouts), ${skippedTests} skipped`);
492
495
  }
493
496
  async sendToApi(payload) {
497
+ // Skip sending if run creation already failed
498
+ if (this.runCreationFailed && payload.type !== 'runStart') {
499
+ return;
500
+ }
494
501
  try {
495
- console.log(`📤 Sending ${payload.type} event to ${this.config.apiEndpoint}`);
496
502
  const response = await this.axiosInstance.post('', payload, {
497
503
  headers: {
498
504
  'X-API-Key': this.config.apiKey
@@ -503,19 +509,89 @@ class TestLensReporter {
503
509
  }
504
510
  }
505
511
  catch (error) {
506
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
507
- message: error?.message || 'Unknown error',
508
- status: error?.response?.status,
509
- statusText: error?.response?.statusText,
510
- data: error?.response?.data,
511
- code: error?.code,
512
- url: error?.config?.url,
513
- method: error?.config?.method
514
- });
512
+ const errorData = error?.response?.data;
513
+ const status = error?.response?.status;
514
+ // Check for limit exceeded (403)
515
+ if (status === 403 && errorData?.error === 'limit_exceeded') {
516
+ // Set flag to skip subsequent events
517
+ if (payload.type === 'runStart' && errorData?.limit_type === 'test_runs') {
518
+ this.runCreationFailed = true;
519
+ }
520
+ console.error('\n' + '='.repeat(80));
521
+ if (errorData?.limit_type === 'test_cases') {
522
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
523
+ }
524
+ else if (errorData?.limit_type === 'test_runs') {
525
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
526
+ }
527
+ else {
528
+ console.error('❌ TESTLENS ERROR: Plan Limit Reached');
529
+ }
530
+ console.error('='.repeat(80));
531
+ console.error('');
532
+ console.error(errorData?.message || 'You have reached your plan limit.');
533
+ console.error('');
534
+ console.error(`Current usage: ${errorData?.current_usage || 'N/A'} / ${errorData?.limit || 'N/A'}`);
535
+ console.error('');
536
+ console.error('To continue, please upgrade your plan.');
537
+ console.error('Contact: support@alternative-path.com');
538
+ console.error('');
539
+ console.error('='.repeat(80));
540
+ console.error('');
541
+ return; // Don't log the full error object for limit errors
542
+ }
543
+ // Check for trial expiration, subscription errors, or limit errors (401)
544
+ if (status === 401) {
545
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
546
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
547
+ console.error('\n' + '='.repeat(80));
548
+ if (errorData?.error === 'test_cases_limit_reached') {
549
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
550
+ }
551
+ else if (errorData?.error === 'test_runs_limit_reached') {
552
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
553
+ }
554
+ else {
555
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
556
+ }
557
+ console.error('='.repeat(80));
558
+ console.error('');
559
+ console.error(errorData?.message || 'Your trial period has expired.');
560
+ console.error('');
561
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
562
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
563
+ console.error('');
564
+ if (errorData?.trial_end_date) {
565
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
566
+ console.error('');
567
+ }
568
+ console.error('='.repeat(80));
569
+ console.error('');
570
+ }
571
+ else {
572
+ console.error(`❌ Authentication failed: ${errorData?.error || 'Invalid API key'}`);
573
+ }
574
+ }
575
+ else if (status !== 403) {
576
+ // Log other errors (but not 403 which we handled above)
577
+ console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
578
+ message: error?.message || 'Unknown error',
579
+ status: status,
580
+ statusText: error?.response?.statusText,
581
+ data: errorData,
582
+ code: error?.code,
583
+ url: error?.config?.url,
584
+ method: error?.config?.method
585
+ });
586
+ }
515
587
  // Don't throw error to avoid breaking test execution
516
588
  }
517
589
  }
518
590
  async processArtifacts(testId, result) {
591
+ // Skip artifact processing if run creation failed
592
+ if (this.runCreationFailed) {
593
+ return;
594
+ }
519
595
  const attachments = result.attachments;
520
596
  for (const attachment of attachments) {
521
597
  if (attachment.path) {
@@ -717,7 +793,7 @@ class TestLensReporter {
717
793
  };
718
794
  }
719
795
  catch (error) {
720
- console.warn('Could not collect Git information:', error.message);
796
+ // Silently skip git information if not in a git repository
721
797
  return null;
722
798
  }
723
799
  }
@@ -823,6 +899,37 @@ class TestLensReporter {
823
899
  }
824
900
  }
825
901
  catch (error) {
902
+ // Check for trial expiration, subscription errors, or limit errors
903
+ if (error?.response?.status === 401) {
904
+ const errorData = error?.response?.data;
905
+ if (errorData?.error === 'trial_expired' || errorData?.error === 'subscription_inactive' ||
906
+ errorData?.error === 'test_cases_limit_reached' || errorData?.error === 'test_runs_limit_reached') {
907
+ console.error('\\n' + '='.repeat(80));
908
+ if (errorData?.error === 'test_cases_limit_reached') {
909
+ console.error('❌ TESTLENS ERROR: Test Cases Limit Reached');
910
+ }
911
+ else if (errorData?.error === 'test_runs_limit_reached') {
912
+ console.error('❌ TESTLENS ERROR: Test Runs Limit Reached');
913
+ }
914
+ else {
915
+ console.error('❌ TESTLENS ERROR: Your trial plan has ended');
916
+ }
917
+ console.error('='.repeat(80));
918
+ console.error('');
919
+ console.error(errorData?.message || 'Your trial period has expired.');
920
+ console.error('');
921
+ console.error('To continue using TestLens, please upgrade to Enterprise plan.');
922
+ console.error('Contact: ' + (errorData?.contactEmail || 'support@alternative-path.com'));
923
+ console.error('');
924
+ if (errorData?.trial_end_date) {
925
+ console.error(`Trial ended: ${new Date(errorData.trial_end_date).toLocaleDateString()}`);
926
+ console.error('');
927
+ }
928
+ console.error('='.repeat(80));
929
+ console.error('');
930
+ return null;
931
+ }
932
+ }
826
933
  // Better error messages for common issues
827
934
  let errorMsg = error.message;
828
935
  if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testlens-playwright-reporter",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Universal Playwright reporter for TestLens - works with both TypeScript and JavaScript projects",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",