@epoint-testtech/ep-stage-skill 0.0.16 → 0.0.17
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/codex-skill/ep-stage/glue-generate-testcase/SKILL.md +7 -6
- package/codex-skill/ep-stage/glue-run-test/SKILL.md +97 -34
- package/codex-skill/ep-stage/glue-run-test/references/ai-runtime-loop.md +15 -9
- package/codex-skill/ep-stage/glue-run-test/references/crud-pipeline.md +10 -3
- package/codex-skill/ep-stage/glue-run-test/references/gap-review-protocol.md +11 -0
- package/codex-skill/ep-stage/glue-run-test/references/playwright-cli-odav.md +13 -2
- package/dist/src/cli/calibrate.d.ts +75 -0
- package/dist/src/cli/calibrate.d.ts.map +1 -0
- package/dist/src/cli/calibrate.js +318 -0
- package/dist/src/cli/demote.d.ts +53 -0
- package/dist/src/cli/demote.d.ts.map +1 -0
- package/dist/src/cli/demote.js +111 -0
- package/dist/src/cli/index.d.ts +5 -3
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +45 -6
- package/dist/src/cli/run-report.d.ts +6 -0
- package/dist/src/cli/run-report.d.ts.map +1 -1
- package/dist/src/cli/run-report.js +161 -147
- package/dist/src/cli/run.d.ts +51 -0
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +229 -27
- package/dist/src/contracts/glue-contract-v1.d.ts +37 -1
- package/dist/src/contracts/glue-contract-v1.d.ts.map +1 -1
- package/dist/src/extractors/code-list-json5.d.ts +29 -0
- package/dist/src/extractors/code-list-json5.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.d.ts +30 -1
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -1
- package/dist/src/generators/stage-skeleton-script.js +74 -11
- package/dist/src/runtime/ai-runtime-trace.d.ts +6 -0
- package/dist/src/runtime/ai-runtime-trace.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.d.ts +23 -4
- package/dist/src/testcase/contract-testcase-assembler.d.ts.map +1 -1
- package/dist/src/testcase/contract-testcase-assembler.js +204 -27
- package/dist/src/testcase/query-component-map.d.ts +51 -0
- package/dist/src/testcase/query-component-map.d.ts.map +1 -0
- package/dist/src/testcase/query-component-map.js +64 -0
- package/dist/src/validation/contract.d.ts.map +1 -1
- package/dist/src/validation/contract.js +45 -3
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 查询组件形态映射 —— 装配器 / calibrate / validation 三方共用的单一事实来源。
|
|
3
|
+
*
|
|
4
|
+
* 纪律(与 docs/00-memory/miniui-component-forms.md 互为镜像,改一必改另一):
|
|
5
|
+
* - 白名单内组件:骨架 glue 用例承载(有对应交互实现);
|
|
6
|
+
* - 白名单外组件(上游显式写了但未识别):用例路由到 AI 桶(uncoveredCandidates),
|
|
7
|
+
* 不再静默压扁成 listbox 生成必败 glue 用例;
|
|
8
|
+
* - 上游未写 component(缺失):回退 input 保住 CRUD 主链路,inference-trace 记 defaulted,
|
|
9
|
+
* 由 calibrate 在运行前用 elementmap 的运行时 controlType 纠正错误回退。
|
|
10
|
+
*/
|
|
11
|
+
/** 骨架 glue 支持的查询组件类型(白名单)。 */
|
|
12
|
+
export type QueryComponentKind = 'input' | 'listbox' | 'datepicker' | 'tree';
|
|
13
|
+
/** 白名单数组形态(供 validation/calibrate 做包含判断)。 */
|
|
14
|
+
export declare const GLUE_QUERY_COMPONENT_WHITELIST: readonly QueryComponentKind[];
|
|
15
|
+
/**
|
|
16
|
+
* 组件解析三态:
|
|
17
|
+
* - mapped:显式命中映射表(含上游直接写白名单类型名);
|
|
18
|
+
* - defaulted:上游未写 component/type,回退 input(保住 CRUD 锚点主链路);
|
|
19
|
+
* - unrecognized:上游显式写了但未在映射表,应路由 AI 桶。
|
|
20
|
+
*/
|
|
21
|
+
export type QueryComponentResolution = {
|
|
22
|
+
kind: QueryComponentKind;
|
|
23
|
+
raw: string;
|
|
24
|
+
source: 'mapped';
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'input';
|
|
27
|
+
raw: '';
|
|
28
|
+
source: 'defaulted';
|
|
29
|
+
} | {
|
|
30
|
+
kind: null;
|
|
31
|
+
raw: string;
|
|
32
|
+
source: 'unrecognized';
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* 解析查询字段的组件形态。
|
|
36
|
+
*
|
|
37
|
+
* @param fieldInfo - 含可选 type/component 的字段描述(code_list queryFields 条目或 elementmap 条目)。
|
|
38
|
+
* @returns 三态解析结果。
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveQueryComponent(fieldInfo: {
|
|
41
|
+
type?: string;
|
|
42
|
+
component?: string;
|
|
43
|
+
}): QueryComponentResolution;
|
|
44
|
+
/**
|
|
45
|
+
* 判断组件值是否落在 glue 白名单(含 MiniUI 原名经映射后命中的情况)。
|
|
46
|
+
*
|
|
47
|
+
* @param component - code_list component 值或运行时 controlType。
|
|
48
|
+
* @returns 可解析为白名单类型时为 true。
|
|
49
|
+
*/
|
|
50
|
+
export declare function isGlueQueryComponent(component: string): component is QueryComponentKind;
|
|
51
|
+
//# sourceMappingURL=query-component-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-component-map.d.ts","sourceRoot":"","sources":["../../../src/testcase/query-component-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,8BAA8B;AAC9B,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,CAAC;AAE7E,6CAA6C;AAC7C,eAAO,MAAM,8BAA8B,EAAE,SAAS,kBAAkB,EAKvE,CAAC;AAwBF;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,EAAE,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,wBAAwB,CAUhH;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,IAAI,kBAAkB,CAEvF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 查询组件形态映射 —— 装配器 / calibrate / validation 三方共用的单一事实来源。
|
|
3
|
+
*
|
|
4
|
+
* 纪律(与 docs/00-memory/miniui-component-forms.md 互为镜像,改一必改另一):
|
|
5
|
+
* - 白名单内组件:骨架 glue 用例承载(有对应交互实现);
|
|
6
|
+
* - 白名单外组件(上游显式写了但未识别):用例路由到 AI 桶(uncoveredCandidates),
|
|
7
|
+
* 不再静默压扁成 listbox 生成必败 glue 用例;
|
|
8
|
+
* - 上游未写 component(缺失):回退 input 保住 CRUD 主链路,inference-trace 记 defaulted,
|
|
9
|
+
* 由 calibrate 在运行前用 elementmap 的运行时 controlType 纠正错误回退。
|
|
10
|
+
*/
|
|
11
|
+
/** 白名单数组形态(供 validation/calibrate 做包含判断)。 */
|
|
12
|
+
export const GLUE_QUERY_COMPONENT_WHITELIST = [
|
|
13
|
+
'input',
|
|
14
|
+
'listbox',
|
|
15
|
+
'datepicker',
|
|
16
|
+
'tree',
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* 显式映射表:code_list component / 运行时 controlType(MiniUI 类名)→ 骨架类型。
|
|
20
|
+
* 键全部小写;解析时输入统一转小写后查表。
|
|
21
|
+
*/
|
|
22
|
+
const COMPONENT_KIND_MAP = {
|
|
23
|
+
input: 'input',
|
|
24
|
+
'mini-textbox': 'input',
|
|
25
|
+
'mini-password': 'input',
|
|
26
|
+
'mini-textarea': 'input',
|
|
27
|
+
listbox: 'listbox',
|
|
28
|
+
'mini-combobox': 'listbox',
|
|
29
|
+
'mini-listbox': 'listbox',
|
|
30
|
+
datepicker: 'datepicker',
|
|
31
|
+
'mini-datepicker': 'datepicker',
|
|
32
|
+
'mini-daterangepicker': 'datepicker',
|
|
33
|
+
'mini-monthpicker': 'datepicker',
|
|
34
|
+
tree: 'tree',
|
|
35
|
+
'mini-filtertree': 'tree',
|
|
36
|
+
'mini-tree': 'tree',
|
|
37
|
+
'mini-treeselect': 'tree',
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 解析查询字段的组件形态。
|
|
41
|
+
*
|
|
42
|
+
* @param fieldInfo - 含可选 type/component 的字段描述(code_list queryFields 条目或 elementmap 条目)。
|
|
43
|
+
* @returns 三态解析结果。
|
|
44
|
+
*/
|
|
45
|
+
export function resolveQueryComponent(fieldInfo) {
|
|
46
|
+
const raw = fieldInfo.type ?? fieldInfo.component ?? '';
|
|
47
|
+
if (!raw) {
|
|
48
|
+
return { kind: 'input', raw: '', source: 'defaulted' };
|
|
49
|
+
}
|
|
50
|
+
const kind = COMPONENT_KIND_MAP[raw.toLowerCase()];
|
|
51
|
+
if (kind) {
|
|
52
|
+
return { kind, raw, source: 'mapped' };
|
|
53
|
+
}
|
|
54
|
+
return { kind: null, raw, source: 'unrecognized' };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 判断组件值是否落在 glue 白名单(含 MiniUI 原名经映射后命中的情况)。
|
|
58
|
+
*
|
|
59
|
+
* @param component - code_list component 值或运行时 controlType。
|
|
60
|
+
* @returns 可解析为白名单类型时为 true。
|
|
61
|
+
*/
|
|
62
|
+
export function isGlueQueryComponent(component) {
|
|
63
|
+
return Boolean(component) && COMPONENT_KIND_MAP[component.toLowerCase()] !== undefined;
|
|
64
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/validation/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../../src/validation/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAA4C,MAAM,kCAAkC,CAAC;AAezH;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CA2KrE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isGlueQueryComponent } from '../testcase/query-component-map.js';
|
|
1
2
|
const ALLOWED_STRATEGIES = new Set(['glue', 'ai']);
|
|
2
3
|
/**
|
|
3
4
|
* 断言值为非空字符串,否则抛错。
|
|
@@ -80,13 +81,19 @@ export function validateContract(obj) {
|
|
|
80
81
|
if (!slotsRec.export || typeof slotsRec.export !== 'object') {
|
|
81
82
|
throw new Error('contract.json5 缺 scenario.skeletonSlots.export');
|
|
82
83
|
}
|
|
83
|
-
if (!slotsRec.export || typeof slotsRec.export !== 'object') {
|
|
84
|
-
throw new Error('contract.json5 缺 scenario.skeletonSlots.export');
|
|
85
|
-
}
|
|
86
84
|
const exportSlot = slotsRec.export;
|
|
87
85
|
requireString(exportSlot.moduleId, 'scenario.skeletonSlots.export.moduleId');
|
|
88
86
|
requireString(exportSlot.label, 'scenario.skeletonSlots.export.label');
|
|
89
87
|
requireString(exportSlot.mode, 'scenario.skeletonSlots.export.mode');
|
|
88
|
+
if (exportSlot.locators !== undefined) {
|
|
89
|
+
const exportLocators = exportSlot.locators;
|
|
90
|
+
if (exportLocators.exportButton !== undefined) {
|
|
91
|
+
requireString(exportLocators.exportButton, 'scenario.skeletonSlots.export.locators.exportButton');
|
|
92
|
+
}
|
|
93
|
+
if (exportLocators.exportContainer !== undefined) {
|
|
94
|
+
requireString(exportLocators.exportContainer, 'scenario.skeletonSlots.export.locators.exportContainer');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
90
97
|
// scenario.skeletonSlots.childGrids(可选)
|
|
91
98
|
if (slotsRec.childGrids !== undefined) {
|
|
92
99
|
if (!Array.isArray(slotsRec.childGrids)) {
|
|
@@ -128,5 +135,40 @@ export function validateContract(obj) {
|
|
|
128
135
|
if (!Array.isArray(raw.unresolvedSlots)) {
|
|
129
136
|
throw new Error('contract.json5 缺 unresolvedSlots[]');
|
|
130
137
|
}
|
|
138
|
+
const unresolvedSlots = raw.unresolvedSlots;
|
|
139
|
+
// 白名单交叉一致性:searchFields.component 与 searchConditions / AI 通道记录必须各就各位。
|
|
140
|
+
// (calibrate 改写契约后同样过本门禁,保证装配期与校准期不分裂。)
|
|
141
|
+
const crudSlots = slotsRec.crud;
|
|
142
|
+
const searchConditions = Array.isArray(crudSlots.searchConditions)
|
|
143
|
+
? crudSlots.searchConditions
|
|
144
|
+
: [];
|
|
145
|
+
const conditionLabels = new Set(searchConditions.map((c) => String(c.label ?? '')));
|
|
146
|
+
const gapIds = new Set(sc.gapCandidates.map((g) => String(g.gapId ?? '')));
|
|
147
|
+
for (const sf of sc.searchFields) {
|
|
148
|
+
const component = String(sf.component);
|
|
149
|
+
const label = String(sf.label);
|
|
150
|
+
const field = String(sf.field);
|
|
151
|
+
if (isGlueQueryComponent(component)) {
|
|
152
|
+
if (!conditionLabels.has(label)) {
|
|
153
|
+
throw new Error(`contract.json5 白名单组件缺槽位:searchFields[${label}].component=${component} 为白名单类型,` +
|
|
154
|
+
`但 scenario.skeletonSlots.crud.searchConditions 中无对应条目`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
if (conditionLabels.has(label)) {
|
|
159
|
+
throw new Error(`contract.json5 未识别组件混入 glue 槽位:searchFields[${label}].component=${component} 不在白名单,` +
|
|
160
|
+
`不应出现在 searchConditions(用例应走 AI 通道)`);
|
|
161
|
+
}
|
|
162
|
+
const expectedGapId = `query-component:${field}`;
|
|
163
|
+
if (!gapIds.has(expectedGapId)) {
|
|
164
|
+
throw new Error(`contract.json5 未识别组件未走 AI 通道路由:searchFields[${label}].component=${component},缺 gapCandidates[gapId=${expectedGapId}]`);
|
|
165
|
+
}
|
|
166
|
+
const hasUnresolvedRecord = unresolvedSlots.some((slot) => slot.kind === 'unsupported_query_component' && slot.slotPath.includes(label));
|
|
167
|
+
if (!hasUnresolvedRecord) {
|
|
168
|
+
throw new Error(`contract.json5 未识别组件未登记 unresolvedSlots:searchFields[${label}].component=${component},` +
|
|
169
|
+
`需 kind=unsupported_query_component 且 slotPath 含「${label}」的记录`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
131
173
|
return raw;
|
|
132
174
|
}
|