import { describe, test, expect, mock, beforeEach } from "bun:test"; import { buildMockUnifiSite, buildMockCompany } from "../setup"; // --------------------------------------------------------------------------- // Stable mock factory // --------------------------------------------------------------------------- function createStablePrismaMock( overrides: Record> = {}, ) { 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)) }); }, }, ); } function createMockUnifi() { return { login: mock(() => Promise.resolve()), getAllSites: mock(() => Promise.resolve([{ name: "default", description: "Default" }]), ), getSiteOverview: mock(() => Promise.resolve({ status: "ok" })), getDevices: mock(() => Promise.resolve([])), getWlanConf: mock(() => Promise.resolve([])), updateWlanConf: mock(() => Promise.resolve({})), getNetworks: mock(() => Promise.resolve([])), createSite: mock(() => Promise.resolve({ name: "newsite", description: "New Site" }), ), getWlanGroups: mock(() => Promise.resolve([])), createWlanGroup: mock(() => Promise.resolve({})), getUserGroups: mock(() => Promise.resolve([])), createUserGroup: mock(() => Promise.resolve({})), getApGroups: mock(() => Promise.resolve([])), createApGroup: mock(() => Promise.resolve({})), updateApGroup: mock(() => Promise.resolve({})), getAccessPoints: mock(() => Promise.resolve([])), getWifiLimits: mock(() => Promise.resolve({})), getPrivatePSKs: mock(() => Promise.resolve([])), createPrivatePSK: mock(() => Promise.resolve({})), }; } // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- describe("unifiSites manager", () => { beforeEach(() => { mock.restore(); }); // ------------------------------------------------------------------- // fetch // ------------------------------------------------------------------- describe("fetch()", () => { test("returns UnifiSite when found", async () => { const siteData = buildMockUnifiSite(); mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findFirst: mock(() => Promise.resolve(siteData)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.fetch("usite-1"); expect(result).toBeDefined(); expect(result.id).toBe("usite-1"); }); test("throws 404 when not found", async () => { mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); try { await unifiSites.fetch("nonexistent"); expect(true).toBe(false); } catch (e: any) { expect(e.name).toBe("UnifiSiteNotFound"); expect(e.status).toBe(404); } }); }); // ------------------------------------------------------------------- // fetchAll // ------------------------------------------------------------------- describe("fetchAll()", () => { test("returns array of UnifiSite records", async () => { const sites = [buildMockUnifiSite()]; mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findMany: mock(() => Promise.resolve(sites)), findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.fetchAll(); expect(result).toBeArrayOfSize(1); }); }); // ------------------------------------------------------------------- // fetchByCompany // ------------------------------------------------------------------- describe("fetchByCompany()", () => { test("returns sites for a company", async () => { const sites = [buildMockUnifiSite({ companyId: "company-1" })]; mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findMany: mock(() => Promise.resolve(sites)), findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.fetchByCompany("company-1"); expect(result).toBeArrayOfSize(1); }); }); // ------------------------------------------------------------------- // linkToCompany // ------------------------------------------------------------------- describe("linkToCompany()", () => { test("links a site to a company", async () => { const site = buildMockUnifiSite(); const company = buildMockCompany(); const updatedSite = { ...site, companyId: "company-1" }; // findFirst returns site first time, company second time let callCount = 0; const findFirstMock = mock(() => { callCount++; return Promise.resolve(callCount === 1 ? site : null); }); mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findFirst: mock(() => Promise.resolve(site)), update: mock(() => Promise.resolve(updatedSite)), }, company: { findFirst: mock(() => Promise.resolve(company)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.linkToCompany("usite-1", "company-1"); expect(result.companyId).toBe("company-1"); }); test("throws when site not found", async () => { mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findFirst: mock(() => Promise.resolve(null)), }, company: { findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); try { await unifiSites.linkToCompany("bad-id", "company-1"); expect(true).toBe(false); } catch (e: any) { expect(e.name).toBe("UnifiSiteNotFound"); } }); }); // ------------------------------------------------------------------- // unlinkFromCompany // ------------------------------------------------------------------- describe("unlinkFromCompany()", () => { test("unlinks a site from its company", async () => { const site = { ...buildMockUnifiSite(), companyId: null }; mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { update: mock(() => Promise.resolve(site)), findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.unlinkFromCompany("usite-1"); expect(result.companyId).toBeNull(); }); }); // ------------------------------------------------------------------- // createSite // ------------------------------------------------------------------- describe("createSite()", () => { test("creates site in controller and DB", async () => { const dbSite = buildMockUnifiSite({ siteId: "newsite", name: "New Site", }); mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { create: mock(() => Promise.resolve(dbSite)), findFirst: mock(() => Promise.resolve(null)), }, }), unifi: createMockUnifi(), unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.createSite("New Site"); expect(result).toBeDefined(); expect(result.name).toBe("New Site"); }); }); // ------------------------------------------------------------------- // syncSites // ------------------------------------------------------------------- describe("syncSites()", () => { test("creates and updates sites from controller", async () => { const existingSite = buildMockUnifiSite({ siteId: "default" }); const updatedSite = { ...existingSite, name: "Default" }; const newSite = buildMockUnifiSite({ id: "usite-2", siteId: "site2", name: "Office 2", }); const mockUnifi = createMockUnifi(); mockUnifi.getAllSites = mock(() => Promise.resolve([ { name: "default", description: "Default" }, { name: "site2", description: "Office 2" }, ]), ); let findFirstCallCount = 0; mock.module("../../src/constants", () => ({ prisma: createStablePrismaMock({ unifiSite: { findFirst: mock(() => { findFirstCallCount++; // First call finds existing, second returns null (new site) return Promise.resolve( findFirstCallCount === 1 ? existingSite : null, ); }), update: mock(() => Promise.resolve(updatedSite)), create: mock(() => Promise.resolve(newSite)), findMany: mock(() => Promise.resolve([])), }, }), unifi: mockUnifi, unifiUsername: "admin", unifiPassword: "pass", })); mock.module("../../src/modules/globalEvents", () => ({ events: { emit: mock(), on: mock() }, setupEventDebugger: mock(), })); const { unifiSites } = await import("../../src/managers/unifiSites"); const result = await unifiSites.syncSites(); expect(result).toBeArrayOfSize(2); }); }); });