Skip to content

Commit ec7dfc5

Browse files
author
延枚
committed
feat: 添加测试管理相关文件
- 添加 tool-registry/test-management.ts - 添加 tool-handlers/test-management.ts - 添加 operations/testhub/ 目录下的文件 - 修复构建错误:找不到 test-management 模块 Change-Id: I5465e0c4d27c434ab5618baf11ac7d196db2e510 Co-developed-by: Cursor <noreply@cursor.com>
1 parent ddc444b commit ec7dfc5

File tree

4 files changed

+585
-0
lines changed

4 files changed

+585
-0
lines changed

operations/testhub/testcases.ts

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
import { z } from 'zod';
2+
import { yunxiaoRequest } from '../../common/utils.js';
3+
4+
// Schema for TestcaseDirectoryDTO
5+
export const TestcaseDirectoryDTOSchema = z.object({
6+
id: z.string().describe("目录id"),
7+
name: z.string().describe("目录名称"),
8+
parentId: z.string().nullable().optional().describe("父目录id"),
9+
});
10+
11+
// Schema for CreateTestcaseDirectoryRequest
12+
export const CreateTestcaseDirectoryRequestSchema = z.object({
13+
organizationId: z.string().describe("组织ID"),
14+
testRepoId: z.string().describe("用例库唯一标识"),
15+
name: z.string().describe("目录名称"),
16+
parentIdentifier: z.string().optional().describe("父目录ID"),
17+
});
18+
19+
export const CreateTestcaseDirectoryResponseSchema = TestcaseDirectoryDTOSchema;
20+
21+
// Schema for ListDirectories
22+
export const ListDirectoriesRequestSchema = z.object({
23+
organizationId: z.string().describe("组织ID"),
24+
testRepoId: z.string().describe("用例库唯一标识"),
25+
});
26+
27+
export const ListDirectoriesResponseSchema = z.array(TestcaseDirectoryDTOSchema);
28+
29+
// Schema for WorkitemSimpleFiled
30+
export const WorkitemSimpleFiledSchema = z.object({
31+
id: z.string().describe("字段id"),
32+
name: z.string().describe("名称"),
33+
type: z.string().describe("字段类型"),
34+
format: z.string().nullable().optional().describe("字段格式"),
35+
required: z.boolean().optional().describe("是否必填"),
36+
showWhenCreate: z.boolean().optional().describe("创建时是否展示"),
37+
description: z.string().nullable().optional().describe("描述"),
38+
defaultValue: z.string().nullable().optional().describe("默认值"),
39+
options: z.array(z.object({
40+
id: z.string().optional(),
41+
value: z.string().optional(),
42+
displayValue: z.string().optional(),
43+
valueEn: z.string().optional(),
44+
})).optional().describe("可选值"),
45+
cascadingOptions: z.any().nullable().optional().describe("层级字段的待选择"),
46+
});
47+
48+
// Schema for GetTestcaseFieldConfig
49+
export const GetTestcaseFieldConfigRequestSchema = z.object({
50+
organizationId: z.string().describe("组织ID"),
51+
testRepoId: z.string().describe("用例库唯一标识"),
52+
});
53+
54+
export const GetTestcaseFieldConfigResponseSchema = z.array(WorkitemSimpleFiledSchema);
55+
56+
// Schema for TestStep
57+
export const TestStepSchema = z.object({
58+
step: z.string().describe("测试步骤"),
59+
expected: z.string().describe("期望结果"),
60+
});
61+
62+
// Schema for TestStepsDTO
63+
export const TestStepsDTOSchema = z.object({
64+
contentType: z.enum(["TABLE", "TEXT"]).describe("内容格式"),
65+
stepContent: z.string().nullable().optional().describe("当contentType为TEXT时,该字段描述了测试步骤的内容"),
66+
expectedResult: z.string().nullable().optional().describe("当contentType为TEXT时,该字段描述了期望结果的内容"),
67+
content: z.array(TestStepSchema).optional().describe("当contentType为TABLE时,该字段描述了测试步骤的内容"),
68+
});
69+
70+
// Schema for CreateTestcaseRequest
71+
export const CreateTestcaseRequestSchema = z.object({
72+
organizationId: z.string().describe("组织ID"),
73+
testRepoId: z.string().describe("用例库唯一标识"),
74+
subject: z.string().min(0).max(256).optional().describe("标题"),
75+
assignedTo: z.string().optional().describe("负责人userId"),
76+
directoryId: z.string().optional().describe("目录id"),
77+
preCondition: z.string().optional().describe("前置条件"),
78+
labels: z.array(z.string()).optional().describe("标签ids"),
79+
customFieldValues: z.record(z.any()).optional().describe("自定义字段值"),
80+
testSteps: TestStepsDTOSchema.optional().describe("测试步骤"),
81+
});
82+
83+
export const CreateTestcaseResponseSchema = z.object({
84+
id: z.string().describe("id"),
85+
});
86+
87+
// Schema for SearchTestcasesRequest
88+
export const SearchTestcasesRequestSchema = z.object({
89+
organizationId: z.string().describe("组织ID"),
90+
testRepoId: z.string().describe("用例库唯一标识"),
91+
page: z.number().int().optional().default(1).describe("分页参数,第几页"),
92+
perPage: z.number().int().min(0).max(200).optional().default(20).describe("分页参数,每页大小"),
93+
orderBy: z.enum(["gmtCreate", "name"]).optional().default("gmtCreate").describe("排序字段"),
94+
sort: z.enum(["desc", "asc"]).optional().default("desc").describe("排序方式"),
95+
directoryId: z.string().optional().describe("目录id"),
96+
conditions: z.string().optional().describe("过滤条件,是一个json串"),
97+
});
98+
99+
// Schema for MiniUser
100+
export const MiniUserSchema = z.object({
101+
id: z.string().describe("用户id"),
102+
name: z.string().describe("名称"),
103+
});
104+
105+
// Schema for MiniLabel
106+
export const MiniLabelSchema = z.object({
107+
id: z.string().describe("id"),
108+
name: z.string().describe("名称"),
109+
color: z.string().optional().describe("颜色"),
110+
});
111+
112+
// Schema for MiniItemDTO
113+
export const MiniItemDTOSchema = z.object({
114+
id: z.string().describe("id"),
115+
name: z.string().describe("名称"),
116+
});
117+
118+
// Schema for FieldValue
119+
export const FieldValueSchema = z.object({
120+
fieldId: z.string().describe("字段id"),
121+
fieldName: z.string().describe("字段名称"),
122+
fieldFormat: z.string().describe("字段类型"),
123+
values: z.array(z.object({
124+
identifier: z.string().describe("值的唯一标识"),
125+
displayValue: z.string().describe("显示的名称"),
126+
})).optional().describe("字段值"),
127+
});
128+
129+
// Schema for TestcaseDTO
130+
export const TestcaseDTOSchema = z.object({
131+
id: z.string().describe("id"),
132+
subject: z.string().describe("标题"),
133+
customCode: z.string().nullable().optional().describe("编号"),
134+
assignedTo: MiniUserSchema.nullable().optional().describe("负责人"),
135+
creator: MiniUserSchema.nullable().optional().describe("创建人"),
136+
modifier: MiniUserSchema.nullable().optional().describe("修改人"),
137+
directory: MiniItemDTOSchema.nullable().optional().describe("目录"),
138+
preCondition: z.string().nullable().optional().describe("前置条件内容"),
139+
preConditionFormat: z.enum(["RICHTEXT", "TEXT"]).nullable().optional().describe("前置条件内容格式"),
140+
labels: z.array(MiniLabelSchema).nullable().optional().describe("标签"),
141+
customFieldValues: z.array(FieldValueSchema).nullable().optional().describe("自定义字段值"),
142+
testSteps: TestStepsDTOSchema.nullable().optional().describe("测试步骤"),
143+
gmtCreate: z.union([z.string(), z.number()]).nullable().optional().describe("创建时间(时间戳或ISO字符串)"),
144+
gmtModified: z.union([z.string(), z.number()]).nullable().optional().describe("修改时间(时间戳或ISO字符串)"),
145+
testRepo: z.object({
146+
id: z.string().describe("id"),
147+
name: z.string().describe("名称"),
148+
}).nullable().optional().describe("测试用例库"),
149+
});
150+
151+
export const SearchTestcasesResponseSchema = z.array(TestcaseDTOSchema);
152+
153+
// Schema for GetTestcase
154+
export const GetTestcaseRequestSchema = z.object({
155+
organizationId: z.string().describe("组织ID"),
156+
testRepoId: z.string().describe("用例库唯一标识"),
157+
testcaseId: z.string().describe("用例唯一标识"),
158+
});
159+
160+
export const GetTestcaseResponseSchema = TestcaseDTOSchema;
161+
162+
// Schema for DeleteTestcase
163+
export const DeleteTestcaseRequestSchema = z.object({
164+
organizationId: z.string().describe("组织ID"),
165+
testRepoId: z.string().describe("用例库唯一标识"),
166+
testcaseId: z.string().describe("用例唯一标识"),
167+
});
168+
169+
// DELETE 请求可能返回空响应(空字符串、空对象或 undefined)
170+
export const DeleteTestcaseResponseSchema = z.union([
171+
z.object({}),
172+
z.string(),
173+
z.undefined(),
174+
]).transform(() => ({}));
175+
176+
// Type exports
177+
export type ListDirectoriesRequest = z.infer<typeof ListDirectoriesRequestSchema>;
178+
export type ListDirectoriesResponse = z.infer<typeof ListDirectoriesResponseSchema>;
179+
export type CreateTestcaseDirectoryRequest = z.infer<typeof CreateTestcaseDirectoryRequestSchema>;
180+
export type CreateTestcaseDirectoryResponse = z.infer<typeof CreateTestcaseDirectoryResponseSchema>;
181+
export type GetTestcaseFieldConfigRequest = z.infer<typeof GetTestcaseFieldConfigRequestSchema>;
182+
export type GetTestcaseFieldConfigResponse = z.infer<typeof GetTestcaseFieldConfigResponseSchema>;
183+
export type CreateTestcaseRequest = z.infer<typeof CreateTestcaseRequestSchema>;
184+
export type CreateTestcaseResponse = z.infer<typeof CreateTestcaseResponseSchema>;
185+
export type SearchTestcasesRequest = z.infer<typeof SearchTestcasesRequestSchema>;
186+
export type SearchTestcasesResponse = z.infer<typeof SearchTestcasesResponseSchema>;
187+
export type GetTestcaseRequest = z.infer<typeof GetTestcaseRequestSchema>;
188+
export type GetTestcaseResponse = z.infer<typeof GetTestcaseResponseSchema>;
189+
export type DeleteTestcaseRequest = z.infer<typeof DeleteTestcaseRequestSchema>;
190+
export type DeleteTestcaseResponse = z.infer<typeof DeleteTestcaseResponseSchema>;
191+
192+
/**
193+
* 获取测试用例目录列表
194+
*/
195+
export async function listDirectories(params: ListDirectoriesRequest): Promise<ListDirectoriesResponse> {
196+
const { organizationId, testRepoId } = params;
197+
const response = await yunxiaoRequest(
198+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/directories`,
199+
{ method: 'GET' }
200+
);
201+
return ListDirectoriesResponseSchema.parse(response);
202+
}
203+
204+
/**
205+
* 创建测试用例目录
206+
*/
207+
export async function createTestcaseDirectory(params: CreateTestcaseDirectoryRequest): Promise<CreateTestcaseDirectoryResponse> {
208+
const { organizationId, testRepoId, name, parentIdentifier } = params;
209+
const body: any = { name };
210+
if (parentIdentifier) {
211+
body.parentIdentifier = parentIdentifier;
212+
}
213+
const response = await yunxiaoRequest(
214+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/directories`,
215+
{ method: 'POST', body }
216+
);
217+
return CreateTestcaseDirectoryResponseSchema.parse(response);
218+
}
219+
220+
/**
221+
* 获取测试用例字段配置
222+
*/
223+
export async function getTestcaseFieldConfig(params: GetTestcaseFieldConfigRequest): Promise<GetTestcaseFieldConfigResponse> {
224+
const { organizationId, testRepoId } = params;
225+
const response = await yunxiaoRequest(
226+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/testcases/fields`,
227+
{ method: 'GET' }
228+
);
229+
return GetTestcaseFieldConfigResponseSchema.parse(response);
230+
}
231+
232+
/**
233+
* 创建测试用例
234+
*/
235+
export async function createTestcase(params: CreateTestcaseRequest): Promise<CreateTestcaseResponse> {
236+
const { organizationId, testRepoId, ...body } = params;
237+
const response = await yunxiaoRequest(
238+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/testcases`,
239+
{ method: 'POST', body }
240+
);
241+
return CreateTestcaseResponseSchema.parse(response);
242+
}
243+
244+
/**
245+
* 搜索测试用例
246+
*/
247+
export async function searchTestcases(params: SearchTestcasesRequest): Promise<SearchTestcasesResponse> {
248+
const { organizationId, testRepoId, ...body } = params;
249+
const response = await yunxiaoRequest(
250+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/testcases:search`,
251+
{ method: 'POST', body }
252+
);
253+
return SearchTestcasesResponseSchema.parse(response);
254+
}
255+
256+
/**
257+
* 获取测试用例信息
258+
*/
259+
export async function getTestcase(params: GetTestcaseRequest): Promise<GetTestcaseResponse> {
260+
const { organizationId, testRepoId, testcaseId } = params;
261+
const response = await yunxiaoRequest(
262+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/testcases/${testcaseId}`,
263+
{ method: 'GET' }
264+
);
265+
return GetTestcaseResponseSchema.parse(response);
266+
}
267+
268+
/**
269+
* 删除测试用例
270+
*/
271+
export async function deleteTestcase(params: DeleteTestcaseRequest): Promise<DeleteTestcaseResponse> {
272+
const { organizationId, testRepoId, testcaseId } = params;
273+
const response = await yunxiaoRequest(
274+
`/oapi/v1/testhub/organizations/${organizationId}/testRepos/${testRepoId}/testcases/${testcaseId}`,
275+
{ method: 'DELETE' }
276+
);
277+
return DeleteTestcaseResponseSchema.parse(response);
278+
}
279+

0 commit comments

Comments
 (0)