|
| 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