45 lines
4.9 KiB
JavaScript
45 lines
4.9 KiB
JavaScript
import { readFileSync } from "node:fs";
|
|
|
|
function source(path) {
|
|
return readFileSync(new URL(path, import.meta.url), "utf8");
|
|
}
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
const page = source("../src/features/IdmPage.tsx");
|
|
const changes = source("../src/features/FunctionAssignmentChangesPanel.tsx");
|
|
const relationships = source("../src/features/TypedRelationshipsPanel.tsx");
|
|
const api = source("../src/api/idm.ts");
|
|
const patterns = source("../src/features/interfacePatterns.ts");
|
|
const moduleSource = source("../src/module.ts");
|
|
const translations = source("../src/i18n/generatedTranslations.ts");
|
|
const styles = source("../src/styles/idm.css");
|
|
|
|
assert(page.includes("ActionBlockerHint") && page.includes("DocumentationHelpLink"), "IDM permissions and prerequisites expose actionable help");
|
|
assert(page.includes("assignmentBaseline") && page.includes("draftKey(assignmentDraft) !== draftKey(assignmentBaseline)"), "Existing assignments compare against their loaded draft baseline");
|
|
assert(page.includes("requestDiscard(() => void loadData())") && page.includes("closeAssignmentEditor"), "Reload and dialog close preserve actual dirty drafts");
|
|
assert(page.includes("disabledReason") && changes.includes("disabledReason"), "Unavailable assignment and decision actions explain their state");
|
|
assert(changes.includes("ConfirmDialog") && changes.includes("confirm_function_action"), "Governed function decisions require explicit shared confirmation");
|
|
assert(changes.includes("useUnsavedDraftGuard") && changes.includes("usePlatformLanguage"), "Governed editors protect drafts and format dates with the platform locale");
|
|
assert(patterns.includes('topicId: "idm.reference.fields-and-consequences"'), "IDM fields use manifest-backed consequence help");
|
|
assert(moduleSource.includes('version: "0.1.8"') && moduleSource.includes('label: "i18n:govoplan-idm.view_assignments.2d40d6a5"'), "WebUI metadata matches the module release and localizes its action surface");
|
|
assert(translations.includes('"i18n:govoplan-idm.state_awaiting_authority"'), "Governed states and decisions are in the translation catalogue");
|
|
assert(!page.includes("window.confirm") && !changes.includes("window.confirm"), "IDM does not use browser-native consequential confirmation");
|
|
assert(styles.includes(".idm-page") && !/\.idm-page\s*\{[^}]*max-width/s.test(styles), "The IDM workspace uses the full shared application width");
|
|
assert(page.includes("TypedRelationshipsPanel") && page.includes("<TypedRelationshipsPanel settings={settings} auth={auth} />"), "The IDM workspace exposes typed-group and relationship administration");
|
|
assert(relationships.includes("SearchableSelect") && relationships.includes('aria-label="Subject identity"') && relationships.includes('aria-label="Target typed group"') && relationships.includes('aria-label="Related identity"'), "Identity and group references use searchable selectors");
|
|
assert(relationships.includes('"future" | "active" | "expired" | "revoked"') && relationships.includes("relationshipState(row)"), "Relationship lifecycle states remain visually distinct");
|
|
assert(relationships.includes("revocationReason.trim()") && relationships.includes('helpContextId="idm.relationships.confirm-revoke"'), "Relationship revocation requires a reason and explicit governed confirmation");
|
|
assert(relationships.includes("resolveTypedGroupMemberships") && relationships.includes('id="idm-typed-group-membership-resolution"'), "Effective group membership is inspectable through the shared resolver");
|
|
assert(relationships.includes("sourceResourceId") && relationships.includes("sourceRevision") && relationships.includes("provenance"), "Relationship administration retains source and provenance evidence");
|
|
assert(api.includes("/api/v1/idm/typed-groups") && api.includes("/api/v1/idm/relationships") && api.includes("/memberships?"), "The WebUI API uses the implemented relationship lifecycle endpoints");
|
|
assert(moduleSource.includes('"idm:relationship:read"') && moduleSource.includes('"idm:relationship:write"'), "Relationship-only administrators can enter the IDM product surface");
|
|
assert(translations.includes('"Typed groups and identity relationships": "Typisierte Gruppen und Identitätsbeziehungen"') && translations.includes('"Revoked": "Widerrufen"'), "The relationship administration vocabulary has German reference translations");
|
|
assert(!relationships.includes("window.confirm"), "Relationship administration does not use browser-native consequential confirmation");
|
|
assert(relationships.includes('<ContentGrid columns={1}>') && (relationships.match(/bodyLayout="table"/g) ?? []).length === 2, "Typed groups and effective relationships use spaced full-width table cards");
|
|
assert(!relationships.includes('className="idm-muted idm-card-note"') && changes.includes('bodyLayout="table"') && page.includes('bodyLayout="table"'), "All IDM collection tables share the table-card treatment without a repeated tagline");
|
|
|
|
console.log("IDM surfaces satisfy the recorded interface pattern-language contract.");
|