@alternative-path/testlens-playwright-reporter 0.3.7 → 0.3.8

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.d.ts +4 -0
  2. package/index.js +202 -18
  3. package/index.ts +222 -18
  4. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -26,6 +26,8 @@ export interface TestLensReporterConfig {
26
26
  rejectUnauthorized?: boolean;
27
27
  /** Alternative SSL option - set to true to ignore SSL certificate errors */
28
28
  ignoreSslErrors?: boolean;
29
+ /** Path to a custom CA certificate file (PEM format) to use for SSL verification */
30
+ caCertificate?: string;
29
31
  /** Custom metadata from CLI arguments (automatically parsed from --key=value arguments) */
30
32
  customMetadata?: Record<string, string | string[]>;
31
33
  }
@@ -56,6 +58,8 @@ export interface TestLensReporterOptions {
56
58
  rejectUnauthorized?: boolean;
57
59
  /** Alternative SSL option - set to true to ignore SSL certificate errors */
58
60
  ignoreSslErrors?: boolean;
61
+ /** Path to a custom CA certificate file (PEM format) to use for SSL verification */
62
+ caCertificate?: string;
59
63
  /** Custom metadata from CLI arguments (automatically parsed from --key=value arguments) */
60
64
  customMetadata?: Record<string, string | string[]>;
61
65
  }
package/index.js CHANGED
@@ -20,6 +20,51 @@ async function getMime() {
20
20
  return mimeModule;
21
21
  }
