28 lines
1.7 KiB
JavaScript
28 lines
1.7 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const webuiRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
const read = (path) => readFileSync(resolve(webuiRoot, path), "utf8");
|
|
|
|
const settings = read("src/features/settings/SettingsPage.tsx");
|
|
const retention = read("src/features/privacy/RetentionPolicyManagement.tsx");
|
|
const credentials = read("src/components/CredentialEnvelopeManager.tsx");
|
|
|
|
assert.match(settings, /contextId: "core\.settings"/, "settings expose stable contextual documentation");
|
|
assert.match(settings, /There are no unsaved profile changes\./, "profile save explains its clean state");
|
|
assert.match(settings, /There are no unsaved interface changes\./, "preference save explains its clean state");
|
|
|
|
assert.match(retention, /<ActionBlockerHint/, "retention renders the shared actionable blocker");
|
|
assert.match(retention, /contextId: "privacy\.retention"/, "retention exposes stable admin documentation");
|
|
assert.match(retention, /locked by platform configuration/, "retention explains platform locks");
|
|
assert.doesNotMatch(retention, /<textarea/, "retention does not use raw text or JSON as its primary editor");
|
|
|
|
assert.match(credentials, /<ActionBlockerHint/, "credentials render the shared actionable blocker");
|
|
assert.match(credentials, /contextId: "access\.credentials"/, "credentials expose stable admin documentation");
|
|
assert.match(credentials, /disabledReason: writeDisabledReason/, "credential row actions retain actionable disabled reasons");
|
|
assert.doesNotMatch(credentials, /<textarea/, "credentials use typed controls rather than a primary JSON editor");
|
|
|
|
console.log("Core interface-pattern contracts passed.");
|