testlens-playwright-reporter 0.2.9 → 0.3.0
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/index.js +0 -48
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -46,15 +46,12 @@ class TestLensReporter {
|
|
|
46
46
|
if (this.config.ignoreSslErrors) {
|
|
47
47
|
// Explicit configuration option
|
|
48
48
|
rejectUnauthorized = false;
|
|
49
|
-
console.log('⚠️ SSL certificate validation disabled via ignoreSslErrors option');
|
|
50
49
|
} else if (this.config.rejectUnauthorized === false) {
|
|
51
50
|
// Explicit configuration option
|
|
52
51
|
rejectUnauthorized = false;
|
|
53
|
-
console.log('⚠️ SSL certificate validation disabled via rejectUnauthorized option');
|
|
54
52
|
} else if (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
|
|
55
53
|
// Environment variable override
|
|
56
54
|
rejectUnauthorized = false;
|
|
57
|
-
console.log('⚠️ SSL certificate validation disabled via NODE_TLS_REJECT_UNAUTHORIZED environment variable');
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
// Set up axios instance with retry logic and enhanced SSL handling
|
|
@@ -144,18 +141,9 @@ class TestLensReporter {
|
|
|
144
141
|
}
|
|
145
142
|
|
|
146
143
|
async onBegin(config, suite) {
|
|
147
|
-
console.log(`🚀 TestLens Reporter starting - Run ID: ${this.runId}`);
|
|
148
|
-
|
|
149
144
|
// Collect Git information if enabled
|
|
150
145
|
if (this.config.enableGitInfo) {
|
|
151
146
|
this.runMetadata.gitInfo = await this.collectGitInfo();
|
|
152
|
-
if (this.runMetadata.gitInfo) {
|
|
153
|
-
console.log(`📦 Git info collected: branch=${this.runMetadata.gitInfo.branch}, commit=${this.runMetadata.gitInfo.shortCommit}, author=${this.runMetadata.gitInfo.author}`);
|
|
154
|
-
} else {
|
|
155
|
-
console.log(`⚠️ Git info collection returned null - not in a git repository or git not available`);
|
|
156
|
-
}
|
|
157
|
-
} else {
|
|
158
|
-
console.log(`ℹ️ Git info collection disabled (enableGitInfo: false)`);
|
|
159
147
|
}
|
|
160
148
|
|
|
161
149
|
// Add shard information if available
|
|
@@ -252,11 +240,8 @@ class TestLensReporter {
|
|
|
252
240
|
const testId = this.getTestId(test);
|
|
253
241
|
let testData = this.testMap.get(testId);
|
|
254
242
|
|
|
255
|
-
console.log(`[TestLens] onTestEnd called for test: ${test.title}, status: ${result.status}, testData exists: ${!!testData}`);
|
|
256
|
-
|
|
257
243
|
// For skipped tests, onTestBegin might not be called, so we need to create the test data here
|
|
258
244
|
if (!testData) {
|
|
259
|
-
console.log(`[TestLens] Creating test data for skipped/uncreated test: ${test.title}`);
|
|
260
245
|
// Create spec data if not exists (skipped tests might not have spec data either)
|
|
261
246
|
const specPath = test.location.file;
|
|
262
247
|
const specKey = `${specPath}-${test.parent.title}`;
|
|
@@ -422,7 +407,6 @@ class TestLensReporter {
|
|
|
422
407
|
const isFinalAttempt = result.status === 'passed' || result.status === 'skipped' || result.retry >= test.retries;
|
|
423
408
|
|
|
424
409
|
if (isFinalAttempt) {
|
|
425
|
-
console.log(`[TestLens] Sending testEnd - testId: ${testData.id}, status: ${testData.status}, originalStatus: ${testData.originalStatus}`);
|
|
426
410
|
// Send test end event to API
|
|
427
411
|
await this.sendToApi({
|
|
428
412
|
type: 'testEnd',
|
|
@@ -508,19 +492,12 @@ class TestLensReporter {
|
|
|
508
492
|
});
|
|
509
493
|
|
|
510
494
|
// Wait for background artifact processing to complete (up to 10 seconds)
|
|
511
|
-
console.log('⏳ Waiting for background artifact processing to complete...');
|
|
512
495
|
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
513
|
-
|
|
514
|
-
console.log(`📊 TestLens Report completed - Run ID: ${this.runId}`);
|
|
515
|
-
console.log(`🎯 Results: ${passedTests} passed, ${failedTests} failed (${timedOutTests} timeouts), ${skippedTests} skipped`);
|
|
516
496
|
}
|
|
517
497
|
|
|
518
498
|
async sendToApi(payload) {
|
|
519
499
|
try {
|
|
520
500
|
const response = await this.axiosInstance.post('', payload);
|
|
521
|
-
if (this.config.enableRealTimeStream) {
|
|
522
|
-
console.log(`✅ Sent ${payload.type} event to TestLens`);
|
|
523
|
-
}
|
|
524
501
|
} catch (error) {
|
|
525
502
|
console.error(`❌ Failed to send ${payload.type} event to TestLens:`, {
|
|
526
503
|
message: error?.message || 'Unknown error',
|
|
@@ -534,19 +511,10 @@ class TestLensReporter {
|
|
|
534
511
|
|
|
535
512
|
async processArtifacts(testId, result) {
|
|
536
513
|
const attachments = result.attachments;
|
|
537
|
-
console.log(`🔍 Processing artifacts for test ${testId}: ${attachments ? attachments.length : 0} attachments found`);
|
|
538
|
-
|
|
539
|
-
if (attachments && attachments.length > 0) {
|
|
540
|
-
console.log('📎 Attachment details:');
|
|
541
|
-
attachments.forEach((attachment, index) => {
|
|
542
|
-
console.log(` ${index + 1}. ${attachment.name} (${attachment.contentType}) - Path: ${attachment.path}`);
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
514
|
|
|
546
515
|
// Process artifacts with controlled async handling to ensure uploads complete
|
|
547
516
|
if (attachments && attachments.length > 0) {
|
|
548
517
|
// Process all artifacts asynchronously but track completion
|
|
549
|
-
console.log(`🔄 Processing ${attachments.length} artifacts asynchronously...`);
|
|
550
518
|
|
|
551
519
|
// Use process.nextTick to defer processing to next event loop iteration
|
|
552
520
|
process.nextTick(async () => {
|
|
@@ -560,18 +528,15 @@ class TestLensReporter {
|
|
|
560
528
|
|
|
561
529
|
// Skip video if disabled in config
|
|
562
530
|
if (isVideo && !this.config.enableVideo) {
|
|
563
|
-
console.log(`⏭️ Skipping video artifact ${attachment.name} - video capture disabled in config`);
|
|
564
531
|
continue;
|
|
565
532
|
}
|
|
566
533
|
|
|
567
534
|
// Skip screenshot if disabled in config
|
|
568
535
|
if (isScreenshot && !this.config.enableScreenshot) {
|
|
569
|
-
console.log(`⏭️ Skipping screenshot artifact ${attachment.name} - screenshot capture disabled in config`);
|
|
570
536
|
continue;
|
|
571
537
|
}
|
|
572
538
|
|
|
573
539
|
try {
|
|
574
|
-
console.log(`📤 Processing ${attachment.name} asynchronously...`);
|
|
575
540
|
|
|
576
541
|
// Determine proper filename with extension
|
|
577
542
|
// Playwright attachment.name often doesn't have extension, so we need to derive it
|
|
@@ -608,7 +573,6 @@ class TestLensReporter {
|
|
|
608
573
|
|
|
609
574
|
// Skip if upload failed or file was too large
|
|
610
575
|
if (!s3Data) {
|
|
611
|
-
console.log(`⏭️ Skipping artifact ${attachment.name} - upload failed or file too large`);
|
|
612
576
|
continue;
|
|
613
577
|
}
|
|
614
578
|
|
|
@@ -631,8 +595,6 @@ class TestLensReporter {
|
|
|
631
595
|
timestamp: new Date().toISOString(),
|
|
632
596
|
artifact: artifactData
|
|
633
597
|
});
|
|
634
|
-
|
|
635
|
-
console.log(`📎 Processed artifact: ${fileName} (uploaded to S3)`);
|
|
636
598
|
} catch (error) {
|
|
637
599
|
console.error(`❌ Failed to process ${attachment.name}:`, error.message);
|
|
638
600
|
}
|
|
@@ -665,8 +627,6 @@ class TestLensReporter {
|
|
|
665
627
|
codeBlocks,
|
|
666
628
|
testSuiteName: path.basename(specPath).replace(/\.(spec|test)\.(js|ts)$/, '')
|
|
667
629
|
});
|
|
668
|
-
|
|
669
|
-
console.log(`📝 Sent ${codeBlocks.length} code blocks for: ${path.basename(specPath)}`);
|
|
670
630
|
} catch (error) {
|
|
671
631
|
console.error('Failed to send spec code blocks:', error?.response?.data || error?.message || 'Unknown error');
|
|
672
632
|
}
|
|
@@ -760,7 +720,6 @@ class TestLensReporter {
|
|
|
760
720
|
}
|
|
761
721
|
} catch (e) {
|
|
762
722
|
// Remote info is optional - handle gracefully
|
|
763
|
-
console.log('ℹ️ No git remote configured, skipping remote info');
|
|
764
723
|
}
|
|
765
724
|
|
|
766
725
|
const isDirty = execSync('git status --porcelain', { encoding: 'utf-8' }).trim().length > 0;
|
|
@@ -828,8 +787,6 @@ class TestLensReporter {
|
|
|
828
787
|
// Check file size first
|
|
829
788
|
const fileSize = this.getFileSize(filePath);
|
|
830
789
|
const fileSizeMB = (fileSize / (1024 * 1024)).toFixed(2);
|
|
831
|
-
|
|
832
|
-
console.log(`📤 Uploading ${fileName} (${fileSizeMB}MB) directly to S3...`);
|
|
833
790
|
|
|
834
791
|
const baseUrl = this.config.apiEndpoint.replace('/api/v1/webhook/playwright', '');
|
|
835
792
|
|
|
@@ -854,8 +811,6 @@ class TestLensReporter {
|
|
|
854
811
|
const { uploadUrl, s3Key, metadata } = presignedResponse.data;
|
|
855
812
|
|
|
856
813
|
// Step 2: Upload directly to S3 using presigned URL
|
|
857
|
-
console.log(`⬆️ Uploading ${fileName} directly to S3 (bypass server)...`);
|
|
858
|
-
|
|
859
814
|
const fileBuffer = fs.readFileSync(filePath);
|
|
860
815
|
|
|
861
816
|
// IMPORTANT: When using presigned URLs, we MUST include exactly the headers that were signed
|
|
@@ -876,8 +831,6 @@ class TestLensReporter {
|
|
|
876
831
|
throw new Error(`S3 upload failed with status ${uploadResponse.status}`);
|
|
877
832
|
}
|
|
878
833
|
|
|
879
|
-
console.log(`✅ S3 direct upload completed for ${fileName}`);
|
|
880
|
-
|
|
881
834
|
// Step 3: Confirm upload with server to save metadata
|
|
882
835
|
const confirmEndpoint = `${baseUrl}/api/v1/artifacts/public/confirm-upload`;
|
|
883
836
|
const confirmResponse = await this.axiosInstance.post(confirmEndpoint, {
|
|
@@ -895,7 +848,6 @@ class TestLensReporter {
|
|
|
895
848
|
|
|
896
849
|
if (confirmResponse.status === 201 && confirmResponse.data.success) {
|
|
897
850
|
const artifact = confirmResponse.data.artifact;
|
|
898
|
-
console.log(`✅ Upload confirmed and saved to database`);
|
|
899
851
|
return {
|
|
900
852
|
key: s3Key,
|
|
901
853
|
url: artifact.s3Url,
|
package/package.json
CHANGED