import { describe, test, expect, mock, beforeEach } from "bun:test"; // --------------------------------------------------------------------------- // Tests // --------------------------------------------------------------------------- describe("cw.opportunityService", () => { beforeEach(() => { mock.restore(); }); // ------------------------------------------------------------------- // submitTimeEntry // ------------------------------------------------------------------- describe("submitTimeEntry()", () => { test("submits time entry and returns success", async () => { const postMock = mock(() => Promise.resolve({ data: { id: 9001 } })); mock.module("../../src/constants", () => ({ connectWiseApi: { post: postMock }, prisma: new Proxy( {}, { get: () => mock(() => Promise.resolve(null)), }, ), })); mock.module( "../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: mock(() => Promise.resolve({})), }, }), ); const { submitTimeEntry } = await import("../../src/services/cw.opportunityService"); const result = await submitTimeEntry({ activityId: 100, cwMemberId: 10, timeStart: "2026-03-01T09:00:00.000Z", timeEnd: "2026-03-01T10:00:00.000Z", notes: "Design review", }); expect(result.success).toBe(true); expect(result.cwTimeEntryId).toBe(9001); expect(result.message).toContain("9001"); }); test("strips milliseconds from ISO timestamps", async () => { const postMock = mock(() => Promise.resolve({ data: { id: 9001 } })); mock.module("../../src/constants", () => ({ connectWiseApi: { post: postMock }, prisma: new Proxy( {}, { get: () => mock(() => Promise.resolve(null)), }, ), })); mock.module( "../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: mock(() => Promise.resolve({})) }, }), ); const { submitTimeEntry } = await import("../../src/services/cw.opportunityService"); await submitTimeEntry({ activityId: 100, cwMemberId: 10, timeStart: "2026-03-01T09:00:00.123Z", timeEnd: "2026-03-01T10:00:00.456Z", notes: "test", }); const body = postMock.mock.calls[0]?.[1]; expect(body.timeStart).toBe("2026-03-01T09:00:00Z"); expect(body.timeEnd).toBe("2026-03-01T10:00:00Z"); }); test("returns failure on API error", async () => { mock.module("../../src/constants", () => ({ connectWiseApi: { post: mock(() => Promise.reject(new Error("CW down"))), }, prisma: new Proxy( {}, { get: () => mock(() => Promise.resolve(null)), }, ), })); mock.module( "../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: mock(() => Promise.resolve({})) }, }), ); const { submitTimeEntry } = await import("../../src/services/cw.opportunityService"); const result = await submitTimeEntry({ activityId: 100, cwMemberId: 10, timeStart: "2026-03-01T09:00:00Z", timeEnd: "2026-03-01T10:00:00Z", notes: "test", }); expect(result.success).toBe(false); expect(result.cwTimeEntryId).toBeNull(); expect(result.message).toContain("Failed"); }); }); // ------------------------------------------------------------------- // syncOpportunityStatus // ------------------------------------------------------------------- describe("syncOpportunityStatus()", () => { test("syncs status to CW and returns success", async () => { const updateMock = mock(() => Promise.resolve({})); mock.module("../../src/constants", () => ({ connectWiseApi: { post: mock(() => Promise.resolve({ data: {} })) }, prisma: new Proxy( {}, { get: () => mock(() => Promise.resolve(null)), }, ), })); mock.module( "../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: updateMock }, }), ); const { syncOpportunityStatus } = await import("../../src/services/cw.opportunityService"); const result = await syncOpportunityStatus({ opportunityId: 1001, statusCwId: 24, }); expect(result.success).toBe(true); expect(result.message).toContain("1001"); }); test("returns failure on API error", async () => { mock.module("../../src/constants", () => ({ connectWiseApi: { post: mock(() => Promise.resolve({ data: {} })) }, prisma: new Proxy( {}, { get: () => mock(() => Promise.resolve(null)), }, ), })); mock.module( "../../src/modules/cw-utils/opportunities/opportunities", () => ({ opportunityCw: { update: mock(() => Promise.reject(new Error("API fail"))), }, }), ); const { syncOpportunityStatus } = await import("../../src/services/cw.opportunityService"); const result = await syncOpportunityStatus({ opportunityId: 1001, statusCwId: 24, }); expect(result.success).toBe(false); expect(result.message).toContain("Failed"); }); }); });