@arghajit/dummy 0.1.0-beta-18 → 0.1.0-beta-19
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.
|
@@ -45,11 +45,10 @@ const ATTACHMENTS_SUBDIR = "attachments"; // Consistent subdirectory name
|
|
|
45
45
|
* @param config The reporter configuration options.
|
|
46
46
|
*/
|
|
47
47
|
function attachFiles(testId, pwResult, pulseResult, config) {
|
|
48
|
-
const baseReportDir = config.outputDir || "pulse-report";
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const testAttachmentsDir = path.join(attachmentsBaseDir, attachmentsSubFolder); // e.g., pulse-report/attachments/test_id_abc
|
|
48
|
+
const baseReportDir = config.outputDir || "pulse-report";
|
|
49
|
+
const attachmentsBaseDir = path.resolve(baseReportDir, ATTACHMENTS_SUBDIR);
|
|
50
|
+
const attachmentsSubFolder = testId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
51
|
+
const testAttachmentsDir = path.join(attachmentsBaseDir, attachmentsSubFolder);
|
|
53
52
|
try {
|
|
54
53
|
if (!fs.existsSync(testAttachmentsDir)) {
|
|
55
54
|
fs.mkdirSync(testAttachmentsDir, { recursive: true });
|
|
@@ -57,53 +56,49 @@ function attachFiles(testId, pwResult, pulseResult, config) {
|
|
|
57
56
|
}
|
|
58
57
|
catch (error) {
|
|
59
58
|
console.error(`Pulse Reporter: Failed to create attachments directory: ${testAttachmentsDir}`, error);
|
|
60
|
-
return;
|
|
59
|
+
return;
|
|
61
60
|
}
|
|
62
61
|
if (!pwResult.attachments)
|
|
63
62
|
return;
|
|
64
|
-
const { base64Images } = config;
|
|
65
|
-
|
|
63
|
+
const { base64Images } = config;
|
|
64
|
+
// --- MODIFICATION: Initialize all attachment arrays to prevent errors ---
|
|
65
|
+
pulseResult.screenshots = [];
|
|
66
|
+
pulseResult.videoPath = [];
|
|
67
|
+
pulseResult.attachments = [];
|
|
66
68
|
pwResult.attachments.forEach((attachment) => {
|
|
67
69
|
const { contentType, name, path: attachmentPath, body } = attachment;
|
|
68
|
-
// Skip attachments without path or body
|
|
69
70
|
if (!attachmentPath && !body) {
|
|
70
71
|
console.warn(`Pulse Reporter: Attachment "${name}" for test ${testId} has no path or body. Skipping.`);
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
|
-
|
|
74
|
-
const safeName = name.replace(/[^a-zA-Z0-9_.-]/g, "_"); // Sanitize original name
|
|
74
|
+
const safeName = name.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
75
75
|
const extension = attachmentPath
|
|
76
76
|
? path.extname(attachmentPath)
|
|
77
77
|
: `.${getFileExtension(contentType)}`;
|
|
78
78
|
const baseFilename = attachmentPath
|
|
79
79
|
? path.basename(attachmentPath, extension)
|
|
80
80
|
: safeName;
|
|
81
|
-
// Ensure unique filename within the test's attachment folder
|
|
82
81
|
const fileName = `${baseFilename}_${Date.now()}${extension}`;
|
|
83
|
-
// Relative path for storing in JSON (relative to baseReportDir)
|
|
84
82
|
const relativePath = path.join(ATTACHMENTS_SUBDIR, attachmentsSubFolder, fileName);
|
|
85
|
-
// Full path for file system operations
|
|
86
83
|
const fullPath = path.join(testAttachmentsDir, fileName);
|
|
87
84
|
if (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("image/")) {
|
|
88
|
-
// Handle all image types consistently
|
|
89
85
|
handleImage(attachmentPath, body, base64Images, fullPath, relativePath, pulseResult, name);
|
|
90
86
|
}
|
|
91
87
|
else if (name === "video" || (contentType === null || contentType === void 0 ? void 0 : contentType.startsWith("video/"))) {
|
|
92
|
-
handleAttachment(attachmentPath, body, fullPath, relativePath, "videoPath", pulseResult);
|
|
88
|
+
handleAttachment(attachmentPath, body, fullPath, relativePath, "videoPath", pulseResult, attachment);
|
|
93
89
|
}
|
|
94
90
|
else if (name === "trace" || contentType === "application/zip") {
|
|
95
|
-
|
|
96
|
-
handleAttachment(attachmentPath, body, fullPath, relativePath, "tracePath", pulseResult);
|
|
91
|
+
handleAttachment(attachmentPath, body, fullPath, relativePath, "tracePath", pulseResult, attachment);
|
|
97
92
|
}
|
|
98
93
|
else {
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
// handleAttachment(attachmentPath, body, fullPath, relativePath, 'otherAttachments', pulseResult); // Example for storing other types
|
|
94
|
+
// --- MODIFICATION: Enabled handling for all other file types ---
|
|
95
|
+
handleAttachment(attachmentPath, body, fullPath, relativePath, "attachments", pulseResult, attachment);
|
|
102
96
|
}
|
|
103
97
|
});
|
|
104
98
|
}
|
|
105
99
|
/**
|
|
106
100
|
* Handles image attachments, either embedding as base64 or copying the file.
|
|
101
|
+
* (This function is unchanged)
|
|
107
102
|
*/
|
|
108
103
|
function handleImage(attachmentPath, body, base64Embed, fullPath, relativePath, pulseResult, attachmentName) {
|
|
109
104
|
let screenshotData = undefined;
|
|
@@ -123,14 +118,10 @@ function handleImage(attachmentPath, body, base64Embed, fullPath, relativePath,
|
|
|
123
118
|
}
|
|
124
119
|
}
|
|
125
120
|
else if (body) {
|
|
126
|
-
// Always embed if only body is available
|
|
127
121
|
screenshotData = `data:image/${getFileExtension(attachmentName)};base64,${body.toString("base64")}`;
|
|
128
122
|
if (!base64Embed) {
|
|
129
|
-
// Optionally save the buffer to a file even if embedding is off,
|
|
130
|
-
// but the primary representation will be base64.
|
|
131
123
|
try {
|
|
132
124
|
fs.writeFileSync(fullPath, body);
|
|
133
|
-
// console.log(`Pulse Reporter: Saved screenshot buffer to ${fullPath}`);
|
|
134
125
|
}
|
|
135
126
|
catch (error) {
|
|
136
127
|
console.error(`Pulse Reporter: Failed to save screenshot buffer: ${fullPath}. Error: ${error.message}`);
|
|
@@ -147,21 +138,36 @@ function handleImage(attachmentPath, body, base64Embed, fullPath, relativePath,
|
|
|
147
138
|
/**
|
|
148
139
|
* Handles non-image attachments by copying the file or writing the buffer.
|
|
149
140
|
*/
|
|
150
|
-
function handleAttachment(attachmentPath, body, fullPath, relativePath, resultKey, //
|
|
151
|
-
pulseResult
|
|
141
|
+
function handleAttachment(attachmentPath, body, fullPath, relativePath, resultKey, // MODIFIED: Added 'attachments'
|
|
142
|
+
pulseResult, originalAttachment // MODIFIED: Pass original attachment
|
|
143
|
+
) {
|
|
144
|
+
var _a, _b;
|
|
152
145
|
try {
|
|
153
146
|
if (attachmentPath) {
|
|
154
147
|
fs.copyFileSync(attachmentPath, fullPath);
|
|
155
|
-
pulseResult[resultKey] = relativePath;
|
|
156
148
|
}
|
|
157
149
|
else if (body) {
|
|
158
150
|
fs.writeFileSync(fullPath, body);
|
|
159
|
-
|
|
151
|
+
}
|
|
152
|
+
// --- MODIFICATION: Logic to handle different properties correctly ---
|
|
153
|
+
switch (resultKey) {
|
|
154
|
+
case "videoPath":
|
|
155
|
+
(_a = pulseResult.videoPath) === null || _a === void 0 ? void 0 : _a.push(relativePath);
|
|
156
|
+
break;
|
|
157
|
+
case "tracePath":
|
|
158
|
+
pulseResult.tracePath = relativePath;
|
|
159
|
+
break;
|
|
160
|
+
case "attachments":
|
|
161
|
+
(_b = pulseResult.attachments) === null || _b === void 0 ? void 0 : _b.push({
|
|
162
|
+
name: originalAttachment.name,
|
|
163
|
+
path: relativePath,
|
|
164
|
+
contentType: originalAttachment.contentType,
|
|
165
|
+
});
|
|
166
|
+
break;
|
|
160
167
|
}
|
|
161
168
|
}
|
|
162
169
|
catch (error) {
|
|
163
170
|
console.error(`Pulse Reporter: Failed to copy/write attachment to ${fullPath}. Error: ${error.message}`);
|
|
164
|
-
// Don't set the path in pulseResult if saving failed
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
/**
|
|
@@ -172,8 +178,7 @@ pulseResult) {
|
|
|
172
178
|
function getFileExtension(contentType) {
|
|
173
179
|
var _a;
|
|
174
180
|
if (!contentType)
|
|
175
|
-
return "bin";
|
|
176
|
-
// More robust mapping
|
|
181
|
+
return "bin";
|
|
177
182
|
const extensions = {
|
|
178
183
|
"image/png": "png",
|
|
179
184
|
"image/jpeg": "jpg",
|
|
@@ -182,9 +187,12 @@ function getFileExtension(contentType) {
|
|
|
182
187
|
"image/svg+xml": "svg",
|
|
183
188
|
"video/webm": "webm",
|
|
184
189
|
"video/mp4": "mp4",
|
|
185
|
-
"application/zip": "zip",
|
|
190
|
+
"application/zip": "zip",
|
|
186
191
|
"text/plain": "txt",
|
|
187
192
|
"application/json": "json",
|
|
193
|
+
"text/html": "html",
|
|
194
|
+
"application/pdf": "pdf",
|
|
195
|
+
"text/csv": "csv",
|
|
188
196
|
};
|
|
189
197
|
return (extensions[contentType.toLowerCase()] ||
|
|
190
198
|
((_a = contentType.split("/")[1]) === null || _a === void 0 ? void 0 : _a.split("+")[0]) ||
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// input_file_0.ts
|
|
3
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
3
|
if (k2 === undefined) k2 = k;
|
|
5
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -38,8 +37,7 @@ exports.PlaywrightPulseReporter = void 0;
|
|
|
38
37
|
const fs = __importStar(require("fs/promises"));
|
|
39
38
|
const path = __importStar(require("path"));
|
|
40
39
|
const crypto_1 = require("crypto");
|
|
41
|
-
const
|
|
42
|
-
const ua_parser_js_1 = require("ua-parser-js"); // Added UAParser import
|
|
40
|
+
const ua_parser_js_1 = require("ua-parser-js");
|
|
43
41
|
const os = __importStar(require("os"));
|
|
44
42
|
const convertStatus = (status, testCase) => {
|
|
45
43
|
if ((testCase === null || testCase === void 0 ? void 0 : testCase.expectedStatus) === "failed") {
|
|
@@ -111,8 +109,8 @@ class PlaywrightPulseReporter {
|
|
|
111
109
|
}
|
|
112
110
|
getBrowserDetails(test) {
|
|
113
111
|
var _a, _b, _c, _d;
|
|
114
|
-
const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
|
|
115
|
-
const projectConfig = project === null || project === void 0 ? void 0 : project.use;
|
|
112
|
+
const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
|
|
113
|
+
const projectConfig = project === null || project === void 0 ? void 0 : project.use;
|
|
116
114
|
const userAgent = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.userAgent;
|
|
117
115
|
const configuredBrowserType = (_b = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.browserName) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
118
116
|
const parser = new ua_parser_js_1.UAParser(userAgent);
|
|
@@ -120,20 +118,18 @@ class PlaywrightPulseReporter {
|
|
|
120
118
|
let browserName = result.browser.name;
|
|
121
119
|
const browserVersion = result.browser.version
|
|
122
120
|
? ` v${result.browser.version.split(".")[0]}`
|
|
123
|
-
: "";
|
|
121
|
+
: "";
|
|
124
122
|
const osName = result.os.name ? ` on ${result.os.name}` : "";
|
|
125
123
|
const osVersion = result.os.version
|
|
126
124
|
? ` ${result.os.version.split(".")[0]}`
|
|
127
|
-
: "";
|
|
128
|
-
const deviceType = result.device.type;
|
|
125
|
+
: "";
|
|
126
|
+
const deviceType = result.device.type;
|
|
129
127
|
let finalString;
|
|
130
|
-
// If UAParser couldn't determine browser name, fallback to configured type
|
|
131
128
|
if (browserName === undefined) {
|
|
132
129
|
browserName = configuredBrowserType;
|
|
133
130
|
finalString = `${browserName}`;
|
|
134
131
|
}
|
|
135
132
|
else {
|
|
136
|
-
// Specific refinements for mobile based on parsed OS and device type
|
|
137
133
|
if (deviceType === "mobile" || deviceType === "tablet") {
|
|
138
134
|
if ((_c = result.os.name) === null || _c === void 0 ? void 0 : _c.toLowerCase().includes("android")) {
|
|
139
135
|
if (browserName.toLowerCase().includes("chrome"))
|
|
@@ -144,10 +140,10 @@ class PlaywrightPulseReporter {
|
|
|
144
140
|
browserName = "Android WebView";
|
|
145
141
|
else if (browserName &&
|
|
146
142
|
!browserName.toLowerCase().includes("mobile")) {
|
|
147
|
-
// Keep it as is
|
|
143
|
+
// Keep it as is
|
|
148
144
|
}
|
|
149
145
|
else {
|
|
150
|
-
browserName = "Android Browser";
|
|
146
|
+
browserName = "Android Browser";
|
|
151
147
|
}
|
|
152
148
|
}
|
|
153
149
|
else if ((_d = result.os.name) === null || _d === void 0 ? void 0 : _d.toLowerCase().includes("ios")) {
|
|
@@ -178,10 +174,9 @@ class PlaywrightPulseReporter {
|
|
|
178
174
|
if (step.location) {
|
|
179
175
|
codeLocation = `${path.relative(this.config.rootDir, step.location.file)}:${step.location.line}:${step.location.column}`;
|
|
180
176
|
}
|
|
181
|
-
let stepTitle = step.title;
|
|
182
177
|
return {
|
|
183
178
|
id: `${testId}_step_${startTime.toISOString()}-${duration}-${(0, crypto_1.randomUUID)()}`,
|
|
184
|
-
title:
|
|
179
|
+
title: step.title,
|
|
185
180
|
status: stepStatus,
|
|
186
181
|
duration: duration,
|
|
187
182
|
startTime: startTime,
|
|
@@ -200,21 +195,16 @@ class PlaywrightPulseReporter {
|
|
|
200
195
|
};
|
|
201
196
|
}
|
|
202
197
|
async onTestEnd(test, result) {
|
|
203
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
198
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
204
199
|
const project = (_a = test.parent) === null || _a === void 0 ? void 0 : _a.project();
|
|
205
200
|
const browserDetails = this.getBrowserDetails(test);
|
|
206
201
|
const testStatus = convertStatus(result.status, test);
|
|
207
202
|
const startTime = new Date(result.startTime);
|
|
208
203
|
const endTime = new Date(startTime.getTime() + result.duration);
|
|
209
|
-
const testIdForFiles = test.id ||
|
|
210
|
-
`${test
|
|
211
|
-
.titlePath()
|
|
212
|
-
.join("_")
|
|
213
|
-
.replace(/[^a-zA-Z0-9]/g, "_")}_${startTime.getTime()}`;
|
|
214
204
|
const processAllSteps = async (steps) => {
|
|
215
205
|
let processed = [];
|
|
216
206
|
for (const step of steps) {
|
|
217
|
-
const processedStep = await this.processStep(step,
|
|
207
|
+
const processedStep = await this.processStep(step, test.id, browserDetails, test);
|
|
218
208
|
processed.push(processedStep);
|
|
219
209
|
if (step.steps && step.steps.length > 0) {
|
|
220
210
|
processedStep.steps = await processAllSteps(step.steps);
|
|
@@ -232,39 +222,14 @@ class PlaywrightPulseReporter {
|
|
|
232
222
|
catch (e) {
|
|
233
223
|
console.warn(`Pulse Reporter: Could not extract code snippet for ${test.title}`, e);
|
|
234
224
|
}
|
|
235
|
-
const stdoutMessages =
|
|
236
|
-
|
|
237
|
-
result.stdout.forEach((item) => {
|
|
238
|
-
stdoutMessages.push(typeof item === "string" ? item : item.toString());
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
const stderrMessages = [];
|
|
242
|
-
if (result.stderr && result.stderr.length > 0) {
|
|
243
|
-
result.stderr.forEach((item) => {
|
|
244
|
-
stderrMessages.push(typeof item === "string" ? item : item.toString());
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
const uniqueTestId = test.id;
|
|
248
|
-
// --- REFINED THIS SECTION for testData ---
|
|
225
|
+
const stdoutMessages = result.stdout.map((item) => typeof item === "string" ? item : item.toString());
|
|
226
|
+
const stderrMessages = result.stderr.map((item) => typeof item === "string" ? item : item.toString());
|
|
249
227
|
const maxWorkers = this.config.workers;
|
|
250
|
-
let mappedWorkerId
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
mappedWorkerId = -1; // Keep it as -1 to clearly identify this special case.
|
|
254
|
-
}
|
|
255
|
-
else if (maxWorkers && maxWorkers > 0) {
|
|
256
|
-
// If there's a valid worker, map it to the concurrency slot...
|
|
257
|
-
const zeroBasedId = result.workerIndex % maxWorkers;
|
|
258
|
-
// ...and then shift it to be 1-based (1 to n).
|
|
259
|
-
mappedWorkerId = zeroBasedId + 1;
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
// Fallback for when maxWorkers is not defined: just use the original index (and shift to 1-based).
|
|
263
|
-
mappedWorkerId = result.workerIndex + 1;
|
|
264
|
-
}
|
|
228
|
+
let mappedWorkerId = result.workerIndex === -1
|
|
229
|
+
? -1
|
|
230
|
+
: (result.workerIndex % (maxWorkers > 0 ? maxWorkers : 1)) + 1;
|
|
265
231
|
const testSpecificData = {
|
|
266
232
|
workerId: mappedWorkerId,
|
|
267
|
-
uniqueWorkerIndex: result.workerIndex, // We'll keep the original for diagnostics
|
|
268
233
|
totalWorkers: maxWorkers,
|
|
269
234
|
configFile: this.config.configFile,
|
|
270
235
|
metadata: this.config.metadata
|
|
@@ -272,7 +237,7 @@ class PlaywrightPulseReporter {
|
|
|
272
237
|
: undefined,
|
|
273
238
|
};
|
|
274
239
|
const pulseResult = {
|
|
275
|
-
id:
|
|
240
|
+
id: test.id,
|
|
276
241
|
runId: "TBD",
|
|
277
242
|
name: test.titlePath().join(" > "),
|
|
278
243
|
suiteName: (project === null || project === void 0 ? void 0 : project.name) || ((_e = this.config.projects[0]) === null || _e === void 0 ? void 0 : _e.name) || "Default Suite",
|
|
@@ -288,20 +253,46 @@ class PlaywrightPulseReporter {
|
|
|
288
253
|
codeSnippet: codeSnippet,
|
|
289
254
|
tags: test.tags.map((tag) => tag.startsWith("@") ? tag.substring(1) : tag),
|
|
290
255
|
screenshots: [],
|
|
291
|
-
videoPath:
|
|
256
|
+
videoPath: [], // MODIFIED: Initialized as an array
|
|
292
257
|
tracePath: undefined,
|
|
258
|
+
attachments: [], // NEW: Initialized
|
|
293
259
|
stdout: stdoutMessages.length > 0 ? stdoutMessages : undefined,
|
|
294
260
|
stderr: stderrMessages.length > 0 ? stderrMessages : undefined,
|
|
295
|
-
// --- UPDATED THESE LINES from testSpecificData ---
|
|
296
261
|
...testSpecificData,
|
|
297
262
|
};
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
263
|
+
// --- NEW SELF-CONTAINED ATTACHMENT PROCESSING LOGIC ---
|
|
264
|
+
for (const attachment of result.attachments) {
|
|
265
|
+
if (!attachment.path)
|
|
266
|
+
continue;
|
|
267
|
+
try {
|
|
268
|
+
const attachmentFileName = path.basename(attachment.path);
|
|
269
|
+
const relativeDestPath = path.join(ATTACHMENTS_SUBDIR, attachmentFileName);
|
|
270
|
+
const absoluteDestPath = path.join(this.outputDir, relativeDestPath);
|
|
271
|
+
await this._ensureDirExists(path.dirname(absoluteDestPath));
|
|
272
|
+
await fs.copyFile(attachment.path, absoluteDestPath);
|
|
273
|
+
if (attachment.contentType.startsWith("image/")) {
|
|
274
|
+
(_j = pulseResult.screenshots) === null || _j === void 0 ? void 0 : _j.push(relativeDestPath);
|
|
275
|
+
}
|
|
276
|
+
else if (attachment.contentType.startsWith("video/")) {
|
|
277
|
+
(_k = pulseResult.videoPath) === null || _k === void 0 ? void 0 : _k.push(relativeDestPath); // MODIFIED: Push to videoPath array
|
|
278
|
+
}
|
|
279
|
+
else if (attachment.name === "trace") {
|
|
280
|
+
pulseResult.tracePath = relativeDestPath;
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
// NEW: Handle all other file types
|
|
284
|
+
(_l = pulseResult.attachments) === null || _l === void 0 ? void 0 : _l.push({
|
|
285
|
+
name: attachment.name,
|
|
286
|
+
path: relativeDestPath,
|
|
287
|
+
contentType: attachment.contentType,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
console.error(`Pulse Reporter: Failed to process attachment "${attachment.name}" for test ${pulseResult.name}. Error: ${err.message}`);
|
|
293
|
+
}
|
|
303
294
|
}
|
|
304
|
-
const existingTestIndex = this.results.findIndex((r) => r.id ===
|
|
295
|
+
const existingTestIndex = this.results.findIndex((r) => r.id === test.id);
|
|
305
296
|
if (existingTestIndex !== -1) {
|
|
306
297
|
if (pulseResult.retries >= this.results[existingTestIndex].retries) {
|
|
307
298
|
this.results[existingTestIndex] = pulseResult;
|
|
@@ -323,10 +314,10 @@ class PlaywrightPulseReporter {
|
|
|
323
314
|
host: os.hostname(),
|
|
324
315
|
os: `${os.platform()} ${os.release()}`,
|
|
325
316
|
cpu: {
|
|
326
|
-
model: os.cpus()[0] ? os.cpus()[0].model : "N/A",
|
|
317
|
+
model: os.cpus()[0] ? os.cpus()[0].model : "N/A",
|
|
327
318
|
cores: os.cpus().length,
|
|
328
319
|
},
|
|
329
|
-
memory: `${(os.totalmem() / 1024 ** 3).toFixed(2)}GB`,
|
|
320
|
+
memory: `${(os.totalmem() / 1024 ** 3).toFixed(2)}GB`,
|
|
330
321
|
node: process.version,
|
|
331
322
|
v8: process.versions.v8,
|
|
332
323
|
cwd: process.cwd(),
|
|
@@ -418,15 +409,13 @@ class PlaywrightPulseReporter {
|
|
|
418
409
|
}
|
|
419
410
|
}
|
|
420
411
|
async onEnd(result) {
|
|
421
|
-
var _a, _b, _c;
|
|
422
412
|
if (this.shardIndex !== undefined) {
|
|
423
413
|
await this._writeShardResults();
|
|
424
414
|
return;
|
|
425
415
|
}
|
|
426
416
|
const runEndTime = Date.now();
|
|
427
417
|
const duration = runEndTime - this.runStartTime;
|
|
428
|
-
const runId = `run-${this.runStartTime}-581d5ad8-ce75-4ca5-94a6-ed29c466c815`;
|
|
429
|
-
// --- CALLING _getEnvDetails HERE ---
|
|
418
|
+
const runId = `run-${this.runStartTime}-581d5ad8-ce75-4ca5-94a6-ed29c466c815`;
|
|
430
419
|
const environmentDetails = this._getEnvDetails();
|
|
431
420
|
const runData = {
|
|
432
421
|
id: runId,
|
|
@@ -436,13 +425,11 @@ class PlaywrightPulseReporter {
|
|
|
436
425
|
failed: 0,
|
|
437
426
|
skipped: 0,
|
|
438
427
|
duration,
|
|
439
|
-
// --- ADDED environmentDetails HERE ---
|
|
440
428
|
environment: environmentDetails,
|
|
441
429
|
};
|
|
442
|
-
let finalReport = undefined;
|
|
430
|
+
let finalReport = undefined;
|
|
443
431
|
if (this.isSharded) {
|
|
444
432
|
finalReport = await this._mergeShardResults(runData);
|
|
445
|
-
// Ensured environment details are on the final merged runData if not already
|
|
446
433
|
if (finalReport && finalReport.run && !finalReport.run.environment) {
|
|
447
434
|
finalReport.run.environment = environmentDetails;
|
|
448
435
|
}
|
|
@@ -470,67 +457,8 @@ class PlaywrightPulseReporter {
|
|
|
470
457
|
}
|
|
471
458
|
if (!finalReport) {
|
|
472
459
|
console.error("PlaywrightPulseReporter: CRITICAL - finalReport object was not generated. Cannot create summary.");
|
|
473
|
-
const errorSummary = `
|
|
474
|
-
PlaywrightPulseReporter: Run Finished
|
|
475
|
-
-----------------------------------------
|
|
476
|
-
Overall Status: ERROR (Report data missing)
|
|
477
|
-
Total Tests: N/A
|
|
478
|
-
Passed: N/A
|
|
479
|
-
Failed: N/A
|
|
480
|
-
Skipped: N/A
|
|
481
|
-
Duration: N/A
|
|
482
|
-
-----------------------------------------`;
|
|
483
|
-
if (this.printsToStdio()) {
|
|
484
|
-
console.log(errorSummary);
|
|
485
|
-
}
|
|
486
|
-
const errorReport = {
|
|
487
|
-
run: {
|
|
488
|
-
id: runId,
|
|
489
|
-
timestamp: new Date(this.runStartTime),
|
|
490
|
-
totalTests: 0,
|
|
491
|
-
passed: 0,
|
|
492
|
-
failed: 0,
|
|
493
|
-
skipped: 0,
|
|
494
|
-
duration: duration,
|
|
495
|
-
environment: environmentDetails,
|
|
496
|
-
},
|
|
497
|
-
results: [],
|
|
498
|
-
metadata: {
|
|
499
|
-
generatedAt: new Date().toISOString(),
|
|
500
|
-
},
|
|
501
|
-
};
|
|
502
|
-
const finalOutputPathOnError = path.join(this.outputDir, this.baseOutputFile);
|
|
503
|
-
try {
|
|
504
|
-
await this._ensureDirExists(this.outputDir);
|
|
505
|
-
await fs.writeFile(finalOutputPathOnError, JSON.stringify(errorReport, null, 2));
|
|
506
|
-
console.warn(`PlaywrightPulseReporter: Wrote an error report to ${finalOutputPathOnError} as finalReport was missing.`);
|
|
507
|
-
}
|
|
508
|
-
catch (writeError) {
|
|
509
|
-
console.error(`PlaywrightPulseReporter: Failed to write error report: ${writeError.message}`);
|
|
510
|
-
}
|
|
511
460
|
return;
|
|
512
461
|
}
|
|
513
|
-
const reportRunData = finalReport.run;
|
|
514
|
-
const finalRunStatus = ((_a = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed) !== null && _a !== void 0 ? _a : 0) > 0
|
|
515
|
-
? "failed"
|
|
516
|
-
: ((_b = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) !== null && _b !== void 0 ? _b : 0) === 0 && result.status !== "passed"
|
|
517
|
-
? result.status === "interrupted"
|
|
518
|
-
? "interrupted"
|
|
519
|
-
: "no tests or error"
|
|
520
|
-
: "passed";
|
|
521
|
-
const summary = `
|
|
522
|
-
PlaywrightPulseReporter: Run Finished
|
|
523
|
-
-----------------------------------------
|
|
524
|
-
Overall Status: ${finalRunStatus.toUpperCase()}
|
|
525
|
-
Total Tests: ${(reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.totalTests) || 0}
|
|
526
|
-
Passed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.passed}
|
|
527
|
-
Failed: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.failed}
|
|
528
|
-
Skipped: ${reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.skipped}
|
|
529
|
-
Duration: ${(((_c = reportRunData === null || reportRunData === void 0 ? void 0 : reportRunData.duration) !== null && _c !== void 0 ? _c : 0) / 1000).toFixed(2)}s
|
|
530
|
-
-----------------------------------------`;
|
|
531
|
-
if (this.printsToStdio()) {
|
|
532
|
-
console.log(summary);
|
|
533
|
-
}
|
|
534
462
|
const finalOutputPath = path.join(this.outputDir, this.baseOutputFile);
|
|
535
463
|
try {
|
|
536
464
|
await this._ensureDirExists(this.outputDir);
|
package/dist/types/index.d.ts
CHANGED
|
@@ -32,8 +32,13 @@ export interface TestResult {
|
|
|
32
32
|
runId: string;
|
|
33
33
|
browser: string;
|
|
34
34
|
screenshots?: string[];
|
|
35
|
-
videoPath?: string;
|
|
35
|
+
videoPath?: string[];
|
|
36
36
|
tracePath?: string;
|
|
37
|
+
attachments?: {
|
|
38
|
+
name: string;
|
|
39
|
+
path: string;
|
|
40
|
+
contentType: string;
|
|
41
|
+
}[];
|
|
37
42
|
stdout?: string[];
|
|
38
43
|
stderr?: string[];
|
|
39
44
|
workerId?: number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arghajit/dummy",
|
|
3
3
|
"author": "Arghajit Singha",
|
|
4
|
-
"version": "0.1.0-beta-
|
|
4
|
+
"version": "0.1.0-beta-19",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"playwright",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"reporting",
|
|
12
12
|
"nextjs",
|
|
13
13
|
"playwright-pulse",
|
|
14
|
+
"playwright-pulse-report",
|
|
14
15
|
"report",
|
|
15
16
|
"email-report",
|
|
16
17
|
"send-report",
|
|
@@ -46,7 +47,8 @@
|
|
|
46
47
|
"report:generate": "node ./scripts/generate-report.mjs",
|
|
47
48
|
"report:merge": "node ./scripts/merge-pulse-report.js",
|
|
48
49
|
"report:email": "node ./scripts/sendReport.mjs",
|
|
49
|
-
"report:minify": "node ./scripts/generate-email-report.mjs"
|
|
50
|
+
"report:minify": "node ./scripts/generate-email-report.mjs",
|
|
51
|
+
"generate-trend": "node ./scripts/generate-trend.mjs"
|
|
50
52
|
},
|
|
51
53
|
"dependencies": {
|
|
52
54
|
"archiver": "^7.0.1",
|