Files
EpicNext-Cms/src/features/housekeeping/domains/economy/pages/economy-pages.test.tsx
T
Simo 43470ebf82
CI / check (pull_request) Failing after 10s
CI / deploy (pull_request) Skipped
CI / release (pull_request) Skipped
feat(housekeeping): unify complete rebuild in gated preview
2026-08-31 20:37:51 +02:00

160 lines
4.5 KiB
TypeScript

import { renderToStaticMarkup } from "react-dom/server";
import { describe, expect, it } from "vitest";
import { PERMS } from "@/lib/permission-slugs";
import {
fail,
type HousekeepingCapabilityContext,
ok,
} from "../../../foundation/contracts";
import { EconomyCatalogPage } from "./catalog";
import { EconomyCommercePage } from "./commerce";
import { EconomyHistoryPage } from "./history";
import { EconomyItemsPage } from "./items";
import { EconomyRewardsPage } from "./rewards";
import { EconomyValuePage } from "./value";
function context(granted: readonly string[]): HousekeepingCapabilityContext {
const permissions = new Set(granted);
return {
actor: { id: 42, username: "operator", rank: 7 },
isSuperAdmin: false,
has: (slug) => permissions.has(slug),
hasAny: (...slugs) => slugs.some((slug) => permissions.has(slug)),
hasAll: (...slugs) => slugs.every((slug) => permissions.has(slug)),
};
}
const cases = [
["catalog", EconomyCatalogPage],
["items", EconomyItemsPage],
["commerce", EconomyCommercePage],
["history", EconomyHistoryPage],
["value", EconomyValuePage],
["rewards", EconomyRewardsPage],
] as const;
describe.each(cases)("Economy %s page", (kind, Component) => {
it("renders loading, forbidden, empty, and canonical ready states", () => {
const render = (result?: unknown) =>
renderToStaticMarkup(
<Component
context={context(Object.values(PERMS))}
result={result as never}
routeId={null}
/>,
);
expect(render()).toContain('data-housekeeping-state="loading"');
expect(
render(fail("FORBIDDEN", "errors.housekeeping.forbidden", "denied")),
).toContain('data-housekeeping-state="forbidden"');
expect(
render(
ok({ kind, items: [], total: 0, partialDependencies: [] }, "empty"),
),
).toContain('data-housekeeping-state="empty"');
const ready = render(
ok(
{
kind,
items: [
{
id: "18446744073709551615",
title: "Canonical economy item",
status: "active",
href: `/ase-next/economy/${kind}`,
},
],
total: 1,
partialDependencies: [],
},
"ready",
),
);
expect(ready).toContain('data-housekeeping-state="ready"');
expect(ready).toContain("Canonical economy item");
expect(ready).not.toContain("/admin");
});
});
describe("Economy mutation forms", () => {
it("renders edit controls only with the exact mutation capability", () => {
const result = ok(
{
kind: "commerce" as const,
items: [{ id: "1", title: "Package", status: "active" }],
total: 1,
partialDependencies: [],
},
"shop",
);
const readOnly = renderToStaticMarkup(
<EconomyCommercePage
context={context([PERMS.SHOP_VIEW])}
result={result}
routeId="economy.commerce.shop"
/>,
);
const editor = renderToStaticMarkup(
<EconomyCommercePage
context={context([PERMS.SHOP_VIEW, PERMS.SHOP_EDIT])}
result={result}
routeId="economy.commerce.shop"
/>,
);
expect(readOnly).not.toContain("economy.commerce.shop-article.change");
expect(editor).toContain("economy.commerce.shop-article.change");
expect(editor).toContain("<form");
});
it("renders validator-shaped catalog, voucher, value, and soundtrack fields", () => {
const all = context(Object.values(PERMS));
const empty = (kind: "catalog" | "commerce" | "value" | "rewards") =>
ok({ kind, items: [], total: 0, partialDependencies: [] }, kind);
const catalog = renderToStaticMarkup(
<EconomyCatalogPage
context={all}
result={empty("catalog")}
routeId="economy.catalog.detail"
/>,
);
for (const field of ["id", "caption", "parentId", "pageLayout"]) {
expect(catalog).toContain(`name="${field}"`);
}
const commerce = renderToStaticMarkup(
<EconomyCommercePage
context={all}
result={empty("commerce")}
routeId="economy.commerce.vouchers"
/>,
);
for (const field of ["code", "amount", "maxUses", "expiresAt"]) {
expect(commerce).toContain(`name="${field}"`);
}
const value = renderToStaticMarkup(
<EconomyValuePage
context={all}
result={empty("value")}
routeId="economy.value.rare-values"
/>,
);
for (const field of [
"categoryId",
"name",
"currencyValue",
"currencyType",
]) {
expect(value).toContain(`name="${field}"`);
}
const rewards = renderToStaticMarkup(
<EconomyRewardsPage
context={all}
result={empty("rewards")}
routeId="economy.rewards.sounds"
/>,
);
for (const field of ["id", "name", "author", "track", "length"]) {
expect(rewards).toContain(`name="${field}"`);
}
});
});