import test from "node:test"; import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; test("changed file list has an independently scrollable bounded layout", async () => { const css = await readFile( new URL("../src/renderer/styles.css", import.meta.url), "utf8", ); assert.match( css, /\.main-canvas\.repository-canvas\s*\{[^}]*overflow:\s*hidden/, ); assert.match( css, /\.file-panel\s*\{[^}]*min-height:\s*0[^}]*overflow:\s*hidden/, ); assert.match( css, /\.file-list\s*\{[^}]*flex:\s*1 1 auto[^}]*overflow-y:\s*auto/, ); }); test("commit workflow explains every disabled prerequisite", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(renderer, /Commit message required/); assert.match(renderer, /Enter a commit message to enable commit and push/); assert.match(renderer, /ForgeFlow stages the selected files automatically/); assert.match(renderer, /data-action="commit-push"/); assert.match(renderer, /Commit staged hunks/); }); test("ITWorx branding is integrated into titlebar and setup", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(renderer, /itworx-mark\.png/); assert.match(renderer, /itworx-wordmark-(?:light|dark)\.png/); }); test("all modal content stays inside the viewport with a persistent action footer", async () => { const css = await readFile( new URL("../src/renderer/styles.css", import.meta.url), "utf8", ); assert.match( css, /\.modal\s*\{[^}]*max-height:\s*calc\(100dvh[^}]*display:\s*flex[^}]*flex-direction:\s*column/, ); assert.match( css, /\.modal-body\s*\{[^}]*min-height:\s*0[^}]*overflow-y:\s*auto/, ); assert.match(css, /\.modal-footer\s*\{[^}]*flex:\s*0 0 auto/); }); test("settings provides one-click normalization for legacy Gitea origins", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(renderer, /data-action="normalize-origins"/); assert.match(renderer, /Normalize all origins/); }); test("Git mutations are serialized per repository and expose repair actions", async () => { const ipc = await readFile( new URL("../src/main/ipc.cjs", import.meta.url), "utf8", ); const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(ipc, /repositoryMutations = new Map/); assert.match(ipc, /withRepositoryMutation/); assert.match(ipc, /GIT_LOCKS_RECENT/); assert.match(ipc, /setTimeout\(resolve, 2_500\)/); assert.match(renderer, /data-action="repair-git-locks"/); assert.match(renderer, /Repository troubleshooting/); assert.match(renderer, /data-action="repair-origin"/); assert.match(renderer, /Open guided repository repair/); }); test("SSH secrets are captured before the loading render clears password inputs", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); const passwordCapture = renderer.search( /const password = document\.querySelector\(["']#server-password["']\)/, ); const loading = renderer.search( /setLoading\(true, ["']Saving encrypted SSH configuration/, ); assert.ok(passwordCapture >= 0 && loading > passwordCapture); }); test("SSH deployments are polled in the background and Portfolio casing is preserved", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(renderer, /function startOperationPolling\(\)/); assert.match(renderer, /startOperationPolling\(\);/); assert.match(renderer, /Visible container name/); assert.match(renderer, /Compose service \(internal\)/); }); test("deployment profiles expose built-in/uploaded DockerMan icons and automatic metadata repair", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); assert.match(renderer, /Built-in high-contrast ITWorx mark/); assert.match(renderer, /profile-icon-mode/); assert.match(renderer, /Repair DockerMan integration/); assert.match(renderer, /reconcile-deployment/); }); test("repository troubleshooting offers personalized synchronization repair actions", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); const ipc = await readFile( new URL("../src/main/ipc.cjs", import.meta.url), "utf8", ); assert.match(renderer, /repair-repository-sync/); assert.match(renderer, /safety branch/); assert.match(ipc, /repository:repair-sync/); }); test("advanced Git, desktop, backup, policy and audit workflows are exposed in the renderer", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); const preload = await readFile( new URL("../preload.cjs", import.meta.url), "utf8", ); for (const phrase of [ "Stage hunks", "Conflict guide", "Create pull request", "Open pull requests", "load-pull-requests", "Check branch protection", "Encrypted configuration backup", "Deployment policy", "Operational audit log", ]) assert.match(renderer, new RegExp(phrase, "i")); for (const method of [ "stageHunks", "resolveConflict", "createPullRequest", "branchProtection", "openEditor", "openTerminal", "exportConfigurationBackup", "listAuditEvents", ]) assert.match(preload, new RegExp(`${method}:`)); }); test("one-click troubleshooting excludes destructive or publishing Git actions", async () => { const renderer = await readFile( new URL("../src/renderer/app.js", import.meta.url), "utf8", ); const ipc = await readFile( new URL("../src/main/ipc.cjs", import.meta.url), "utf8", ); assert.match(ipc, /action: 'abort-operation', safe: false/); assert.match(ipc, /action: 'push', safe: false/); assert.match(ipc, /const stale = lock\.ageMs >= 10_000/); assert.match(ipc, /\['fast-forward', 'fetch'\]\.includes\(issue\.action\)/); assert.doesNotMatch( ipc, /\['fast-forward', 'push', 'fetch'\]\.includes\(issue\.action\)/, ); assert.match( renderer, /trouble\?\.issues\?\.some\(\(item\) => item\.repairable && item\.safe\)/, ); }); test("premium repository workspace reserves separate rows for actions and release status", async () => { const styles = await readFile( new URL("../src/renderer/styles.css", import.meta.url), "utf8", ); assert.match( styles, /\.repo-workspace\s*\{[^}]*grid-template-rows:\s*auto auto auto 39px minmax\(0, 1fr\)/s, ); assert.match(styles, /prefers-reduced-motion/); assert.match(styles, /ForgeFlow 0\.8 premium visual system/); });