22
22
  class TestLensReporter {
23
+ /**
24
+ * Automatically detect and load system CA certificates
25
+ * Tries multiple common system certificate locations
26
+ */
27
+ static getSystemCaCertificates() {
28
+ const certificates = [];
29
+ const platform = os.platform();
30
+ // Common certificate store locations by platform
31
+ const certPaths = [];
32
+ if (platform === 'win32') {
33
+ // Windows: Node.js uses Windows certificate store automatically
34
+ // But we can also check common locations
35
+ const winPaths = [
36
+ process.env.CERT_PATH,
37
+ 'C:\\Windows\\System32\\certmgr.msc', // Not a file, but indicates cert store
38
+ ];
39
+ certPaths.push(...winPaths.filter(Boolean));
40
+ }
41
+ else if (platform === 'darwin') {
42
+ // macOS: Common certificate locations
43
+ certPaths.push('/etc/ssl/cert.pem', '/usr/local/etc/openssl/cert.pem', '/opt/homebrew/etc/openssl/cert.pem', '/System/Library/OpenSSL/certs/cert.pem');
44
+ }
45
+ else {
46
+ // Linux and other Unix-like systems
47
+ certPaths.push('/etc/ssl/certs/ca-certificates.crt', '/etc/ssl/certs/ca-bundle.crt', '/etc/pki/tls/certs/ca-bundle.crt', '/etc/ssl/ca-bundle.pem', '/usr/share/ssl/certs/ca-bundle.crt', '/usr/local/share/certs/ca-root-nss.crt', '/etc/ca-certificates/extracted/tls-ca-bundle.pem');
48
+ }
49
+ // Try to load certificates from common locations
50
+ for (const certPath of certPaths) {
51
+ try {
52
+ if (certPath && fs.existsSync(certPath)) {
53
+ const certData = fs.readFileSync(certPath);
54
+ certificates.push(certData);
55
+ // Only log in debug mode to avoid noise
56
+ if (process.env.DEBUG) {
57
+ console.log(`✓ Loaded CA certificates from: ${certPath}`);
58
+ }
59
+ }
60
+ }
61
+ catch (error) {
62
+ // Silently continue if a certificate file can't be read
63
+ // This is expected as not all paths will exist on every system
64
+ }
65
+ }
66
+ return certificates;
67
+ }
23
68
  /**
24
69
  * Parse custom metadata from environment variables
25
70
  * Checks for common metadata environment variables
@@ -97,6 +142,37 @@ class TestLensReporter {
97
142
  }
98
143
  // Determine SSL validation behavior
99
144
  let rejectUnauthorized = true; // Default to secure
145
+ let ca = undefined;
146
+ // Automatically detect and load system CA certificates
147
+ // This helps resolve "unable to get local issuer certificate" errors
148
+ const systemCerts = TestLensReporter.getSystemCaCertificates();
149
+ // Load custom CA certificate if explicitly provided (for advanced users)
150
+ if (this.config.caCertificate) {
151
+ try {
152
+ if (fs.existsSync(this.config.caCertificate)) {
153
+ const customCert = fs.readFileSync(this.config.caCertificate);
154
+ // Combine system certs with custom cert
155
+ ca = systemCerts.length > 0 ? [...systemCerts, customCert] : customCert;
156
+ console.log(`✓ Using custom CA certificate: ${this.config.caCertificate}`);
157
+ }
158
+ else {
159
+ console.warn(`⚠️ CA certificate file not found: ${this.config.caCertificate}`);
160
+ // Fall back to system certs if custom cert not found
161
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
162
+ }
163
+ }
164
+ catch (error) {
165
+ console.warn(`⚠️ Failed to read CA certificate file: ${this.config.caCertificate}`, error.message);
166
+ // Fall back to system certs if custom cert read fails
167
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
168
+ }
169
+ }
170
+ else {
171
+ // Use automatically detected system certificates
172
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
173
+ // Node.js will use system default CA store if we don't specify 'ca'
174
+ // But providing system certs explicitly can help in some environments
175
+ }
100
176
  // Check various ways SSL validation can be disabled (in order of precedence)
101
177
  if (this.config.ignoreSslErrors) {
102
178
  // Explicit configuration option
@@ -114,6 +190,17 @@ class TestLensReporter {
114
190
  console.log('⚠️ SSL certificate validation disabled via NODE_TLS_REJECT_UNAUTHORIZED environment variable');
115
191
  }
116
192
  // Set up axios instance with retry logic and enhanced SSL handling
193
+ const httpsAgentOptions = {
194
+ rejectUnauthorized: rejectUnauthorized,
195
+ // Allow any TLS version for better compatibility
196
+ minVersion: 'TLSv1.2',
197
+ maxVersion: 'TLSv1.3'
198
+ };
199
+ // Add CA certificates if available (Node.js will use system defaults if not specified)
200
+ // Explicitly setting 'ca' can help in environments where Node.js doesn't find certs automatically
201
+ if (ca && ca.length > 0) {
202
+ httpsAgentOptions.ca = ca;
203
+ }
117
204
  this.axiosInstance = axios_1.default.create({
118
205
  baseURL: this.config.apiEndpoint,
119
206
  timeout: this.config.timeout,
@@ -122,12 +209,7 @@ class TestLensReporter {
122
209
  ...(this.config.apiKey && { 'X-API-Key': this.config.apiKey }),
123
210
  },
124
211
  // Enhanced SSL handling with flexible TLS configuration
125
- httpsAgent: new https.Agent({
126
- rejectUnauthorized: rejectUnauthorized,
127
- // Allow any TLS version for better compatibility
128
- minVersion: 'TLSv1.2',
129
- maxVersion: 'TLSv1.3'
130
- })
212
+ httpsAgent: new https.Agent(httpsAgentOptions)
131
213
  });
132
214
  // Add retry interceptor
133
215
  this.axiosInstance.interceptors.response.use((response) => response, async (error) => {
@@ -647,17 +729,68 @@ class TestLensReporter {
647
729
  console.error(`❌ Authentication failed: ${errorData?.error || 'Invalid API key'}`);
648
730
  }
649
731
  }
650
- else if (status !== 403) {
651
- // Log other errors (but not 403 which we handled above)
652
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
653
- message: error?.message || 'Unknown error',
654
- status: status,
655
- statusText: error?.response?.statusText,
656
- data: errorData,
657
- code: error?.code,
658
- url: error?.config?.url,
659
- method: error?.config?.method
660
- });
732
+ else {
733
+ // Check for SSL certificate errors
734
+ const isSslError = error?.code === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' ||
735
+ error?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
736
+ error?.code === 'CERT_HAS_EXPIRED' ||
737
+ error?.code === 'SELF_SIGNED_CERT_IN_CHAIN' ||
738
+ error?.message?.includes('certificate') ||
739
+ error?.message?.includes('SSL') ||
740
+ error?.message?.includes('TLS');
741
+ if (isSslError && status !== 403) {
742
+ console.error('\n' + '='.repeat(80));
743
+ console.error('❌ SSL Certificate Error');
744
+ console.error('='.repeat(80));
745
+ console.error('');
746
+ console.error(`Failed to send ${payload.type} event to TestLens due to SSL certificate issue.`);
747
+ console.error('');
748
+ console.error('The reporter automatically attempts to detect and use system CA certificates.');
749
+ console.error('If this error persists, it may indicate:');
750
+ console.error(' - Missing or outdated system CA certificates');
751
+ console.error(' - Corporate proxy with custom CA certificate');
752
+ console.error(' - Incomplete certificate chain from the server');
753
+ console.error('');
754
+ console.error('Error details:');
755
+ console.error(` Code: ${error?.code || 'Unknown'}`);
756
+ console.error(` Message: ${error?.message || 'Unknown error'}`);
757
+ console.error('');
758
+ console.error('Possible solutions:');
759
+ console.error('');
760
+ console.error('1. Update your system\'s CA certificate store:');
761
+ console.error(' - Windows: Update Windows root certificates via Windows Update');
762
+ console.error(' - macOS: Run: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <certificate.pem>');
763
+ console.error(' - Linux: Update ca-certificates package: sudo apt-get update && sudo apt-get install ca-certificates');
764
+ console.error('');
765
+ console.error('2. If you have a custom CA certificate file (e.g., from corporate proxy),');
766
+ console.error(' you can specify it in your config (optional):');
767
+ console.error(' reporter: [');
768
+ console.error(' [\'@testlens/playwright-reporter\', {');
769
+ console.error(' caCertificate: \'/path/to/your/ca-certificate.pem\'');
770
+ console.error(' }]');
771
+ console.error(' ]');
772
+ console.error('');
773
+ console.error('3. Contact your network administrator if you\'re behind a corporate proxy');
774
+ console.error(' that uses a custom CA certificate.');
775
+ console.error('');
776
+ console.error('⚠️ WARNING: Setting NODE_TLS_REJECT_UNAUTHORIZED=0 disables SSL verification');
777
+ console.error(' and is insecure. Only use this as a last resort in development.');
778
+ console.error('');
779
+ console.error('='.repeat(80));
780
+ console.error('');
781
+ }
782
+ else if (status !== 403) {
783
+ // Log other errors (but not 403 which we handled above)
784
+ console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
785
+ message: error?.message || 'Unknown error',
786
+ status: status,
787
+ statusText: error?.response?.statusText,
788
+ data: errorData,
789
+ code: error?.code,
790
+ url: error?.config?.url,
791
+ method: error?.config?.method
792
+ });
793
+ }
661
794
  }
662
795
  // Don't throw error to avoid breaking test execution
663
796
  }
@@ -776,7 +909,58 @@ class TestLensReporter {
776
909
  console.log(`ℹ️ Spec code blocks already exist for: ${path.basename(specPath)} (skipped)`);
777
910
  return;
778
911
  }
779
- console.error('Failed to send spec code blocks:', errorData || error?.message || 'Unknown error');
912
+ // Check for SSL certificate errors
913
+ const isSslError = error?.code === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' ||
914
+ error?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
915
+ error?.code === 'CERT_HAS_EXPIRED' ||
916
+ error?.code === 'SELF_SIGNED_CERT_IN_CHAIN' ||
917
+ error?.message?.includes('certificate') ||
918
+ error?.message?.includes('SSL') ||
919
+ error?.message?.includes('TLS');
920
+ if (isSslError) {
921
+ console.error('\n' + '='.repeat(80));
922
+ console.error('❌ SSL Certificate Error');
923
+ console.error('='.repeat(80));
924
+ console.error('');
925
+ console.error('Failed to send spec code blocks due to SSL certificate issue.');
926
+ console.error('');
927
+ console.error('The reporter automatically attempts to detect and use system CA certificates.');
928
+ console.error('If this error persists, it may indicate:');
929
+ console.error(' - Missing or outdated system CA certificates');
930
+ console.error(' - Corporate proxy with custom CA certificate');
931
+ console.error(' - Incomplete certificate chain from the server');
932
+ console.error('');
933
+ console.error('Error details:');
934
+ console.error(` Code: ${error?.code || 'Unknown'}`);
935
+ console.error(` Message: ${error?.message || 'Unknown error'}`);
936
+ console.error('');
937
+ console.error('Possible solutions:');
938
+ console.error('');
939
+ console.error('1. Update your system\'s CA certificate store:');
940
+ console.error(' - Windows: Update Windows root certificates via Windows Update');
941
+ console.error(' - macOS: Run: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <certificate.pem>');
942
+ console.error(' - Linux: Update ca-certificates package: sudo apt-get update && sudo apt-get install ca-certificates');
943
+ console.error('');
944
+ console.error('2. If you have a custom CA certificate file (e.g., from corporate proxy),');
945
+ console.error(' you can specify it in your config (optional):');
946
+ console.error(' reporter: [');
947
+ console.error(' [\'@testlens/playwright-reporter\', {');
948
+ console.error(' caCertificate: \'/path/to/your/ca-certificate.pem\'');
949
+ console.error(' }]');
950
+ console.error(' ]');
951
+ console.error('');
952
+ console.error('3. Contact your network administrator if you\'re behind a corporate proxy');
953
+ console.error(' that uses a custom CA certificate.');
954
+ console.error('');
955
+ console.error('⚠️ WARNING: Setting NODE_TLS_REJECT_UNAUTHORIZED=0 disables SSL verification');
956
+ console.error(' and is insecure. Only use this as a last resort in development.');
957
+ console.error('');
958
+ console.error('='.repeat(80));
959
+ console.error('');
960
+ }
961
+ else {
962
+ console.error('Failed to send spec code blocks:', errorData || error?.message || 'Unknown error');
963
+ }
780
964
  }
781
965
  }
782
966
  extractTestBlocks(filePath) {
package/index.ts CHANGED
@@ -46,6 +46,8 @@ export interface TestLensReporterConfig {
46
46
  rejectUnauthorized?: boolean;
47
47
  /** Alternative SSL option - set to true to ignore SSL certificate errors */
48
48
  ignoreSslErrors?: boolean;
49
+ /** Path to a custom CA certificate file (PEM format) to use for SSL verification */
50
+ caCertificate?: string;
49
51
  /** Custom metadata from CLI arguments (automatically parsed from --key=value arguments) */
50
52
  customMetadata?: Record<string, string | string[]>;
51
53
  }
