diff --git a/Dockerfile b/Dockerfile index b03ea4c..45d761a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,4 +9,4 @@ COPY . . RUN mkdir -p results test-results playwright-report -CMD ["bash", "-lc", "node run-api-checks.js && npx playwright test --reporter=list --workers=1; echo 'Tests completed. Container kept alive.'; tail -f /dev/null"] \ No newline at end of file +CMD ["bash", "-lc", "node run-api-checks.js && npx playwright test --reporter=list --workers=1; npm run report:json; npm run update:excel; echo 'Tests completed. Starting result server.'; node scripts/result-server.js"] \ No newline at end of file diff --git a/scripts/result-server.js b/scripts/result-server.js new file mode 100644 index 0000000..a76e22c --- /dev/null +++ b/scripts/result-server.js @@ -0,0 +1,257 @@ +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 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", + }, +]; + +function safeJoin(relativePath) { + const fullPath = path.resolve(ROOT, relativePath); + if (!fullPath.startsWith(path.resolve(ROOT))) { + throw new Error("Invalid path"); + } + return fullPath; +} + +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, + }; + } +} + +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]}`; +} + +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"; +} + +function renderHome() { + const rows = FILES.map((item) => { + const info = fileInfo(item.path); + const status = info.exists ? "Available" : "Missing"; + const downloadLink = info.exists + ? `Download` + : `Not available`; + + return ` + + ${item.title} + ${item.type} + ${status} + ${formatBytes(info.size)} + ${info.mtime ? info.mtime.toLocaleString() : "-"} + ${downloadLink} + + `; + }).join(""); + + return ` + + + + Playwright UAT/VAPT Results + + + +
+

Playwright UAT/VAPT Results

+
Last refreshed: ${new Date().toLocaleString()}
+ + + + + + + + + + + + + ${rows} +
FileTypeStatusSizeModifiedAction
+ +
+ Keep this page private. Test reports may contain screenshots, URLs, user emails, and error details. + Recommended Coolify port: 3000. +
+
+ +`; +} + +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)}"`, + }); + + fs.createReadStream(fullPath).pipe(res); +} + +const server = 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}`); +});