You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
4.0 KiB

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");
});
});