import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { resetEnvCache } from "@/lib/env"; import { CcHttpError } from "@/services/cc/errors"; import { CcHttpClient } from "@/services/cc/http"; import { ccAuth } from "@/services/cc/auth"; import { getMockTargetAPI, resetMockTargetAPI, } from "@/services/cc/mock-target-api"; import { getTargetSystemClient, setTargetSystemClientOverride, } from "@/services/cc/target-system-client"; import { isCcMock } from "@/services/cc/settings-config"; import { resolveWriteMode } from "@/services/cc/write-capability"; function enableTestMode() { process.env.DATABASE_URL = process.env.DATABASE_URL || "mysql://app:app@localhost:7023/email_forecast"; process.env.TEST_MODE = "1"; resetEnvCache(); resetMockTargetAPI(); setTargetSystemClientOverride(null); } function disableTestMode() { delete process.env.TEST_MODE; resetEnvCache(); resetMockTargetAPI(); setTargetSystemClientOverride(null); } describe("MockTargetAPI", () => { beforeEach(() => { enableTestMode(); }); afterEach(() => { disableTestMode(); }); it("records each request for assertions", async () => { const mock = getMockTargetAPI(); await mock.request("/Container/SaveContainer", { F_ContainerNo: "WHSU8127240" }); await mock.requestGet("/ConfigModule/GetShippingLineList"); const rec = mock.getRequests(); expect(rec).toHaveLength(2); expect(rec[0]).toMatchObject({ method: "POST", path: "/Container/SaveContainer", body: { F_ContainerNo: "WHSU8127240" }, }); expect(rec[1].method).toBe("GET"); expect(rec[1].path).toBe("/ConfigModule/GetShippingLineList"); }); it.each([ ["400", 400], ["401", 401], ["500", 500], ] as const)("can return %s", async (fault, code) => { const mock = getMockTargetAPI(); mock.setFault(fault); const res = await mock.request("/Container/SaveContainer", {}); expect(res.code).toBe(code); }); it("throws timeout as CcHttpError", async () => { const mock = getMockTargetAPI(); mock.setFault("timeout"); await expect(mock.request("/Container/SaveContainer", {})).rejects.toBeInstanceOf( CcHttpError, ); await expect(mock.request("/Container/SaveContainer", {})).rejects.toMatchObject({ timeout: true, }); }); it("returns partial success payload", async () => { const mock = getMockTargetAPI(); mock.setFault("partial"); const res = await mock.request("/Container/SaveStockBatchTransfer", {}); expect(res.code).toBe(200); expect(res.info).toBe("PARTIAL_SUCCESS"); expect(res.data).toMatchObject({ ok_count: 1, fail_count: 1 }); }); it("supports per-path fault overlay", async () => { const mock = getMockTargetAPI(); mock.setFault("ok"); mock.setFault("500", "/Container/SaveContainer"); const save = await mock.request("/Container/SaveContainer", {}); const list = await mock.request("/Container/GetContainerList", {}); expect(save.code).toBe(500); expect(list.code).toBe(200); }); }); describe("TargetSystemClient TEST_MODE wiring", () => { afterEach(() => { disableTestMode(); }); it("CcHttpClient.request goes to MockTargetAPI when TEST_MODE=1", async () => { enableTestMode(); const http = new CcHttpClient(ccAuth); const res = await http.request("/Container/SaveContainer", { entity: { F_ContainerNo: "ABCD1234567" }, }); expect(res.code).toBe(200); const rec = getMockTargetAPI().getRequests(); expect(rec.some((r) => r.path === "/Container/SaveContainer")).toBe(true); }); it("getTargetSystemClient returns mock in TEST_MODE", () => { enableTestMode(); expect(getTargetSystemClient()).toBe(getMockTargetAPI()); }); it("isCcMock is false and write mode is live so HTTP mock is reachable", async () => { enableTestMode(); expect(await isCcMock()).toBe(false); expect(await resolveWriteMode("save_container")).toBe("live"); expect(await resolveWriteMode("batch_transfer")).toBe("live"); }); });