#!/usr/bin/env node import assert from "node:assert/strict"; import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { runCli } from "../tools/hwlab-cli/lib/cli.mjs"; const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); async function captureCli(args) { let stdout = ""; let stderr = ""; const exitCode = await runCli(args, { cwd: repoRoot, stdout: { write(chunk) { stdout += chunk; } }, stderr: { write(chunk) { stderr += chunk; } } }); return { exitCode, stdout, stderr }; } const dryRun = await captureCli(["test", "e2e", "--env", "dev", "--mvp"]); assert.equal(dryRun.exitCode, 0, dryRun.stderr); const dryRunJson = JSON.parse(dryRun.stdout); assert.equal(dryRunJson.mode, "dry-run"); assert.equal(dryRunJson.environment, "dev"); assert.match(String(dryRunJson.endpoint ?? ""), /^http:\/\//u); assert.match(dryRunJson.statement, /no DEV\/PROD changes/); const explicitDryRun = await captureCli(["test", "e2e", "--env", "dev", "--mvp", "--dry-run"]); assert.equal(explicitDryRun.exitCode, 0, explicitDryRun.stderr); assert.equal(JSON.parse(explicitDryRun.stdout).mode, "dry-run"); const liveBlocked = await captureCli([ "test", "e2e", "--env", "dev", "--mvp", "--live", "--confirm-dev", "--confirmed-non-production" ]); assert.equal(liveBlocked.exitCode, 2); const liveBlockedJson = JSON.parse(liveBlocked.stderr); assert.equal(liveBlockedJson.code, "BLOCKED"); assert.ok(Array.isArray(liveBlockedJson.blockers)); const activeWebSource = [ "web/hwlab-cloud-web/index.html", "web/hwlab-cloud-web/app.mjs", "web/hwlab-cloud-web/live-status.mjs", "web/hwlab-cloud-web/help.md" ].map((file) => fs.readFileSync(path.resolve(repoRoot, file), "utf8")).join("\n"); const distContract = fs.readFileSync(path.resolve(repoRoot, "web/hwlab-cloud-web/scripts/dist-contract.mjs"), "utf8"); assert.match(activeWebSource, /Device Pod/u); assert.match(activeWebSource, /\/v1\/device-pods/u); for (const legacyTerm of ["Gateway-SIMU", "BOX-SIMU", "Patch Panel", "hwlab-patch-panel", "gateway-simu", "box-simu", "/v1/m3"]) { assert.doesNotMatch(activeWebSource, new RegExp(escapeRegExp(legacyTerm), "u"), `legacy frontend term returned: ${legacyTerm}`); } assert.doesNotMatch(distContract, /gate-summary\.mjs/u, "Cloud Web dist must not ship the legacy gate-summary topology asset"); assert.equal(fs.existsSync(path.resolve(repoRoot, "web/hwlab-cloud-web/gate-summary.mjs")), false, "legacy web gate-summary asset must be removed"); console.log("L6 CLI/Web smoke passed: CLI dry-run remains non-mutating and Cloud Web uses the Device Pod contract without the legacy gate-summary topology asset"); function escapeRegExp(value) { return String(value).replace(/[.*+?^${}()|[\]\\]/gu, "\\$&"); }