import { describe, test, expect } from "bun:test"; import { CatalogItemController } from "../../../src/controllers/CatalogItemController"; import { buildMockCatalogItem } from "../../setup"; describe("CatalogItemController", () => { // ------------------------------------------------------------------- // Constructor // ------------------------------------------------------------------- describe("constructor", () => { test("sets core identification fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.id).toBe("cat-1"); expect(ctrl.cwCatalogId).toBe(500); expect(ctrl.identifier).toBe("USW-Pro-24"); }); test("sets name and description fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.name).toBe("UniFi Switch Pro 24"); expect(ctrl.description).toBe("24-port managed switch"); expect(ctrl.customerDescription).toBe("Enterprise switch"); expect(ctrl.internalNotes).toBeNull(); }); test("sets category and subcategory fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.category).toBe("Technology"); expect(ctrl.categoryCwId).toBe(18); expect(ctrl.subcategory).toBe("Network-Switch"); expect(ctrl.subcategoryCwId).toBe(112); }); test("sets manufacturer fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.manufacturer).toBe("Ubiquiti"); expect(ctrl.manufactureCwId).toBe(248); expect(ctrl.partNumber).toBe("USW-Pro-24"); }); test("sets vendor fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.vendorName).toBe("Ubiquiti Inc"); expect(ctrl.vendorSku).toBe("USW-Pro-24"); expect(ctrl.vendorCwId).toBe(100); }); test("sets financial fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.price).toBe(500.0); expect(ctrl.cost).toBe(360.0); }); test("sets boolean flags", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.inactive).toBe(false); expect(ctrl.salesTaxable).toBe(true); }); test("sets inventory fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.onHand).toBe(10); }); test("sets timestamps", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.cwLastUpdated).toBeInstanceOf(Date); expect(ctrl.createdAt).toBeInstanceOf(Date); expect(ctrl.updatedAt).toBeInstanceOf(Date); }); test("builds linked items recursively", () => { const linked = buildMockCatalogItem({ id: "cat-2", name: "Linked Item", linkedItems: undefined, }); const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: [linked] }), ); const items = ctrl.getLinkedItems(); expect(items).toHaveLength(1); expect(items[0].id).toBe("cat-2"); expect(items[0]).toBeInstanceOf(CatalogItemController); }); test("defaults to empty linked items when undefined", () => { const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: undefined }), ); expect(ctrl.getLinkedItems()).toHaveLength(0); }); test("handles null optional fields", () => { const ctrl = new CatalogItemController( buildMockCatalogItem({ description: null, customerDescription: null, identifier: null, category: null, categoryCwId: null, subcategory: null, subcategoryCwId: null, manufacturer: null, manufactureCwId: null, partNumber: null, vendorName: null, vendorSku: null, vendorCwId: null, cwLastUpdated: null, }), ); expect(ctrl.description).toBeNull(); expect(ctrl.customerDescription).toBeNull(); expect(ctrl.identifier).toBeNull(); expect(ctrl.category).toBeNull(); expect(ctrl.manufacturer).toBeNull(); expect(ctrl.cwLastUpdated).toBeNull(); }); }); // ------------------------------------------------------------------- // getLinkedItems // ------------------------------------------------------------------- describe("getLinkedItems()", () => { test("returns empty array when no linked items", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); expect(ctrl.getLinkedItems()).toEqual([]); }); test("returns array of CatalogItemController instances", () => { const linked1 = buildMockCatalogItem({ id: "cat-2", name: "Item 2" }); const linked2 = buildMockCatalogItem({ id: "cat-3", name: "Item 3" }); const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: [linked1, linked2] }), ); const items = ctrl.getLinkedItems(); expect(items).toHaveLength(2); expect(items[0].name).toBe("Item 2"); expect(items[1].name).toBe("Item 3"); }); }); // ------------------------------------------------------------------- // toJson // ------------------------------------------------------------------- describe("toJson()", () => { test("returns all core fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); const json = ctrl.toJson(); expect(json.id).toBe("cat-1"); expect(json.cwCatalogId).toBe(500); expect(json.identifier).toBe("USW-Pro-24"); expect(json.name).toBe("UniFi Switch Pro 24"); expect(json.description).toBe("24-port managed switch"); expect(json.customerDescription).toBe("Enterprise switch"); expect(json.internalNotes).toBeNull(); }); test("returns classification fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); const json = ctrl.toJson(); expect(json.category).toBe("Technology"); expect(json.categoryCwId).toBe(18); expect(json.subcategory).toBe("Network-Switch"); expect(json.subcategoryCwId).toBe(112); expect(json.manufacturer).toBe("Ubiquiti"); expect(json.manufactureCwId).toBe(248); expect(json.partNumber).toBe("USW-Pro-24"); }); test("returns financial fields", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); const json = ctrl.toJson(); expect(json.price).toBe(500.0); expect(json.cost).toBe(360.0); }); test("returns boolean flags", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); const json = ctrl.toJson(); expect(json.inactive).toBe(false); expect(json.salesTaxable).toBe(true); }); test("returns timestamps", () => { const ctrl = new CatalogItemController(buildMockCatalogItem()); const json = ctrl.toJson(); expect(json.createdAt).toBeInstanceOf(Date); expect(json.updatedAt).toBeInstanceOf(Date); expect(json.cwLastUpdated).toBeInstanceOf(Date); }); test("excludes linkedItems when includeLinkedItems not set", () => { const linked = buildMockCatalogItem({ id: "cat-2" }); const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: [linked] }), ); const json = ctrl.toJson(); expect(json.linkedItems).toBeUndefined(); }); test("includes linkedItems when includeLinkedItems is true", () => { const linked = buildMockCatalogItem({ id: "cat-2", name: "Linked" }); const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: [linked] }), ); const json = ctrl.toJson({ includeLinkedItems: true }); expect(json.linkedItems).toHaveLength(1); expect(json.linkedItems[0].id).toBe("cat-2"); expect(json.linkedItems[0].name).toBe("Linked"); }); test("linked items toJson does not recursively include their linked items", () => { const linked = buildMockCatalogItem({ id: "cat-2" }); const ctrl = new CatalogItemController( buildMockCatalogItem({ linkedItems: [linked] }), ); const json = ctrl.toJson({ includeLinkedItems: true }); // Nested linked items called without opts, so linkedItems is undefined expect(json.linkedItems[0].linkedItems).toBeUndefined(); }); }); });