221 lines
5.1 KiB
TypeScript
221 lines
5.1 KiB
TypeScript
import { afterEach, expect, test, vi } from "vitest";
|
|
|
|
import { POST } from "../../../app/api/orders/route";
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
test("proxies order creation to the backend and returns normalized success data", async () => {
|
|
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
|
|
|
|
const fetchMock = vi.fn().mockResolvedValue(
|
|
new Response(
|
|
JSON.stringify({
|
|
order_id: 77,
|
|
workflow_id: "wf-77",
|
|
status: "created",
|
|
}),
|
|
{
|
|
status: 201,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
},
|
|
),
|
|
);
|
|
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
const request = new Request("http://localhost/api/orders", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
customer_level: "mid",
|
|
service_mode: "semi_pro",
|
|
model_id: 101,
|
|
garment_asset_id: 303,
|
|
scene_ref_asset_id: 404,
|
|
}),
|
|
});
|
|
|
|
const response = await POST(request);
|
|
const payload = await response.json();
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(payload).toEqual({
|
|
mode: "proxy",
|
|
data: {
|
|
orderId: 77,
|
|
workflowId: "wf-77",
|
|
status: "created",
|
|
},
|
|
});
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"http://backend.test/api/v1/orders",
|
|
expect.objectContaining({
|
|
method: "POST",
|
|
}),
|
|
);
|
|
});
|
|
|
|
test("rejects invalid order creation payloads before proxying", async () => {
|
|
const fetchMock = vi.fn();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
const request = new Request("http://localhost/api/orders", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
customer_level: "low",
|
|
service_mode: "semi_pro",
|
|
model_id: 101,
|
|
garment_asset_id: 303,
|
|
scene_ref_asset_id: 404,
|
|
}),
|
|
});
|
|
|
|
const response = await POST(request);
|
|
const payload = await response.json();
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(payload).toMatchObject({
|
|
error: "VALIDATION_ERROR",
|
|
});
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("rejects malformed JSON before validation or proxying", async () => {
|
|
const fetchMock = vi.fn();
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
const request = new Request("http://localhost/api/orders", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: "{bad json",
|
|
});
|
|
|
|
const response = await POST(request);
|
|
const payload = await response.json();
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(payload).toEqual({
|
|
error: "INVALID_JSON",
|
|
message: "请求体必须是合法 JSON。",
|
|
});
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("normalizes upstream validation errors from the backend", async () => {
|
|
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
|
|
|
|
const fetchMock = vi.fn().mockResolvedValue(
|
|
new Response(
|
|
JSON.stringify({
|
|
detail: "scene_ref_asset_id is invalid",
|
|
}),
|
|
{
|
|
status: 422,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
},
|
|
),
|
|
);
|
|
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
const request = new Request("http://localhost/api/orders", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
customer_level: "mid",
|
|
service_mode: "semi_pro",
|
|
model_id: 101,
|
|
garment_asset_id: 303,
|
|
scene_ref_asset_id: 404,
|
|
}),
|
|
});
|
|
|
|
const response = await POST(request);
|
|
const payload = await response.json();
|
|
|
|
expect(response.status).toBe(400);
|
|
expect(payload).toEqual({
|
|
error: "VALIDATION_ERROR",
|
|
message: "scene_ref_asset_id is invalid",
|
|
details: {
|
|
detail: "scene_ref_asset_id is invalid",
|
|
},
|
|
});
|
|
});
|
|
|
|
test("accepts order creation payloads without a scene asset id", async () => {
|
|
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
|
|
|
|
const fetchMock = vi.fn().mockResolvedValue(
|
|
new Response(
|
|
JSON.stringify({
|
|
order_id: 88,
|
|
workflow_id: "wf-88",
|
|
status: "created",
|
|
}),
|
|
{
|
|
status: 201,
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
},
|
|
),
|
|
);
|
|
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
const request = new Request("http://localhost/api/orders", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
customer_level: "low",
|
|
service_mode: "auto_basic",
|
|
model_id: 101,
|
|
garment_asset_id: 303,
|
|
}),
|
|
});
|
|
|
|
const response = await POST(request);
|
|
const payload = await response.json();
|
|
|
|
expect(response.status).toBe(201);
|
|
expect(payload).toEqual({
|
|
mode: "proxy",
|
|
data: {
|
|
orderId: 88,
|
|
workflowId: "wf-88",
|
|
status: "created",
|
|
},
|
|
});
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"http://backend.test/api/v1/orders",
|
|
expect.objectContaining({
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
customer_level: "low",
|
|
service_mode: "auto_basic",
|
|
model_id: 101,
|
|
garment_asset_id: 303,
|
|
}),
|
|
}),
|
|
);
|
|
});
|