refactor: split renderer ipc and unraid domains
This commit is contained in:
@@ -2,15 +2,16 @@ import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
async function rendererSource() {
|
||||
return (await Promise.all(["app.js", "views.js", "dialogs.js", "operations.js", "actions/shell.js", "actions/inventory.js", "actions/deployment-profile.js", "actions/deployment-operation.js", "actions/setup-and-settings.js", "actions/recovery.js", "actions/command.js", "events.js"].map((file) => readFile(new URL(`../src/renderer/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
}
|
||||
|
||||
test("every preload invoke channel has a registered IPC handler", async () => {
|
||||
const preload = await readFile(
|
||||
new URL("../preload.cjs", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const ipc = await readFile(
|
||||
new URL("../src/main/ipc.cjs", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const ipc = (await Promise.all(["ipc.cjs", "ipc/repository-handlers.cjs", "ipc/deployment-handlers.cjs", "ipc/operations-handlers.cjs"].map((file) => readFile(new URL(`../src/main/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
const invokes = [...preload.matchAll(/invoke\(\s*['"]([^'"]+)['"]/g)].map(
|
||||
(match) => match[1],
|
||||
);
|
||||
@@ -27,10 +28,7 @@ test("every preload invoke channel has a registered IPC handler", async () => {
|
||||
});
|
||||
|
||||
test("every renderer bridge call is exposed by the preload contract", async () => {
|
||||
const renderer = await readFile(
|
||||
new URL("../src/renderer/app.js", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
const preload = await readFile(
|
||||
new URL("../preload.cjs", import.meta.url),
|
||||
"utf8",
|
||||
|
||||
@@ -2,6 +2,14 @@ import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
const rendererFiles = ["app.js", "views.js", "dialogs.js", "operations.js", "actions/shell.js", "actions/inventory.js", "actions/deployment-profile.js", "actions/deployment-operation.js", "actions/setup-and-settings.js", "actions/recovery.js", "actions/command.js", "events.js"];
|
||||
async function rendererSource() {
|
||||
return (await Promise.all(rendererFiles.map((file) => readFile(new URL(`../src/renderer/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
}
|
||||
async function ipcSource() {
|
||||
return (await Promise.all(["ipc.cjs", "ipc/repository-handlers.cjs", "ipc/deployment-handlers.cjs", "ipc/operations-handlers.cjs"].map((file) => readFile(new URL(`../src/main/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
}
|
||||
|
||||
test("changed file list has an independently scrollable bounded layout", async () => {
|
||||
const css = await readFile(
|
||||
new URL("../src/renderer/styles.css", import.meta.url),
|
||||
@@ -22,10 +30,7 @@ test("changed file list has an independently scrollable bounded layout", async (
|
||||
});
|
||||
|
||||
test("commit workflow explains every disabled prerequisite", async () => {
|
||||
const renderer = await readFile(
|
||||
new URL("../src/renderer/app.js", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
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/);
|
||||
@@ -34,10 +39,7 @@ test("commit workflow explains every disabled prerequisite", async () => {
|
||||
});
|
||||
|
||||
test("ITWorx branding is integrated into titlebar and setup", async () => {
|
||||
const renderer = await readFile(
|
||||
new URL("../src/renderer/app.js", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
assert.match(renderer, /itworx-mark\.png/);
|
||||
assert.match(renderer, /itworx-wordmark-(?:light|dark)\.png/);
|
||||
});
|
||||
@@ -59,23 +61,14 @@ test("all modal content stays inside the viewport with a persistent action foote
|
||||
});
|
||||
|
||||
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",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
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",
|
||||
);
|
||||
const ipc = await ipcSource();
|
||||
const renderer = await rendererSource();
|
||||
assert.match(ipc, /repositoryMutations = new Map/);
|
||||
assert.match(ipc, /withRepositoryMutation/);
|
||||
assert.match(ipc, /GIT_LOCKS_RECENT/);
|
||||
@@ -87,10 +80,7 @@ test("Git mutations are serialized per repository and expose repair actions", as
|
||||
});
|
||||
|
||||
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 renderer = await rendererSource();
|
||||
const passwordCapture = renderer.search(
|
||||
/const password = document\.querySelector\(["']#server-password["']\)/,
|
||||
);
|
||||
@@ -101,10 +91,7 @@ test("SSH secrets are captured before the loading render clears password inputs"
|
||||
});
|
||||
|
||||
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",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
assert.match(renderer, /function startOperationPolling\(\)/);
|
||||
assert.match(renderer, /startOperationPolling\(\);/);
|
||||
assert.match(renderer, /Visible container name/);
|
||||
@@ -112,10 +99,7 @@ test("SSH deployments are polled in the background and Portfolio casing is prese
|
||||
});
|
||||
|
||||
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",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
assert.match(renderer, /Built-in high-contrast ITWorx mark/);
|
||||
assert.match(renderer, /profile-icon-mode/);
|
||||
assert.match(renderer, /Repair DockerMan integration/);
|
||||
@@ -123,24 +107,15 @@ test("deployment profiles expose built-in/uploaded DockerMan icons and automatic
|
||||
});
|
||||
|
||||
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",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
const ipc = await ipcSource();
|
||||
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 renderer = await rendererSource();
|
||||
const preload = await readFile(
|
||||
new URL("../preload.cjs", import.meta.url),
|
||||
"utf8",
|
||||
@@ -171,10 +146,7 @@ test("advanced Git, desktop, backup, policy and audit workflows are exposed in t
|
||||
});
|
||||
|
||||
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 renderer = await rendererSource();
|
||||
const ipc = await readFile(
|
||||
new URL("../src/main/ipc.cjs", import.meta.url),
|
||||
"utf8",
|
||||
@@ -210,10 +182,7 @@ test("premium repository workspace reserves separate rows for actions and releas
|
||||
});
|
||||
|
||||
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 renderer = await rendererSource();
|
||||
const styles = await readFile(
|
||||
new URL("../src/renderer/styles.css", import.meta.url),
|
||||
"utf8",
|
||||
@@ -228,10 +197,7 @@ test("interactive project illustrations are semantic, responsive and motion-safe
|
||||
});
|
||||
|
||||
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 renderer = await rendererSource();
|
||||
const styles = await readFile(
|
||||
new URL("../src/renderer/styles.css", import.meta.url),
|
||||
"utf8",
|
||||
@@ -245,10 +211,7 @@ test("the diff canvas uses a contextual and motion-safe code illustration", asyn
|
||||
});
|
||||
|
||||
test("Git Validator exposes scored best-practice checks and bounded repairs", async () => {
|
||||
const renderer = await readFile(
|
||||
new URL("../src/renderer/app.js", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const renderer = await rendererSource();
|
||||
const styles = await readFile(
|
||||
new URL("../src/renderer/styles.css", import.meta.url),
|
||||
"utf8",
|
||||
@@ -267,7 +230,7 @@ test("Git Validator exposes scored best-practice checks and bounded repairs", as
|
||||
});
|
||||
|
||||
test("renderer guards accessible names, labels and uncertain inventory evidence", async () => {
|
||||
const renderer = await readFile(new URL("../src/renderer/app.js", import.meta.url), "utf8");
|
||||
const renderer = await rendererSource();
|
||||
const styles = await readFile(new URL("../src/renderer/styles.css", import.meta.url), "utf8");
|
||||
assert.match(renderer, /button\.icon-button:not\(\[aria-label\]\)/);
|
||||
assert.match(renderer, /\.field > label:not\(\[for\]\)/);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { createRequire } from "node:module";
|
||||
import { readFile } from "node:fs/promises";
|
||||
const require = createRequire(import.meta.url);
|
||||
const {
|
||||
UnraidDeploymentService,
|
||||
@@ -18,6 +19,11 @@ const {
|
||||
const { fingerprintKey, shellQuote } = require("../src/main/ssh-service.cjs");
|
||||
const { buildWorkloadInventory, deploymentRootCandidate } = require("../src/main/server-inventory.cjs");
|
||||
|
||||
async function unraidSource() {
|
||||
const files = ["unraid-deployment-service.cjs", "unraid-access-methods.cjs", "unraid-preflight-methods.cjs", "unraid-runtime-methods.cjs", "unraid-deployment-methods.cjs", "unraid-inventory-methods.cjs"];
|
||||
return (await Promise.all(files.map((file) => readFile(new URL(`../src/main/${file}`, import.meta.url), "utf8")))).join("\n");
|
||||
}
|
||||
|
||||
test("Unraid remote paths cannot escape appdata project folder", () => {
|
||||
assert.equal(safeRemoteFolder("lumaops"), "lumaops");
|
||||
assert.throws(() => safeRemoteFolder("../lumaops"));
|
||||
@@ -656,15 +662,10 @@ test("SSH deployment dispatch returns a running operation while the remote build
|
||||
});
|
||||
|
||||
test("Unraid preflight verifies repository access before a deployment can start", async () => {
|
||||
const source = await import("node:fs/promises").then(({ readFile }) =>
|
||||
readFile(
|
||||
new URL("../src/main/unraid-deployment-service.cjs", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
const source = await unraidSource();
|
||||
assert.match(source, /server-git-access/);
|
||||
assert.match(source, /git ls-remote --exit-code/);
|
||||
assert.match(source, /Unraid → Gitea read access/);
|
||||
assert.match(source, /Unraid .* Gitea read access/);
|
||||
});
|
||||
|
||||
test("DockerMan metadata uses dockerman labels, a template WebUI and lowercase-safe service/image names", () => {
|
||||
@@ -855,12 +856,7 @@ test("stuck SSH deployment is reconciled to success when exact SHA and container
|
||||
});
|
||||
|
||||
test("DockerMan metadata repair refreshes known Unraid icon caches after container recreation", async () => {
|
||||
const source = await import("node:fs/promises").then(({ readFile }) =>
|
||||
readFile(
|
||||
new URL("../src/main/unraid-deployment-service.cjs", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
const source = await unraidSource();
|
||||
assert.match(source, /\/var\/lib\/docker\/unraid\/images/);
|
||||
assert.match(source, /dynamix\.docker\.manager\/images/);
|
||||
assert.match(source, /-icon\.png/);
|
||||
|
||||
Reference in New Issue
Block a user