feat: bootstrap auto virtual tryon admin frontend

This commit is contained in:
afei A
2026-03-27 23:38:50 +08:00
commit 98c6b741d6
119 changed files with 19046 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
import { afterEach, expect, test, vi } from "vitest";
import { GET } from "../../../app/api/reviews/pending/route";
afterEach(() => {
vi.unstubAllEnvs();
vi.unstubAllGlobals();
});
test("adapts an empty pending review list into a business-empty queue state", async () => {
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
const fetchMock = vi.fn().mockResolvedValue(
new Response(JSON.stringify([]), {
status: 200,
headers: {
"content-type": "application/json",
},
}),
);
vi.stubGlobal("fetch", fetchMock);
const response = await GET(new Request("http://localhost/api/reviews/pending"));
const payload = await response.json();
expect(response.status).toBe(200);
expect(payload).toEqual({
mode: "proxy",
data: {
items: [],
state: {
kind: "business-empty",
title: "暂无待审核订单",
description: "当前没有等待人工处理的审核任务。",
},
},
});
});
test("normalizes upstream server errors for pending review proxying", async () => {
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
const fetchMock = vi.fn().mockResolvedValue(
new Response(
JSON.stringify({
detail: "database unavailable",
}),
{
status: 503,
headers: {
"content-type": "application/json",
},
},
),
);
vi.stubGlobal("fetch", fetchMock);
const response = await GET(new Request("http://localhost/api/reviews/pending"));
const payload = await response.json();
expect(response.status).toBe(502);
expect(payload).toEqual({
error: "BACKEND_ERROR",
message: "database unavailable",
details: {
detail: "database unavailable",
},
});
});
test("enriches pending review items with workflow summary chips", async () => {
vi.stubEnv("BACKEND_BASE_URL", "http://backend.test/api/v1");
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
const url = input.toString();
if (url === "http://backend.test/api/v1/reviews/pending") {
return new Response(
JSON.stringify([
{
review_task_id: 301,
order_id: 101,
workflow_id: "wf-101",
current_step: "review",
created_at: "2026-03-27T00:00:00Z",
},
]),
{
status: 200,
headers: {
"content-type": "application/json",
},
},
);
}
if (url === "http://backend.test/api/v1/workflows/101") {
return new Response(
JSON.stringify({
order_id: 101,
workflow_id: "wf-101",
workflow_type: "mid_end",
workflow_status: "waiting_review",
current_step: "review",
steps: [
{
id: 1,
workflow_run_id: 9001,
step_name: "fusion",
step_status: "failed",
input_json: null,
output_json: null,
error_message: "fusion failed",
started_at: "2026-03-27T00:07:00Z",
ended_at: "2026-03-27T00:08:00Z",
},
{
id: 2,
workflow_run_id: 9001,
step_name: "review",
step_status: "waiting",
input_json: {
preview_uri: "mock://fusion-preview",
},
output_json: null,
error_message: null,
started_at: "2026-03-27T00:09:00Z",
ended_at: null,
},
],
created_at: "2026-03-27T00:00:00Z",
updated_at: "2026-03-27T00:10:00Z",
}),
{
status: 200,
headers: {
"content-type": "application/json",
},
},
);
}
throw new Error(`Unhandled fetch url: ${url}`);
});
vi.stubGlobal("fetch", fetchMock);
const response = await GET(new Request("http://localhost/api/reviews/pending"));
const payload = await response.json();
expect(response.status).toBe(200);
expect(payload.data.items[0]).toMatchObject({
orderId: 101,
workflowType: "mid_end",
hasMockAssets: true,
failureCount: 1,
});
});