@arghajit/dummy 0.3.1 → 0.3.2
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.2",
|
|
5
5
|
"description": "A Playwright reporter and dashboard for visualizing test results.",
|
|
6
6
|
"homepage": "https://playwright-pulse-report.netlify.app/",
|
|
7
7
|
"keywords": [
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as fs from "fs/promises";
|
|
4
4
|
import path from "path";
|
|
5
|
+
import { getOutputDir } from "./config-reader.mjs";
|
|
5
6
|
|
|
6
7
|
// Use dynamic import for chalk as it's ESM only
|
|
7
8
|
let chalk;
|
|
@@ -661,12 +662,20 @@ function generateMinifiedHTML(reportData) {
|
|
|
661
662
|
`;
|
|
662
663
|
}
|
|
663
664
|
async function main() {
|
|
664
|
-
const outputDir = customOutputDir
|
|
665
|
-
? path.resolve(process.cwd(), customOutputDir)
|
|
666
|
-
: path.resolve(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
665
|
+
const outputDir = await getOutputDir(customOutputDir);
|
|
667
666
|
const reportJsonPath = path.resolve(outputDir, DEFAULT_JSON_FILE);
|
|
668
667
|
const minifiedReportHtmlPath = path.resolve(outputDir, MINIFIED_HTML_FILE); // Path for the new minified HTML
|
|
669
668
|
|
|
669
|
+
console.log(chalk.blue(`Generating email report...`));
|
|
670
|
+
console.log(chalk.blue(`Output directory set to: ${outputDir}`));
|
|
671
|
+
if (customOutputDir) {
|
|
672
|
+
console.log(chalk.gray(` (from CLI argument)`));
|
|
673
|
+
} else {
|
|
674
|
+
console.log(
|
|
675
|
+
chalk.gray(` (auto-detected from playwright.config or using default)`)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
670
679
|
// Step 2: Load current run's data
|
|
671
680
|
let currentRunReportData;
|
|
672
681
|
try {
|
|
@@ -5,6 +5,7 @@ import { readFileSync, existsSync as fsExistsSync } from "fs";
|
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fork } from "child_process";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
|
+
import { getOutputDir } from "./config-reader.mjs";
|
|
8
9
|
|
|
9
10
|
// Use dynamic import for chalk as it's ESM only
|
|
10
11
|
let chalk;
|
|
@@ -615,8 +616,9 @@ function generatePieChart(data, chartWidth = 300, chartHeight = 300) {
|
|
|
615
616
|
chart: {
|
|
616
617
|
type: 'pie',
|
|
617
618
|
width: ${chartWidth},
|
|
618
|
-
height: ${
|
|
619
|
-
|
|
619
|
+
height: ${
|
|
620
|
+
chartHeight - 40
|
|
621
|
+
}, // Adjusted height to make space for legend if chartHeight is for the whole wrapper
|
|
620
622
|
backgroundColor: 'transparent',
|
|
621
623
|
plotShadow: false,
|
|
622
624
|
spacingBottom: 40 // Ensure space for legend
|
|
@@ -668,8 +670,9 @@ function generatePieChart(data, chartWidth = 300, chartHeight = 300) {
|
|
|
668
670
|
return `
|
|
669
671
|
<div class="pie-chart-wrapper" style="align-items: center; max-height: 450px">
|
|
670
672
|
<div style="display: flex; align-items: start; width: 100%;"><h3>Test Distribution</h3></div>
|
|
671
|
-
<div id="${chartId}" style="width: ${chartWidth}px; height: ${
|
|
672
|
-
|
|
673
|
+
<div id="${chartId}" style="width: ${chartWidth}px; height: ${
|
|
674
|
+
chartHeight - 40
|
|
675
|
+
}px;"></div>
|
|
673
676
|
<script>
|
|
674
677
|
document.addEventListener('DOMContentLoaded', function() {
|
|
675
678
|
if (typeof Highcharts !== 'undefined') {
|
|
@@ -897,14 +900,15 @@ function generateEnvironmentDashboard(environment, dashboardHeight = 600) {
|
|
|
897
900
|
<span class="env-detail-value">
|
|
898
901
|
<div class="env-cpu-cores">
|
|
899
902
|
${Array.from(
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
903
|
+
{ length: Math.max(0, environment.cpu.cores || 0) },
|
|
904
|
+
(_, i) =>
|
|
905
|
+
`<div class="env-core-indicator ${
|
|
906
|
+
i >=
|
|
907
|
+
(environment.cpu.cores >= 8 ? 8 : environment.cpu.cores)
|
|
908
|
+
? "inactive"
|
|
909
|
+
: ""
|
|
910
|
+
}" title="Core ${i + 1}"></div>`
|
|
911
|
+
).join("")}
|
|
908
912
|
<span>${environment.cpu.cores || "N/A"} cores</span>
|
|
909
913
|
</div>
|
|
910
914
|
</span>
|
|
@@ -924,20 +928,23 @@ function generateEnvironmentDashboard(environment, dashboardHeight = 600) {
|
|
|
924
928
|
<div class="env-card-content">
|
|
925
929
|
<div class="env-detail-row">
|
|
926
930
|
<span class="env-detail-label">OS Type</span>
|
|
927
|
-
<span class="env-detail-value">${
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
+
<span class="env-detail-value">${
|
|
932
|
+
environment.os.split(" ")[0] === "darwin"
|
|
933
|
+
? "darwin (macOS)"
|
|
934
|
+
: environment.os.split(" ")[0] || "Unknown"
|
|
935
|
+
}</span>
|
|
931
936
|
</div>
|
|
932
937
|
<div class="env-detail-row">
|
|
933
938
|
<span class="env-detail-label">OS Version</span>
|
|
934
|
-
<span class="env-detail-value">${
|
|
935
|
-
|
|
939
|
+
<span class="env-detail-value">${
|
|
940
|
+
environment.os.split(" ")[1] || "N/A"
|
|
941
|
+
}</span>
|
|
936
942
|
</div>
|
|
937
943
|
<div class="env-detail-row">
|
|
938
944
|
<span class="env-detail-label">Hostname</span>
|
|
939
|
-
<span class="env-detail-value" title="${environment.host}">${
|
|
940
|
-
|
|
945
|
+
<span class="env-detail-value" title="${environment.host}">${
|
|
946
|
+
environment.host
|
|
947
|
+
}</span>
|
|
941
948
|
</div>
|
|
942
949
|
</div>
|
|
943
950
|
</div>
|
|
@@ -958,10 +965,11 @@ function generateEnvironmentDashboard(environment, dashboardHeight = 600) {
|
|
|
958
965
|
</div>
|
|
959
966
|
<div class="env-detail-row">
|
|
960
967
|
<span class="env-detail-label">Working Dir</span>
|
|
961
|
-
<span class="env-detail-value" title="${environment.cwd}">${
|
|
968
|
+
<span class="env-detail-value" title="${environment.cwd}">${
|
|
969
|
+
environment.cwd.length > 25
|
|
962
970
|
? "..." + environment.cwd.slice(-22)
|
|
963
971
|
: environment.cwd
|
|
964
|
-
|
|
972
|
+
}</span>
|
|
965
973
|
</div>
|
|
966
974
|
</div>
|
|
967
975
|
</div>
|
|
@@ -975,30 +983,33 @@ function generateEnvironmentDashboard(environment, dashboardHeight = 600) {
|
|
|
975
983
|
<div class="env-detail-row">
|
|
976
984
|
<span class="env-detail-label">Platform Arch</span>
|
|
977
985
|
<span class="env-detail-value">
|
|
978
|
-
<span class="env-chip ${
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
986
|
+
<span class="env-chip ${
|
|
987
|
+
environment.os.includes("darwin") &&
|
|
988
|
+
environment.cpu.model.toLowerCase().includes("apple")
|
|
989
|
+
? "env-chip-success"
|
|
990
|
+
: "env-chip-warning"
|
|
991
|
+
}">
|
|
992
|
+
${
|
|
993
|
+
environment.os.includes("darwin") &&
|
|
994
|
+
environment.cpu.model.toLowerCase().includes("apple")
|
|
995
|
+
? "Apple Silicon"
|
|
996
|
+
: environment.cpu.model.toLowerCase().includes("arm") ||
|
|
997
|
+
environment.cpu.model.toLowerCase().includes("aarch64")
|
|
998
|
+
? "ARM-based"
|
|
999
|
+
: "x86/Other"
|
|
1000
|
+
}
|
|
991
1001
|
</span>
|
|
992
1002
|
</span>
|
|
993
1003
|
</div>
|
|
994
1004
|
<div class="env-detail-row">
|
|
995
1005
|
<span class="env-detail-label">Memory per Core</span>
|
|
996
|
-
<span class="env-detail-value">${
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1006
|
+
<span class="env-detail-value">${
|
|
1007
|
+
environment.cpu.cores > 0
|
|
1008
|
+
? (
|
|
1009
|
+
parseFloat(environment.memory) / environment.cpu.cores
|
|
1010
|
+
).toFixed(2) + " GB"
|
|
1011
|
+
: "N/A"
|
|
1012
|
+
}</span>
|
|
1002
1013
|
</div>
|
|
1003
1014
|
<div class="env-detail-row">
|
|
1004
1015
|
<span class="env-detail-label">Run Context</span>
|
|
@@ -1330,19 +1341,19 @@ function generateTestHistoryContent(trendData) {
|
|
|
1330
1341
|
|
|
1331
1342
|
<div class="test-history-grid">
|
|
1332
1343
|
${testHistory
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1344
|
+
.map((test) => {
|
|
1345
|
+
const latestRun =
|
|
1346
|
+
test.history.length > 0
|
|
1347
|
+
? test.history[test.history.length - 1]
|
|
1348
|
+
: { status: "unknown" };
|
|
1349
|
+
return `
|
|
1339
1350
|
<div class="test-history-card" data-test-name="${sanitizeHTML(
|
|
1340
|
-
|
|
1341
|
-
|
|
1351
|
+
test.testTitle.toLowerCase()
|
|
1352
|
+
)}" data-latest-status="${latestRun.status}">
|
|
1342
1353
|
<div class="test-history-header">
|
|
1343
1354
|
<p title="${sanitizeHTML(test.testTitle)}">${capitalize(
|
|
1344
|
-
|
|
1345
|
-
|
|
1355
|
+
sanitizeHTML(test.testTitle)
|
|
1356
|
+
)}</p>
|
|
1346
1357
|
<span class="status-badge ${getStatusClass(latestRun.status)}">
|
|
1347
1358
|
${String(latestRun.status).toUpperCase()}
|
|
1348
1359
|
</span>
|
|
@@ -1357,27 +1368,27 @@ function generateTestHistoryContent(trendData) {
|
|
|
1357
1368
|
<thead><tr><th>Run</th><th>Status</th><th>Duration</th><th>Date</th></tr></thead>
|
|
1358
1369
|
<tbody>
|
|
1359
1370
|
${test.history
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1371
|
+
.slice()
|
|
1372
|
+
.reverse()
|
|
1373
|
+
.map(
|
|
1374
|
+
(run) => `
|
|
1364
1375
|
<tr>
|
|
1365
1376
|
<td>${run.runId}</td>
|
|
1366
1377
|
<td><span class="status-badge-small ${getStatusClass(
|
|
1367
|
-
|
|
1368
|
-
|
|
1378
|
+
run.status
|
|
1379
|
+
)}">${String(run.status).toUpperCase()}</span></td>
|
|
1369
1380
|
<td>${formatDuration(run.duration)}</td>
|
|
1370
1381
|
<td>${formatDate(run.timestamp)}</td>
|
|
1371
1382
|
</tr>`
|
|
1372
|
-
|
|
1373
|
-
|
|
1383
|
+
)
|
|
1384
|
+
.join("")}
|
|
1374
1385
|
</tbody>
|
|
1375
1386
|
</table>
|
|
1376
1387
|
</div>
|
|
1377
1388
|
</details>
|
|
1378
1389
|
</div>`;
|
|
1379
|
-
|
|
1380
|
-
|
|
1390
|
+
})
|
|
1391
|
+
.join("")}
|
|
1381
1392
|
</div>
|
|
1382
1393
|
</div>
|
|
1383
1394
|
`;
|
|
@@ -1462,11 +1473,12 @@ function generateSuitesWidget(suitesData) {
|
|
|
1462
1473
|
<div class="suites-widget">
|
|
1463
1474
|
<div class="suites-header">
|
|
1464
1475
|
<h2>Test Suites</h2>
|
|
1465
|
-
<span class="summary-badge">${
|
|
1476
|
+
<span class="summary-badge">${
|
|
1477
|
+
suitesData.length
|
|
1466
1478
|
} suites • ${suitesData.reduce(
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1479
|
+
(sum, suite) => sum + suite.count,
|
|
1480
|
+
0
|
|
1481
|
+
)} tests</span>
|
|
1470
1482
|
</div>
|
|
1471
1483
|
<div class="suites-grid">
|
|
1472
1484
|
${suitesData
|
|
@@ -1479,24 +1491,28 @@ function generateSuitesWidget(suitesData) {
|
|
|
1479
1491
|
)} (${sanitizeHTML(suite.browser)})">${sanitizeHTML(suite.name)}</h3>
|
|
1480
1492
|
</div>
|
|
1481
1493
|
<div>🖥️ <span class="browser-tag">${sanitizeHTML(
|
|
1482
|
-
|
|
1483
|
-
|
|
1494
|
+
suite.browser
|
|
1495
|
+
)}</span></div>
|
|
1484
1496
|
<div class="suite-card-body">
|
|
1485
|
-
<span class="test-count">${suite.count} test${
|
|
1486
|
-
|
|
1497
|
+
<span class="test-count">${suite.count} test${
|
|
1498
|
+
suite.count !== 1 ? "s" : ""
|
|
1499
|
+
}</span>
|
|
1487
1500
|
<div class="suite-stats">
|
|
1488
|
-
${
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1501
|
+
${
|
|
1502
|
+
suite.passed > 0
|
|
1503
|
+
? `<span class="stat-passed" title="Passed"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-check-circle-fill" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/></svg> ${suite.passed}</span>`
|
|
1504
|
+
: ""
|
|
1505
|
+
}
|
|
1506
|
+
${
|
|
1507
|
+
suite.failed > 0
|
|
1508
|
+
? `<span class="stat-failed" title="Failed"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-x-circle-fill" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/></svg> ${suite.failed}</span>`
|
|
1509
|
+
: ""
|
|
1510
|
+
}
|
|
1511
|
+
${
|
|
1512
|
+
suite.skipped > 0
|
|
1513
|
+
? `<span class="stat-skipped" title="Skipped"><svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" class="bi bi-exclamation-triangle-fill" viewBox="0 0 16 16"><path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/></svg> ${suite.skipped}</span>`
|
|
1514
|
+
: ""
|
|
1515
|
+
}
|
|
1500
1516
|
</div>
|
|
1501
1517
|
</div>
|
|
1502
1518
|
</div>`
|
|
@@ -3078,9 +3094,7 @@ async function main() {
|
|
|
3078
3094
|
"generate-trend.mjs" // Keeping the filename as per your request
|
|
3079
3095
|
);
|
|
3080
3096
|
|
|
3081
|
-
const outputDir = customOutputDir
|
|
3082
|
-
? path.resolve(process.cwd(), customOutputDir)
|
|
3083
|
-
: path.resolve(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
3097
|
+
const outputDir = await getOutputDir(customOutputDir);
|
|
3084
3098
|
const reportJsonPath = path.resolve(outputDir, DEFAULT_JSON_FILE); // Current run's main JSON
|
|
3085
3099
|
const reportHtmlPath = path.resolve(outputDir, DEFAULT_HTML_FILE);
|
|
3086
3100
|
|
|
@@ -3090,6 +3104,13 @@ async function main() {
|
|
|
3090
3104
|
|
|
3091
3105
|
console.log(chalk.blue(`Starting static HTML report generation...`));
|
|
3092
3106
|
console.log(chalk.blue(`Output directory set to: ${outputDir}`));
|
|
3107
|
+
if (customOutputDir) {
|
|
3108
|
+
console.log(chalk.gray(` (from CLI argument)`));
|
|
3109
|
+
} else {
|
|
3110
|
+
console.log(
|
|
3111
|
+
chalk.gray(` (auto-detected from playwright.config or using default)`)
|
|
3112
|
+
);
|
|
3113
|
+
}
|
|
3093
3114
|
|
|
3094
3115
|
// Step 1: Ensure current run data is archived to the history folder
|
|
3095
3116
|
try {
|
|
@@ -5,6 +5,7 @@ import { readFileSync, existsSync as fsExistsSync } from "fs";
|
|
|
5
5
|
import path from "path";
|
|
6
6
|
import { fork } from "child_process";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
|
+
import { getOutputDir } from "./config-reader.mjs";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Dynamically imports the 'chalk' library for terminal string styling.
|
|
@@ -3201,9 +3202,7 @@ async function main() {
|
|
|
3201
3202
|
"generate-trend.mjs" // Keeping the filename as per your request
|
|
3202
3203
|
);
|
|
3203
3204
|
|
|
3204
|
-
const outputDir = customOutputDir
|
|
3205
|
-
? path.resolve(process.cwd(), customOutputDir)
|
|
3206
|
-
: path.resolve(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
3205
|
+
const outputDir = await getOutputDir(customOutputDir);
|
|
3207
3206
|
const reportJsonPath = path.resolve(outputDir, DEFAULT_JSON_FILE); // Current run's main JSON
|
|
3208
3207
|
const reportHtmlPath = path.resolve(outputDir, DEFAULT_HTML_FILE);
|
|
3209
3208
|
|
|
@@ -3213,6 +3212,16 @@ async function main() {
|
|
|
3213
3212
|
|
|
3214
3213
|
console.log(chalk.blue(`Starting static HTML report generation...`));
|
|
3215
3214
|
console.log(chalk.blue(`Output directory set to: ${outputDir}`));
|
|
3215
|
+
if (customOutputDir) {
|
|
3216
|
+
console.log(chalk.gray(` (from CLI argument)`));
|
|
3217
|
+
} else {
|
|
3218
|
+
const { exists } = await import("./config-reader.mjs").then((m) => ({
|
|
3219
|
+
exists: true,
|
|
3220
|
+
}));
|
|
3221
|
+
console.log(
|
|
3222
|
+
chalk.gray(` (auto-detected from playwright.config or using default)`)
|
|
3223
|
+
);
|
|
3224
|
+
}
|
|
3216
3225
|
|
|
3217
3226
|
// Step 1: Ensure current run data is archived to the history folder
|
|
3218
3227
|
try {
|
|
@@ -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;
|
|
@@ -25,16 +26,14 @@ const MAX_HISTORY_FILES = 15; // Store last 15 runs
|
|
|
25
26
|
const args = process.argv.slice(2);
|
|
26
27
|
let customOutputDir = null;
|
|
27
28
|
for (let i = 0; i < args.length; i++) {
|
|
28
|
-
if (args[i] ===
|
|
29
|
+
if (args[i] === "--outputDir" || args[i] === "-o") {
|
|
29
30
|
customOutputDir = args[i + 1];
|
|
30
31
|
break;
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
async function archiveCurrentRunData() {
|
|
35
|
-
const outputDir = customOutputDir
|
|
36
|
-
? path.resolve(process.cwd(), customOutputDir)
|
|
37
|
-
: path.resolve(process.cwd(), DEFAULT_OUTPUT_DIR);
|
|
36
|
+
const outputDir = await getOutputDir(customOutputDir);
|
|
38
37
|
const currentRunJsonPath = path.join(outputDir, CURRENT_RUN_JSON_FILE);
|
|
39
38
|
const historyDir = path.join(outputDir, HISTORY_SUBDIR);
|
|
40
39
|
|
|
@@ -12,9 +12,21 @@ for (let i = 0; i < args.length; i++) {
|
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const REPORT_DIR = customOutputDir || "./pulse-report";
|
|
16
15
|
const OUTPUT_FILE = "playwright-pulse-report.json";
|
|
17
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
|
+
|
|
18
30
|
function getReportFiles(dir) {
|
|
19
31
|
return fs
|
|
20
32
|
.readdirSync(dir)
|
|
@@ -24,7 +36,7 @@ function getReportFiles(dir) {
|
|
|
24
36
|
);
|
|
25
37
|
}
|
|
26
38
|
|
|
27
|
-
function mergeReports(files) {
|
|
39
|
+
function mergeReports(files, reportDir) {
|
|
28
40
|
let combinedRun = {
|
|
29
41
|
totalTests: 0,
|
|
30
42
|
passed: 0,
|
|
@@ -39,7 +51,7 @@ function mergeReports(files) {
|
|
|
39
51
|
let latestGeneratedAt = "";
|
|
40
52
|
|
|
41
53
|
for (const file of files) {
|
|
42
|
-
const filePath = path.join(
|
|
54
|
+
const filePath = path.join(reportDir, file);
|
|
43
55
|
const json = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
44
56
|
|
|
45
57
|
const run = json.run || {};
|
|
@@ -75,17 +87,28 @@ function mergeReports(files) {
|
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
// Main execution
|
|
78
|
-
|
|
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
|
+
}
|
|
79
99
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
+
}
|
|
84
106
|
|
|
85
|
-
const merged = mergeReports(reportFiles);
|
|
107
|
+
const merged = mergeReports(reportFiles, REPORT_DIR);
|
|
86
108
|
|
|
87
|
-
fs.writeFileSync(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
91
|
-
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.
|
|
@@ -37,8 +38,6 @@ for (let i = 0; i < args.length; i++) {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
const reportDir = customOutputDir || "./pulse-report";
|
|
41
|
-
|
|
42
41
|
let fetch;
|
|
43
42
|
// Ensure fetch is imported and available before it's used in fetchCredentials
|
|
44
43
|
// Using a top-level import is generally cleaner:
|
|
@@ -49,11 +48,8 @@ let fetch;
|
|
|
49
48
|
|
|
50
49
|
let projectName;
|
|
51
50
|
|
|
52
|
-
function getUUID() {
|
|
53
|
-
const reportPath = path.join(
|
|
54
|
-
process.cwd(),
|
|
55
|
-
`${reportDir}/playwright-pulse-report.json`
|
|
56
|
-
);
|
|
51
|
+
function getUUID(reportDir) {
|
|
52
|
+
const reportPath = path.join(reportDir, "playwright-pulse-report.json");
|
|
57
53
|
console.log("Report path:", reportPath);
|
|
58
54
|
|
|
59
55
|
if (!fsExistsSync(reportPath)) {
|
|
@@ -80,18 +76,15 @@ const formatStartTime = (isoString) => {
|
|
|
80
76
|
return date.toLocaleString(); // Default locale
|
|
81
77
|
};
|
|
82
78
|
|
|
83
|
-
const getPulseReportSummary = () => {
|
|
84
|
-
const reportPath = path.join(
|
|
85
|
-
process.cwd(),
|
|
86
|
-
`${reportDir}/playwright-pulse-report.json`
|
|
87
|
-
);
|
|
79
|
+
const getPulseReportSummary = (reportDir) => {
|
|
80
|
+
const reportPath = path.join(reportDir, "playwright-pulse-report.json");
|
|
88
81
|
|
|
89
82
|
if (!fsExistsSync(reportPath)) {
|
|
90
83
|
// CHANGED
|
|
91
84
|
throw new Error("Pulse report file not found.");
|
|
92
85
|
}
|
|
93
86
|
|
|
94
|
-
const content = JSON.parse(fsReadFileSync(reportPath, "utf-8")); //
|
|
87
|
+
const content = JSON.parse(fsReadFileSync(reportPath, "utf-8")); // D
|
|
95
88
|
const run = content.run;
|
|
96
89
|
|
|
97
90
|
const total = run.totalTests || 0;
|
|
@@ -253,7 +246,7 @@ async function runScript(scriptPath, args = []) {
|
|
|
253
246
|
});
|
|
254
247
|
}
|
|
255
248
|
|
|
256
|
-
const sendEmail = async (credentials) => {
|
|
249
|
+
const sendEmail = async (credentials, reportDir) => {
|
|
257
250
|
const archiveArgs = customOutputDir ? ["--outputDir", customOutputDir] : [];
|
|
258
251
|
await runScript(archiveRunScriptPath, archiveArgs);
|
|
259
252
|
try {
|
|
@@ -269,7 +262,7 @@ const sendEmail = async (credentials) => {
|
|
|
269
262
|
},
|
|
270
263
|
});
|
|
271
264
|
|
|
272
|
-
const reportData = getPulseReportSummary();
|
|
265
|
+
const reportData = getPulseReportSummary(reportDir);
|
|
273
266
|
const htmlContent = generateHtmlTable(reportData);
|
|
274
267
|
|
|
275
268
|
const mailOptions = {
|
|
@@ -299,7 +292,7 @@ const sendEmail = async (credentials) => {
|
|
|
299
292
|
}
|
|
300
293
|
};
|
|
301
294
|
|
|
302
|
-
async function fetchCredentials(retries = 10) {
|
|
295
|
+
async function fetchCredentials(reportDir, retries = 10) {
|
|
303
296
|
// Ensure fetch is initialized from the dynamic import before calling this
|
|
304
297
|
if (!fetch) {
|
|
305
298
|
try {
|
|
@@ -314,7 +307,7 @@ async function fetchCredentials(retries = 10) {
|
|
|
314
307
|
}
|
|
315
308
|
|
|
316
309
|
const timeout = 10000;
|
|
317
|
-
const key = getUUID();
|
|
310
|
+
const key = getUUID(reportDir);
|
|
318
311
|
|
|
319
312
|
if (!key) {
|
|
320
313
|
console.error(
|
|
@@ -394,7 +387,19 @@ const main = async () => {
|
|
|
394
387
|
}
|
|
395
388
|
}
|
|
396
389
|
|
|
397
|
-
const
|
|
390
|
+
const reportDir = await getOutputDir(customOutputDir);
|
|
391
|
+
|
|
392
|
+
console.log(chalk.blue(`Preparing to send email report...`));
|
|
393
|
+
console.log(chalk.blue(`Report directory set to: ${reportDir}`));
|
|
394
|
+
if (customOutputDir) {
|
|
395
|
+
console.log(chalk.gray(` (from CLI argument)`));
|
|
396
|
+
} else {
|
|
397
|
+
console.log(
|
|
398
|
+
chalk.gray(` (auto-detected from playwright.config or using default)`)
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const credentials = await fetchCredentials(reportDir);
|
|
398
403
|
if (!credentials) {
|
|
399
404
|
console.warn(
|
|
400
405
|
"Skipping email sending due to missing or failed credential fetch"
|
|
@@ -403,7 +408,7 @@ const main = async () => {
|
|
|
403
408
|
}
|
|
404
409
|
// Removed await delay(10000); // If not strictly needed, remove it.
|
|
405
410
|
try {
|
|
406
|
-
await sendEmail(credentials);
|
|
411
|
+
await sendEmail(credentials, reportDir);
|
|
407
412
|
} catch (error) {
|
|
408
413
|
console.error("Error in main function: ", error);
|
|
409
414
|
}
|