@epoint-testtech/ep-stage-skill 0.0.12 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/generators/stage-skeleton-script.d.ts +2 -4
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +6 -32
- package/dist/src/testcase/contract-testcase-assembler.d.ts +1 -10
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.js +25 -37
- package/package.json +1 -1
|
@@ -92,10 +92,6 @@ export type StageSkeletonCrudFlowSlots = {
|
|
|
92
92
|
createButton: string;
|
|
93
93
|
addAutofillTrigger?: string;
|
|
94
94
|
addSaveButton: string;
|
|
95
|
-
/** 新增页「保存」按钮(草稿保存,弹窗不关闭);条件性删除的草稿用例需要 */
|
|
96
|
-
addDraftSaveButton?: string;
|
|
97
|
-
/** 新增页「关闭」按钮;草稿保存后弹窗不关闭,需显式关闭回列表页 */
|
|
98
|
-
addDialogCloseButton?: string;
|
|
99
95
|
listSearchSubmit: string;
|
|
100
96
|
listResultValueLocatorTemplate: string;
|
|
101
97
|
listEditActionLocatorTemplate: string;
|
|
@@ -107,6 +103,8 @@ export type StageSkeletonCrudFlowSlots = {
|
|
|
107
103
|
assertions: {
|
|
108
104
|
deletePolicy: StageSkeletonCrudDeletePolicy;
|
|
109
105
|
blockedDeleteMessage?: string;
|
|
106
|
+
/** 条件性删除(如"草稿可删、在用不可删"):骨架 runDeleteWorkflow 运行时按记录是否仍存在分流断言 */
|
|
107
|
+
conditionalDelete?: boolean;
|
|
110
108
|
};
|
|
111
109
|
};
|
|
112
110
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-skeleton-script.d.ts","sourceRoot":"","sources":["../../../src/generators/stage-skeleton-script.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"stage-skeleton-script.d.ts","sourceRoot":"","sources":["../../../src/generators/stage-skeleton-script.ts"],"names":[],"mappings":"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"}
|
|
@@ -423,8 +423,6 @@ ${renderSearchConditions(slots.searchConditions, 8)}
|
|
|
423
423
|
createButton: ${locatorLiteral(slots.locators.createButton)},
|
|
424
424
|
${renderOptionalStringProperty('addAutofillTrigger', slots.locators.addAutofillTrigger, 12)}
|
|
425
425
|
addSaveButton: ${locatorLiteral(slots.locators.addSaveButton)},
|
|
426
|
-
${renderOptionalStringProperty('addDraftSaveButton', slots.locators.addDraftSaveButton, 12)}
|
|
427
|
-
${renderOptionalStringProperty('addDialogCloseButton', slots.locators.addDialogCloseButton, 12)}
|
|
428
426
|
listSearchSubmit: ${locatorLiteral(slots.locators.listSearchSubmit)},
|
|
429
427
|
listResultValueLocatorTemplate: ${locatorLiteral(slots.locators.listResultValueLocatorTemplate)},
|
|
430
428
|
listEditActionLocatorTemplate: ${locatorLiteral(slots.locators.listEditActionLocatorTemplate)},
|
|
@@ -434,7 +432,8 @@ ${renderOptionalStringProperty('addDialogCloseButton', slots.locators.addDialogC
|
|
|
434
432
|
${renderOptionalStringProperty('deleteConfirmButton', slots.locators.deleteConfirmButton, 12)} },
|
|
435
433
|
assertions: {
|
|
436
434
|
deletePolicy: ${singleQuoted(slots.assertions.deletePolicy)},
|
|
437
|
-
${renderOptionalStringProperty('blockedDeleteMessage', slots.assertions.blockedDeleteMessage, 12)}
|
|
435
|
+
${renderOptionalStringProperty('blockedDeleteMessage', slots.assertions.blockedDeleteMessage, 12)}
|
|
436
|
+
${slots.assertions.conditionalDelete ? ' conditionalDelete: true,\n' : ''} },
|
|
438
437
|
}`;
|
|
439
438
|
}
|
|
440
439
|
function renderChildGridColumns(columns, level) {
|
|
@@ -742,28 +741,14 @@ function renderChildGridTests(slots, crudSlots, moduleLabel, moduleId, glueCases
|
|
|
742
741
|
})
|
|
743
742
|
.join('\n\n');
|
|
744
743
|
}
|
|
745
|
-
/** 解析 glue CRUD 用例标题:`${moduleName} ${actionKind}(${queryKey})`。
|
|
746
|
-
* 条件性删除用例标题带变体后缀:`delete(${queryKey}-草稿)` / `delete(${queryKey}-在用)`,
|
|
747
|
-
* 解析时剥离后缀还原 base queryKey(保证数据分组不受后缀影响),并返回 deleteVariant。 */
|
|
744
|
+
/** 解析 glue CRUD 用例标题:`${moduleName} ${actionKind}(${queryKey})`。 */
|
|
748
745
|
function parseCrudCaseTitle(title) {
|
|
749
746
|
const match = title.match(/\s(create|read|update|delete)((.+))\s*$/);
|
|
750
747
|
if (!match)
|
|
751
748
|
return null;
|
|
752
|
-
const actionKind = match[1];
|
|
753
|
-
const rawKey = match[2];
|
|
754
|
-
if (actionKind === 'delete') {
|
|
755
|
-
const variantMatch = rawKey.match(/^(.*)-(?:草稿|在用)$/);
|
|
756
|
-
if (variantMatch) {
|
|
757
|
-
return {
|
|
758
|
-
actionKind,
|
|
759
|
-
queryKeyLabel: variantMatch[1],
|
|
760
|
-
deleteVariant: rawKey.endsWith('-草稿') ? 'draft_success' : 'blocked',
|
|
761
|
-
};
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
749
|
return {
|
|
765
|
-
actionKind,
|
|
766
|
-
queryKeyLabel:
|
|
750
|
+
actionKind: match[1],
|
|
751
|
+
queryKeyLabel: match[2],
|
|
767
752
|
};
|
|
768
753
|
}
|
|
769
754
|
/** 把用例 steps 文本("1. …。 2. …。")拆成 elementActions 数组。 */
|
|
@@ -828,24 +813,13 @@ ${componentForLabel(key) === 'listbox'
|
|
|
828
813
|
: ` await crudPage.runUpdateWorkflow(data);`}`;
|
|
829
814
|
break;
|
|
830
815
|
case 'delete':
|
|
831
|
-
|
|
832
|
-
// 条件性删除-草稿可删用例:自建草稿数据(保存,不关闭)再删除,断言删除成功。
|
|
833
|
-
// 不复用 create 组的在用数据(deleteVariant='blocked' 的用例依赖它保持未被删除)。
|
|
834
|
-
body = ` await openModule(page);
|
|
835
|
-
const crudPage = new CrudPage(page, crudSlots);
|
|
836
|
-
const data = crudPage.prepareWorkflowData();
|
|
837
|
-
await crudPage.runCreateDraftWorkflow(data);
|
|
838
|
-
await crudPage.runDeleteWorkflow(data, { expectation: 'success' });`;
|
|
839
|
-
}
|
|
840
|
-
else {
|
|
841
|
-
body = ` await openModule(page);
|
|
816
|
+
body = ` await openModule(page);
|
|
842
817
|
const data = workflowDataByKey[${singleQuoted(dataKey)}];
|
|
843
818
|
if (!data) {
|
|
844
819
|
throw new Error(${singleQuoted(`${testCase.title} 依赖 create(${dataKey})用例先行生成 workflowData`)});
|
|
845
820
|
}
|
|
846
821
|
const crudPage = new CrudPage(page, crudSlots);
|
|
847
822
|
await crudPage.runDeleteWorkflow(data);`;
|
|
848
|
-
}
|
|
849
823
|
break;
|
|
850
824
|
}
|
|
851
825
|
return ` test(${singleQuoted(fullTitle)}, async ({ page }) => {
|
|
@@ -43,12 +43,6 @@ export type CrudCaseStage = {
|
|
|
43
43
|
actionKind: GlueActionKind;
|
|
44
44
|
queryKeyLabel: string;
|
|
45
45
|
component: 'input' | 'listbox';
|
|
46
|
-
/**
|
|
47
|
-
* 条件性删除(如"草稿可删、在用不可删")时的删除用例变体:
|
|
48
|
-
* draft_success = 满足可删条件(草稿)删除成功;blocked = 不满足条件(在用)被业务规则阻断。
|
|
49
|
-
* 仅 actionKind='delete' 且条件性规则时出现;无条件阻断/正常可删不设置(保持原有用例形态)。
|
|
50
|
-
*/
|
|
51
|
-
deleteVariant?: 'draft_success' | 'blocked';
|
|
52
46
|
};
|
|
53
47
|
/**
|
|
54
48
|
* 按查询字段推导 CRUD 用例阶段序列。
|
|
@@ -56,18 +50,15 @@ export type CrudCaseStage = {
|
|
|
56
50
|
* 规则:在新增表单中出现的查询字段(可写)产出完整 create/read/update/delete 四条;
|
|
57
51
|
* 不在表单中的字段(如系统管理的状态)只产出 read 一条。
|
|
58
52
|
* export 不在此计划内,由装配器单独追加。
|
|
59
|
-
* 条件性删除规则(conditionalDelete=true)时,可写键的 delete 由一条变两条:
|
|
60
|
-
* 草稿删除成功(draft_success)在前、在用删除阻断(blocked)在后。
|
|
61
53
|
*
|
|
62
54
|
* @param searchFields - 列表页查询字段(有序)。
|
|
63
55
|
* @param formFieldLabels - 新增表单字段标签集合。
|
|
64
|
-
* @param conditionalDelete - 删除是否为条件性(businessRules 的 delete 规则带 deletableCondition)。
|
|
65
56
|
* @returns 有序阶段计划,顺序与 buildGlueCases 产出的用例顺序一一对应。
|
|
66
57
|
*/
|
|
67
58
|
export declare function planCrudCaseStages(searchFields: Array<{
|
|
68
59
|
label: string;
|
|
69
60
|
component: 'input' | 'listbox';
|
|
70
|
-
}>, formFieldLabels: string[]
|
|
61
|
+
}>, formFieldLabels: string[]): CrudCaseStage[];
|
|
71
62
|
/**
|
|
72
63
|
* 装配 contract + testcase + inference-trace 账本。
|
|
73
64
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-testcase-assembler.d.ts","sourceRoot":"","sources":["../../../src/testcase/contract-testcase-assembler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAA2E,MAAM,kCAAkC,CAAC;AACxJ,OAAO,KAAK,EAAE,sBAAsB,EAAqB,MAAM,kCAAkC,CAAC;AAElG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AASrE,oBAAoB;AACpB,MAAM,MAAM,aAAa,GAAG;IAC1B,iCAAiC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC,CAAC;
|
|
1
|
+
{"version":3,"file":"contract-testcase-assembler.d.ts","sourceRoot":"","sources":["../../../src/testcase/contract-testcase-assembler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAA2E,MAAM,kCAAkC,CAAC;AACxJ,OAAO,KAAK,EAAE,sBAAsB,EAAqB,MAAM,kCAAkC,CAAC;AAElG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AASrE,oBAAoB;AACpB,MAAM,MAAM,aAAa,GAAG;IAC1B,iCAAiC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,gEAAgE;AAChE,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,mEAAmE;IACnE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC,CAAC;AAkZF,mBAAmB;AACnB,KAAK,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,cAAc,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,CAAC,EACtE,eAAe,EAAE,MAAM,EAAE,GACxB,aAAa,EAAE,CAejB;AAsbD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc,CAyLrF"}
|
|
@@ -49,7 +49,7 @@ const DEFAULT_LOCATORS = {
|
|
|
49
49
|
* @param listPage - code_list.pages[role=list]。
|
|
50
50
|
* @returns 覆盖 StageSkeletonCrudFlowSlots.locators 全部字段的定位表达式。
|
|
51
51
|
*/
|
|
52
|
-
function buildCrudLocators(listPage
|
|
52
|
+
function buildCrudLocators(listPage) {
|
|
53
53
|
const gridId = 'datagrid';
|
|
54
54
|
const createLabel = listPage.buttons?.find((b) => b.action === 'create')?.label ?? '新增';
|
|
55
55
|
const deleteLabel = listPage.buttons?.find((b) => b.action === 'delete')?.label ?? '删除选定';
|
|
@@ -59,10 +59,6 @@ function buildCrudLocators(listPage, addOrEditPage, conditionalDelete = false) {
|
|
|
59
59
|
})?.label ?? '修改';
|
|
60
60
|
const miniButton = (label) => `xpath=//a[contains(@class,'mini-button')][normalize-space()='${label}']`;
|
|
61
61
|
const gridCell = `xpath=//*[@id='${gridId}']//div[text()='{{value}}']`;
|
|
62
|
-
// 条件性删除需要「草稿删除成功」用例:新增页保存草稿按钮(action=save,如「保存」)
|
|
63
|
-
// 与关闭按钮(action=cancel,草稿保存后弹窗不关闭,需显式关闭回列表页)。
|
|
64
|
-
const draftSaveLabel = addOrEditPage?.buttons?.find((b) => b.action === 'save')?.label;
|
|
65
|
-
const dialogCloseLabel = addOrEditPage?.buttons?.find((b) => b.action === 'cancel')?.label;
|
|
66
62
|
return {
|
|
67
63
|
createButton: miniButton(createLabel),
|
|
68
64
|
addAutofillTrigger: `xpath=//*[@title='默认填充']`,
|
|
@@ -74,8 +70,6 @@ function buildCrudLocators(listPage, addOrEditPage, conditionalDelete = false) {
|
|
|
74
70
|
listRowSelectLocatorTemplate: gridCell,
|
|
75
71
|
listDeleteButton: miniButton(deleteLabel),
|
|
76
72
|
deleteConfirmButton: 'text=确定',
|
|
77
|
-
...(conditionalDelete && draftSaveLabel ? { addDraftSaveButton: miniButton(draftSaveLabel) } : {}),
|
|
78
|
-
...(conditionalDelete && dialogCloseLabel ? { addDialogCloseButton: miniButton(dialogCloseLabel) } : {}),
|
|
79
73
|
};
|
|
80
74
|
}
|
|
81
75
|
/**
|
|
@@ -371,25 +365,16 @@ function normalizeQueryComponent(fieldInfo) {
|
|
|
371
365
|
* 规则:在新增表单中出现的查询字段(可写)产出完整 create/read/update/delete 四条;
|
|
372
366
|
* 不在表单中的字段(如系统管理的状态)只产出 read 一条。
|
|
373
367
|
* export 不在此计划内,由装配器单独追加。
|
|
374
|
-
* 条件性删除规则(conditionalDelete=true)时,可写键的 delete 由一条变两条:
|
|
375
|
-
* 草稿删除成功(draft_success)在前、在用删除阻断(blocked)在后。
|
|
376
368
|
*
|
|
377
369
|
* @param searchFields - 列表页查询字段(有序)。
|
|
378
370
|
* @param formFieldLabels - 新增表单字段标签集合。
|
|
379
|
-
* @param conditionalDelete - 删除是否为条件性(businessRules 的 delete 规则带 deletableCondition)。
|
|
380
371
|
* @returns 有序阶段计划,顺序与 buildGlueCases 产出的用例顺序一一对应。
|
|
381
372
|
*/
|
|
382
|
-
export function planCrudCaseStages(searchFields, formFieldLabels
|
|
373
|
+
export function planCrudCaseStages(searchFields, formFieldLabels) {
|
|
383
374
|
const stages = [];
|
|
384
375
|
for (const field of searchFields) {
|
|
385
376
|
if (formFieldLabels.includes(field.label)) {
|
|
386
|
-
stages.push({ actionKind: 'create', queryKeyLabel: field.label, component: field.component }, { actionKind: 'read', queryKeyLabel: field.label, component: field.component }, { actionKind: 'update', queryKeyLabel: field.label, component: field.component });
|
|
387
|
-
if (conditionalDelete) {
|
|
388
|
-
stages.push({ actionKind: 'delete', queryKeyLabel: field.label, component: field.component, deleteVariant: 'draft_success' }, { actionKind: 'delete', queryKeyLabel: field.label, component: field.component, deleteVariant: 'blocked' });
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
stages.push({ actionKind: 'delete', queryKeyLabel: field.label, component: field.component });
|
|
392
|
-
}
|
|
377
|
+
stages.push({ actionKind: 'create', queryKeyLabel: field.label, component: field.component }, { actionKind: 'read', queryKeyLabel: field.label, component: field.component }, { actionKind: 'update', queryKeyLabel: field.label, component: field.component }, { actionKind: 'delete', queryKeyLabel: field.label, component: field.component });
|
|
393
378
|
}
|
|
394
379
|
else {
|
|
395
380
|
stages.push({ actionKind: 'read', queryKeyLabel: field.label, component: field.component });
|
|
@@ -440,7 +425,7 @@ function pickQueryKeyLabel(label, searchFieldLabels, dataKeyLabel) {
|
|
|
440
425
|
* 仅 delete 用例消费;缺省按 success_delete 出文案。
|
|
441
426
|
* @returns testcase 执行字段。
|
|
442
427
|
*/
|
|
443
|
-
function buildGlueExecutionFields(actionKind, queryKeyLabel, queryComponent, queryKeyInForm, searchFieldLabels, dataKeyLabel, deleteOutcome
|
|
428
|
+
function buildGlueExecutionFields(actionKind, queryKeyLabel, queryComponent, queryKeyInForm, searchFieldLabels, dataKeyLabel, deleteOutcome) {
|
|
444
429
|
const queryKey = actionKind === 'export'
|
|
445
430
|
? pickQueryKeyLabel(dataKeyLabel ?? searchFieldLabels[0] ?? '不适用', searchFieldLabels, dataKeyLabel)
|
|
446
431
|
: pickQueryKeyLabel(queryKeyLabel, searchFieldLabels, dataKeyLabel);
|
|
@@ -506,20 +491,21 @@ function buildGlueExecutionFields(actionKind, queryKeyLabel, queryComponent, que
|
|
|
506
491
|
'3. 点击{{删除按钮}}。',
|
|
507
492
|
'4. 在确认弹窗中点击{{确认按钮}}。',
|
|
508
493
|
].join(' ');
|
|
509
|
-
//
|
|
510
|
-
//
|
|
511
|
-
//
|
|
512
|
-
//
|
|
513
|
-
if (
|
|
494
|
+
// 断言文案必须与骨架 runDeleteWorkflow 的实际执行保持一致:
|
|
495
|
+
// - 条件性删除(如"草稿可删、在用不可删"):单用例双预期,骨架运行时按记录是否仍存在分流断言;
|
|
496
|
+
// - 无条件阻断:断言阻断文案 + 记录仍存在;
|
|
497
|
+
// - 无删除规则:断言删后查无记录。
|
|
498
|
+
if (deleteOutcome?.deletePolicy === 'blocked_by_business_rule' && deleteOutcome.conditional) {
|
|
499
|
+
const blockMessage = deleteOutcome.blockedDeleteMessage ?? '不允许删除';
|
|
514
500
|
return {
|
|
515
501
|
queryKey,
|
|
516
|
-
precondition: `${smokeEntry} 2. 已基于${queryKey}
|
|
502
|
+
precondition: `${smokeEntry} 2. 已基于${queryKey}完成一条测试数据新增。`,
|
|
517
503
|
steps: deleteSteps,
|
|
518
|
-
assertion:
|
|
504
|
+
assertion: `删除结果按业务规则分流:若记录满足可删除条件,应删除成功,再次按${queryKey}搜索无匹配记录;若命中阻断规则,应提示『${blockMessage}』且记录仍存在。`,
|
|
519
505
|
};
|
|
520
506
|
}
|
|
521
|
-
if (
|
|
522
|
-
const blockMessage = deleteOutcome
|
|
507
|
+
if (deleteOutcome?.deletePolicy === 'blocked_by_business_rule') {
|
|
508
|
+
const blockMessage = deleteOutcome.blockedDeleteMessage ?? '不允许删除';
|
|
523
509
|
return {
|
|
524
510
|
queryKey,
|
|
525
511
|
precondition: `${smokeEntry} 2. 已基于${queryKey}完成一条测试数据新增(保存并关闭,数据为在用状态)。`,
|
|
@@ -554,25 +540,23 @@ function buildGlueExecutionFields(actionKind, queryKeyLabel, queryComponent, que
|
|
|
554
540
|
* @param dataKeyLabel - dataKey 对应的中文标签。
|
|
555
541
|
* @returns cases 数组(generationStrategy 全 glue)。
|
|
556
542
|
*/
|
|
557
|
-
function buildGlueCases(moduleName, searchFields, formFieldLabels, sequence, dataKeyLabel, deleteOutcome
|
|
543
|
+
function buildGlueCases(moduleName, searchFields, formFieldLabels, sequence, dataKeyLabel, deleteOutcome) {
|
|
558
544
|
const searchFieldLabels = searchFields.map((fieldInfo) => fieldInfo.label);
|
|
559
545
|
const componentForLabel = (label) => searchFields.find((fieldInfo) => fieldInfo.label === label)?.component ?? 'input';
|
|
560
546
|
const queryKeyInForm = (label) => formFieldLabels.includes(label);
|
|
561
|
-
|
|
562
|
-
const deleteTitleSuffix = (variant) => variant === 'draft_success' ? '-草稿' : variant === 'blocked' ? '-在用' : '';
|
|
563
|
-
const mk = (actionKind, queryKeyLabel, coverageStatus, deleteVariant) => ({
|
|
547
|
+
const mk = (actionKind, queryKeyLabel, coverageStatus) => ({
|
|
564
548
|
caseId: nextCaseId(sequence),
|
|
565
549
|
title: actionKind === 'export'
|
|
566
550
|
? `${moduleName} export`
|
|
567
|
-
: `${moduleName} ${actionKind}(${queryKeyLabel}
|
|
551
|
+
: `${moduleName} ${actionKind}(${queryKeyLabel})`,
|
|
568
552
|
generationStrategy: 'glue',
|
|
569
553
|
coverageStatus,
|
|
570
554
|
reviewStatus: 'confirmed',
|
|
571
|
-
...buildGlueExecutionFields(actionKind, queryKeyLabel, componentForLabel(queryKeyLabel), queryKeyInForm(queryKeyLabel), searchFieldLabels, dataKeyLabel, deleteOutcome
|
|
555
|
+
...buildGlueExecutionFields(actionKind, queryKeyLabel, componentForLabel(queryKeyLabel), queryKeyInForm(queryKeyLabel), searchFieldLabels, dataKeyLabel, deleteOutcome),
|
|
572
556
|
});
|
|
573
557
|
// 计划驱动:保证用例条数/顺序与 spec 生成器逐条渲染的 test 一一对应。
|
|
574
558
|
// listbox 键的 read 已由骨架强制断言行锚点命中,不再是 partial。
|
|
575
|
-
const cases = planCrudCaseStages(searchFields, formFieldLabels
|
|
559
|
+
const cases = planCrudCaseStages(searchFields, formFieldLabels).map((stage) => mk(stage.actionKind, stage.queryKeyLabel, 'covered'));
|
|
576
560
|
cases.push(mk('export', dataKeyLabel ?? searchFieldLabels[0] ?? '不适用', 'covered'));
|
|
577
561
|
return cases;
|
|
578
562
|
}
|
|
@@ -775,10 +759,13 @@ export function assembleJson5ContractAndTestcase(input) {
|
|
|
775
759
|
moduleId: module,
|
|
776
760
|
searchConditions: buildSearchConditionSlots(codeList, listPage, addOrEditPage),
|
|
777
761
|
frames: resolveFrameKeywords(codeList),
|
|
778
|
-
locators: buildCrudLocators(listPage
|
|
762
|
+
locators: buildCrudLocators(listPage),
|
|
779
763
|
assertions: {
|
|
780
764
|
deletePolicy,
|
|
781
765
|
blockedDeleteMessage,
|
|
766
|
+
// 条件性删除标记:骨架 runDeleteWorkflow 据此在运行时按「记录是否仍存在」分流断言
|
|
767
|
+
// (存在 → 断言阻断文案;不存在 → 断言删除成功),而非 slots 级单一预期。
|
|
768
|
+
...(conditionalDelete ? { conditionalDelete: true } : {}),
|
|
782
769
|
},
|
|
783
770
|
};
|
|
784
771
|
const childGridSlots = buildChildGridSlots(codeList, input.sourceRoot);
|
|
@@ -824,7 +811,8 @@ export function assembleJson5ContractAndTestcase(input) {
|
|
|
824
811
|
const cases = buildGlueCases(moduleName, searchFields, formFieldLabels, caseIdSequence, dataKeyLabel, {
|
|
825
812
|
deletePolicy,
|
|
826
813
|
blockedDeleteMessage,
|
|
827
|
-
|
|
814
|
+
conditional: conditionalDelete,
|
|
815
|
+
});
|
|
828
816
|
const childGridCases = childGridSlots ? buildChildGridCases(childGridSlots, firstRole, caseIdSequence) : [];
|
|
829
817
|
cases.push(...childGridCases);
|
|
830
818
|
const buttonInferences = inferButtonInteractions(codeList, {
|