fix: 修复测试套件质量审查问题——act环境、正则匹配、mock排序、超时设置
This commit is contained in:
@@ -4,6 +4,13 @@
|
|||||||
* 噪声过滤对所有测试生效
|
* 噪声过滤对所有测试生效
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// eslint-disable-next-line no-var
|
||||||
|
var IS_REACT_ACT_ENVIRONMENT: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||||
|
|
||||||
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
||||||
process.stderr.write = (chunk: string | Uint8Array, encodingOrCb?: unknown, cb?: unknown) => {
|
process.stderr.write = (chunk: string | Uint8Array, encodingOrCb?: unknown, cb?: unknown) => {
|
||||||
const str = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
|
const str = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString();
|
||||||
@@ -19,6 +26,7 @@ const originalConsoleError = console.error;
|
|||||||
console.error = (...args: unknown[]) => {
|
console.error = (...args: unknown[]) => {
|
||||||
const message = args.map(String).join(" ");
|
const message = args.map(String).join(" ");
|
||||||
if (message.includes("NaN") && message.includes("height") && message.includes("css style property")) return;
|
if (message.includes("NaN") && message.includes("height") && message.includes("css style property")) return;
|
||||||
|
if (message.includes("not wrapped in act")) return;
|
||||||
originalConsoleError(...args);
|
originalConsoleError(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +87,9 @@ globalThis.Selection = class Selection {
|
|||||||
} as unknown as typeof Selection;
|
} as unknown as typeof Selection;
|
||||||
|
|
||||||
const { afterEach } = await import("bun:test");
|
const { afterEach } = await import("bun:test");
|
||||||
|
const { cleanup } = await import("@testing-library/react");
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
cleanup();
|
||||||
document.body.innerHTML = "";
|
document.body.innerHTML = "";
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ function setupFetchMock() {
|
|||||||
if (call.url.includes("/models")) {
|
if (call.url.includes("/models")) {
|
||||||
return jsonResponse({ items: [TEXT_MODEL], total: 1 });
|
return jsonResponse({ items: [TEXT_MODEL], total: 1 });
|
||||||
}
|
}
|
||||||
|
if (call.url.includes("/messages")) {
|
||||||
|
return jsonResponse({ items: [], total: 0 });
|
||||||
|
}
|
||||||
|
if (call.method === "GET" && /\/conversations\/conv-/.exec(call.url)) {
|
||||||
|
return jsonResponse({ conversation: CONVERSATION });
|
||||||
|
}
|
||||||
if (call.url.includes("/conversations") && call.method === "GET") {
|
if (call.url.includes("/conversations") && call.method === "GET") {
|
||||||
return jsonResponse({ items: [CONVERSATION], page: 1, pageSize: 200, total: 1 });
|
return jsonResponse({ items: [CONVERSATION], page: 1, pageSize: 200, total: 1 });
|
||||||
}
|
}
|
||||||
@@ -63,12 +69,6 @@ function setupFetchMock() {
|
|||||||
if (call.method === "DELETE" && call.url.includes("/conversations/")) {
|
if (call.method === "DELETE" && call.url.includes("/conversations/")) {
|
||||||
return new Response(null, { status: 204 });
|
return new Response(null, { status: 204 });
|
||||||
}
|
}
|
||||||
if (call.url.includes("/messages")) {
|
|
||||||
return jsonResponse({ items: [], total: 0 });
|
|
||||||
}
|
|
||||||
if (/\/conversations\/conv-1$/.exec(call.url)) {
|
|
||||||
return jsonResponse({ conversation: CONVERSATION });
|
|
||||||
}
|
|
||||||
return jsonResponse({ error: "not found" }, { status: 404 });
|
return jsonResponse({ error: "not found" }, { status: 404 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -143,15 +143,18 @@ describe("ChatPage", () => {
|
|||||||
if (call.url.includes("/models")) {
|
if (call.url.includes("/models")) {
|
||||||
return jsonResponse({ items: [TEXT_MODEL], total: 1 });
|
return jsonResponse({ items: [TEXT_MODEL], total: 1 });
|
||||||
}
|
}
|
||||||
|
if (call.url.includes("/messages")) {
|
||||||
|
return jsonResponse({ items: [], total: 0 });
|
||||||
|
}
|
||||||
|
if (call.method === "GET" && /\/conversations\/conv-/.exec(call.url)) {
|
||||||
|
return jsonResponse({ conversation: CONVERSATION });
|
||||||
|
}
|
||||||
if (call.url.includes("/conversations") && call.method === "GET") {
|
if (call.url.includes("/conversations") && call.method === "GET") {
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
return jsonResponse({ items: [], page: 1, pageSize: 200, total: 0 });
|
return jsonResponse({ items: [], page: 1, pageSize: 200, total: 0 });
|
||||||
}
|
}
|
||||||
return jsonResponse({ items: [CONVERSATION], page: 1, pageSize: 200, total: 1 });
|
return jsonResponse({ items: [CONVERSATION], page: 1, pageSize: 200, total: 1 });
|
||||||
}
|
}
|
||||||
if (call.url.includes("/messages")) {
|
|
||||||
return jsonResponse({ items: [], total: 0 });
|
|
||||||
}
|
|
||||||
return jsonResponse({ error: "not found" }, { status: 404 });
|
return jsonResponse({ error: "not found" }, { status: 404 });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const DEEPSEEK_PROVIDER: Provider = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function clickLatestConfirmButton() {
|
function clickLatestConfirmButton() {
|
||||||
const buttons = screen.getAllByRole("button", { name: /OK|确定/ });
|
const buttons = screen.getAllByRole("button", { name: /OK|确\s*定/ });
|
||||||
fireEvent.click(buttons[buttons.length - 1]!);
|
fireEvent.click(buttons[buttons.length - 1]!);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,28 +149,37 @@ const TABLE_ACTION_TEST_CASES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
describe("ResourceTable", () => {
|
describe("ResourceTable", () => {
|
||||||
|
// Ant Design Table 在 happy-dom 中渲染较慢,并行测试时需要更多时间
|
||||||
for (const tc of TABLE_TEST_CASES) {
|
for (const tc of TABLE_TEST_CASES) {
|
||||||
test(`${tc.componentName} 渲染表格数据`, () => {
|
test(
|
||||||
tc.render();
|
`${tc.componentName} 渲染表格数据`,
|
||||||
tc.assertData();
|
() => {
|
||||||
tc.assertNoExtra();
|
tc.render();
|
||||||
});
|
tc.assertData();
|
||||||
|
tc.assertNoExtra();
|
||||||
|
},
|
||||||
|
{ timeout: 30000 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const tc of TABLE_ACTION_TEST_CASES) {
|
for (const tc of TABLE_ACTION_TEST_CASES) {
|
||||||
test(`${tc.componentName} 表格操作触发 edit/delete`, async () => {
|
test(
|
||||||
const onDelete = mock(() => Promise.resolve());
|
`${tc.componentName} 表格操作触发 edit/delete`,
|
||||||
const onEdit = mock(() => undefined);
|
async () => {
|
||||||
|
const onDelete = mock(() => Promise.resolve());
|
||||||
|
const onEdit = mock(() => undefined);
|
||||||
|
|
||||||
tc.render({ onDelete, onEdit });
|
tc.render({ onDelete, onEdit });
|
||||||
|
|
||||||
fireEvent.click(screen.getAllByRole("button", { name: /编辑/ })[0]!);
|
fireEvent.click(screen.getAllByRole("button", { name: /编辑/ })[0]!);
|
||||||
expect(onEdit).toHaveBeenCalledWith(tc.editArg);
|
expect(onEdit).toHaveBeenCalledWith(tc.editArg);
|
||||||
|
|
||||||
fireEvent.click(screen.getAllByRole("button", { name: /删除/ })[0]!);
|
fireEvent.click(screen.getAllByRole("button", { name: /删除/ })[0]!);
|
||||||
await screen.findByText(tc.deleteConfirmText);
|
await screen.findByText(tc.deleteConfirmText);
|
||||||
clickLatestConfirmButton();
|
clickLatestConfirmButton();
|
||||||
await waitFor(() => expect(onDelete).toHaveBeenCalledWith(tc.deleteId));
|
await waitFor(() => expect(onDelete).toHaveBeenCalledWith(tc.deleteId));
|
||||||
});
|
},
|
||||||
|
{ timeout: 30000 },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -55,10 +55,13 @@ describe("AddMaterialModal", () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByText("确 定"));
|
fireEvent.click(screen.getByText("确 定"));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(
|
||||||
expect(screen.getByText("请输入描述")).not.toBeNull();
|
() => {
|
||||||
});
|
expect(screen.getByText("请输入描述")).not.toBeNull();
|
||||||
});
|
},
|
||||||
|
{ timeout: 10000 },
|
||||||
|
);
|
||||||
|
}, 30000);
|
||||||
|
|
||||||
test("点击确定触发表单提交", async () => {
|
test("点击确定触发表单提交", async () => {
|
||||||
const onAdd = vi.fn<(body: CreateMaterialRequest) => Promise<Material>>();
|
const onAdd = vi.fn<(body: CreateMaterialRequest) => Promise<Material>>();
|
||||||
@@ -76,16 +79,19 @@ describe("AddMaterialModal", () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByText("确 定"));
|
fireEvent.click(screen.getByText("确 定"));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(
|
||||||
expect(onAdd).toHaveBeenCalledTimes(1);
|
() => {
|
||||||
});
|
expect(onAdd).toHaveBeenCalledTimes(1);
|
||||||
|
},
|
||||||
|
{ timeout: 10000 },
|
||||||
|
);
|
||||||
|
|
||||||
const callArgs = onAdd.mock.calls[0];
|
const callArgs = onAdd.mock.calls[0];
|
||||||
expect(callArgs).toBeDefined();
|
expect(callArgs).toBeDefined();
|
||||||
const calledBody = callArgs![0];
|
const calledBody = callArgs![0];
|
||||||
expect(calledBody.description).toBe("测试描述");
|
expect(calledBody.description).toBe("测试描述");
|
||||||
expect(calledBody.associatedDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
expect(calledBody.associatedDate).toMatch(/^\d{4}-\d{2}-\d{2}$/);
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("提交失败显示错误提示", async () => {
|
test("提交失败显示错误提示", async () => {
|
||||||
const onAdd = vi.fn<(body: CreateMaterialRequest) => Promise<Material>>();
|
const onAdd = vi.fn<(body: CreateMaterialRequest) => Promise<Material>>();
|
||||||
@@ -103,8 +109,11 @@ describe("AddMaterialModal", () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByText("确 定"));
|
fireEvent.click(screen.getByText("确 定"));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(
|
||||||
expect(onAdd).toHaveBeenCalledTimes(1);
|
() => {
|
||||||
});
|
expect(onAdd).toHaveBeenCalledTimes(1);
|
||||||
});
|
},
|
||||||
|
{ timeout: 10000 },
|
||||||
|
);
|
||||||
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ describe("InboxPage", () => {
|
|||||||
const cards = screen.getAllByText("新增的素材");
|
const cards = screen.getAllByText("新增的素材");
|
||||||
expect(cards.length).toBeGreaterThanOrEqual(1);
|
expect(cards.length).toBeGreaterThanOrEqual(1);
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("删除素材后列表更新", async () => {
|
test("删除素材后列表更新", async () => {
|
||||||
let deleted = false;
|
let deleted = false;
|
||||||
@@ -131,5 +131,5 @@ describe("InboxPage", () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(screen.getByText("暂无素材")).not.toBeNull();
|
expect(screen.getByText("暂无素材")).not.toBeNull();
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ describe("ModelSettingsCard", () => {
|
|||||||
expect(screen.getByText("音频生成")).not.toBeNull();
|
expect(screen.getByText("音频生成")).not.toBeNull();
|
||||||
expect(screen.getByText("视频生成")).not.toBeNull();
|
expect(screen.getByText("视频生成")).not.toBeNull();
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("回显已保存的默认模型值", async () => {
|
test("回显已保存的默认模型值", async () => {
|
||||||
installFetchMock((call) => {
|
installFetchMock((call) => {
|
||||||
@@ -63,5 +63,5 @@ describe("ModelSettingsCard", () => {
|
|||||||
expect(screen.getByText("GPT-4")).not.toBeNull();
|
expect(screen.getByText("GPT-4")).not.toBeNull();
|
||||||
expect(screen.getByText("Claude Vision")).not.toBeNull();
|
expect(screen.getByText("Claude Vision")).not.toBeNull();
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,34 +46,38 @@ function clickLatestConfirmButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("ModelFormModal", () => {
|
describe("ModelFormModal", () => {
|
||||||
test("编辑模型表单只提交变更字段", async () => {
|
test(
|
||||||
const updateCalls: unknown[] = [];
|
"编辑模型表单只提交变更字段",
|
||||||
|
async () => {
|
||||||
|
const updateCalls: unknown[] = [];
|
||||||
|
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
createElement(ModelFormModal, {
|
createElement(ModelFormModal, {
|
||||||
editingModel: ENABLED_MODEL,
|
editingModel: ENABLED_MODEL,
|
||||||
onCancel: () => undefined,
|
onCancel: () => undefined,
|
||||||
onCreate: () => Promise.resolve(),
|
onCreate: () => Promise.resolve(),
|
||||||
onOpenChange: () => undefined,
|
onOpenChange: () => undefined,
|
||||||
onUpdate: (args: unknown) => {
|
onUpdate: (args: unknown) => {
|
||||||
updateCalls.push(args);
|
updateCalls.push(args);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
open: true,
|
open: true,
|
||||||
providers: [ENABLED_PROVIDER, DISABLED_PROVIDER],
|
providers: [ENABLED_PROVIDER, DISABLED_PROVIDER],
|
||||||
providersError: null,
|
providersError: null,
|
||||||
providersLoading: false,
|
providersLoading: false,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await screen.findByPlaceholderText("请输入模型名称");
|
await screen.findByPlaceholderText("请输入模型名称");
|
||||||
fireEvent.change(screen.getByPlaceholderText("请输入模型名称"), { target: { value: "GPT-4o Mini" } });
|
fireEvent.change(screen.getByPlaceholderText("请输入模型名称"), { target: { value: "GPT-4o Mini" } });
|
||||||
clickLatestConfirmButton();
|
clickLatestConfirmButton();
|
||||||
|
|
||||||
await waitFor(() => expect(updateCalls.length).toBe(1));
|
await waitFor(() => expect(updateCalls.length).toBe(1));
|
||||||
expect(updateCalls[0]).toEqual({ data: { name: "GPT-4o Mini" }, id: "m1" });
|
expect(updateCalls[0]).toEqual({ data: { name: "GPT-4o Mini" }, id: "m1" });
|
||||||
});
|
},
|
||||||
|
{ timeout: 15000 },
|
||||||
|
);
|
||||||
|
|
||||||
test("模型表单校验失败不会提交", async () => {
|
test("模型表单校验失败不会提交", async () => {
|
||||||
const onCreate = mock(() => Promise.resolve());
|
const onCreate = mock(() => Promise.resolve());
|
||||||
@@ -121,80 +125,92 @@ describe("ModelFormModal", () => {
|
|||||||
expect((reasoningCheckbox as { checked?: boolean }).checked).toBe(true);
|
expect((reasoningCheckbox as { checked?: boolean }).checked).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("新建模型展示供应商 options 列表", async () => {
|
test(
|
||||||
renderWithProviders(
|
"新建模型展示供应商 options 列表",
|
||||||
createElement(ModelFormModal, {
|
async () => {
|
||||||
editingModel: null,
|
renderWithProviders(
|
||||||
onCancel: () => undefined,
|
createElement(ModelFormModal, {
|
||||||
onCreate: () => Promise.resolve(),
|
editingModel: null,
|
||||||
onOpenChange: () => undefined,
|
onCancel: () => undefined,
|
||||||
onUpdate: () => Promise.resolve(),
|
onCreate: () => Promise.resolve(),
|
||||||
open: true,
|
onOpenChange: () => undefined,
|
||||||
providers: [ENABLED_PROVIDER, DISABLED_PROVIDER],
|
onUpdate: () => Promise.resolve(),
|
||||||
providersError: null,
|
open: true,
|
||||||
providersLoading: false,
|
providers: [ENABLED_PROVIDER, DISABLED_PROVIDER],
|
||||||
submitting: false,
|
providersError: null,
|
||||||
}),
|
providersLoading: false,
|
||||||
);
|
submitting: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
await screen.findByPlaceholderText("请输入模型名称");
|
await screen.findByPlaceholderText("请输入模型名称");
|
||||||
fireEvent.mouseDown(screen.getByRole("combobox"));
|
fireEvent.mouseDown(screen.getByRole("combobox"));
|
||||||
|
|
||||||
expect(await screen.findByText("OpenAI")).not.toBeNull();
|
expect(await screen.findByText("OpenAI")).not.toBeNull();
|
||||||
expect(await screen.findByText("DeepSeek")).not.toBeNull();
|
expect(await screen.findByText("DeepSeek")).not.toBeNull();
|
||||||
});
|
},
|
||||||
|
{ timeout: 15000 },
|
||||||
|
);
|
||||||
|
|
||||||
test("供应商下拉展示加载错误提示", async () => {
|
test(
|
||||||
renderWithProviders(
|
"供应商下拉展示加载错误提示",
|
||||||
createElement(ModelFormModal, {
|
async () => {
|
||||||
editingModel: null,
|
renderWithProviders(
|
||||||
onCancel: () => undefined,
|
createElement(ModelFormModal, {
|
||||||
onCreate: () => Promise.resolve(),
|
editingModel: null,
|
||||||
onOpenChange: () => undefined,
|
onCancel: () => undefined,
|
||||||
onUpdate: () => Promise.resolve(),
|
onCreate: () => Promise.resolve(),
|
||||||
open: true,
|
onOpenChange: () => undefined,
|
||||||
providers: [],
|
onUpdate: () => Promise.resolve(),
|
||||||
providersError: new Error("options failed"),
|
open: true,
|
||||||
providersLoading: false,
|
providers: [],
|
||||||
submitting: false,
|
providersError: new Error("options failed"),
|
||||||
}),
|
providersLoading: false,
|
||||||
);
|
submitting: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
await screen.findByPlaceholderText("请输入模型名称");
|
await screen.findByPlaceholderText("请输入模型名称");
|
||||||
fireEvent.mouseDown(screen.getByRole("combobox"));
|
fireEvent.mouseDown(screen.getByRole("combobox"));
|
||||||
|
|
||||||
expect(await screen.findByText("供应商加载失败:options failed")).not.toBeNull();
|
expect(await screen.findByText("供应商加载失败:options failed")).not.toBeNull();
|
||||||
});
|
},
|
||||||
|
{ timeout: 15000 },
|
||||||
|
);
|
||||||
|
|
||||||
test("编辑模型时可测试模型连接", async () => {
|
test(
|
||||||
const testModelConnection = mock(() => Promise.resolve({ message: "模型连接成功", ok: true }));
|
"编辑模型时可测试模型连接",
|
||||||
|
async () => {
|
||||||
|
const testModelConnection = mock(() => Promise.resolve({ message: "模型连接成功", ok: true }));
|
||||||
|
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
createElement(ModelFormModal, {
|
createElement(ModelFormModal, {
|
||||||
editingModel: ENABLED_MODEL,
|
editingModel: ENABLED_MODEL,
|
||||||
onCancel: () => undefined,
|
onCancel: () => undefined,
|
||||||
onCreate: () => Promise.resolve(),
|
onCreate: () => Promise.resolve(),
|
||||||
onOpenChange: () => undefined,
|
onOpenChange: () => undefined,
|
||||||
onUpdate: () => Promise.resolve(),
|
onUpdate: () => Promise.resolve(),
|
||||||
open: true,
|
open: true,
|
||||||
providers: [ENABLED_PROVIDER],
|
providers: [ENABLED_PROVIDER],
|
||||||
providersError: null,
|
providersError: null,
|
||||||
providersLoading: false,
|
providersLoading: false,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
testModelConnection,
|
testModelConnection,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await screen.findByRole("button", { name: "测试连接" });
|
await screen.findByRole("button", { name: "测试连接" });
|
||||||
fireEvent.click(screen.getByRole("button", { name: "测试连接" }));
|
fireEvent.click(screen.getByRole("button", { name: "测试连接" }));
|
||||||
|
|
||||||
await waitFor(() =>
|
await waitFor(() =>
|
||||||
expect(testModelConnection).toHaveBeenCalledWith({
|
expect(testModelConnection).toHaveBeenCalledWith({
|
||||||
externalId: "gpt-4o",
|
externalId: "gpt-4o",
|
||||||
providerId: "pv1",
|
providerId: "pv1",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
{ timeout: 15000 },
|
||||||
|
);
|
||||||
|
|
||||||
test("新建模型也显示测试连接按钮", async () => {
|
test("新建模型也显示测试连接按钮", async () => {
|
||||||
renderWithProviders(
|
renderWithProviders(
|
||||||
@@ -300,7 +316,7 @@ describe("ModelListPage", () => {
|
|||||||
expect(screen.getByPlaceholderText("搜索模型名称或 ID")).not.toBeNull();
|
expect(screen.getByPlaceholderText("搜索模型名称或 ID")).not.toBeNull();
|
||||||
expect(screen.getByRole("button", { name: /新建模型/ })).not.toBeNull();
|
expect(screen.getByRole("button", { name: /新建模型/ })).not.toBeNull();
|
||||||
expect(calls.some((call) => call.url.includes("/api/models"))).toBe(true);
|
expect(calls.some((call) => call.url.includes("/api/models"))).toBe(true);
|
||||||
}, 15000);
|
}, 30000);
|
||||||
|
|
||||||
test("搜索模型更新请求参数", async () => {
|
test("搜索模型更新请求参数", async () => {
|
||||||
const calls = createModelFetchMock();
|
const calls = createModelFetchMock();
|
||||||
@@ -312,7 +328,7 @@ describe("ModelListPage", () => {
|
|||||||
fireEvent.change(input, { target: { value: "gpt" } });
|
fireEvent.change(input, { target: { value: "gpt" } });
|
||||||
fireEvent.keyDown(input, { key: "Enter" });
|
fireEvent.keyDown(input, { key: "Enter" });
|
||||||
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=gpt"))).toBe(true));
|
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=gpt"))).toBe(true));
|
||||||
}, 15000);
|
}, 30000);
|
||||||
|
|
||||||
test("新建模型弹窗可以打开", async () => {
|
test("新建模型弹窗可以打开", async () => {
|
||||||
createModelFetchMock();
|
createModelFetchMock();
|
||||||
@@ -322,5 +338,5 @@ describe("ModelListPage", () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: /新建模型/ }));
|
fireEvent.click(screen.getByRole("button", { name: /新建模型/ }));
|
||||||
await screen.findByPlaceholderText("请输入模型名称");
|
await screen.findByPlaceholderText("请输入模型名称");
|
||||||
}, 15000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ describe("ProjectsPage", () => {
|
|||||||
await waitFor(() => expect(calls.some((call) => call.url.includes("status=archived"))).toBe(true));
|
await waitFor(() => expect(calls.some((call) => call.url.includes("status=archived"))).toBe(true));
|
||||||
|
|
||||||
await screen.findByText("归档项目");
|
await screen.findByText("归档项目");
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("清空搜索条件复位请求参数并重新展示全部项目", async () => {
|
test("清空搜索条件复位请求参数并重新展示全部项目", async () => {
|
||||||
const calls = createProjectFetchMock();
|
const calls = createProjectFetchMock();
|
||||||
@@ -190,7 +190,7 @@ describe("ProjectsPage", () => {
|
|||||||
const createCall = calls.find((call) => call.url.endsWith("/api/projects") && call.method === "POST");
|
const createCall = calls.find((call) => call.url.endsWith("/api/projects") && call.method === "POST");
|
||||||
expect(createCall).toBeDefined();
|
expect(createCall).toBeDefined();
|
||||||
expect(jsonBody(createCall?.body)).toEqual({ description: "新增描述", name: "新增项目" });
|
expect(jsonBody(createCall?.body)).toEqual({ description: "新增描述", name: "新增项目" });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("编辑项目表单只提交变更字段", async () => {
|
test("编辑项目表单只提交变更字段", async () => {
|
||||||
const updateCalls: unknown[] = [];
|
const updateCalls: unknown[] = [];
|
||||||
@@ -217,7 +217,7 @@ describe("ProjectsPage", () => {
|
|||||||
|
|
||||||
await waitFor(() => expect(onUpdate).toHaveBeenCalled());
|
await waitFor(() => expect(onUpdate).toHaveBeenCalled());
|
||||||
expect(updateCalls[0]).toEqual({ data: { name: "编辑项目" }, id: "p1" });
|
expect(updateCalls[0]).toEqual({ data: { name: "编辑项目" }, id: "p1" });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("项目表单校验失败不会提交,接口失败时保留弹窗", async () => {
|
test("项目表单校验失败不会提交,接口失败时保留弹窗", async () => {
|
||||||
const onCreate = mock(() => Promise.reject(new Error("创建失败")));
|
const onCreate = mock(() => Promise.reject(new Error("创建失败")));
|
||||||
@@ -244,7 +244,7 @@ describe("ProjectsPage", () => {
|
|||||||
await waitFor(() => expect(onCreate).toHaveBeenCalled());
|
await waitFor(() => expect(onCreate).toHaveBeenCalled());
|
||||||
expect(onOpenChange).not.toHaveBeenCalledWith(false);
|
expect(onOpenChange).not.toHaveBeenCalledWith(false);
|
||||||
expect(screen.getByText("新建项目")).not.toBeNull();
|
expect(screen.getByText("新建项目")).not.toBeNull();
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("项目表格操作触发导航和行级动作", async () => {
|
test("项目表格操作触发导航和行级动作", async () => {
|
||||||
const onArchive = mock(() => Promise.resolve());
|
const onArchive = mock(() => Promise.resolve());
|
||||||
@@ -287,5 +287,5 @@ describe("ProjectsPage", () => {
|
|||||||
await screen.findByText("确认永久删除此项目?");
|
await screen.findByText("确认永久删除此项目?");
|
||||||
await clickLatestConfirmButton();
|
await clickLatestConfirmButton();
|
||||||
await waitFor(() => expect(onDelete).toHaveBeenCalledWith("p2"));
|
await waitFor(() => expect(onDelete).toHaveBeenCalledWith("p2"));
|
||||||
}, 15000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ describe("ProviderFormModal", () => {
|
|||||||
|
|
||||||
await waitFor(() => expect(updateCalls.length).toBe(1));
|
await waitFor(() => expect(updateCalls.length).toBe(1));
|
||||||
expect(updateCalls[0]).toEqual({ data: { name: "New OpenAI" }, id: "pv1" });
|
expect(updateCalls[0]).toEqual({ data: { name: "New OpenAI" }, id: "pv1" });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("新建供应商默认使用 openai-compatible 类型", async () => {
|
test("新建供应商默认使用 openai-compatible 类型", async () => {
|
||||||
const createCalls: unknown[] = [];
|
const createCalls: unknown[] = [];
|
||||||
@@ -85,7 +85,7 @@ describe("ProviderFormModal", () => {
|
|||||||
name: "兼容供应商",
|
name: "兼容供应商",
|
||||||
type: "openai-compatible",
|
type: "openai-compatible",
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("供应商表单可使用当前表单配置测试连接", async () => {
|
test("供应商表单可使用当前表单配置测试连接", async () => {
|
||||||
const testCalls: unknown[] = [];
|
const testCalls: unknown[] = [];
|
||||||
@@ -121,7 +121,7 @@ describe("ProviderFormModal", () => {
|
|||||||
name: "兼容供应商",
|
name: "兼容供应商",
|
||||||
type: "openai-compatible",
|
type: "openai-compatible",
|
||||||
});
|
});
|
||||||
});
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|
||||||
const TEST_PROVIDER: Provider = {
|
const TEST_PROVIDER: Provider = {
|
||||||
@@ -197,7 +197,7 @@ describe("ProviderListPage", () => {
|
|||||||
expect(screen.getByPlaceholderText("搜索供应商名称")).not.toBeNull();
|
expect(screen.getByPlaceholderText("搜索供应商名称")).not.toBeNull();
|
||||||
expect(screen.getByRole("button", { name: /新建供应商/ })).not.toBeNull();
|
expect(screen.getByRole("button", { name: /新建供应商/ })).not.toBeNull();
|
||||||
expect(calls.some((call) => call.url.includes("/api/providers"))).toBe(true);
|
expect(calls.some((call) => call.url.includes("/api/providers"))).toBe(true);
|
||||||
}, 15000);
|
}, 30000);
|
||||||
|
|
||||||
test("搜索供应商更新请求参数", async () => {
|
test("搜索供应商更新请求参数", async () => {
|
||||||
const calls = createProviderFetchMock();
|
const calls = createProviderFetchMock();
|
||||||
@@ -209,7 +209,7 @@ describe("ProviderListPage", () => {
|
|||||||
fireEvent.change(input, { target: { value: "Open" } });
|
fireEvent.change(input, { target: { value: "Open" } });
|
||||||
fireEvent.keyDown(input, { key: "Enter" });
|
fireEvent.keyDown(input, { key: "Enter" });
|
||||||
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=Open"))).toBe(true));
|
await waitFor(() => expect(calls.some((call) => call.url.includes("keyword=Open"))).toBe(true));
|
||||||
}, 15000);
|
}, 30000);
|
||||||
|
|
||||||
test("新建供应商弹窗可以打开", async () => {
|
test("新建供应商弹窗可以打开", async () => {
|
||||||
createProviderFetchMock();
|
createProviderFetchMock();
|
||||||
@@ -219,5 +219,5 @@ describe("ProviderListPage", () => {
|
|||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: /新建供应商/ }));
|
fireEvent.click(screen.getByRole("button", { name: /新建供应商/ }));
|
||||||
await screen.findByPlaceholderText("请输入供应商名称");
|
await screen.findByPlaceholderText("请输入供应商名称");
|
||||||
}, 15000);
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe("Workbench 路由", () => {
|
|||||||
},
|
},
|
||||||
{ timeout: 10000 },
|
{ timeout: 10000 },
|
||||||
);
|
);
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("Workbench 显示返回管理台按钮", async () => {
|
test("Workbench 显示返回管理台按钮", async () => {
|
||||||
createMockHandler();
|
createMockHandler();
|
||||||
@@ -75,7 +75,7 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("返回管理台", {}, { timeout: 10000 });
|
await screen.findByText("返回管理台", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("不存在项目显示不可访问", async () => {
|
test("不存在项目显示不可访问", async () => {
|
||||||
createMockHandler();
|
createMockHandler();
|
||||||
@@ -85,7 +85,7 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("项目不存在或不可访问", {}, { timeout: 10000 });
|
await screen.findByText("项目不存在或不可访问", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("archived 项目显示不可访问", async () => {
|
test("archived 项目显示不可访问", async () => {
|
||||||
createMockHandler({ status: "archived" });
|
createMockHandler({ status: "archived" });
|
||||||
@@ -95,7 +95,7 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("项目不存在或不可访问", {}, { timeout: 10000 });
|
await screen.findByText("项目不存在或不可访问", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("Workbench 显示聊天室菜单", async () => {
|
test("Workbench 显示聊天室菜单", async () => {
|
||||||
createMockHandler();
|
createMockHandler();
|
||||||
@@ -105,7 +105,7 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("聊天室", {}, { timeout: 10000 });
|
await screen.findByText("聊天室", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("Workbench 收集箱路由可达", async () => {
|
test("Workbench 收集箱路由可达", async () => {
|
||||||
createMockHandler();
|
createMockHandler();
|
||||||
@@ -115,7 +115,7 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("新增素材", {}, { timeout: 10000 });
|
await screen.findByText("新增素材", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
|
|
||||||
test("Workbench 显示收集箱菜单", async () => {
|
test("Workbench 显示收集箱菜单", async () => {
|
||||||
createMockHandler();
|
createMockHandler();
|
||||||
@@ -125,5 +125,5 @@ describe("Workbench 路由", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await screen.findByText("收集箱", {}, { timeout: 10000 });
|
await screen.findByText("收集箱", {}, { timeout: 10000 });
|
||||||
});
|
}, 30000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,32 +24,10 @@ describe("getDateGroup", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("本周内的日期返回 thisWeek", () => {
|
test("本周内的日期返回 thisWeek", () => {
|
||||||
const now = new Date();
|
const now = new Date(2026, 5, 10);
|
||||||
const dayOfWeek = now.getDay();
|
const monday = new Date(2026, 5, 8);
|
||||||
const mondayOffset = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
|
const result = getDateGroup(monday.toISOString(), now);
|
||||||
const wednesday = new Date(now);
|
expect(result).toBe("thisWeek");
|
||||||
wednesday.setDate(now.getDate() - (dayOfWeek === 0 ? 6 : dayOfWeek - 1) + 2);
|
|
||||||
if (wednesday > now) {
|
|
||||||
const tuesday = new Date(now);
|
|
||||||
tuesday.setDate(now.getDate() - mondayOffset + 1);
|
|
||||||
if (tuesday < now && tuesday.getDate() !== now.getDate() - 1) {
|
|
||||||
const result = getDateGroup(tuesday.toISOString(), now);
|
|
||||||
expect(result).toBe("thisWeek");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const tuesday = new Date(now);
|
|
||||||
tuesday.setDate(now.getDate() - mondayOffset + 1);
|
|
||||||
if (tuesday.toDateString() !== now.toDateString()) {
|
|
||||||
const yesterday = new Date(now);
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
if (tuesday.toDateString() !== yesterday.toDateString()) {
|
|
||||||
const result = getDateGroup(tuesday.toISOString(), now);
|
|
||||||
expect(result).toBe("thisWeek");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(true).toBe(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("本月内的日期返回 thisMonth", () => {
|
test("本月内的日期返回 thisMonth", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user