@@ -77,6 +79,8 @@ export interface TestLensReporterOptions {
77
79
  rejectUnauthorized?: boolean;
78
80
  /** Alternative SSL option - set to true to ignore SSL certificate errors */
79
81
  ignoreSslErrors?: boolean;
82
+ /** Path to a custom CA certificate file (PEM format) to use for SSL verification */
83
+ caCertificate?: string;
80
84
  /** Custom metadata from CLI arguments (automatically parsed from --key=value arguments) */
81
85
  customMetadata?: Record<string, string | string[]>;
82
86
  }
@@ -178,6 +182,66 @@ export interface SpecData {
178
182
  export class TestLensReporter implements Reporter {
179
183
  private config: Required<TestLensReporterConfig>;
180
184
  private axiosInstance: AxiosInstance;
185
+
186
+ /**
187
+ * Automatically detect and load system CA certificates
188
+ * Tries multiple common system certificate locations
189
+ */
190
+ private static getSystemCaCertificates(): Buffer[] {
191
+ const certificates: Buffer[] = [];
192
+ const platform = os.platform();
193
+
194
+ // Common certificate store locations by platform
195
+ const certPaths: string[] = [];
196
+
197
+ if (platform === 'win32') {
198
+ // Windows: Node.js uses Windows certificate store automatically
199
+ // But we can also check common locations
200
+ const winPaths = [
201
+ process.env.CERT_PATH,
202
+ 'C:\\Windows\\System32\\certmgr.msc', // Not a file, but indicates cert store
203
+ ];
204
+ certPaths.push(...winPaths.filter(Boolean) as string[]);
205
+ } else if (platform === 'darwin') {
206
+ // macOS: Common certificate locations
207
+ certPaths.push(
208
+ '/etc/ssl/cert.pem',
209
+ '/usr/local/etc/openssl/cert.pem',
210
+ '/opt/homebrew/etc/openssl/cert.pem',
211
+ '/System/Library/OpenSSL/certs/cert.pem'
212
+ );
213
+ } else {
214
+ // Linux and other Unix-like systems
215
+ certPaths.push(
216
+ '/etc/ssl/certs/ca-certificates.crt',
217
+ '/etc/ssl/certs/ca-bundle.crt',
218
+ '/etc/pki/tls/certs/ca-bundle.crt',
219
+ '/etc/ssl/ca-bundle.pem',
220
+ '/usr/share/ssl/certs/ca-bundle.crt',
221
+ '/usr/local/share/certs/ca-root-nss.crt',
222
+ '/etc/ca-certificates/extracted/tls-ca-bundle.pem'
223
+ );
224
+ }
225
+
226
+ // Try to load certificates from common locations
227
+ for (const certPath of certPaths) {
228
+ try {
229
+ if (certPath && fs.existsSync(certPath)) {
230
+ const certData = fs.readFileSync(certPath);
231
+ certificates.push(certData);
232
+ // Only log in debug mode to avoid noise
233
+ if (process.env.DEBUG) {
234
+ console.log(`✓ Loaded CA certificates from: ${certPath}`);
235
+ }
236
+ }
237
+ } catch (error) {
238
+ // Silently continue if a certificate file can't be read
239
+ // This is expected as not all paths will exist on every system
240
+ }
241
+ }
242
+
243
+ return certificates;
244
+ }
181
245
  private runId: string;
182
246
  private runMetadata: RunMetadata;
183
247
  private specMap: Map<string, SpecData>;
@@ -268,6 +332,36 @@ export class TestLensReporter implements Reporter {
268
332
 
269
333
  // Determine SSL validation behavior
270
334
  let rejectUnauthorized = true; // Default to secure
335
+ let ca: Buffer | string | Buffer[] | undefined = undefined;
336
+
337
+ // Automatically detect and load system CA certificates
338
+ // This helps resolve "unable to get local issuer certificate" errors
339
+ const systemCerts = TestLensReporter.getSystemCaCertificates();
340
+
341
+ // Load custom CA certificate if explicitly provided (for advanced users)
342
+ if (this.config.caCertificate) {
343
+ try {
344
+ if (fs.existsSync(this.config.caCertificate)) {
345
+ const customCert = fs.readFileSync(this.config.caCertificate);
346
+ // Combine system certs with custom cert
347
+ ca = systemCerts.length > 0 ? [...systemCerts, customCert] : customCert;
348
+ console.log(`✓ Using custom CA certificate: ${this.config.caCertificate}`);
349
+ } else {
350
+ console.warn(`⚠️ CA certificate file not found: ${this.config.caCertificate}`);
351
+ // Fall back to system certs if custom cert not found
352
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
353
+ }
354
+ } catch (error) {
355
+ console.warn(`⚠️ Failed to read CA certificate file: ${this.config.caCertificate}`, (error as Error).message);
356
+ // Fall back to system certs if custom cert read fails
357
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
358
+ }
359
+ } else {
360
+ // Use automatically detected system certificates
361
+ ca = systemCerts.length > 0 ? systemCerts : undefined;
362
+ // Node.js will use system default CA store if we don't specify 'ca'
363
+ // But providing system certs explicitly can help in some environments
364
+ }
271
365
 
272
366
  // Check various ways SSL validation can be disabled (in order of precedence)
273
367
  if (this.config.ignoreSslErrors) {
@@ -285,6 +379,19 @@ export class TestLensReporter implements Reporter {
285
379
  }
286
380
 
287
381
  // Set up axios instance with retry logic and enhanced SSL handling
382
+ const httpsAgentOptions: https.AgentOptions = {
383
+ rejectUnauthorized: rejectUnauthorized,
384
+ // Allow any TLS version for better compatibility
385
+ minVersion: 'TLSv1.2',
386
+ maxVersion: 'TLSv1.3'
387
+ };
388
+
389
+ // Add CA certificates if available (Node.js will use system defaults if not specified)
390
+ // Explicitly setting 'ca' can help in environments where Node.js doesn't find certs automatically
391
+ if (ca && ca.length > 0) {
392
+ httpsAgentOptions.ca = ca;
393
+ }
394
+
288
395
  this.axiosInstance = axios.create({
289
396
  baseURL: this.config.apiEndpoint,
290
397
  timeout: this.config.timeout,
@@ -293,12 +400,7 @@ export class TestLensReporter implements Reporter {
293
400
  ...(this.config.apiKey && { 'X-API-Key': this.config.apiKey }),
294
401
  },
295
402
  // Enhanced SSL handling with flexible TLS configuration
296
- httpsAgent: new https.Agent({
297
- rejectUnauthorized: rejectUnauthorized,
298
- // Allow any TLS version for better compatibility
299
- minVersion: 'TLSv1.2',
300
- maxVersion: 'TLSv1.3'
301
- })
403
+ httpsAgent: new https.Agent(httpsAgentOptions)
302
404
  });
303
405
 
304
406
  // Add retry interceptor
@@ -876,17 +978,68 @@ export class TestLensReporter implements Reporter {
876
978
  } else {
877
979
  console.error(`❌ Authentication failed: ${errorData?.error || 'Invalid API key'}`);
878
980
  }
879
- } else if (status !== 403) {
880
- // Log other errors (but not 403 which we handled above)
881
- console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
882
- message: error?.message || 'Unknown error',
883
- status: status,
884
- statusText: error?.response?.statusText,
885
- data: errorData,
886
- code: error?.code,
887
- url: error?.config?.url,
888
- method: error?.config?.method
889
- });
981
+ } else {
982
+ // Check for SSL certificate errors
983
+ const isSslError = error?.code === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' ||
984
+ error?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
985
+ error?.code === 'CERT_HAS_EXPIRED' ||
986
+ error?.code === 'SELF_SIGNED_CERT_IN_CHAIN' ||
987
+ error?.message?.includes('certificate') ||
988
+ error?.message?.includes('SSL') ||
989
+ error?.message?.includes('TLS');
990
+
991
+ if (isSslError && status !== 403) {
992
+ console.error('\n' + '='.repeat(80));
993
+ console.error('❌ SSL Certificate Error');
994
+ console.error('='.repeat(80));
995
+ console.error('');
996
+ console.error(`Failed to send ${payload.type} event to TestLens due to SSL certificate issue.`);
997
+ console.error('');
998
+ console.error('The reporter automatically attempts to detect and use system CA certificates.');
999
+ console.error('If this error persists, it may indicate:');
1000
+ console.error(' - Missing or outdated system CA certificates');
1001
+ console.error(' - Corporate proxy with custom CA certificate');
1002
+ console.error(' - Incomplete certificate chain from the server');
1003
+ console.error('');
1004
+ console.error('Error details:');
1005
+ console.error(` Code: ${error?.code || 'Unknown'}`);
1006
+ console.error(` Message: ${error?.message || 'Unknown error'}`);
1007
+ console.error('');
1008
+ console.error('Possible solutions:');
1009
+ console.error('');
1010
+ console.error('1. Update your system\'s CA certificate store:');
1011
+ console.error(' - Windows: Update Windows root certificates via Windows Update');
1012
+ console.error(' - macOS: Run: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <certificate.pem>');
1013
+ console.error(' - Linux: Update ca-certificates package: sudo apt-get update && sudo apt-get install ca-certificates');
1014
+ console.error('');
1015
+ console.error('2. If you have a custom CA certificate file (e.g., from corporate proxy),');
1016
+ console.error(' you can specify it in your config (optional):');
1017
+ console.error(' reporter: [');
1018
+ console.error(' [\'@testlens/playwright-reporter\', {');
1019
+ console.error(' caCertificate: \'/path/to/your/ca-certificate.pem\'');
1020
+ console.error(' }]');
1021
+ console.error(' ]');
1022
+ console.error('');
1023
+ console.error('3. Contact your network administrator if you\'re behind a corporate proxy');
1024
+ console.error(' that uses a custom CA certificate.');
1025
+ console.error('');
1026
+ console.error('⚠️ WARNING: Setting NODE_TLS_REJECT_UNAUTHORIZED=0 disables SSL verification');
1027
+ console.error(' and is insecure. Only use this as a last resort in development.');
1028
+ console.error('');
1029
+ console.error('='.repeat(80));
1030
+ console.error('');
1031
+ } else if (status !== 403) {
1032
+ // Log other errors (but not 403 which we handled above)
1033
+ console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
1034
+ message: error?.message || 'Unknown error',
1035
+ status: status,
1036
+ statusText: error?.response?.statusText,
1037
+ data: errorData,
1038
+ code: error?.code,
1039
+ url: error?.config?.url,
1040
+ method: error?.config?.method
1041
+ });
1042
+ }
890
1043
  }
