testlens-playwright-reporter 0.2.4 → 0.2.6
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.d.ts +2 -2
- package/index.js +55 -36
- package/index.ts +57 -20
- package/lib/index.js +56 -17
- package/package.json +1 -1
- package/CHANGELOG.md +0 -23
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,12 +6,23 @@ const path = require('path');
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const https = require('https');
|
|
8
8
|
const axios = require('axios');
|
|
9
|
-
const mime = require('mime');
|
|
10
9
|
const FormData = require('form-data');
|
|
10
|
+
|
|
11
|
+
// Lazy-load mime module to support ESM
|
|
12
|
+
let mimeModule = null;
|
|
13
|
+
async function getMime() {
|
|
14
|
+
if (!mimeModule) {
|
|
15
|
+
const imported = await import('mime');
|
|
16
|
+
// Handle both default export and named exports
|
|
17
|
+
mimeModule = imported.default || imported;
|
|
18
|
+
}
|
|
19
|
+
return mimeModule;
|
|
20
|
+
}
|
|
21
|
+
|
|
11
22
|
class TestLensReporter {
|
|
12
23
|
constructor(options = {}) {
|
|
13
24
|
this.config = {
|
|
14
|
-
apiEndpoint: 'https://testlens.qa-path.com/api/v1/webhook/playwright',
|
|
25
|
+
apiEndpoint: options.apiEndpoint || 'https://testlens.qa-path.com/api/v1/webhook/playwright',
|
|
15
26
|
apiKey: options.apiKey, // API key must come from config file
|
|
16
27
|
enableRealTimeStream: options.enableRealTimeStream !== undefined ? options.enableRealTimeStream : true,
|
|
17
28
|
enableGitInfo: options.enableGitInfo !== undefined ? options.enableGitInfo : true,
|
|
@@ -136,6 +147,13 @@ class TestLensReporter {
|
|
|
136
147
|
// Collect Git information if enabled
|
|
137
148
|
if (this.config.enableGitInfo) {
|
|
138
149
|
this.runMetadata.gitInfo = await this.collectGitInfo();
|
|
150
|
+
if (this.runMetadata.gitInfo) {
|
|
151
|
+
console.log(`📦 Git info collected: branch=${this.runMetadata.gitInfo.branch}, commit=${this.runMetadata.gitInfo.shortCommit}, author=${this.runMetadata.gitInfo.author}`);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(`⚠️ Git info collection returned null - not in a git repository or git not available`);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
console.log(`ℹ️ Git info collection disabled (enableGitInfo: false)`);
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
// Add shard information if available
|
|
@@ -371,20 +389,14 @@ class TestLensReporter {
|
|
|
371
389
|
try {
|
|
372
390
|
console.log(`📤 Processing ${attachment.name} asynchronously...`);
|
|
373
391
|
|
|
374
|
-
// Preserve original file extension from path (important for traces which must be .zip)
|
|
375
|
-
const originalExt = path.extname(attachment.path);
|
|
376
|
-
const fileName = attachment.name.includes(originalExt)
|
|
377
|
-
? attachment.name
|
|
378
|
-
: attachment.name + originalExt;
|
|
379
|
-
|
|
380
392
|
// Upload to S3 first
|
|
381
|
-
const s3Data = await this.uploadArtifactToS3(attachment.path, testId,
|
|
393
|
+
const s3Data = await this.uploadArtifactToS3(attachment.path, testId, attachment.name);
|
|
382
394
|
|
|
383
395
|
const artifactData = {
|
|
384
396
|
testId,
|
|
385
|
-
type: this.getArtifactType(
|
|
397
|
+
type: this.getArtifactType(attachment.name),
|
|
386
398
|
path: attachment.path,
|
|
387
|
-
name:
|
|
399
|
+
name: attachment.name,
|
|
388
400
|
contentType: attachment.contentType,
|
|
389
401
|
fileSize: this.getFileSize(attachment.path),
|
|
390
402
|
storageType: 's3',
|
|
@@ -538,8 +550,8 @@ class TestLensReporter {
|
|
|
538
550
|
commit,
|
|
539
551
|
shortCommit,
|
|
540
552
|
author,
|
|
541
|
-
commitMessage,
|
|
542
|
-
commitTimestamp,
|
|
553
|
+
message: commitMessage,
|
|
554
|
+
timestamp: commitTimestamp,
|
|
543
555
|
isDirty,
|
|
544
556
|
remoteName,
|
|
545
557
|
remoteUrl
|
|
@@ -579,24 +591,6 @@ class TestLensReporter {
|
|
|
579
591
|
return `${test.location.file}:${test.location.line}:${cleanTitle}`;
|
|
580
592
|
}
|
|
581
593
|
|
|
582
|
-
getContentType(ext) {
|
|
583
|
-
const contentTypes = {
|
|
584
|
-
'.mp4': 'video/mp4',
|
|
585
|
-
'.webm': 'video/webm',
|
|
586
|
-
'.png': 'image/png',
|
|
587
|
-
'.jpg': 'image/jpeg',
|
|
588
|
-
'.jpeg': 'image/jpeg',
|
|
589
|
-
'.gif': 'image/gif',
|
|
590
|
-
'.json': 'application/json',
|
|
591
|
-
'.txt': 'text/plain',
|
|
592
|
-
'.html': 'text/html',
|
|
593
|
-
'.xml': 'application/xml',
|
|
594
|
-
'.zip': 'application/zip',
|
|
595
|
-
'.pdf': 'application/pdf'
|
|
596
|
-
};
|
|
597
|
-
return contentTypes[ext] || 'application/octet-stream';
|
|
598
|
-
}
|
|
599
|
-
|
|
600
594
|
getFileSize(filePath) {
|
|
601
595
|
try {
|
|
602
596
|
const stats = fs.statSync(filePath);
|
|
@@ -624,7 +618,7 @@ class TestLensReporter {
|
|
|
624
618
|
testRunId: this.runId,
|
|
625
619
|
testId: testId,
|
|
626
620
|
fileName: fileName,
|
|
627
|
-
fileType: this.getContentType(fileName),
|
|
621
|
+
fileType: await this.getContentType(fileName),
|
|
628
622
|
fileSize: fileSize,
|
|
629
623
|
artifactType: this.getArtifactType(fileName)
|
|
630
624
|
}, {
|
|
@@ -670,7 +664,7 @@ class TestLensReporter {
|
|
|
670
664
|
testId: testId,
|
|
671
665
|
s3Key: s3Key,
|
|
672
666
|
fileName: fileName,
|
|
673
|
-
fileType: this.getContentType(fileName),
|
|
667
|
+
fileType: await this.getContentType(fileName),
|
|
674
668
|
fileSize: fileSize,
|
|
675
669
|
artifactType: this.getArtifactType(fileName)
|
|
676
670
|
}, {
|
|
@@ -714,10 +708,35 @@ class TestLensReporter {
|
|
|
714
708
|
}
|
|
715
709
|
}
|
|
716
710
|
|
|
717
|
-
getContentType(fileName) {
|
|
711
|
+
async getContentType(fileName) {
|
|
718
712
|
const ext = path.extname(fileName).toLowerCase();
|
|
719
|
-
|
|
720
|
-
|
|
713
|
+
try {
|
|
714
|
+
const mime = await getMime();
|
|
715
|
+
// Try different ways to access getType method
|
|
716
|
+
const getType = mime.getType || mime.default?.getType;
|
|
717
|
+
if (typeof getType === 'function') {
|
|
718
|
+
const mimeType = getType.call(mime, ext) || getType.call(mime.default, ext);
|
|
719
|
+
return mimeType || 'application/octet-stream';
|
|
720
|
+
}
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.warn(`Failed to get MIME type for ${fileName}:`, error.message);
|
|
723
|
+
}
|
|
724
|
+
// Fallback to basic content type mapping
|
|
725
|
+
const contentTypes = {
|
|
726
|
+
'.mp4': 'video/mp4',
|
|
727
|
+
'.webm': 'video/webm',
|
|
728
|
+
'.png': 'image/png',
|
|
729
|
+
'.jpg': 'image/jpeg',
|
|
730
|
+
'.jpeg': 'image/jpeg',
|
|
731
|
+
'.gif': 'image/gif',
|
|
732
|
+
'.json': 'application/json',
|
|
733
|
+
'.txt': 'text/plain',
|
|
734
|
+
'.html': 'text/html',
|
|
735
|
+
'.xml': 'application/xml',
|
|
736
|
+
'.zip': 'application/zip',
|
|
737
|
+
'.pdf': 'application/pdf'
|
|
738
|
+
};
|
|
739
|
+
return contentTypes[ext] || 'application/octet-stream';
|
|
721
740
|
}
|
|
722
741
|
}
|
|
723
742
|
|
package/index.ts
CHANGED
|
@@ -8,8 +8,19 @@ import * as https from 'https';
|
|
|
8
8
|
import axios, { AxiosInstance } from 'axios';
|
|
9
9
|
import type { Reporter, TestCase, TestResult, FullConfig, Suite } from '@playwright/test/reporter';
|
|
10
10
|
import { execSync } from 'child_process';
|
|
11
|
-
import * as mime from 'mime';
|
|
12
11
|
import FormData from 'form-data';
|
|
12
|
+
|
|
13
|
+
// Lazy-load mime module to support ESM
|
|
14
|
+
let mimeModule: any = null;
|
|
15
|
+
async function getMime() {
|
|
16
|
+
if (!mimeModule) {
|
|
17
|
+
const imported = await import('mime');
|
|
18
|
+
// Handle both default export and named exports
|
|
19
|
+
mimeModule = imported.default || imported;
|
|
20
|
+
}
|
|
21
|
+
return mimeModule;
|
|
22
|
+
}
|
|
23
|
+
|
|
13
24
|
export interface TestLensReporterConfig {
|
|
14
25
|
/** TestLens API endpoint URL */
|
|
15
26
|
apiEndpoint?: string;
|
|
@@ -65,8 +76,8 @@ export interface GitInfo {
|
|
|
65
76
|
commit: string;
|
|
66
77
|
shortCommit: string;
|
|
67
78
|
author: string;
|
|
68
|
-
|
|
69
|
-
|
|
79
|
+
message: string;
|
|
80
|
+
timestamp: string;
|
|
70
81
|
isDirty: boolean;
|
|
71
82
|
remoteName: string;
|
|
72
83
|
remoteUrl: string;
|
|
@@ -265,6 +276,13 @@ export class TestLensReporter implements Reporter {
|
|
|
265
276
|
// Collect Git information if enabled
|
|
266
277
|
if (this.config.enableGitInfo) {
|
|
267
278
|
this.runMetadata.gitInfo = await this.collectGitInfo();
|
|
279
|
+
if (this.runMetadata.gitInfo) {
|
|
280
|
+
console.log(`📦 Git info collected: branch=${this.runMetadata.gitInfo.branch}, commit=${this.runMetadata.gitInfo.shortCommit}, author=${this.runMetadata.gitInfo.author}`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log(`⚠️ Git info collection returned null - not in a git repository or git not available`);
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
console.log(`ℹ️ Git info collection disabled (enableGitInfo: false)`);
|
|
268
286
|
}
|
|
269
287
|
|
|
270
288
|
// Add shard information if available
|
|
@@ -483,26 +501,20 @@ export class TestLensReporter implements Reporter {
|
|
|
483
501
|
for (const attachment of attachments) {
|
|
484
502
|
if (attachment.path) {
|
|
485
503
|
try {
|
|
486
|
-
// Preserve original file extension from path (important for traces which must be .zip)
|
|
487
|
-
const originalExt = path.extname(attachment.path);
|
|
488
|
-
const fileName = attachment.name.includes(originalExt)
|
|
489
|
-
? attachment.name
|
|
490
|
-
: attachment.name + originalExt;
|
|
491
|
-
|
|
492
504
|
// Upload to S3 first
|
|
493
|
-
const s3Data = await this.uploadArtifactToS3(attachment.path, testId,
|
|
505
|
+
const s3Data = await this.uploadArtifactToS3(attachment.path, testId, attachment.name);
|
|
494
506
|
|
|
495
507
|
// Skip if upload failed or file was too large
|
|
496
508
|
if (!s3Data) {
|
|
497
|
-
console.log(`⏭️ Skipping artifact ${
|
|
509
|
+
console.log(`⏭️ Skipping artifact ${attachment.name} - upload failed or file too large`);
|
|
498
510
|
continue;
|
|
499
511
|
}
|
|
500
512
|
|
|
501
513
|
const artifactData = {
|
|
502
514
|
testId,
|
|
503
|
-
type: this.getArtifactType(
|
|
515
|
+
type: this.getArtifactType(attachment.name),
|
|
504
516
|
path: attachment.path,
|
|
505
|
-
name:
|
|
517
|
+
name: attachment.name,
|
|
506
518
|
contentType: attachment.contentType,
|
|
507
519
|
fileSize: this.getFileSize(attachment.path),
|
|
508
520
|
storageType: 's3',
|
|
@@ -652,8 +664,8 @@ export class TestLensReporter implements Reporter {
|
|
|
652
664
|
commit,
|
|
653
665
|
shortCommit,
|
|
654
666
|
author,
|
|
655
|
-
commitMessage,
|
|
656
|
-
commitTimestamp,
|
|
667
|
+
message: commitMessage,
|
|
668
|
+
timestamp: commitTimestamp,
|
|
657
669
|
isDirty,
|
|
658
670
|
remoteName,
|
|
659
671
|
remoteUrl
|
|
@@ -711,7 +723,7 @@ export class TestLensReporter implements Reporter {
|
|
|
711
723
|
testRunId: this.runId,
|
|
712
724
|
testId: testId,
|
|
713
725
|
fileName: fileName,
|
|
714
|
-
fileType: this.getContentType(fileName),
|
|
726
|
+
fileType: await this.getContentType(fileName),
|
|
715
727
|
fileSize: fileSize,
|
|
716
728
|
artifactType: this.getArtifactType(fileName)
|
|
717
729
|
}, {
|
|
@@ -757,7 +769,7 @@ export class TestLensReporter implements Reporter {
|
|
|
757
769
|
testId: testId,
|
|
758
770
|
s3Key: s3Key,
|
|
759
771
|
fileName: fileName,
|
|
760
|
-
fileType: this.getContentType(fileName),
|
|
772
|
+
fileType: await this.getContentType(fileName),
|
|
761
773
|
fileSize: fileSize,
|
|
762
774
|
artifactType: this.getArtifactType(fileName)
|
|
763
775
|
}, {
|
|
@@ -801,10 +813,35 @@ export class TestLensReporter implements Reporter {
|
|
|
801
813
|
}
|
|
802
814
|
}
|
|
803
815
|
|
|
804
|
-
private getContentType(fileName: string): string {
|
|
816
|
+
private async getContentType(fileName: string): Promise<string> {
|
|
805
817
|
const ext = path.extname(fileName).toLowerCase();
|
|
806
|
-
|
|
807
|
-
|
|
818
|
+
try {
|
|
819
|
+
const mime = await getMime();
|
|
820
|
+
// Try different ways to access getType method
|
|
821
|
+
const getType = mime.getType || mime.default?.getType;
|
|
822
|
+
if (typeof getType === 'function') {
|
|
823
|
+
const mimeType = getType.call(mime, ext) || getType.call(mime.default, ext);
|
|
824
|
+
return mimeType || 'application/octet-stream';
|
|
825
|
+
}
|
|
826
|
+
} catch (error: any) {
|
|
827
|
+
console.warn(`Failed to get MIME type for ${fileName}:`, error.message);
|
|
828
|
+
}
|
|
829
|
+
// Fallback to basic content type mapping
|
|
830
|
+
const contentTypes: Record<string, string> = {
|
|
831
|
+
'.mp4': 'video/mp4',
|
|
832
|
+
'.webm': 'video/webm',
|
|
833
|
+
'.png': 'image/png',
|
|
834
|
+
'.jpg': 'image/jpeg',
|
|
835
|
+
'.jpeg': 'image/jpeg',
|
|
836
|
+
'.gif': 'image/gif',
|
|
837
|
+
'.json': 'application/json',
|
|
838
|
+
'.txt': 'text/plain',
|
|
839
|
+
'.html': 'text/html',
|
|
840
|
+
'.xml': 'application/xml',
|
|
841
|
+
'.zip': 'application/zip',
|
|
842
|
+
'.pdf': 'application/pdf'
|
|
843
|
+
};
|
|
844
|
+
return contentTypes[ext] || 'application/octet-stream';
|
|
808
845
|
}
|
|
809
846
|
|
|
810
847
|
private generateS3Key(runId: string, testId: string, fileName: string): string {
|
package/lib/index.js
CHANGED
|
@@ -45,7 +45,16 @@ const fs = __importStar(require("fs"));
|
|
|
45
45
|
const https = __importStar(require("https"));
|
|
46
46
|
const axios_1 = __importDefault(require("axios"));
|
|
47
47
|
const child_process_1 = require("child_process");
|
|
48
|
-
|
|
48
|
+
// Lazy-load mime module to support ESM
|
|
49
|
+
let mimeModule = null;
|
|
50
|
+
async function getMime() {
|
|
51
|
+
if (!mimeModule) {
|
|
52
|
+
const imported = await Promise.resolve().then(() => __importStar(require('mime')));
|
|
53
|
+
// Handle both default export and named exports
|
|
54
|
+
mimeModule = imported.default || imported;
|
|
55
|
+
}
|
|
56
|
+
return mimeModule;
|
|
57
|
+
}
|
|
49
58
|
class TestLensReporter {
|
|
50
59
|
constructor(options) {
|
|
51
60
|
this.config = {
|
|
@@ -159,6 +168,15 @@ class TestLensReporter {
|
|
|
159
168
|
// Collect Git information if enabled
|
|
160
169
|
if (this.config.enableGitInfo) {
|
|
161
170
|
this.runMetadata.gitInfo = await this.collectGitInfo();
|
|
171
|
+
if (this.runMetadata.gitInfo) {
|
|
172
|
+
console.log(`📦 Git info collected: branch=${this.runMetadata.gitInfo.branch}, commit=${this.runMetadata.gitInfo.shortCommit}, author=${this.runMetadata.gitInfo.author}`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
console.log(`⚠️ Git info collection returned null - not in a git repository or git not available`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
console.log(`ℹ️ Git info collection disabled (enableGitInfo: false)`);
|
|
162
180
|
}
|
|
163
181
|
// Add shard information if available
|
|
164
182
|
if (config.shard) {
|
|
@@ -352,23 +370,18 @@ class TestLensReporter {
|
|
|
352
370
|
for (const attachment of attachments) {
|
|
353
371
|
if (attachment.path) {
|
|
354
372
|
try {
|
|
355
|
-
// Preserve original file extension from path (important for traces which must be .zip)
|
|
356
|
-
const originalExt = path.extname(attachment.path);
|
|
357
|
-
const fileName = attachment.name.includes(originalExt)
|
|
358
|
-
? attachment.name
|
|
359
|
-
: attachment.name + originalExt;
|
|
360
373
|
// Upload to S3 first
|
|
361
|
-
const s3Data = await this.uploadArtifactToS3(attachment.path, testId,
|
|
374
|
+
const s3Data = await this.uploadArtifactToS3(attachment.path, testId, attachment.name);
|
|
362
375
|
// Skip if upload failed or file was too large
|
|
363
376
|
if (!s3Data) {
|
|
364
|
-
console.log(`⏭️ Skipping artifact ${
|
|
377
|
+
console.log(`⏭️ Skipping artifact ${attachment.name} - upload failed or file too large`);
|
|
365
378
|
continue;
|
|
366
379
|
}
|
|
367
380
|
const artifactData = {
|
|
368
381
|
testId,
|
|
369
|
-
type: this.getArtifactType(
|
|
382
|
+
type: this.getArtifactType(attachment.name),
|
|
370
383
|
path: attachment.path,
|
|
371
|
-
name:
|
|
384
|
+
name: attachment.name,
|
|
372
385
|
contentType: attachment.contentType,
|
|
373
386
|
fileSize: this.getFileSize(attachment.path),
|
|
374
387
|
storageType: 's3',
|
|
@@ -503,8 +516,8 @@ class TestLensReporter {
|
|
|
503
516
|
commit,
|
|
504
517
|
shortCommit,
|
|
505
518
|
author,
|
|
506
|
-
commitMessage,
|
|
507
|
-
commitTimestamp,
|
|
519
|
+
message: commitMessage,
|
|
520
|
+
timestamp: commitTimestamp,
|
|
508
521
|
isDirty,
|
|
509
522
|
remoteName,
|
|
510
523
|
remoteUrl
|
|
@@ -555,7 +568,7 @@ class TestLensReporter {
|
|
|
555
568
|
testRunId: this.runId,
|
|
556
569
|
testId: testId,
|
|
557
570
|
fileName: fileName,
|
|
558
|
-
fileType: this.getContentType(fileName),
|
|
571
|
+
fileType: await this.getContentType(fileName),
|
|
559
572
|
fileSize: fileSize,
|
|
560
573
|
artifactType: this.getArtifactType(fileName)
|
|
561
574
|
}, {
|
|
@@ -593,7 +606,7 @@ class TestLensReporter {
|
|
|
593
606
|
testId: testId,
|
|
594
607
|
s3Key: s3Key,
|
|
595
608
|
fileName: fileName,
|
|
596
|
-
fileType: this.getContentType(fileName),
|
|
609
|
+
fileType: await this.getContentType(fileName),
|
|
597
610
|
fileSize: fileSize,
|
|
598
611
|
artifactType: this.getArtifactType(fileName)
|
|
599
612
|
}, {
|
|
@@ -637,10 +650,36 @@ class TestLensReporter {
|
|
|
637
650
|
return null;
|
|
638
651
|
}
|
|
639
652
|
}
|
|
640
|
-
getContentType(fileName) {
|
|
653
|
+
async getContentType(fileName) {
|
|
641
654
|
const ext = path.extname(fileName).toLowerCase();
|
|
642
|
-
|
|
643
|
-
|
|
655
|
+
try {
|
|
656
|
+
const mime = await getMime();
|
|
657
|
+
// Try different ways to access getType method
|
|
658
|
+
const getType = mime.getType || mime.default?.getType;
|
|
659
|
+
if (typeof getType === 'function') {
|
|
660
|
+
const mimeType = getType.call(mime, ext) || getType.call(mime.default, ext);
|
|
661
|
+
return mimeType || 'application/octet-stream';
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
console.warn(`Failed to get MIME type for ${fileName}:`, error.message);
|
|
666
|
+
}
|
|
667
|
+
// Fallback to basic content type mapping
|
|
668
|
+
const contentTypes = {
|
|
669
|
+
'.mp4': 'video/mp4',
|
|
670
|
+
'.webm': 'video/webm',
|
|
671
|
+
'.png': 'image/png',
|
|
672
|
+
'.jpg': 'image/jpeg',
|
|
673
|
+
'.jpeg': 'image/jpeg',
|
|
674
|
+
'.gif': 'image/gif',
|
|
675
|
+
'.json': 'application/json',
|
|
676
|
+
'.txt': 'text/plain',
|
|
677
|
+
'.html': 'text/html',
|
|
678
|
+
'.xml': 'application/xml',
|
|
679
|
+
'.zip': 'application/zip',
|
|
680
|
+
'.pdf': 'application/pdf'
|
|
681
|
+
};
|
|
682
|
+
return contentTypes[ext] || 'application/octet-stream';
|
|
644
683
|
}
|
|
645
684
|
generateS3Key(runId, testId, fileName) {
|
|
646
685
|
const date = new Date().toISOString().slice(0, 10);
|
package/package.json
CHANGED
package/CHANGELOG.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to the testlens-playwright-reporter package will be documented in this file.
|
|
4
|
-
|
|
5
|
-
## [0.2.4] - 2025-11-18
|
|
6
|
-
|
|
7
|
-
### Fixed
|
|
8
|
-
- **TypeScript source updated**: Applied trace file extension preservation fix to TypeScript source (`index.ts`) and rebuilt `lib/index.js` to ensure both TypeScript and JavaScript implementations have the fix.
|
|
9
|
-
|
|
10
|
-
### Fixed
|
|
11
|
-
- **Package entry point**: Changed main entry point from `lib/index.js` to `index.js` to use the correct implementation with trace file extension preservation fix.
|
|
12
|
-
|
|
13
|
-
## [0.2.3] - 2025-11-18
|
|
14
|
-
|
|
15
|
-
### Fixed
|
|
16
|
-
- **Trace file extension preservation**: Fixed issue where Playwright trace files were being uploaded to S3 without their `.zip` extension, causing "Could not load trace" errors in Playwright Trace Viewer. The reporter now preserves the original file extension from `attachment.path` when uploading artifacts, ensuring trace files maintain their `.zip` format required by the viewer.
|
|
17
|
-
|
|
18
|
-
## [0.2.2] - Previous release
|
|
19
|
-
|
|
20
|
-
### Features
|
|
21
|
-
- Direct S3 uploads with presigned URLs
|
|
22
|
-
- Asynchronous artifact processing
|
|
23
|
-
- Enhanced error handling and retry logic
|