testlens-playwright-reporter 0.3.2 → 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 -6
  2. package/index.ts +123 -11
  3. package/lib/index.js +119 -11
  4. package/package.json +1 -1
package/index.js CHANGED
@@ -95,6 +95,7 @@ class TestLensReporter {
95
95
  this.runMetadata = this.initializeRunMetadata();
96
96
  this.specMap = new Map();
97
97
  this.testMap = new Map();
98
+ this.runCreationFailed = false; // Track if run creation failed due to limits
98
99
  }
99
100
 
100
101
  initializeRunMetadata() {
@@ -162,6 +163,9 @@ class TestLensReporter {
162
163
  }
163
164
 
164
165
  async onTestBegin(test, result) {
166
+ // Log which test is starting
167
+ console.log(`\n▶️ Running test: ${test.title}`);
168
+
165
169
  const specPath = test.location.file;
166
170
  const specKey = `${specPath}-${test.parent.title}`;
167
171
 
@@ -494,24 +498,108 @@ class TestLensReporter {
494
498
  }
495
499
 
496
500
  async sendToApi(payload) {
501
+ // Skip sending if run creation already failed
502
+ if (this.runCreationFailed && payload.type !== 'runStart') {
503
+ return false;
504
+ }
505
+
497
506
  try {
498
507
  const response = await this.axiosInstance.post('', payload, {
499
508
  headers: {
500
509
  'X-API-Key': this.config.apiKey
501
510
  }
502
511
  });
512
+ if (this.config.enableRealTimeStream) {
513
+ console.log(`✅ Sent ${payload.type} event to TestLens (HTTP ${response.status})`);
514
+ }
515
+ return true;
503
516
  } catch (error) {
504
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
505
- message: error?.message || 'Unknown error',
506
- status: error?.response?.status,
507
- data: error?.response?.data
508
- });
517
+ const errorData = error?.response?.data;
518
+ const status = error?.response?.status;
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
+ }
509
591
 
592
+ return false; // Return false on error
510
593
  // Don't throw error to avoid breaking test execution
511
594
  }
512
595
  }
513
596
 
514
597
  async processArtifacts(testId, result) {
598
+ // Skip artifact processing if run creation failed
599
+ if (this.runCreationFailed) {
600
+ return;
601
+ }
602
+
515
603
  const attachments = result.attachments;
516
604
 
517
605
  // Process artifacts with controlled async handling to ensure uploads complete
@@ -738,7 +826,7 @@ class TestLensReporter {
738
826
  remoteUrl
739
827
  };
740
828
  } catch (error) {
741
- console.warn('Could not collect Git information:', error.message);
829
+ // Silently skip git information if not in a git repository
742
830
  return null;
743
831
  }
744
832
  }
@@ -861,6 +949,39 @@ class TestLensReporter {
861
949
  throw new Error(`Upload confirmation failed: ${confirmResponse.data.error || 'Unknown error'}`);
862
950
  }
863
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
+
864
985
  // Better error messages for common issues
865
986
  let errorMsg = error.message;
866
987
 
