Verified with the coordinated workspace changes by devkit full run 2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed). This shared UI pass does not mark the individual module reviews complete.
125 lines
6.5 KiB
TypeScript
125 lines
6.5 KiB
TypeScript
function assert(condition: unknown, message = "assertion failed"): void {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
import PageActionBar from "../src/components/PageActionBar";
|
|
import PageLayout from "../src/components/PageLayout";
|
|
import { PlatformLanguageProvider } from "../src/i18n/LanguageContext";
|
|
|
|
const standaloneMarkup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageLayout
|
|
archetype="collection"
|
|
title="Shared page"
|
|
description="One page frame"
|
|
actions={<PageActionBar variant="collection" refreshable reloadAction={{ onReload: () => undefined }} />}
|
|
error="Could not load"
|
|
success="Saved"
|
|
interfaceId="test.page"
|
|
helpContextId="test.page.help"
|
|
helpModuleId="test-module"
|
|
>
|
|
<section>Page content</section>
|
|
</PageLayout>
|
|
</PlatformLanguageProvider>
|
|
);
|
|
|
|
assert(standaloneMarkup.includes('class="page-scroll-viewport"'), "standalone pages own their scroll viewport");
|
|
assert(standaloneMarkup.includes("page-layout-standalone content-pad workspace-data-page"), "standalone pages use the shared padded workspace frame");
|
|
assert(standaloneMarkup.includes("page-layout-header"), "the central page header is rendered");
|
|
assert(standaloneMarkup.includes("page-layout-actions"), "route actions use the central responsive action region");
|
|
assert(standaloneMarkup.includes('data-interface-id="test.page"'), "page identity reaches the shared frame");
|
|
assert(standaloneMarkup.includes('data-help-context-id="test.page.help"'), "context help reaches the shared frame");
|
|
assert(standaloneMarkup.includes('data-help-module-id="test-module"'), "documentation ownership reaches the shared frame");
|
|
assert(standaloneMarkup.includes('data-page-archetype="collection"'), "page intent is independent from layout geometry");
|
|
assert(standaloneMarkup.includes("Could not load"), "page errors use the shared alert region");
|
|
assert(standaloneMarkup.includes("Saved"), "page success notices use the shared alert region");
|
|
assert(standaloneMarkup.includes("Page content"), "page content is preserved");
|
|
|
|
const embeddedMarkup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageLayout archetype="detail" title="Embedded page" mode="embedded" documentationType="admin">
|
|
Embedded content
|
|
</PageLayout>
|
|
</PlatformLanguageProvider>
|
|
);
|
|
|
|
assert(!embeddedMarkup.includes("page-scroll-viewport"), "embedded pages defer scrolling to their owner");
|
|
assert(!embeddedMarkup.includes("content-pad"), "embedded pages do not add a second content inset");
|
|
assert(embeddedMarkup.includes("page-layout-embedded"), "embedded mode remains explicit");
|
|
assert(embeddedMarkup.includes('data-help-documentation-type="admin"'), "embedded administration keeps its documentation type");
|
|
|
|
const workspaceMarkup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageLayout
|
|
archetype="workspace"
|
|
title="Workspace page"
|
|
description={<p className="version-line">Version 3</p>}
|
|
mode="workspace"
|
|
notices={<div role="status">Additional notice</div>}
|
|
>
|
|
Workspace content
|
|
</PageLayout>
|
|
</PlatformLanguageProvider>
|
|
);
|
|
|
|
assert(!workspaceMarkup.includes("page-scroll-viewport"), "workspace pages defer scrolling to the workspace content pane");
|
|
assert(workspaceMarkup.includes("page-layout-workspace content-pad workspace-data-page"), "workspace pages keep the standard content inset");
|
|
assert(workspaceMarkup.includes('class="version-line"'), "rich page descriptions keep their own semantic element");
|
|
assert(!workspaceMarkup.includes("<p><p"), "rich page descriptions are not nested in an invalid paragraph");
|
|
assert(workspaceMarkup.includes("page-layout-notices"), "additional page notices use the central notice region");
|
|
|
|
const headerLoadingMarkup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageLayout archetype="detail" title="Refreshing" mode="workspace" headerLoading>
|
|
Stable content
|
|
</PageLayout>
|
|
</PlatformLanguageProvider>
|
|
);
|
|
|
|
assert(headerLoadingMarkup.includes("loading-indicator"), "page headings can expose partial refresh progress");
|
|
assert(!headerLoadingMarkup.includes('aria-busy="true"'), "partial refresh does not block the stable page body");
|
|
|
|
const delegatedHeaderMarkup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageLayout archetype="workspace" title="Administration" mode="workspace" showHeader={false}>
|
|
<section><h1>Contributed administration panel</h1></section>
|
|
</PageLayout>
|
|
</PlatformLanguageProvider>
|
|
);
|
|
|
|
assert(!delegatedHeaderMarkup.includes("page-layout-header"), "composite workspaces can delegate their visible heading to contributed content");
|
|
assert(delegatedHeaderMarkup.includes("page-layout-workspace content-pad workspace-data-page"), "headerless composite pages retain the central content frame");
|
|
|
|
for (const state of ["clean", "dirty", "invalid", "save-failed", "conflict", "saving"] as const) {
|
|
for (const behavior of ["reset", "exit"] as const) {
|
|
const markup = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageActionBar variant="editor" state={state}
|
|
discardAction={{ label: "Cancel", behavior, "aria-label": "test-cancel" }}
|
|
saveAction={{ label: "Save", "aria-label": "test-save" }} />
|
|
</PlatformLanguageProvider>
|
|
);
|
|
const cancelButton = markup.match(/<button\b[^>]*aria-label="test-cancel"[^>]*>/)?.[0];
|
|
const saveButton = markup.match(/<button\b[^>]*aria-label="test-save"[^>]*>/)?.[0];
|
|
assert(cancelButton && saveButton, "editor actions remain visible in every draft state");
|
|
const disabled = (button: string | undefined) => /\bdisabled=""/.test(button ?? "");
|
|
assert(disabled(cancelButton) === (state === "saving" || (state === "clean" && behavior === "reset")),
|
|
`${behavior} action has the correct disabled state when ${state}`);
|
|
assert(disabled(saveButton) === ["clean", "invalid", "saving"].includes(state),
|
|
`cancel availability must not enable invalid/no-op/concurrent saving when ${state}`);
|
|
assert(!markup.includes('behavior="'), "the action contract must not leak non-HTML attributes");
|
|
}
|
|
}
|
|
|
|
const permissionBlockedExit = renderToStaticMarkup(
|
|
<PlatformLanguageProvider>
|
|
<PageActionBar variant="editor" state="clean"
|
|
discardAction={{ label: "Cancel", behavior: "exit", disabled: true, disabledReason: "Explicitly blocked", "aria-label": "test-blocked-cancel" }}
|
|
saveAction={{ label: "Save" }} />
|
|
</PlatformLanguageProvider>
|
|
);
|
|
assert(/\bdisabled=""/.test(permissionBlockedExit.match(/<button\b[^>]*aria-label="test-blocked-cancel"[^>]*>/)?.[0] ?? ""),
|
|
"exit semantics preserve an explicit owning-page blocker");
|