Files
EpicNext-Cms/src/features/catalog/components/packages/catalog-package-preview-model.test.ts
T
Simo 047cd9f3dd
CI / check (push) Successful in 52s
CI / deploy (push) Successful in 1m23s
CI / publish-container (push) Failing after 27s
feat(catalog): add saved packages, preview and bulk price editing
2026-09-09 20:04:10 +02:00

165 lines
4.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
buildPackagePreview,
createPreviewAssetLoader,
parsePreviewItemIds,
} from "./catalog-package-preview-model";
const page = (id: number, parentId = -1, overrides = {}) => ({
id,
parentId,
caption: `Page ${id}`,
enabled: "1" as const,
visible: "1" as const,
iconImage: 0,
minRank: 1,
clubOnly: "0" as const,
vipOnly: "0" as const,
orderNum: id,
pageLayout: "default_3x3",
...overrides,
});
const profile = { playerMode: true, rank: 1, club: false, vip: false };
describe("package preview access", () => {
it("honors restrictions on every included ancestor", () => {
const result = buildPackagePreview(
{ pages: [page(1, -1, { minRank: 5 }), page(2, 1)], offers: [] },
profile,
"",
);
expect(result.pages).toEqual([]);
expect(result.restrictedCount).toBe(2);
});
it("handles hidden/disabled ancestors and club membership", () => {
for (const restriction of [
{ visible: "0" },
{ enabled: "0" },
{ clubOnly: "1" },
{ vipOnly: "1" },
]) {
expect(
buildPackagePreview(
{ pages: [page(1, -1, restriction), page(2, 1)], offers: [] },
profile,
"",
).pages,
).toEqual([]);
}
expect(
buildPackagePreview(
{ pages: [page(1, -1, { clubOnly: "1" })], offers: [] },
{ ...profile, vip: true },
"",
).pages,
).toHaveLength(1);
});
it("rejects cycles without hanging and reports external subtree boundaries", () => {
const result = buildPackagePreview(
{ pages: [page(1, 2), page(2, 1), page(3, 999)], offers: [] },
profile,
"",
);
expect(result.pages.map((p) => p.id)).toEqual([3]);
expect(result.invalidCount).toBe(2);
expect(result.externalParents).toBe(true);
});
it("bounds oversized snapshots before traversing", () => {
const result = buildPackagePreview(
{ pages: Array.from({ length: 500 }, (_, i) => page(i + 1)), offers: [] },
profile,
"",
);
expect(result.pages).toHaveLength(200);
expect(result.truncated).toBe(true);
});
it("preserves parent navigation when only a child offer matches", () => {
const result = buildPackagePreview(
{
pages: [page(1), page(2, 1)],
offers: [
{
id: 1,
pageId: 2,
catalogName: "Sofa",
itemIds: "4;5",
costCredits: 2,
costPoints: 0,
pointsType: 0,
amount: 1,
},
],
},
profile,
"sofa",
);
expect(result.pages.map((p) => p.id)).toEqual([1, 2]);
expect(result.matchingPageIds).toEqual([2]);
});
it("parses bundle IDs strictly without treating partial numbers as IDs", () => {
expect(parsePreviewItemIds("2; 3,4;2;abc;5x;-1;0")).toEqual([2, 3, 4]);
});
});
describe("preview asset requests", () => {
it("ignores older responses after changing selection", async () => {
const resolves: ((value: number[]) => void)[] = [];
const loader = createPreviewAssetLoader(
() => new Promise<number[]>((resolve) => resolves.push(resolve)),
);
const seen: number[][] = [];
const first = loader.run([1], (value) => seen.push(value));
const second = loader.run([2], (value) => seen.push(value));
resolves[1]([2]);
await second;
resolves[0]([1]);
await first;
expect(seen).toEqual([[2]]);
});
it("does not publish after unmount/cancellation", async () => {
let finish = (_value: number[]) => {};
const loader = createPreviewAssetLoader(
() =>
new Promise<number[]>((resolve) => {
finish = resolve;
}),
);
const seen: number[][] = [];
const pending = loader.run([1], (value) => seen.push(value));
loader.cancel();
finish([1]);
await pending;
expect(seen).toEqual([]);
});
});
describe("offer membership access", () => {
it("filters Club offers separately from their public category and permits VIP", () => {
const snapshot = {
pages: [page(1)],
offers: [
{
id: 1,
pageId: 1,
catalogName: "Club chair",
clubOnly: "1" as const,
itemIds: "2",
costCredits: 1,
costPoints: 0,
pointsType: 0,
amount: 1,
},
],
};
const guest = buildPackagePreview(snapshot, profile, "");
expect(guest.pages).toHaveLength(1);
expect(guest.offers).toHaveLength(0);
expect(guest.restrictedOfferCounts[1]).toBe(1);
expect(
buildPackagePreview(snapshot, { ...profile, vip: true }, "").offers,
).toHaveLength(1);
expect(
buildPackagePreview(snapshot, { ...profile, playerMode: false }, "")
.offers,
).toHaveLength(1);
});
});