Files
optima/api/tests/unit/procurementManager.test.ts
2026-04-07 23:56:31 +00:00

361 lines
12 KiB
TypeScript

import { describe, test, expect, mock, beforeEach } from "bun:test";
import { buildMockCatalogItem, buildMockConstants } from "../setup";
// ---------------------------------------------------------------------------
// Stable mock factory
// ---------------------------------------------------------------------------
function createStablePrismaMock(
overrides: Record<string, Record<string, any>> = {}
) {
return new Proxy(
{},
{
get(_target, model: string) {
if (model === "$connect" || model === "$disconnect")
return mock(() => Promise.resolve());
if (overrides[model]) return overrides[model];
return new Proxy({}, { get: () => mock(() => Promise.resolve(null)) });
},
}
);
}
// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
describe("procurement manager", () => {
beforeEach(() => {
mock.restore();
});
// -------------------------------------------------------------------
// fetchItem
// -------------------------------------------------------------------
describe("fetchItem()", () => {
test("returns CatalogItemController by internal ID", async () => {
const mockData = { ...buildMockCatalogItem(), linkedItems: [] };
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findFirst: mock(() => Promise.resolve(mockData)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.fetchItem("cat-1");
expect(result).toBeDefined();
expect(result.id).toBe("cat-1");
});
test("looks up by cwCatalogId for numeric identifiers", async () => {
const mockData = { ...buildMockCatalogItem(), linkedItems: [] };
const findFirst = mock(() => Promise.resolve(mockData));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: { findFirst },
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.fetchItem(500);
const where = findFirst.mock.calls[0]?.[0]?.where;
expect(where).toHaveProperty("cwCatalogId", 500);
});
test("throws 404 when not found", async () => {
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
try {
await procurement.fetchItem("nonexistent");
expect(true).toBe(false);
} catch (e: any) {
expect(e.name).toBe("CatalogItemNotFound");
expect(e.status).toBe(404);
}
});
});
// -------------------------------------------------------------------
// fetchPages
// -------------------------------------------------------------------
describe("fetchPages()", () => {
test("returns paginated catalog items", async () => {
const items = [
{ ...buildMockCatalogItem(), linkedItems: [] },
{ ...buildMockCatalogItem({ id: "cat-2" }), linkedItems: [] },
];
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany: mock(() => Promise.resolve(items)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.fetchPages(1, 10);
expect(result).toBeArrayOfSize(2);
});
test("clamps page to minimum 1", async () => {
const findMany = mock(() => Promise.resolve([]));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany,
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.fetchPages(0, 10);
const opts = findMany.mock.calls[0]?.[0];
expect(opts.skip).toBe(0); // (max(0,1)-1) * 10 = 0
});
test("falls back to safe pagination when page/rpp are invalid", async () => {
const findMany = mock(() => Promise.resolve([]));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany,
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.fetchPages(Number.NaN, Number.NaN);
const opts = findMany.mock.calls[0]?.[0];
expect(opts.skip).toBe(0);
expect(opts.take).toBe(30);
});
test("uses relational manufacturer filter when manufacturer option is provided", async () => {
const findMany = mock(() => Promise.resolve([]));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany,
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.fetchPages(1, 20, { manufacturer: "Ubiquiti" });
const where = findMany.mock.calls[0]?.[0]?.where;
expect(JSON.stringify(where)).toContain(
'"manufacturer":{"is":{"name":{"contains":"Ubiquiti"'
);
});
});
// -------------------------------------------------------------------
// search
// -------------------------------------------------------------------
describe("search()", () => {
test("returns matching catalog items", async () => {
const items = [{ ...buildMockCatalogItem(), linkedItems: [] }];
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany: mock(() => Promise.resolve(items)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.search("switch", 1, 10);
expect(result).toBeArrayOfSize(1);
});
test("ignores invalid numeric filters instead of passing NaN to Prisma", async () => {
const findMany = mock(() => Promise.resolve([]));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany,
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.search("switch", Number.NaN, Number.NaN, {
minPrice: Number.NaN,
maxPrice: Number.NaN,
});
const where = findMany.mock.calls[0]?.[0]?.where;
expect(where).toHaveProperty("OR");
expect(JSON.stringify(where)).not.toContain("NaN");
});
test("uses relational manufacturer search clause", async () => {
const findMany = mock(() => Promise.resolve([]));
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany,
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
await procurement.search("wir", 1, 20);
const where = findMany.mock.calls[0]?.[0]?.where;
expect(JSON.stringify(where)).toContain(
'"manufacturer":{"is":{"name":{"contains":"wir"'
);
});
});
// -------------------------------------------------------------------
// count
// -------------------------------------------------------------------
describe("count()", () => {
test("returns total count", async () => {
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
count: mock(() => Promise.resolve(50)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.count();
expect(result).toBe(50);
});
});
// -------------------------------------------------------------------
// countSearch
// -------------------------------------------------------------------
describe("countSearch()", () => {
test("returns count of matching items", async () => {
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
count: mock(() => Promise.resolve(12)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.countSearch("switch");
expect(result).toBe(12);
});
});
// -------------------------------------------------------------------
// fetchDistinctValues
// -------------------------------------------------------------------
describe("fetchDistinctValues()", () => {
test("returns sorted distinct category values", async () => {
const items = [{ category: "Technology" }, { category: "Accessories" }];
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany: mock(() => Promise.resolve(items)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.fetchDistinctValues("category");
expect(result).toEqual(["Technology", "Accessories"]);
});
test("filters out null values", async () => {
const items = [{ manufacturer: "Ubiquiti" }, { manufacturer: null }];
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findMany: mock(() => Promise.resolve(items)),
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
const result = await procurement.fetchDistinctValues("manufacturer");
expect(result).toEqual(["Ubiquiti"]);
});
});
// -------------------------------------------------------------------
// fetchLaborCatalogItems
// -------------------------------------------------------------------
describe("fetchLaborCatalogItems()", () => {
test("throws when labor items not found", async () => {
mock.module("../../src/constants", () =>
buildMockConstants({
prisma: createStablePrismaMock({
catalogItem: {
findFirst: mock(() => Promise.resolve(null)),
},
}),
})
);
const { procurement } = await import("../../src/managers/procurement");
try {
await procurement.fetchLaborCatalogItems();
expect(true).toBe(false);
} catch (e: any) {
expect(e.name).toBe("LaborCatalogProductsNotFound");
expect(e.status).toBe(500);
}
});
});
});