Files
Epicnabbo-Catalogus-Updated…/src/features/housekeeping/migration/hotel.test.ts
T

149 lines
3.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { PERMS } from "@/lib/permission-slugs";
import { ownedLegacyPages } from "./discover-legacy-pages";
import { hotelMigrationEntries } from "./hotel";
import { validateMigrationEntries } from "./validate-matrix";
const HOTEL_PREFIXES = [
"/admin/rooms",
"/admin/navigation",
"/admin/radio",
"/admin/studio",
] as const;
describe("hotelMigrationEntries", () => {
it("maps all hotel tools below the hotel target root", () => {
expect(
validateMigrationEntries(
ownedLegacyPages(HOTEL_PREFIXES),
hotelMigrationEntries,
),
).toEqual([]);
expect(
hotelMigrationEntries.every(
(row) =>
row.targetPath === null || row.targetPath.startsWith("/ase/hotel/"),
),
).toBe(true);
});
it("preserves room ids while merging only the detail aliases", () => {
expect(
hotelMigrationEntries
.filter((row) => row.legacyPath.startsWith("/admin/rooms"))
.map(({ legacyPath, targetPath, decision }) => ({
legacyPath,
targetPath,
decision,
})),
).toEqual([
{
legacyPath: "/admin/rooms",
targetPath: "/ase/hotel/rooms",
decision: "REBUILD",
},
{
legacyPath: "/admin/rooms/:id",
targetPath: "/ase/hotel/rooms/:id",
decision: "MERGE",
},
{
legacyPath: "/admin/rooms/:id/furni",
targetPath: "/ase/hotel/rooms/:id/furni",
decision: "REBUILD",
},
{
legacyPath: "/admin/rooms/edit/:id",
targetPath: "/ase/hotel/rooms/:id",
decision: "MERGE",
},
{
legacyPath: "/admin/rooms/show/:id",
targetPath: "/ase/hotel/rooms/:id",
decision: "MERGE",
},
]);
});
it("keeps every audited workflow planned without parity claims", () => {
expect(
hotelMigrationEntries.every(
(row) => row.status === "PLANNED" && row.parityEvidence.length === 0,
),
).toBe(true);
});
it("requires privileged audit and an explicit capability for every mutation", () => {
const mutationRows = hotelMigrationEntries.filter(
(row) => row.dependencies.mutations.length > 0,
);
expect(mutationRows.length).toBeGreaterThan(0);
expect(
mutationRows.every(
(row) =>
row.capabilities.mutate.length > 0 &&
row.auditRequirement === "PRIVILEGED_MUTATION",
),
).toBe(true);
});
it("classifies Studio Audit repair operations as privileged mutations", () => {
const studioAudit = hotelMigrationEntries.find(
(row) => row.legacyPath === "/admin/studio/audit",
);
expect(studioAudit).toEqual(
expect.objectContaining({
capabilities: {
read: [PERMS.ASSETS_IMPORT],
mutate: [PERMS.ASSETS_IMPORT],
},
dependencies: expect.objectContaining({
mutations: expect.arrayContaining([
"POST /api/admin/import/audit",
"applyCatalogSql",
"ensureDirectories",
"repairDuplicateClassnames",
"repairFurniData",
"repairMissingIcons",
"repairMissingNitros",
"repairOrphanedCatalog",
]),
}),
auditRequirement: "PRIVILEGED_MUTATION",
}),
);
});
it("records the actual permissions for room, radio, and Studio mutations", () => {
expect(hotelMigrationEntries).toContainEqual(
expect.objectContaining({
legacyPath: "/admin/rooms/edit/:id",
capabilities: {
read: [PERMS.ROOMS_EDIT],
mutate: [PERMS.ROOMS_EDIT, PERMS.ROOMS_DELETE],
},
}),
);
expect(hotelMigrationEntries).toContainEqual(
expect.objectContaining({
legacyPath: "/admin/radio/api-keys",
capabilities: {
read: [PERMS.RADIO_VIEW],
mutate: [PERMS.RADIO_EDIT],
},
}),
);
expect(hotelMigrationEntries).toContainEqual(
expect.objectContaining({
legacyPath: "/admin/studio/sync",
capabilities: {
read: [PERMS.ASSETS_IMPORT],
mutate: [PERMS.ASSETS_IMPORT],
},
}),
);
});
});