Files
ForgeFlow/tests/renderer-workflow.test.mjs
T

246 lines
8.2 KiB
JavaScript

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 <span class="required-mark">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:\s*["']abort-operation["'],\s*safe:\s*false/);
assert.match(ipc, /action:\s*["']push["'],\s*safe:\s*false/);
assert.match(ipc, /const stale = lock\.ageMs >= 10_000/);
assert.match(
ipc,
/\[\s*["']fast-forward["'],\s*["']fetch["']\s*\]\.includes\(issue\.action\)/,
);
assert.doesNotMatch(
ipc,
/\[\s*["']fast-forward["'],\s*["']push["'],\s*["']fetch["']\s*\]\.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/);
});
test("interactive project illustrations are semantic, responsive and motion-safe", async () => {
const renderer = await readFile(
new URL("../src/renderer/app.js", import.meta.url),
"utf8",
);
const styles = await readFile(
new URL("../src/renderer/styles.css", import.meta.url),
"utf8",
);
assert.match(renderer, /function projectIllustration/);
assert.match(renderer, /data-project-illustration/);
assert.match(renderer, /document\.addEventListener\("pointermove"/);
assert.match(styles, /\.project-illustration/);
assert.match(styles, /@keyframes signal-travel/);
assert.match(styles, /prefers-reduced-motion/);
assert.match(styles, /transform: none !important/);
});
test("the diff canvas uses a contextual and motion-safe code illustration", async () => {
const renderer = await readFile(
new URL("../src/renderer/app.js", import.meta.url),
"utf8",
);
const styles = await readFile(
new URL("../src/renderer/styles.css", import.meta.url),
"utf8",
);
assert.match(renderer, /function diffAtmosphere/);
assert.match(renderer, /data-diff-atmosphere/);
assert.match(renderer, /--diff-tilt-x/);
assert.match(styles, /\.diff-atmosphere/);
assert.match(styles, /@keyframes code-packet-travel/);
assert.match(styles, /prefers-reduced-motion/);
});