Files
Epicnabbo-Catalogus-Updated…/src/features/housekeeping/foundation/shell/operational-inbox.test.tsx
T

131 lines
3.5 KiB
TypeScript

import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { anyCapability, type HousekeepingWorkItem } from "../contracts";
import {
filterOperationalInboxItems,
OperationalInbox,
projectOperationalInboxHref,
} from "./operational-inbox";
const labels = {
title: "Operational inbox",
domainFilter: "Filter by domain",
stateFilter: "Filter by state",
priorityFilter: "Filter by priority",
all: "All",
loading: "Loading operational work",
empty: "No operational work",
partial: "Some sources are unavailable",
open: "Open workflow",
};
function item(
itemId: string,
options: Partial<HousekeepingWorkItem> = {},
): HousekeepingWorkItem {
return {
sourceId: "people.queue",
itemId,
deduplicationKey: `people.queue:${itemId}`,
domain: "people",
capability: anyCapability("admin.users.view"),
severity: "warning",
priority: "high",
ageMs: 1_000,
state: "open",
occurredAt: "2026-08-30T10:00:00.000Z",
titleKey: `Item ${itemId}`,
href: "/ase/people/users",
freshness: "fresh",
actions: [],
...options,
};
}
describe("OperationalInbox", () => {
it("filters deterministically by domain, state, and priority", () => {
const items = [
item("people-open"),
item("content-draft", {
domain: "content",
state: "draft",
priority: "normal",
href: "/ase/content/editorial/articles",
}),
];
expect(
filterOperationalInboxItems(items, {
domain: "people",
state: "open",
priority: "high",
}).map((entry) => entry.itemId),
).toEqual(["people-open"]);
expect(
filterOperationalInboxItems(items, {
domain: "all",
state: "draft",
priority: "all",
}).map((entry) => entry.itemId),
).toEqual(["content-draft"]);
});
it("renders accessible filters, partial errors, and preview links", () => {
const html = renderToStaticMarkup(
<OperationalInbox
labels={labels}
surface="preview"
response={{
items: [item("ticket-1")],
errors: [{ sourceId: "content.publication", code: "TIMEOUT" }],
correlationId: "inbox-ui",
}}
/>,
);
expect(html).toContain('aria-label="Filter by domain"');
expect(html).toContain('aria-label="Filter by state"');
expect(html).toContain('aria-label="Filter by priority"');
expect(html).toContain("Some sources are unavailable");
expect(html).not.toContain("content.publication");
expect(html).not.toContain("TIMEOUT");
expect(html).toContain('role="alert"');
expect(html).toContain('href="/ase-next/people/users"');
expect(html).not.toContain("Dismiss");
expect(html).not.toContain("Assign");
});
it("renders explicit loading and empty states", () => {
const response = {
items: [],
errors: [],
correlationId: "inbox-empty",
} as const;
const loading = renderToStaticMarkup(
<OperationalInbox
labels={labels}
surface="preview"
response={response}
loading
/>,
);
const empty = renderToStaticMarkup(
<OperationalInbox
labels={labels}
surface="preview"
response={response}
/>,
);
expect(loading).toContain('role="status"');
expect(loading).toContain("Loading operational work");
expect(empty).toContain("No operational work");
});
it("projects canonical hrefs without changing production destinations", () => {
expect(
projectOperationalInboxHref("/ase/system/operations/alerts", "preview"),
).toBe("/ase-next/system/operations/alerts");
expect(
projectOperationalInboxHref("/ase/system/operations/alerts", "canonical"),
).toBe("/ase/system/operations/alerts");
});
});