feat: build housekeeping command deck shell
This commit is contained in:
1 parent
cfeb0f19b8
commit
addc9c7b1a
9 files changed
+528
No files matched your search
@@ -0,0 +1,174 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { HousekeepingNavigationDomain } from "../navigation";
|
||||
import { HousekeepingShell } from "./housekeeping-shell";
|
||||
|
||||
const labels = {
|
||||
skipToContent: "Skip to housekeeping content",
|
||||
primaryNavigation: "Primary housekeeping navigation",
|
||||
contextualNavigation: "Operations navigation",
|
||||
command: "Commands are unavailable in preview",
|
||||
preview: "Preview",
|
||||
backToSite: "Back to site",
|
||||
};
|
||||
|
||||
const domains: readonly HousekeepingNavigationDomain[] = [
|
||||
{
|
||||
id: "operations",
|
||||
href: "/admin-next/operations",
|
||||
iconId: "inbox",
|
||||
label: "Operations",
|
||||
description: "Manage operations",
|
||||
items: [
|
||||
{ id: "queue", href: "/admin-next/operations/queue", label: "Queue" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "people",
|
||||
href: "/admin-next/people",
|
||||
iconId: "users",
|
||||
label: "People",
|
||||
description: "Manage people",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: "content",
|
||||
href: "/admin-next/content",
|
||||
iconId: "file-text",
|
||||
label: "Content",
|
||||
description: "Manage content",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: "economy",
|
||||
href: "/admin-next/economy",
|
||||
iconId: "gem",
|
||||
label: "Economy",
|
||||
description: "Manage economy",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: "hotel",
|
||||
href: "/admin-next/hotel",
|
||||
iconId: "hotel",
|
||||
label: "Hotel",
|
||||
description: "Manage hotel",
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
id: "system",
|
||||
href: "/admin-next/system",
|
||||
iconId: "settings",
|
||||
label: "System",
|
||||
description: "Manage system",
|
||||
items: [],
|
||||
},
|
||||
];
|
||||
|
||||
function renderShell(
|
||||
activeDomainId: HousekeepingNavigationDomain["id"] = "operations",
|
||||
): string {
|
||||
return renderToStaticMarkup(
|
||||
<HousekeepingShell
|
||||
actor={{ id: 7, username: "Nora", rank: 6 }}
|
||||
activeDomainId={activeDomainId}
|
||||
domains={domains}
|
||||
labels={labels}
|
||||
>
|
||||
<p>Deck body</p>
|
||||
</HousekeepingShell>,
|
||||
);
|
||||
}
|
||||
|
||||
describe("HousekeepingShell", () => {
|
||||
it("renders the accessible command deck landmarks and supplied shell content", () => {
|
||||
const html = renderShell();
|
||||
|
||||
expect(html).toContain('href="#housekeeping-content"');
|
||||
expect(html).toContain(">Skip to housekeeping content<");
|
||||
expect(html).toContain("<aside");
|
||||
expect(html).toContain("<header");
|
||||
expect(html).toContain('<nav aria-label="Primary housekeeping navigation"');
|
||||
expect(html).toContain('<nav aria-label="Operations navigation"');
|
||||
expect(html).toContain('<main id="housekeeping-content"');
|
||||
expect(html).toContain(">Deck body</p>");
|
||||
expect(html).toMatch(
|
||||
/<a(?=[^>]*href="\/admin-next\/operations")(?=[^>]*aria-current="page")/,
|
||||
);
|
||||
expect(html).toContain('href="/admin-next/operations/queue"');
|
||||
expect(html).toContain(">Queue<");
|
||||
expect(html).toContain(">Nora<");
|
||||
expect(html).toContain(">6<");
|
||||
expect(html).toContain(">Preview<");
|
||||
expect(html).toContain('href="/"');
|
||||
expect(html).toContain(">Back to site<");
|
||||
expect(html).toMatch(
|
||||
/<button type="button" disabled=""[^>]*>Commands are unavailable in preview<\/button>/,
|
||||
);
|
||||
});
|
||||
|
||||
it("maps every authorized domain icon and only marks the active domain", () => {
|
||||
const html = renderShell("people");
|
||||
|
||||
for (const iconId of [
|
||||
"inbox",
|
||||
"users",
|
||||
"file-text",
|
||||
"gem",
|
||||
"hotel",
|
||||
"settings",
|
||||
]) {
|
||||
expect(html).toContain(`data-domain-icon="${iconId}"`);
|
||||
}
|
||||
expect(html).toMatch(
|
||||
/<a(?=[^>]*href="\/admin-next\/people")(?=[^>]*aria-current="page")/,
|
||||
);
|
||||
expect(html).not.toContain(
|
||||
'href="/admin-next/operations" aria-current="page"',
|
||||
);
|
||||
});
|
||||
|
||||
it("renders no contextual items when the active domain is absent", () => {
|
||||
const html = renderShell("system");
|
||||
|
||||
expect(html).not.toContain('href="/admin-next/operations/queue"');
|
||||
expect(html).not.toContain(">Queue<");
|
||||
});
|
||||
|
||||
it("keeps Task 10 modules within the server-rendered source boundary", () => {
|
||||
const taskFiles = [
|
||||
"src/features/housekeeping/foundation/shell/housekeeping-shell.tsx",
|
||||
"src/features/housekeeping/foundation/shell/domain-rail.tsx",
|
||||
"src/features/housekeeping/foundation/shell/context-nav.tsx",
|
||||
"src/features/housekeeping/foundation/shell/command-trigger.tsx",
|
||||
"src/features/housekeeping/foundation/shell/operator-summary.tsx",
|
||||
"src/features/housekeeping/foundation/page/housekeeping-page-shell.tsx",
|
||||
"src/features/housekeeping/foundation/page/housekeeping-page-state.tsx",
|
||||
"src/features/housekeeping/foundation/shell/housekeeping-shell.test.tsx",
|
||||
"src/features/housekeeping/foundation/page/housekeeping-page-state.test.tsx",
|
||||
];
|
||||
const prohibited = [
|
||||
new RegExp("use " + "client"),
|
||||
new RegExp("cmd" + "k", "i"),
|
||||
new RegExp("addEvent" + "Listener"),
|
||||
new RegExp(
|
||||
"from\\s+['\"][^'\"]*(?:@/lib/" +
|
||||
"db|drizzle|/" +
|
||||
"actions)[^'\"]*['\"]",
|
||||
),
|
||||
new RegExp("next" + "-intl"),
|
||||
/(?:bg|text|border|from|to)-(?:red|blue|green|yellow|orange|purple|pink|gray|slate|zinc|neutral)-\d{2,3}/,
|
||||
new RegExp("#" + "[0-9a-fA-F]{3,8}"),
|
||||
new RegExp("(?:r" + "gb|h" + "sl)\\("),
|
||||
];
|
||||
|
||||
for (const path of taskFiles) {
|
||||
const source = readFileSync(resolve(process.cwd(), path), "utf8");
|
||||
for (const pattern of prohibited) {
|
||||
expect(source).not.toMatch(pattern);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user