891
1044
 
892
1045
  // Don't throw error to avoid breaking test execution
@@ -1022,7 +1175,58 @@ export class TestLensReporter implements Reporter {
1022
1175
  return;
1023
1176
  }
1024
1177
 
1025
- console.error('Failed to send spec code blocks:', errorData || error?.message || 'Unknown error');
1178
+ // Check for SSL certificate errors
1179
+ const isSslError = error?.code === 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY' ||
1180
+ error?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ||
1181
+ error?.code === 'CERT_HAS_EXPIRED' ||
1182
+ error?.code === 'SELF_SIGNED_CERT_IN_CHAIN' ||
1183
+ error?.message?.includes('certificate') ||
1184
+ error?.message?.includes('SSL') ||
1185
+ error?.message?.includes('TLS');
1186
+
1187
+ if (isSslError) {
1188
+ console.error('\n' + '='.repeat(80));
1189
+ console.error('❌ SSL Certificate Error');
1190
+ console.error('='.repeat(80));
1191
+ console.error('');
1192
+ console.error('Failed to send spec code blocks due to SSL certificate issue.');
1193
+ console.error('');
1194
+ console.error('The reporter automatically attempts to detect and use system CA certificates.');
1195
+ console.error('If this error persists, it may indicate:');
1196
+ console.error(' - Missing or outdated system CA certificates');
1197
+ console.error(' - Corporate proxy with custom CA certificate');
1198
+ console.error(' - Incomplete certificate chain from the server');
1199
+ console.error('');
1200
+ console.error('Error details:');
1201
+ console.error(` Code: ${error?.code || 'Unknown'}`);
1202
+ console.error(` Message: ${error?.message || 'Unknown error'}`);
1203
+ console.error('');
1204
+ console.error('Possible solutions:');
1205
+ console.error('');
1206
+ console.error('1. Update your system\'s CA certificate store:');
1207
+ console.error(' - Windows: Update Windows root certificates via Windows Update');
1208
+ console.error(' - macOS: Run: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain <certificate.pem>');
1209
+ console.error(' - Linux: Update ca-certificates package: sudo apt-get update && sudo apt-get install ca-certificates');
1210
+ console.error('');
1211
+ console.error('2. If you have a custom CA certificate file (e.g., from corporate proxy),');
1212
+ console.error(' you can specify it in your config (optional):');
1213
+ console.error(' reporter: [');
1214
+ console.error(' [\'@testlens/playwright-reporter\', {');
1215
+ console.error(' caCertificate: \'/path/to/your/ca-certificate.pem\'');
1216
+ console.error(' }]');
1217
+ console.error(' ]');
1218
+ console.error('');
1219
+ console.error('3. Contact your network administrator if you\'re behind a corporate proxy');
1220
+ console.error(' that uses a custom CA certificate.');
1221
+ console.error('');
1222
+ console.error('⚠️ WARNING: Setting NODE_TLS_REJECT_UNAUTHORIZED=0 disables SSL verification');
1223
+ console.error(' and is insecure. Only use this as a last resort in development.');
1224
+ console.error('');
1225
+ console.error('='.repeat(80));
1226
+ console.error('');
1227
+ } else {
1228
+ console.error('Failed to send spec code blocks:', errorData || error?.message || 'Unknown error');
1229
+ }
1026
1230
  }
1027
1231
  }
1028
1232
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alternative-path/testlens-playwright-reporter",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
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",