import { describe, expect, it, vi } from "vitest"; import { PERMS } from "@/lib/permission-slugs"; import { anyCapability, type HousekeepingCapabilityContext, } from "../../foundation/contracts"; import { createEconomyInboxSources, ECONOMY_INBOX_SOURCE_IDS } from "./inbox"; import { createEconomySearchProviders, ECONOMY_SEARCH_PROVIDER_IDS, } from "./search"; import { createEconomyWidgets, ECONOMY_WIDGET_IDS } from "./widgets"; 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)), }; } describe("Economy providers", () => { it("registers exact bounded catalog, item, and transaction search providers", async () => { const candidates = Array.from({ length: 30 }, (_, index) => ({ id: `item-${index}`, title: `Item ${index}`, href: `/ase/economy/items/${index + 1}`, capability: anyCapability(PERMS.CATALOG_VIEW), })); const adapters = { catalogPages: vi.fn(async () => []), items: vi.fn(async () => candidates), transactions: vi.fn(async () => []), }; const providers = createEconomySearchProviders(adapters); expect(ECONOMY_SEARCH_PROVIDER_IDS).toEqual([ "economy.catalog-pages", "economy.items", "economy.transactions", ]); expect(providers.map((provider) => provider.id)).toEqual( ECONOMY_SEARCH_PROVIDER_IDS, ); const result = await providers[1].search(context([PERMS.CATALOG_VIEW]), { term: " sofa ", limit: 999, }); expect(adapters.items).toHaveBeenCalledWith(expect.anything(), "sofa", 25); expect(result).toMatchObject({ ok: true }); if (result.ok) expect(result.data).toHaveLength(25); }); it("exposes capability-selective catalog and commerce anomaly sources", async () => { const catalog = vi.fn(async () => []); const commerce = vi.fn(async () => []); const sources = createEconomyInboxSources({ catalog, commerce }); expect(ECONOMY_INBOX_SOURCE_IDS).toEqual([ "economy.catalog-attention", "economy.commerce-anomalies", ]); await sources[0].getItems( context([PERMS.CATALOG_VIEW]), new AbortController().signal, ); const forbidden = await sources[1].getItems( context([PERMS.CATALOG_VIEW]), new AbortController().signal, ); expect(catalog).toHaveBeenCalledOnce(); expect(commerce).not.toHaveBeenCalled(); expect(forbidden).toMatchObject({ ok: false, error: { code: "FORBIDDEN" }, }); }); it("keeps catalog mandatory and commerce/value widgets optional", async () => { const widgets = createEconomyWidgets({ catalog: vi.fn(async () => ({ pages: 12, items: 40 })), commerce: vi.fn(async () => ({ orders: 4 })), value: vi.fn(async () => ({ rares: 9 })), }); expect(ECONOMY_WIDGET_IDS).toEqual([ "economy.catalog-summary", "economy.commerce-summary", "economy.value-summary", ]); expect(widgets.map((widget) => widget.kind)).toEqual([ "mandatory", "optional", "optional", ]); expect( await widgets[0].load( context([PERMS.CATALOG_VIEW]), new AbortController().signal, ), ).toMatchObject({ ok: true, data: { pages: 12, items: 40 } }); }); });