// Run with: node tests/vhost_ui_layout.cjs // Regression guard for purely presentational Vhost grouping and corner settings. "use strict"; const fs = require("node:fs"); const path = require("node:path"); const assert = require("node:assert/strict"); const root = path.resolve(__dirname, ".."); const source = file => fs.readFileSync(path.join(root, file), "utf8"); const core = source("src/admin/web/vhosts/core.js"); const editor = source("src/admin/web/vhosts/editor.js"); const rates = source("src/admin/web/vhosts/rates.js"); const docker = source("src/admin/web/docker.js"); const css = source("src/admin/web/style.css"); const keys = [ "vhGeneralDetailsSection", "vhWebsocketOptionsSection", "vhBalancerAlgorithmSection", "vhBalancerRetrySection", "vhBalancerKeepaliveSection", "vhTrafficMethodsSection", "vhTrafficRateSection", "vhTrafficCountrySection", "vhTrafficCountryRatesSection", "vhSecurityHstsSection", "vhSecurityHeadersSection", "vhUaBlockSection", "vhLocationIpAclSection", "vhSslSettings", ]; for (const locale of ["en_US", "pl_pl"]) { const pack = JSON.parse(source(`langs/${locale}.json`)); for (const key of keys) { assert.ok(pack.translations[key]?.trim(), `${locale}: ${key} must be translated`); const occurrences = source(`langs/${locale}.json`).split("\n").filter(line => line.trimStart().startsWith(`"${key}":`)); assert.equal(occurrences.length, 1, `${locale}: ${key} must occur exactly once`); } } assert.match(core, /const subsection = \(parent, key\) =>/); assert.match(core, /"vh-wide vh-setting-section"/); assert.match(core, /vhSslSettings: "ssl"/); assert.match(core, /subsection\(accessBody, "vhAclProfile"\)/); assert.match(core, /subsection\(accessBody, "vhTrafficMethodsSection"\)/); assert.match(core, /subsection\(accessBody, "vhTrafficCountrySection"\)/); assert.match(core, /subsection\(accessBody, "vhLocationIpAclSection"\)/); for (const key of keys.filter(k => k !== "vhLocationIpAclSection" && k !== "vhSslSettings")) { if (key === "vhTrafficCountryRatesSection" || key === "vhGeneralDetailsSection" || key.startsWith("vhBalancer") || key.startsWith("vhSecurity") || key === "vhUaBlockSection" || key.includes("Traffic") || key === "vhWebsocketOptionsSection") { assert.ok(editor.includes(`subsection(g, "${key}")`), `missing editor subgroup ${key}`); } } assert.match(editor, /g = group\("vhSsl"\);[\s\S]*?g = group\("vhSslSettings"\)/); assert.match(editor, /"allow-certificate-mismatch"/); assert.match(editor, /"tls-policy-custom"/); assert.match(editor, /"ua-block-enabled"/); assert.match(editor, /"ua-block-patterns"/); assert.match(rates, /showHeading = true/); assert.match(editor, /userAgentRateEditor\(uaRateFields, rate\.user_agent_limits \|\| \[\], false\)/); assert.match(docker, /backendIpSettings\.append\(labeled\("dockerBackendIp", target\), certificateBar\)/); assert.match(css, /\.docker-backend-ip-settings\s*\{[^}]*gap:\s*12px;/); for (const selector of [".vh-setting-section", ".cache-memory-sizing", ".appearance-chart-preview", ".draft-dock"]) { const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); const block = css.match(new RegExp(escaped + "\\s*\\{([^}]+)\\}")); assert.ok(block, `missing CSS: ${selector}`); assert.match(block[1], /border-radius:\s*var\(--rp-radius-surface/, `${selector} must use system corner setting`); } assert.match(css, /\.vh-form \.vh-grid>\.vh-check:not\(\.vh-enable-control\)/); assert.match(css, /\.form-actions \.check/); assert.match(css, /\.docker-service-certificate-bar>\.check\s*\{[^}]*margin:\s*0\s*!important/); console.log("Vhost UI grouping, certificate controls, checkbox alignment and corner preset: PASS");