package/index.ts CHANGED
@@ -176,6 +176,7 @@ export class TestLensReporter implements Reporter {
176
176
  private runMetadata: RunMetadata;
177
177
  private specMap: Map<string, SpecData>;
178
178
  private testMap: Map<string, TestData>;
179
+ private runCreationFailed: boolean = false; // Track if run creation failed due to limits
179
180
 
180
181
  constructor(options: TestLensReporterOptions) {
181
182
  this.config = {
@@ -257,6 +258,7 @@ export class TestLensReporter implements Reporter {
257
258
  this.runMetadata = this.initializeRunMetadata();
258
259
  this.specMap = new Map<string, SpecData>();
259
260
  this.testMap = new Map<string, TestData>();
261
+ this.runCreationFailed = false;
260
262
  }
261
263
 
262
264
  private initializeRunMetadata(): RunMetadata {
@@ -333,6 +335,9 @@ export class TestLensReporter implements Reporter {
333
335
  }
334
336
 
335
337
  async onTestBegin(test: TestCase, result: TestResult): Promise<void> {
338
+ // Log which test is starting
339
+ console.log(`\n▶️ Running test: ${test.title}`);
340
+
336
341
  const specPath = test.location.file;
337
342
  const specKey = `${specPath}-${test.parent.title}`;
338
343
 
@@ -669,8 +674,12 @@ export class TestLensReporter implements Reporter {
669
674
  }
670
675
 
671
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
+
672
682
  try {
673
- console.log(`📤 Sending ${payload.type} event to ${this.config.apiEndpoint}`);
674
683
  const response = await this.axiosInstance.post('', payload, {
675
684
  headers: {
676
685
  'X-API-Key': this.config.apiKey
@@ -680,21 +689,91 @@ export class TestLensReporter implements Reporter {
680
689
  console.log(`✅ Sent ${payload.type} event to TestLens (HTTP ${response.status})`);
681
690
  }
682
691
  } catch (error: any) {
683
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
684
- message: error?.message || 'Unknown error',
685
- status: error?.response?.status,
686
- statusText: error?.response?.statusText,
687
- data: error?.response?.data,
688
- code: error?.code,
689
- url: error?.config?.url,
690
- method: error?.config?.method
691
- });
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
+ }
692
766
 
693
767
  // Don't throw error to avoid breaking test execution
694
768
  }
695
769
  }
696
770
 
697
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
+
698
777
  const attachments = result.attachments;
699
778
 
700
779
  for (const attachment of attachments) {
@@ -917,7 +996,7 @@ export class TestLensReporter implements Reporter {
917
996
  remoteUrl
918
997
  };
919
998
  } catch (error: any) {
920
- console.warn('Could not collect Git information:', error.message);
999
+ // Silently skip git information if not in a git repository
921
1000
  return null;
922
1001
  }
923
1002
  }
@@ -1038,6 +1117,39 @@ export class TestLensReporter implements Reporter {
1038
1117
  throw new Error(`Upload confirmation failed: ${confirmResponse.data.error || 'Unknown error'}`);
1039
1118
  }
1040
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
+
1041
1153
  // Better error messages for common issues
1042
1154
  let errorMsg = error.message;
1043
1155
 
package/lib/index.js CHANGED
@@ -56,6 +56,7 @@ async function getMime() {
56
56
  }
57
57
  class TestLensReporter {
58
58
  constructor(options) {
59
+ this.runCreationFailed = false; // Track if run creation failed due to limits
59
60
  this.config = {
60
61
  apiEndpoint: options.apiEndpoint || 'https://testlens.qa-path.com/api/v1/webhook/playwright',
61
62
  apiKey: options.apiKey, // API key must come from config file
@@ -125,6 +126,7 @@ class TestLensReporter {
125
126
  this.runMetadata = this.initializeRunMetadata();
126
127
  this.specMap = new Map();
127
128
  this.testMap = new Map();
129
+ this.runCreationFailed = false;
128
130
  }
129
131
  initializeRunMetadata() {
130
132
  return {
@@ -195,6 +197,8 @@ class TestLensReporter {
195
197
  });
196
198
  }
197
199
  async onTestBegin(test, result) {
200
+ // Log which test is starting
201
+ console.log(`\n▶️ Running test: ${test.title}`);
198
202
  const specPath = test.location.file;
199
203
  const specKey = `${specPath}-${test.parent.title}`;
200
204
  // Create or update spec data
@@ -490,8 +494,11 @@ class TestLensReporter {
490
494
  console.log(`🎯 Results: ${passedTests} passed, ${failedTests} failed (${timedOutTests} timeouts), ${skippedTests} skipped`);
491
495
  }
492
496
  async sendToApi(payload) {
497
+ // Skip sending if run creation already failed
498
+ if (this.runCreationFailed && payload.type !== 'runStart') {
499
+ return;
500
+ }
493
501
  try {
494
- console.log(`📤 Sending ${payload.type} event to ${this.config.apiEndpoint}`);
495
502
  const response = await this.axiosInstance.post('', payload, {
496
503
  headers: {
497
504
  'X-API-Key': this.config.apiKey
@@ -502,19 +509,89 @@ class TestLensReporter {
502
509
  }
503
510
  }
504
511
  catch (error) {
505
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
506
- message: error?.message || 'Unknown error',
507
- status: error?.response?.status,
508
- statusText: error?.response?.statusText,
509
- data: error?.response?.data,
510
- code: error?.code,
511
- url: error?.config?.url,
512
- method: error?.config?.method
513
- });
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
+ }
514
587
  // Don't throw error to avoid breaking test execution
515
588
  }
516
589
  }
517
590
  async processArtifacts(testId, result) {
591
+ // Skip artifact processing if run creation failed
592
+ if (this.runCreationFailed) {
593
+ return;
594
+ }
518
595
  const attachments = result.attachments;
519
596
  for (const attachment of attachments) {
520
597
  if (attachment.path) {
@@ -716,7 +793,7 @@ class TestLensReporter {
716
793
  };
717
794
  }
718
795
  catch (error) {
719
- console.warn('Could not collect Git information:', error.message);
796
+ // Silently skip git information if not in a git repository
720
797
  return null;
721
798
  }
722
799
  }
@@ -822,6 +899,37 @@ class TestLensReporter {
822
899
  }
823
900
  }
824
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
+ }
825
933
  // Better error messages for common issues
826
934
  let errorMsg = error.message;
827
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.2",
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",