@arghajit/playwright-pulse-report 0.2.10 → 0.3.1
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/README.md +97 -0
- package/dist/pulse.d.ts +12 -0
- package/dist/pulse.js +24 -0
- package/dist/reporter/index.d.ts +2 -0
- package/dist/reporter/index.js +5 -1
- package/dist/reporter/playwright-pulse-reporter.d.ts +1 -0
- package/dist/reporter/playwright-pulse-reporter.js +27 -9
- package/dist/types/index.d.ts +12 -0
- package/package.json +8 -8
- package/scripts/config-reader.mjs +180 -0
- package/scripts/generate-email-report.mjs +81 -11
- package/scripts/generate-report.mjs +996 -306
- package/scripts/generate-static-report.mjs +895 -318
- package/scripts/generate-trend.mjs +11 -1
- package/scripts/merge-pulse-report.js +46 -14
- package/scripts/sendReport.mjs +109 -34
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import { getOutputDir } from "./config-reader.mjs";
|
|
4
5
|
|
|
5
6
|
// Use dynamic import for chalk as it's ESM only for prettier console logs
|
|
6
7
|
let chalk;
|
|
@@ -22,8 +23,17 @@ const HISTORY_SUBDIR = "history"; // Subdirectory for historical JSON files
|
|
|
22
23
|
const HISTORY_FILE_PREFIX = "trend-";
|
|
23
24
|
const MAX_HISTORY_FILES = 15; // Store last 15 runs
|
|
24
25
|
|
|
26
|
+
const args = process.argv.slice(2);
|
|
27
|
+
let customOutputDir = null;
|
|
28
|
+
for (let i = 0; i < args.length; i++) {
|
|
29
|
+
if (args[i] === "--outputDir" || args[i] === "-o") {
|
|
30
|
+
customOutputDir = args[i + 1];
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
async function archiveCurrentRunData() {
|
|
26
|
-
const outputDir =
|
|
36
|
+
const outputDir = await getOutputDir(customOutputDir);
|
|
27
37
|
const currentRunJsonPath = path.join(outputDir, CURRENT_RUN_JSON_FILE);
|
|
28
38
|
const historyDir = path.join(outputDir, HISTORY_SUBDIR);
|
|
29
39
|
|
|
@@ -3,9 +3,30 @@
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const args = process.argv.slice(2);
|
|
7
|
+
let customOutputDir = null;
|
|
8
|
+
for (let i = 0; i < args.length; i++) {
|
|
9
|
+
if (args[i] === '--outputDir' || args[i] === '-o') {
|
|
10
|
+
customOutputDir = args[i + 1];
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
const OUTPUT_FILE = "playwright-pulse-report.json";
|
|
8
16
|
|
|
17
|
+
async function getReportDir() {
|
|
18
|
+
if (customOutputDir) {
|
|
19
|
+
return path.resolve(process.cwd(), customOutputDir);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const { getOutputDir } = await import("./config-reader.mjs");
|
|
24
|
+
return await getOutputDir();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return path.resolve(process.cwd(), "pulse-report");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
9
30
|
function getReportFiles(dir) {
|
|
10
31
|
return fs
|
|
11
32
|
.readdirSync(dir)
|
|
@@ -15,7 +36,7 @@ function getReportFiles(dir) {
|
|
|
15
36
|
);
|
|
16
37
|
}
|
|
17
38
|
|
|
18
|
-
function mergeReports(files) {
|
|
39
|
+
function mergeReports(files, reportDir) {
|
|
19
40
|
let combinedRun = {
|
|
20
41
|
totalTests: 0,
|
|
21
42
|
passed: 0,
|
|
@@ -30,7 +51,7 @@ function mergeReports(files) {
|
|
|
30
51
|
let latestGeneratedAt = "";
|
|
31
52
|
|
|
32
53
|
for (const file of files) {
|
|
33
|
-
const filePath = path.join(
|
|
54
|
+
const filePath = path.join(reportDir, file);
|
|
34
55
|
const json = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
35
56
|
|
|
36
57
|
const run = json.run || {};
|
|
@@ -66,17 +87,28 @@ function mergeReports(files) {
|
|
|
66
87
|
}
|
|
67
88
|
|
|
68
89
|
// Main execution
|
|
69
|
-
|
|
90
|
+
(async () => {
|
|
91
|
+
const REPORT_DIR = await getReportDir();
|
|
92
|
+
|
|
93
|
+
console.log(`Report directory set to: ${REPORT_DIR}`);
|
|
94
|
+
if (customOutputDir) {
|
|
95
|
+
console.log(` (from CLI argument)`);
|
|
96
|
+
} else {
|
|
97
|
+
console.log(` (auto-detected from playwright.config or using default)`);
|
|
98
|
+
}
|
|
70
99
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
100
|
+
const reportFiles = getReportFiles(REPORT_DIR);
|
|
101
|
+
|
|
102
|
+
if (reportFiles.length === 0) {
|
|
103
|
+
console.log("No matching JSON report files found.");
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
75
106
|
|
|
76
|
-
const merged = mergeReports(reportFiles);
|
|
107
|
+
const merged = mergeReports(reportFiles, REPORT_DIR);
|
|
77
108
|
|
|
78
|
-
fs.writeFileSync(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
82
|
-
console.log(`✅ Merged report saved as ${OUTPUT_FILE}`);
|
|
109
|
+
fs.writeFileSync(
|
|
110
|
+
path.join(REPORT_DIR, OUTPUT_FILE),
|
|
111
|
+
JSON.stringify(merged, null, 2)
|
|
112
|
+
);
|
|
113
|
+
console.log(`✅ Merged report saved as ${OUTPUT_FILE}`);
|
|
114
|
+
})();
|
package/scripts/sendReport.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { fileURLToPath } from "url";
|
|
11
11
|
import { fork } from "child_process"; // This was missing in your sendReport.js but present in generate-email-report.js and needed for runScript
|
|
12
12
|
import "dotenv/config"; // CHANGED for dotenv
|
|
13
|
+
import { getOutputDir } from "./config-reader.mjs";
|
|
13
14
|
|
|
14
15
|
// Import chalk using top-level await if your Node version supports it (14.8+)
|
|
15
16
|
// or keep the dynamic import if preferred, but ensure chalk is resolved before use.
|
|
@@ -28,7 +29,14 @@ try {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
const
|
|
32
|
+
const args = process.argv.slice(2);
|
|
33
|
+
let customOutputDir = null;
|
|
34
|
+
for (let i = 0; i < args.length; i++) {
|
|
35
|
+
if (args[i] === "--outputDir" || args[i] === "-o") {
|
|
36
|
+
customOutputDir = args[i + 1];
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
32
40
|
|
|
33
41
|
let fetch;
|
|
34
42
|
// Ensure fetch is imported and available before it's used in fetchCredentials
|
|
@@ -40,11 +48,8 @@ let fetch;
|
|
|
40
48
|
|
|
41
49
|
let projectName;
|
|
42
50
|
|
|
43
|
-
function getUUID() {
|
|
44
|
-
const reportPath = path.join(
|
|
45
|
-
process.cwd(),
|
|
46
|
-
`${reportDir}/playwright-pulse-report.json`
|
|
47
|
-
);
|
|
51
|
+
function getUUID(reportDir) {
|
|
52
|
+
const reportPath = path.join(reportDir, "playwright-pulse-report.json");
|
|
48
53
|
console.log("Report path:", reportPath);
|
|
49
54
|
|
|
50
55
|
if (!fsExistsSync(reportPath)) {
|
|
@@ -71,18 +76,15 @@ const formatStartTime = (isoString) => {
|
|
|
71
76
|
return date.toLocaleString(); // Default locale
|
|
72
77
|
};
|
|
73
78
|
|
|
74
|
-
const getPulseReportSummary = () => {
|
|
75
|
-
const reportPath = path.join(
|
|
76
|
-
process.cwd(),
|
|
77
|
-
`${reportDir}/playwright-pulse-report.json`
|
|
78
|
-
);
|
|
79
|
+
const getPulseReportSummary = (reportDir) => {
|
|
80
|
+
const reportPath = path.join(reportDir, "playwright-pulse-report.json");
|
|
79
81
|
|
|
80
82
|
if (!fsExistsSync(reportPath)) {
|
|
81
83
|
// CHANGED
|
|
82
84
|
throw new Error("Pulse report file not found.");
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
const content = JSON.parse(fsReadFileSync(reportPath, "utf-8")); //
|
|
87
|
+
const content = JSON.parse(fsReadFileSync(reportPath, "utf-8")); // D
|
|
86
88
|
const run = content.run;
|
|
87
89
|
|
|
88
90
|
const total = run.totalTests || 0;
|
|
@@ -220,9 +222,9 @@ const archiveRunScriptPath = path.resolve(
|
|
|
220
222
|
"generate-email-report.mjs" // Or input_file_0.mjs if you rename it, or input_file_0.js if you configure package.json
|
|
221
223
|
);
|
|
222
224
|
|
|
223
|
-
async function runScript(scriptPath) {
|
|
225
|
+
async function runScript(scriptPath, args = []) {
|
|
224
226
|
return new Promise((resolve, reject) => {
|
|
225
|
-
const childProcess = fork(scriptPath,
|
|
227
|
+
const childProcess = fork(scriptPath, args, {
|
|
226
228
|
// Renamed variable
|
|
227
229
|
stdio: "inherit",
|
|
228
230
|
});
|
|
@@ -244,22 +246,46 @@ async function runScript(scriptPath) {
|
|
|
244
246
|
});
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
const sendEmail = async (credentials) => {
|
|
248
|
-
|
|
249
|
+
const sendEmail = async (credentials, reportDir) => {
|
|
250
|
+
const archiveArgs = customOutputDir ? ["--outputDir", customOutputDir] : [];
|
|
251
|
+
await runScript(archiveRunScriptPath, archiveArgs);
|
|
249
252
|
try {
|
|
250
253
|
console.log("Starting the sendEmail function...");
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
255
|
+
let secureTransporter;
|
|
256
|
+
const mailHost = credentials.host
|
|
257
|
+
? credentials.host.toLowerCase()
|
|
258
|
+
: "gmail";
|
|
259
|
+
|
|
260
|
+
if (mailHost === "gmail") {
|
|
261
|
+
secureTransporter = nodemailer.createTransport({
|
|
262
|
+
service: "gmail",
|
|
263
|
+
auth: {
|
|
264
|
+
user: credentials.username,
|
|
265
|
+
pass: credentials.password,
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
} else if (mailHost === "outlook") {
|
|
269
|
+
secureTransporter = nodemailer.createTransport({
|
|
270
|
+
host: "smtp.outlook.com",
|
|
271
|
+
port: 587,
|
|
272
|
+
secure: false,
|
|
273
|
+
auth: {
|
|
274
|
+
user: credentials.username,
|
|
275
|
+
pass: credentials.password,
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
} else {
|
|
279
|
+
// Should be caught in main, but safety check here
|
|
280
|
+
console.log(
|
|
281
|
+
chalk.red(
|
|
282
|
+
"Pulse report currently do not support provided mail host, kindly use either outlook mail or, gmail"
|
|
283
|
+
)
|
|
284
|
+
);
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
261
287
|
|
|
262
|
-
const reportData = getPulseReportSummary();
|
|
288
|
+
const reportData = getPulseReportSummary(reportDir);
|
|
263
289
|
const htmlContent = generateHtmlTable(reportData);
|
|
264
290
|
|
|
265
291
|
const mailOptions = {
|
|
@@ -289,7 +315,7 @@ const sendEmail = async (credentials) => {
|
|
|
289
315
|
}
|
|
290
316
|
};
|
|
291
317
|
|
|
292
|
-
async function fetchCredentials(retries = 10) {
|
|
318
|
+
async function fetchCredentials(reportDir, retries = 10) {
|
|
293
319
|
// Ensure fetch is initialized from the dynamic import before calling this
|
|
294
320
|
if (!fetch) {
|
|
295
321
|
try {
|
|
@@ -304,7 +330,7 @@ async function fetchCredentials(retries = 10) {
|
|
|
304
330
|
}
|
|
305
331
|
|
|
306
332
|
const timeout = 10000;
|
|
307
|
-
const key = getUUID();
|
|
333
|
+
const key = getUUID(reportDir);
|
|
308
334
|
|
|
309
335
|
if (!key) {
|
|
310
336
|
console.error(
|
|
@@ -384,16 +410,65 @@ const main = async () => {
|
|
|
384
410
|
}
|
|
385
411
|
}
|
|
386
412
|
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
413
|
+
const reportDir = await getOutputDir(customOutputDir);
|
|
414
|
+
|
|
415
|
+
console.log(chalk.blue(`Preparing to send email report...`));
|
|
416
|
+
console.log(chalk.blue(`Report directory set to: ${reportDir}`));
|
|
417
|
+
if (customOutputDir) {
|
|
418
|
+
console.log(chalk.gray(` (from CLI argument)`));
|
|
419
|
+
} else {
|
|
420
|
+
console.log(
|
|
421
|
+
chalk.gray(` (auto-detected from playwright.config or using default)`)
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// --- MODIFIED: Credentials Selection Logic ---
|
|
426
|
+
let credentials;
|
|
427
|
+
|
|
428
|
+
// Check if custom environment variables are provided
|
|
429
|
+
if (
|
|
430
|
+
process.env.PULSE_MAIL_HOST &&
|
|
431
|
+
process.env.PULSE_MAIL_USERNAME &&
|
|
432
|
+
process.env.PULSE_MAIL_PASSWORD
|
|
433
|
+
) {
|
|
434
|
+
const host = process.env.PULSE_MAIL_HOST.toLowerCase();
|
|
435
|
+
|
|
436
|
+
// Validate host immediately
|
|
437
|
+
if (host !== "gmail" && host !== "outlook") {
|
|
438
|
+
console.log(
|
|
439
|
+
chalk.red(
|
|
440
|
+
"Pulse report currently do not support provided mail host, kindly use either outlook mail or, gmail."
|
|
441
|
+
)
|
|
442
|
+
);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
console.log(
|
|
447
|
+
chalk.blue(
|
|
448
|
+
`Using custom credentials from environment variables for ${host}.`
|
|
449
|
+
)
|
|
391
450
|
);
|
|
392
|
-
|
|
451
|
+
credentials = {
|
|
452
|
+
username: process.env.PULSE_MAIL_USERNAME,
|
|
453
|
+
password: process.env.PULSE_MAIL_PASSWORD,
|
|
454
|
+
host: host,
|
|
455
|
+
};
|
|
456
|
+
} else {
|
|
457
|
+
// Fallback to existing fetch mechanism
|
|
458
|
+
credentials = await fetchCredentials(reportDir);
|
|
459
|
+
if (!credentials) {
|
|
460
|
+
console.warn(
|
|
461
|
+
"Skipping email sending due to missing or failed credential fetch"
|
|
462
|
+
);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
// Mark fetched credentials as gmail by default for compatibility
|
|
466
|
+
credentials.host = "gmail";
|
|
393
467
|
}
|
|
468
|
+
// --- END MODIFICATION ---
|
|
394
469
|
// Removed await delay(10000); // If not strictly needed, remove it.
|
|
395
470
|
try {
|
|
396
|
-
await sendEmail(credentials);
|
|
471
|
+
await sendEmail(credentials, reportDir);
|
|
397
472
|
} catch (error) {
|
|
398
473
|
console.error("Error in main function: ", error);
|
|
399
474
|
}
|