@arghajit/dummy 0.3.15 โ 0.3.16
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arghajit/dummy",
|
|
3
3
|
"author": "Arghajit Singha",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.16",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
6
|
"homepage": "https://arghajit47.github.io/playwright-pulse/",
|
|
7
7
|
"repository": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -5,6 +5,7 @@ const path = require("path");
|
|
|
5
5
|
|
|
6
6
|
const args = process.argv.slice(2);
|
|
7
7
|
let customOutputDir = null;
|
|
8
|
+
|
|
8
9
|
for (let i = 0; i < args.length; i++) {
|
|
9
10
|
if (args[i] === '--outputDir' || args[i] === '-o') {
|
|
10
11
|
customOutputDir = args[i + 1];
|
|
@@ -16,17 +17,13 @@ const OUTPUT_FILE = "playwright-pulse-report.json";
|
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Securely resolves the report directory.
|
|
19
|
-
* Prevents Path Traversal by ensuring the output directory
|
|
20
|
+
* Prevents Path Traversal by ensuring the output directory
|
|
20
21
|
* is contained within the current working directory.
|
|
21
22
|
*/
|
|
22
23
|
async function getReportDir() {
|
|
23
24
|
if (customOutputDir) {
|
|
24
|
-
// 1. Resolve the absolute path
|
|
25
25
|
const resolvedPath = path.resolve(process.cwd(), customOutputDir);
|
|
26
26
|
|
|
27
|
-
// 2. Security Check: Prevent Path Traversal
|
|
28
|
-
// We ensure the resolved path starts with the project root (process.cwd())
|
|
29
|
-
// This blocks inputs like "../../" that try to escape the project.
|
|
30
27
|
if (!resolvedPath.startsWith(process.cwd())) {
|
|
31
28
|
console.error(
|
|
32
29
|
"โ Security Error: Custom output directory must be within the current project root.",
|
|
@@ -45,21 +42,26 @@ async function getReportDir() {
|
|
|
45
42
|
}
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Scans the report directory for subdirectories (shards).
|
|
47
|
+
* Returns an array of absolute paths to these subdirectories.
|
|
48
|
+
* Excludes the 'attachments' folder itself.
|
|
49
|
+
*/
|
|
50
|
+
function getShardDirectories(dir) {
|
|
50
51
|
if (!fs.existsSync(dir)) {
|
|
51
52
|
return [];
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
return fs
|
|
55
|
-
.readdirSync(dir)
|
|
56
|
-
.filter(
|
|
57
|
-
|
|
58
|
-
file.startsWith("playwright-pulse-report-") && file.endsWith(".json"),
|
|
59
|
-
);
|
|
56
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
57
|
+
.filter((dirent) => dirent.isDirectory() && dirent.name !== "attachments")
|
|
58
|
+
.map((dirent) => path.join(dir, dirent.name));
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Merges JSON reports from all shard directories.
|
|
63
|
+
*/
|
|
64
|
+
function mergeReports(shardDirs) {
|
|
63
65
|
let combinedRun = {
|
|
64
66
|
totalTests: 0,
|
|
65
67
|
passed: 0,
|
|
@@ -69,16 +71,19 @@ function mergeReports(files, reportDir) {
|
|
|
69
71
|
};
|
|
70
72
|
|
|
71
73
|
let combinedResults = [];
|
|
72
|
-
|
|
73
74
|
let latestTimestamp = "";
|
|
74
75
|
let latestGeneratedAt = "";
|
|
75
76
|
|
|
76
|
-
for (const
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
for (const shardDir of shardDirs) {
|
|
78
|
+
const jsonPath = path.join(shardDir, OUTPUT_FILE);
|
|
79
|
+
|
|
80
|
+
if (!fs.existsSync(jsonPath)) {
|
|
81
|
+
console.warn(` Warning: No ${OUTPUT_FILE} found in ${path.basename(shardDir)}`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
try {
|
|
81
|
-
const fileContent = fs.readFileSync(
|
|
86
|
+
const fileContent = fs.readFileSync(jsonPath, "utf-8");
|
|
82
87
|
const json = JSON.parse(fileContent);
|
|
83
88
|
|
|
84
89
|
const run = json.run || {};
|
|
@@ -87,7 +92,10 @@ function mergeReports(files, reportDir) {
|
|
|
87
92
|
combinedRun.failed += run.failed || 0;
|
|
88
93
|
combinedRun.skipped += run.skipped || 0;
|
|
89
94
|
combinedRun.duration += run.duration || 0;
|
|
90
|
-
|
|
95
|
+
|
|
96
|
+
if (run.environment) {
|
|
97
|
+
combinedRun.environment = run.environment;
|
|
98
|
+
}
|
|
91
99
|
|
|
92
100
|
if (json.results) {
|
|
93
101
|
combinedResults.push(...json.results);
|
|
@@ -97,7 +105,9 @@ function mergeReports(files, reportDir) {
|
|
|
97
105
|
if (json.metadata?.generatedAt > latestGeneratedAt)
|
|
98
106
|
latestGeneratedAt = json.metadata.generatedAt;
|
|
99
107
|
} catch (e) {
|
|
100
|
-
console.warn(
|
|
108
|
+
console.warn(
|
|
109
|
+
` Warning: Failed to process JSON in ${path.basename(shardDir)}: ${e.message}`,
|
|
110
|
+
);
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
113
|
|
|
@@ -116,30 +126,104 @@ function mergeReports(files, reportDir) {
|
|
|
116
126
|
return finalJson;
|
|
117
127
|
}
|
|
118
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Copies attachments from all shard directories to the main attachments folder.
|
|
131
|
+
*/
|
|
132
|
+
function mergeAttachments(shardDirs, outputDir) {
|
|
133
|
+
const globalAttachmentsDir = path.join(outputDir, "attachments");
|
|
134
|
+
|
|
135
|
+
for (const shardDir of shardDirs) {
|
|
136
|
+
const shardAttachmentsDir = path.join(shardDir, "attachments");
|
|
137
|
+
|
|
138
|
+
if (!fs.existsSync(shardAttachmentsDir)) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
if (!fs.existsSync(globalAttachmentsDir)) {
|
|
144
|
+
fs.mkdirSync(globalAttachmentsDir, { recursive: true });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Recursively copy contents from shard attachments to global attachments
|
|
148
|
+
fs.cpSync(shardAttachmentsDir, globalAttachmentsDir, {
|
|
149
|
+
recursive: true,
|
|
150
|
+
});
|
|
151
|
+
} catch (e) {
|
|
152
|
+
console.warn(
|
|
153
|
+
` Warning: Failed to copy attachments from ${path.basename(shardDir)}: ${e.message}`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Cleans up shard directories after merging.
|
|
161
|
+
*/
|
|
162
|
+
function cleanupShardDirectories(shardDirs) {
|
|
163
|
+
console.log("\n๐งน Cleaning up shard directories...");
|
|
164
|
+
for (const shardDir of shardDirs) {
|
|
165
|
+
try {
|
|
166
|
+
fs.rmSync(shardDir, { recursive: true, force: true });
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.warn(
|
|
169
|
+
` Warning: Could not delete ${path.basename(shardDir)}: ${e.message}`,
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
console.log("โจ Cleanup complete.");
|
|
174
|
+
}
|
|
175
|
+
|
|
119
176
|
// Main execution
|
|
120
177
|
(async () => {
|
|
121
178
|
const REPORT_DIR = await getReportDir();
|
|
122
179
|
|
|
123
|
-
console.log(
|
|
180
|
+
console.log(`\n๐ Playwright Pulse - Merge Reports (Sharding Mode)\n`);
|
|
181
|
+
console.log(` Report directory: ${REPORT_DIR}`);
|
|
124
182
|
if (customOutputDir) {
|
|
125
183
|
console.log(` (from CLI argument)`);
|
|
126
184
|
} else {
|
|
127
185
|
console.log(` (auto-detected from playwright.config or using default)`);
|
|
128
186
|
}
|
|
187
|
+
console.log();
|
|
129
188
|
|
|
130
|
-
|
|
189
|
+
// 1. Get Shard Directories
|
|
190
|
+
const shardDirs = getShardDirectories(REPORT_DIR);
|
|
131
191
|
|
|
132
|
-
if (
|
|
133
|
-
console.log("No
|
|
134
|
-
|
|
192
|
+
if (shardDirs.length === 0) {
|
|
193
|
+
console.log("โ No shard directories found.");
|
|
194
|
+
console.log(
|
|
195
|
+
" Expected structure: <report-dir>/<shard-folder>/playwright-pulse-report.json",
|
|
196
|
+
);
|
|
197
|
+
process.exit(0);
|
|
135
198
|
}
|
|
136
199
|
|
|
137
|
-
|
|
200
|
+
console.log(`๐ Found ${shardDirs.length} shard director${shardDirs.length === 1 ? 'y' : 'ies'}:`);
|
|
201
|
+
shardDirs.forEach((dir) => {
|
|
202
|
+
console.log(` - ${path.basename(dir)}`);
|
|
203
|
+
});
|
|
204
|
+
console.log();
|
|
205
|
+
|
|
206
|
+
// 2. Merge JSON Reports
|
|
207
|
+
console.log(`๐ Merging reports...`);
|
|
208
|
+
const merged = mergeReports(shardDirs);
|
|
209
|
+
console.log(` โ Merged ${shardDirs.length} report(s)`);
|
|
210
|
+
console.log();
|
|
211
|
+
|
|
212
|
+
// 3. Copy Attachments
|
|
213
|
+
console.log(`๐ Merging attachments...`);
|
|
214
|
+
mergeAttachments(shardDirs, REPORT_DIR);
|
|
215
|
+
console.log(` โ Attachments merged`);
|
|
216
|
+
|
|
217
|
+
// 4. Write Final Merged JSON
|
|
218
|
+
const finalReportPath = path.join(REPORT_DIR, OUTPUT_FILE);
|
|
219
|
+
fs.writeFileSync(finalReportPath, JSON.stringify(merged, null, 2));
|
|
220
|
+
|
|
221
|
+
console.log(`\nโ
Merged report saved as ${OUTPUT_FILE}`);
|
|
222
|
+
console.log(` Total tests: ${merged.run.totalTests}`);
|
|
223
|
+
console.log(` Passed: ${merged.run.passed} | Failed: ${merged.run.failed} | Skipped: ${merged.run.skipped}`);
|
|
224
|
+
|
|
225
|
+
// 5. Cleanup Shard Directories
|
|
226
|
+
cleanupShardDirectories(shardDirs);
|
|
138
227
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
path.join(REPORT_DIR, OUTPUT_FILE),
|
|
142
|
-
JSON.stringify(merged, null, 2),
|
|
143
|
-
);
|
|
144
|
-
console.log(`โ
Merged report saved as ${OUTPUT_FILE}`);
|
|
145
|
-
})();
|
|
228
|
+
console.log();
|
|
229
|
+
})();
|
package/scripts/sendReport.mjs
CHANGED
|
File without changes
|