Upgrade Playwright suite to v2.5.1 SQLite deep testing

This commit is contained in:
A R R R Associates
2026-06-24 20:05:36 +05:30
parent 89ba3e85a1
commit ba1075ef19
33 changed files with 16167 additions and 240 deletions
+41 -224
View File
@@ -1,38 +1,23 @@
const http = require("http");
const fs = require("fs");
const path = require("path");
const http = require('http');
const fs = require('fs');
const path = require('path');
const PORT = Number(process.env.RESULT_SERVER_PORT || 3000);
const ROOT = process.env.RESULT_ROOT || "/tests";
const ROOT = process.env.RESULT_ROOT || process.cwd();
const FILES = [
{
title: "Updated Excel Result",
path: "results/Audit_Firm_ERP_Master_UAT_VAPT_Checklist_v2_4_Results.xlsx",
type: "Excel",
},
{
title: "Merged Results JSON",
path: "results/merged-results.json",
type: "JSON",
},
{
title: "API Check Results JSON",
path: "results/api-check-results.json",
type: "JSON",
},
{
title: "Playwright Report Index",
path: "playwright-report/index.html",
type: "HTML",
},
{ title: 'SQLite Database', path: 'results/uat_vapt_results.sqlite', type: 'SQLite' },
{ title: 'SQLite Excel Export', path: 'results/UAT_VAPT_SQLite_Export.xlsx', type: 'Excel' },
{ title: 'Updated Master Excel Result', path: 'results/Audit_Firm_ERP_Master_UAT_VAPT_Checklist_v2_4_Results.xlsx', type: 'Excel' },
{ title: 'Merged Results JSON', path: 'results/merged-results.json', type: 'JSON' },
{ title: 'Playwright Results JSON', path: 'results/playwright-results.json', type: 'JSON' },
{ title: 'API Check Results JSON', path: 'results/api-check-results.json', type: 'JSON' },
{ title: 'Playwright Report Index', path: 'playwright-report/index.html', type: 'HTML' },
];
function safeJoin(relativePath) {
const fullPath = path.resolve(ROOT, relativePath);
if (!fullPath.startsWith(path.resolve(ROOT))) {
throw new Error("Invalid path");
}
if (!fullPath.startsWith(path.resolve(ROOT))) throw new Error('Invalid path');
return fullPath;
}
@@ -40,218 +25,50 @@ function fileInfo(relativePath) {
try {
const full = safeJoin(relativePath);
const stat = fs.statSync(full);
return {
exists: true,
size: stat.size,
mtime: stat.mtime,
};
} catch {
return {
exists: false,
size: 0,
mtime: null,
};
}
return { exists: true, size: stat.size, mtime: stat.mtime };
} catch { return { exists: false, size: 0, mtime: null }; }
}
function formatBytes(bytes) {
if (!bytes) return "-";
const units = ["B", "KB", "MB", "GB"];
let size = bytes;
let unit = 0;
while (size >= 1024 && unit < units.length - 1) {
size = size / 1024;
unit++;
}
return `${size.toFixed(unit === 0 ? 0 : 2)} ${units[unit]}`;
if (!bytes) return '-';
const units = ['B','KB','MB','GB']; let size = bytes; let u = 0;
while (size >= 1024 && u < units.length - 1) { size /= 1024; u++; }
return `${size.toFixed(u === 0 ? 0 : 2)} ${units[u]}`;
}
function contentType(filePath) {
if (filePath.endsWith(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if (filePath.endsWith(".json")) return "application/json";
if (filePath.endsWith(".html")) return "text/html; charset=utf-8";
if (filePath.endsWith(".png")) return "image/png";
if (filePath.endsWith(".webm")) return "video/webm";
if (filePath.endsWith(".zip")) return "application/zip";
return "application/octet-stream";
if (filePath.endsWith('.xlsx')) return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
if (filePath.endsWith('.sqlite') || filePath.endsWith('.db')) return 'application/vnd.sqlite3';
if (filePath.endsWith('.json')) return 'application/json';
if (filePath.endsWith('.html')) return 'text/html; charset=utf-8';
if (filePath.endsWith('.png')) return 'image/png';
if (filePath.endsWith('.webm')) return 'video/webm';
if (filePath.endsWith('.zip')) return 'application/zip';
return 'application/octet-stream';
}
function renderHome() {
const rows = FILES.map((item) => {
const rows = FILES.map(item => {
const info = fileInfo(item.path);
const status = info.exists ? "Available" : "Missing";
const downloadLink = info.exists
? `<a class="btn" href="/download?file=${encodeURIComponent(item.path)}">Download</a>`
: `<span class="btn disabled">Not available</span>`;
return `
<tr>
<td>${item.title}</td>
<td>${item.type}</td>
<td class="${info.exists ? "ok" : "bad"}">${status}</td>
<td>${formatBytes(info.size)}</td>
<td>${info.mtime ? info.mtime.toLocaleString() : "-"}</td>
<td>${downloadLink}</td>
</tr>
`;
}).join("");
return `<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Playwright UAT/VAPT Results</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 32px;
background: #f7f7f7;
color: #222;
}
.card {
background: white;
border-radius: 12px;
padding: 24px;
box-shadow: 0 2px 10px rgba(0,0,0,.08);
max-width: 1100px;
margin: auto;
}
h1 {
margin-top: 0;
font-size: 26px;
}
.sub {
color: #666;
margin-bottom: 20px;
}
table {
width: 100%;
border-collapse: collapse;
background: white;
}
th, td {
padding: 12px;
border-bottom: 1px solid #e5e5e5;
text-align: left;
font-size: 14px;
}
th {
background: #fafafa;
}
.ok {
color: #0a7a2f;
font-weight: bold;
}
.bad {
color: #b00020;
font-weight: bold;
}
.btn {
display: inline-block;
padding: 8px 12px;
background: #1f6feb;
color: white;
text-decoration: none;
border-radius: 6px;
font-size: 13px;
}
.disabled {
background: #999;
pointer-events: none;
}
.note {
margin-top: 18px;
padding: 12px;
background: #fff8dc;
border: 1px solid #f0dc8c;
border-radius: 8px;
font-size: 14px;
}
code {
background: #eee;
padding: 2px 5px;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="card">
<h1>Playwright UAT/VAPT Results</h1>
<div class="sub">Last refreshed: ${new Date().toLocaleString()}</div>
<table>
<thead>
<tr>
<th>File</th>
<th>Type</th>
<th>Status</th>
<th>Size</th>
<th>Modified</th>
<th>Action</th>
</tr>
</thead>
<tbody>${rows}</tbody>
</table>
<div class="note">
Keep this page private. Test reports may contain screenshots, URLs, user emails, and error details.
Recommended Coolify port: <code>3000</code>.
</div>
</div>
</body>
</html>`;
const action = info.exists ? `<a class="btn" href="/download?file=${encodeURIComponent(item.path)}">Download</a>` : '<span class="btn disabled">Missing</span>';
return `<tr><td>${item.title}</td><td>${item.type}</td><td class="${info.exists ? 'ok':'bad'}">${info.exists ? 'Available':'Missing'}</td><td>${formatBytes(info.size)}</td><td>${info.mtime ? info.mtime.toLocaleString() : '-'}</td><td>${action}</td></tr>`;
}).join('');
return `<!doctype html><html><head><meta charset="utf-8"><title>Playwright UAT/VAPT Results</title><style>
body{font-family:Arial,sans-serif;margin:32px;background:#f7f7f7;color:#222}.card{background:#fff;border-radius:12px;padding:24px;box-shadow:0 2px 10px rgba(0,0,0,.08);max-width:1150px;margin:auto}h1{margin-top:0}.sub{color:#666;margin-bottom:20px}table{width:100%;border-collapse:collapse}th,td{padding:12px;border-bottom:1px solid #e5e5e5;text-align:left;font-size:14px}th{background:#fafafa}.ok{color:#0a7a2f;font-weight:bold}.bad{color:#b00020;font-weight:bold}.btn{display:inline-block;padding:8px 12px;background:#1f6feb;color:#fff;text-decoration:none;border-radius:6px;font-size:13px}.disabled{background:#999;pointer-events:none}.note{margin-top:18px;padding:12px;background:#fff8dc;border:1px solid #f0dc8c;border-radius:8px;font-size:14px}code{background:#eee;padding:2px 5px;border-radius:4px}
</style></head><body><div class="card"><h1>Playwright UAT/VAPT Results</h1><div class="sub">Last refreshed: ${new Date().toLocaleString()}</div><table><thead><tr><th>File</th><th>Type</th><th>Status</th><th>Size</th><th>Modified</th><th>Action</th></tr></thead><tbody>${rows}</tbody></table><div class="note">Keep this page private. Reports may contain screenshots, URLs, user emails, and error details. Recommended port: <code>3000</code>.</div></div></body></html>`;
}
function sendFile(res, relativePath) {
let fullPath;
try {
fullPath = safeJoin(relativePath);
} catch {
res.writeHead(400);
res.end("Invalid file path");
return;
}
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
res.writeHead(404);
res.end("File not found");
return;
}
res.writeHead(200, {
"Content-Type": contentType(fullPath),
"Content-Disposition": `attachment; filename="${path.basename(fullPath)}"`,
});
try { fullPath = safeJoin(relativePath); } catch { res.writeHead(400); res.end('Invalid file path'); return; }
if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) { res.writeHead(404); res.end('File not found'); return; }
res.writeHead(200, { 'Content-Type': contentType(fullPath), 'Content-Disposition': `attachment; filename="${path.basename(fullPath)}"` });
fs.createReadStream(fullPath).pipe(res);
}
const server = http.createServer((req, res) => {
http.createServer((req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`);
if (url.pathname === "/") {
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
res.end(renderHome());
return;
}
if (url.pathname === "/download") {
const file = url.searchParams.get("file");
if (!file) {
res.writeHead(400);
res.end("Missing file parameter");
return;
}
sendFile(res, file);
return;
}
res.writeHead(404);
res.end("Not found");
});
server.listen(PORT, "0.0.0.0", () => {
console.log(`Playwright result server running on http://0.0.0.0:${PORT}`);
});
if (url.pathname === '/') { res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'}); res.end(renderHome()); return; }
if (url.pathname === '/download') { const file = url.searchParams.get('file'); if (!file) { res.writeHead(400); res.end('Missing file parameter'); return; } sendFile(res, file); return; }
res.writeHead(404); res.end('Not found');
}).listen(PORT, '0.0.0.0', () => console.log(`Result server running on http://0.0.0.0:${PORT}`));