refactor(housekeeping): stabilize service contracts
This commit is contained in:
1 parent
67cb4b488d
commit
b7edbca043
10 files changed
+145
-28
No files matched your search
@@ -13,6 +13,7 @@ import {
|
||||
type HousekeepingSearchResult,
|
||||
type HousekeepingWidgetDefinition,
|
||||
type HousekeepingWorkItem,
|
||||
mapUnknownError,
|
||||
ok,
|
||||
} from ".";
|
||||
|
||||
@@ -25,18 +26,32 @@ const workItem = {
|
||||
domain: "people",
|
||||
capability,
|
||||
severity: "warning",
|
||||
priority: "high",
|
||||
ageMs: 60_000,
|
||||
state: "open",
|
||||
occurredAt: "2026-08-24T12:00:00.000Z",
|
||||
titleKey: "pages.housekeeping.items.ticket",
|
||||
context: { ticketId: "42" },
|
||||
href: "/ase-next/people/tickets/42",
|
||||
href: "/ase/people/tickets/42",
|
||||
freshness: "fresh",
|
||||
actions: [
|
||||
{
|
||||
id: "people.ticket.open",
|
||||
labelKey: "pages.housekeeping.items.ticket.open",
|
||||
commandId: "people.ticket.open",
|
||||
capability,
|
||||
},
|
||||
],
|
||||
} satisfies HousekeepingWorkItem;
|
||||
|
||||
const searchResult = {
|
||||
id: "user-42",
|
||||
domain: "people",
|
||||
type: "entity",
|
||||
title: "operator",
|
||||
href: "/ase-next/people/users/42",
|
||||
description: "A Housekeeping operator",
|
||||
href: "/ase/people/users/42",
|
||||
capability,
|
||||
} satisfies HousekeepingSearchResult;
|
||||
|
||||
const searchProvider: HousekeepingSearchProvider = {
|
||||
@@ -87,7 +102,7 @@ const manifest: HousekeepingDomainManifest = {
|
||||
labelKey: "pages.housekeeping.domains.people.title",
|
||||
descriptionKey: "pages.housekeeping.domains.people.description",
|
||||
iconId: "users",
|
||||
canonicalHref: "/ase-next/people",
|
||||
canonicalHref: "/ase/people",
|
||||
capability,
|
||||
routes: [],
|
||||
searchProviders: [searchProvider],
|
||||
@@ -96,19 +111,47 @@ const manifest: HousekeepingDomainManifest = {
|
||||
};
|
||||
|
||||
describe("housekeeping foundation contracts", () => {
|
||||
it("creates typed success and error results", () => {
|
||||
it("preserves correlation IDs for successful results", () => {
|
||||
expect(ok({ count: 2 }, "corr-1")).toEqual({
|
||||
ok: true,
|
||||
data: { count: 2 },
|
||||
correlationId: "corr-1",
|
||||
});
|
||||
expect(fail("CAPABILITY_DENIED", "corr-2")).toEqual({
|
||||
});
|
||||
|
||||
it.each([
|
||||
"UNAUTHENTICATED",
|
||||
"FORBIDDEN",
|
||||
"VALIDATION",
|
||||
"NOT_FOUND",
|
||||
"CONFLICT",
|
||||
"RATE_LIMITED",
|
||||
"DEPENDENCY_UNAVAILABLE",
|
||||
"TIMEOUT",
|
||||
"INTERNAL",
|
||||
] as const)("returns the approved %s error contract", (code) => {
|
||||
expect(
|
||||
fail(code, `errors.housekeeping.${code.toLowerCase()}`, "corr-2", {
|
||||
name: ["errors.validation.required"],
|
||||
}),
|
||||
).toEqual({
|
||||
ok: false,
|
||||
error: { code: "CAPABILITY_DENIED" },
|
||||
error: {
|
||||
code,
|
||||
messageKey: `errors.housekeeping.${code.toLowerCase()}`,
|
||||
fieldErrors: { name: ["errors.validation.required"] },
|
||||
},
|
||||
correlationId: "corr-2",
|
||||
});
|
||||
});
|
||||
|
||||
it("sanitizes unknown errors with the stable internal taxonomy", () => {
|
||||
expect(mapUnknownError(new Error("database password exposed"))).toEqual({
|
||||
code: "INTERNAL",
|
||||
messageKey: "errors.housekeeping.internal",
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects empty capability requirements", () => {
|
||||
expect(() => anyCapability()).toThrow("capability requirement is empty");
|
||||
expect(() => allCapabilities()).toThrow("capability requirement is empty");
|
||||
|
||||
Reference in new issue
Block a user