@epoint-testtech/ep-stage-skill 0.0.3-alpha.1
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/SKILL.md +27 -0
- package/codex-skill/ep-stage/create-project/SKILL.md +59 -0
- package/codex-skill/ep-stage/glue-test/SKILL.md +258 -0
- package/codex-skill/ep-stage/glue-test/references/crud-pipeline.md +139 -0
- package/codex-skill/ep-stage/glue-test/references/gap-review-protocol.md +43 -0
- package/codex-skill/ep-stage/glue-test/references/harness-principles.md +46 -0
- package/codex-skill/ep-stage/glue-test/scripts/generate-crud-spec.mjs +149 -0
- package/codex-skill/ep-stage/glue-testcase/SKILL.md +31 -0
- package/codex-skill/ep-stage/glue-testcase/examples/observable-testcase.json +40 -0
- package/codex-skill/ep-stage/glue-testcase/references/testcase-schema.md +67 -0
- package/codex-skill/ep-stage/recording-to-glue/SKILL.md +27 -0
- package/codex-skill/ep-stage/scripts/validate-skill.mjs +73 -0
- package/dist/src/capability/coverage-diff.d.ts +34 -0
- package/dist/src/capability/coverage-diff.d.ts.map +1 -0
- package/dist/src/capability/coverage-diff.js +91 -0
- package/dist/src/capability/page-structure.d.ts +31 -0
- package/dist/src/capability/page-structure.d.ts.map +1 -0
- package/dist/src/capability/page-structure.js +50 -0
- package/dist/src/capability/scenario-inference.d.ts +36 -0
- package/dist/src/capability/scenario-inference.d.ts.map +1 -0
- package/dist/src/capability/scenario-inference.js +114 -0
- package/dist/src/cli/generate-crud-contract.d.ts +2 -0
- package/dist/src/cli/generate-crud-contract.d.ts.map +1 -0
- package/dist/src/cli/generate-crud-contract.js +77 -0
- package/dist/src/cli/generate-playwright-tests.d.ts +30 -0
- package/dist/src/cli/generate-playwright-tests.d.ts.map +1 -0
- package/dist/src/cli/generate-playwright-tests.js +81 -0
- package/dist/src/cli/run-gap-pipeline.d.ts +256 -0
- package/dist/src/cli/run-gap-pipeline.d.ts.map +1 -0
- package/dist/src/cli/run-gap-pipeline.js +1468 -0
- package/dist/src/context/stage-context.d.ts +63 -0
- package/dist/src/context/stage-context.d.ts.map +1 -0
- package/dist/src/context/stage-context.js +297 -0
- package/dist/src/contracts/crud-business-module.d.ts +645 -0
- package/dist/src/contracts/crud-business-module.d.ts.map +1 -0
- package/dist/src/contracts/crud-business-module.js +1 -0
- package/dist/src/contracts/gap-inference.d.ts +213 -0
- package/dist/src/contracts/gap-inference.d.ts.map +1 -0
- package/dist/src/contracts/gap-inference.js +11 -0
- package/dist/src/contracts/observable-chain.d.ts +250 -0
- package/dist/src/contracts/observable-chain.d.ts.map +1 -0
- package/dist/src/contracts/observable-chain.js +1 -0
- package/dist/src/extractors/code-list.d.ts +40 -0
- package/dist/src/extractors/code-list.d.ts.map +1 -0
- package/dist/src/extractors/code-list.js +225 -0
- package/dist/src/extractors/html-page.d.ts +67 -0
- package/dist/src/extractors/html-page.d.ts.map +1 -0
- package/dist/src/extractors/html-page.js +195 -0
- package/dist/src/extractors/java-action.d.ts +8 -0
- package/dist/src/extractors/java-action.d.ts.map +1 -0
- package/dist/src/extractors/java-action.js +53 -0
- package/dist/src/extractors/spec-yaml.d.ts +28 -0
- package/dist/src/extractors/spec-yaml.d.ts.map +1 -0
- package/dist/src/extractors/spec-yaml.js +29 -0
- package/dist/src/gap-planner/action-candidates.d.ts +9 -0
- package/dist/src/gap-planner/action-candidates.d.ts.map +1 -0
- package/dist/src/gap-planner/action-candidates.js +66 -0
- package/dist/src/gap-planner/list-gap-workflows.d.ts +17 -0
- package/dist/src/gap-planner/list-gap-workflows.d.ts.map +1 -0
- package/dist/src/gap-planner/list-gap-workflows.js +47 -0
- package/dist/src/gap-planner/plan-agent-workflows.d.ts +26 -0
- package/dist/src/gap-planner/plan-agent-workflows.d.ts.map +1 -0
- package/dist/src/gap-planner/plan-agent-workflows.js +116 -0
- package/dist/src/gap-planner/skeleton-coverage.d.ts +9 -0
- package/dist/src/gap-planner/skeleton-coverage.d.ts.map +1 -0
- package/dist/src/gap-planner/skeleton-coverage.js +41 -0
- package/dist/src/gap-planner/stable-id.d.ts +16 -0
- package/dist/src/gap-planner/stable-id.d.ts.map +1 -0
- package/dist/src/gap-planner/stable-id.js +19 -0
- package/dist/src/generalization/generalization-eval.d.ts +71 -0
- package/dist/src/generalization/generalization-eval.d.ts.map +1 -0
- package/dist/src/generalization/generalization-eval.js +53 -0
- package/dist/src/generators/agent-inferred-workflow-script.d.ts +22 -0
- package/dist/src/generators/agent-inferred-workflow-script.d.ts.map +1 -0
- package/dist/src/generators/agent-inferred-workflow-script.js +230 -0
- package/dist/src/generators/stage-skeleton-script.d.ts +107 -0
- package/dist/src/generators/stage-skeleton-script.d.ts.map +1 -0
- package/dist/src/generators/stage-skeleton-script.js +607 -0
- package/dist/src/index.d.ts +52 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +26 -0
- package/dist/src/material/material-inventory.d.ts +92 -0
- package/dist/src/material/material-inventory.d.ts.map +1 -0
- package/dist/src/material/material-inventory.js +191 -0
- package/dist/src/normalizers/crud-contract.d.ts +107 -0
- package/dist/src/normalizers/crud-contract.d.ts.map +1 -0
- package/dist/src/normalizers/crud-contract.js +1068 -0
- package/dist/src/testcase/testcase-generator.d.ts +43 -0
- package/dist/src/testcase/testcase-generator.d.ts.map +1 -0
- package/dist/src/testcase/testcase-generator.js +152 -0
- package/dist/src/testcase/testcase-skeleton.d.ts +91 -0
- package/dist/src/testcase/testcase-skeleton.d.ts.map +1 -0
- package/dist/src/testcase/testcase-skeleton.js +121 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts +11 -0
- package/dist/src/testcase/testcase-spec-assembly.d.ts.map +1 -0
- package/dist/src/testcase/testcase-spec-assembly.js +24 -0
- package/dist/src/trace/review-summary.d.ts +17 -0
- package/dist/src/trace/review-summary.d.ts.map +1 -0
- package/dist/src/trace/review-summary.js +34 -0
- package/dist/src/trace/trace-writer.d.ts +17 -0
- package/dist/src/trace/trace-writer.d.ts.map +1 -0
- package/dist/src/trace/trace-writer.js +81 -0
- package/dist/test/crud-contract.test.d.ts +2 -0
- package/dist/test/crud-contract.test.d.ts.map +1 -0
- package/dist/test/crud-contract.test.js +819 -0
- package/dist/test/gap-inference.test.d.ts +2 -0
- package/dist/test/gap-inference.test.d.ts.map +1 -0
- package/dist/test/gap-inference.test.js +597 -0
- package/dist/test/generalization.test.d.ts +2 -0
- package/dist/test/generalization.test.d.ts.map +1 -0
- package/dist/test/generalization.test.js +73 -0
- package/dist/test/material-inventory.test.d.ts +2 -0
- package/dist/test/material-inventory.test.d.ts.map +1 -0
- package/dist/test/material-inventory.test.js +141 -0
- package/dist/test/observable-chain.test.d.ts +2 -0
- package/dist/test/observable-chain.test.d.ts.map +1 -0
- package/dist/test/observable-chain.test.js +123 -0
- package/dist/test/observable-pipeline.test.d.ts +2 -0
- package/dist/test/observable-pipeline.test.d.ts.map +1 -0
- package/dist/test/observable-pipeline.test.js +461 -0
- package/dist/test/page-structure.test.d.ts +2 -0
- package/dist/test/page-structure.test.d.ts.map +1 -0
- package/dist/test/page-structure.test.js +45 -0
- package/dist/test/scenario-inference.test.d.ts +2 -0
- package/dist/test/scenario-inference.test.d.ts.map +1 -0
- package/dist/test/scenario-inference.test.js +73 -0
- package/dist/test/stage-context.test.d.ts +2 -0
- package/dist/test/stage-context.test.d.ts.map +1 -0
- package/dist/test/stage-context.test.js +263 -0
- package/dist/test/testcase-generator.test.d.ts +2 -0
- package/dist/test/testcase-generator.test.d.ts.map +1 -0
- package/dist/test/testcase-generator.test.js +276 -0
- package/dist/test/testcase-skeleton.test.d.ts +2 -0
- package/dist/test/testcase-skeleton.test.d.ts.map +1 -0
- package/dist/test/testcase-skeleton.test.js +185 -0
- package/dist/test/testcase-spec-assembly.test.d.ts +2 -0
- package/dist/test/testcase-spec-assembly.test.d.ts.map +1 -0
- package/dist/test/testcase-spec-assembly.test.js +105 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +7 -0
- package/docs/README.md +134 -0
- package/docs/mvp-usage-guide.md +298 -0
- package/examples/schemeresource-observable-docs/schemeresource.context.md +20 -0
- package/examples/schemeresource.module-hints.json +38 -0
- package/examples/schemeresource.observable.code_list.md +37 -0
- package/examples/zwplace-observable-docs/zwplace.context.md +16 -0
- package/examples/zwplace-placecategory-validation.json +29 -0
- package/examples/zwplace.module-hints.json +69 -0
- package/examples/zwplace.observable.code_list.md +37 -0
- package/package.json +38 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { mapContractToCrudTestcaseSlots, renderGlueTestcaseSkeleton, selectTestcaseSkeletonByScenario, } from '../src/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* 构造用例骨架映射测试所需的最小 CRUD 契约。
|
|
5
|
+
*
|
|
6
|
+
* @returns 包含完整 CRUD 槽位来源的测试契约。
|
|
7
|
+
*/
|
|
8
|
+
function createCrudContract() {
|
|
9
|
+
return {
|
|
10
|
+
contractVersion: 'crud-business-module/v1',
|
|
11
|
+
module: {
|
|
12
|
+
id: 'zwplace',
|
|
13
|
+
label: '场所窗口信息管理',
|
|
14
|
+
},
|
|
15
|
+
pages: {
|
|
16
|
+
list: {
|
|
17
|
+
role: 'list',
|
|
18
|
+
pageId: 'gxhzwplacelist',
|
|
19
|
+
title: '场所窗口信息列表',
|
|
20
|
+
iframeSrcKeyword: 'gxhzwplacelist',
|
|
21
|
+
fields: [],
|
|
22
|
+
buttons: [],
|
|
23
|
+
grids: [],
|
|
24
|
+
dialogs: [],
|
|
25
|
+
sources: [],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
dataKey: {
|
|
29
|
+
field: 'windowname',
|
|
30
|
+
label: '窗口名称',
|
|
31
|
+
availability: 'derivable',
|
|
32
|
+
generationStrategy: 'timestamp_prefix',
|
|
33
|
+
sources: [],
|
|
34
|
+
},
|
|
35
|
+
searchConditions: [
|
|
36
|
+
{
|
|
37
|
+
field: 'windowname',
|
|
38
|
+
label: '窗口名称',
|
|
39
|
+
component: 'input',
|
|
40
|
+
seedValue: '自动化测试窗口',
|
|
41
|
+
generationStrategy: 'timestamp_prefix',
|
|
42
|
+
sources: [],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
flows: {
|
|
46
|
+
create: {
|
|
47
|
+
entryButton: {
|
|
48
|
+
pageRole: 'list',
|
|
49
|
+
label: '新增场所窗口',
|
|
50
|
+
sources: [],
|
|
51
|
+
},
|
|
52
|
+
targetPageId: 'gxhzwplaceadd',
|
|
53
|
+
saveButton: {
|
|
54
|
+
pageRole: 'add',
|
|
55
|
+
label: '保存并关闭',
|
|
56
|
+
sources: [],
|
|
57
|
+
},
|
|
58
|
+
overrideFields: [],
|
|
59
|
+
},
|
|
60
|
+
search: {
|
|
61
|
+
searchField: {
|
|
62
|
+
pageRole: 'list',
|
|
63
|
+
field: 'windowname',
|
|
64
|
+
label: '窗口名称',
|
|
65
|
+
sources: [],
|
|
66
|
+
},
|
|
67
|
+
submitControl: {
|
|
68
|
+
pageRole: 'list',
|
|
69
|
+
label: '查询',
|
|
70
|
+
sources: [],
|
|
71
|
+
},
|
|
72
|
+
resultGrid: 'datagrid',
|
|
73
|
+
},
|
|
74
|
+
update: {
|
|
75
|
+
entryAction: {
|
|
76
|
+
pageRole: 'list',
|
|
77
|
+
label: '修改',
|
|
78
|
+
sources: [],
|
|
79
|
+
},
|
|
80
|
+
targetPageId: 'gxhzwplaceedit',
|
|
81
|
+
updateField: {
|
|
82
|
+
pageRole: 'edit',
|
|
83
|
+
field: 'windowname',
|
|
84
|
+
label: '窗口名称',
|
|
85
|
+
sources: [],
|
|
86
|
+
},
|
|
87
|
+
saveButton: {
|
|
88
|
+
pageRole: 'edit',
|
|
89
|
+
label: '保存并关闭',
|
|
90
|
+
sources: [],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
delete: {
|
|
94
|
+
entryButton: {
|
|
95
|
+
pageRole: 'list',
|
|
96
|
+
label: '删除选定',
|
|
97
|
+
sources: [],
|
|
98
|
+
},
|
|
99
|
+
expectedOutcome: 'success_delete',
|
|
100
|
+
confirmControl: {
|
|
101
|
+
pageRole: 'list',
|
|
102
|
+
label: '确定',
|
|
103
|
+
sources: [],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
assertions: [],
|
|
108
|
+
businessRules: [],
|
|
109
|
+
unresolvedSlots: [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
describe('glue testcase skeleton', () => {
|
|
113
|
+
it('selects the CRUD testcase skeleton for a single-page CRUD scenario', () => {
|
|
114
|
+
expect(selectTestcaseSkeletonByScenario('crud.single-page')).toMatchObject({
|
|
115
|
+
skeletonId: 'crud.skeleton-testcase/v1',
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
it('selects the same CRUD testcase skeleton for a nested CRUD pilot scenario', () => {
|
|
119
|
+
expect(selectTestcaseSkeletonByScenario('crud.nested')).toMatchObject({
|
|
120
|
+
skeletonId: 'crud.skeleton-testcase/v1',
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
it('maps a CRUD contract to testcase slots without guessing unresolved business values', () => {
|
|
124
|
+
const slots = mapContractToCrudTestcaseSlots({
|
|
125
|
+
contract: createCrudContract(),
|
|
126
|
+
scenario: 'crud.single-page',
|
|
127
|
+
menu: '场所窗口信息管理>场所窗口信息列表',
|
|
128
|
+
});
|
|
129
|
+
expect(slots).toMatchObject({
|
|
130
|
+
moduleId: 'zwplace',
|
|
131
|
+
moduleName: '场所窗口信息管理',
|
|
132
|
+
listPageTitle: '场所窗口信息列表',
|
|
133
|
+
createActionLabel: '新增场所窗口',
|
|
134
|
+
searchFieldLabel: '窗口名称',
|
|
135
|
+
envBaseUrl: '.env: LOGIN_SYSTEM_URL',
|
|
136
|
+
envUsername: '.env: LOGIN_USERNAME',
|
|
137
|
+
envPassword: '.env: LOGIN_PASSWORD',
|
|
138
|
+
unresolved: [],
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
it('treats unresolved menu placeholders as unresolved instead of resolved slot sources', () => {
|
|
142
|
+
const slots = mapContractToCrudTestcaseSlots({
|
|
143
|
+
contract: createCrudContract(),
|
|
144
|
+
scenario: 'crud.single-page',
|
|
145
|
+
menu: '未确认菜单路径',
|
|
146
|
+
});
|
|
147
|
+
expect(slots.reviewStatus).toBe('needs_review');
|
|
148
|
+
expect(slots.menu).toBe('待人工确认');
|
|
149
|
+
expect(slots.unresolved).toContain('menu: 缺少 input.menu');
|
|
150
|
+
expect(slots.slotSources).not.toContain('menu=input.menu');
|
|
151
|
+
});
|
|
152
|
+
it('records missing contract slots as unresolved without guessing business values', () => {
|
|
153
|
+
const contract = createCrudContract();
|
|
154
|
+
delete contract.flows.create;
|
|
155
|
+
const slots = mapContractToCrudTestcaseSlots({
|
|
156
|
+
contract,
|
|
157
|
+
scenario: 'crud.single-page',
|
|
158
|
+
menu: '场所窗口信息管理>场所窗口信息列表',
|
|
159
|
+
});
|
|
160
|
+
expect(slots.reviewStatus).toBe('needs_review');
|
|
161
|
+
expect(slots.createActionLabel).toBe('待人工确认');
|
|
162
|
+
expect(slots.unresolved).toContain('createActionLabel: 缺少 contract.flows.create.entryButton.label');
|
|
163
|
+
});
|
|
164
|
+
it('renders the testcase skeleton template from slots', () => {
|
|
165
|
+
const template = [
|
|
166
|
+
'# {{moduleName}}',
|
|
167
|
+
'',
|
|
168
|
+
'## {{createCaseTitle}}',
|
|
169
|
+
'',
|
|
170
|
+
'- 列表页:{{listPageTitle}}',
|
|
171
|
+
'- 步骤:{{createSteps}}',
|
|
172
|
+
'- 查询字段:{{searchFieldLabel}}',
|
|
173
|
+
].join('\n');
|
|
174
|
+
const markdown = renderGlueTestcaseSkeleton(template, mapContractToCrudTestcaseSlots({
|
|
175
|
+
contract: createCrudContract(),
|
|
176
|
+
scenario: 'crud.single-page',
|
|
177
|
+
menu: '场所窗口信息管理>场所窗口信息列表',
|
|
178
|
+
}));
|
|
179
|
+
expect(markdown).toContain('# 场所窗口信息管理');
|
|
180
|
+
expect(markdown).toContain('## 新增场所窗口信息管理');
|
|
181
|
+
expect(markdown).toContain('列表页:场所窗口信息列表');
|
|
182
|
+
expect(markdown).toContain('查询字段:窗口名称');
|
|
183
|
+
expect(markdown).not.toContain('{{');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testcase-spec-assembly.test.d.ts","sourceRoot":"","sources":["../../test/testcase-spec-assembly.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { validateGlueTestcaseDocumentForSpecAssembly } from '../src/testcase/testcase-spec-assembly.js';
|
|
3
|
+
/**
|
|
4
|
+
* 构造 spec assembly 校验所需的最小契约。
|
|
5
|
+
*
|
|
6
|
+
* @returns CRUD 业务模块契约的模块标识部分。
|
|
7
|
+
*/
|
|
8
|
+
function createContract() {
|
|
9
|
+
return {
|
|
10
|
+
contractVersion: 'crud-business-module/v1',
|
|
11
|
+
module: {
|
|
12
|
+
id: 'zwplace',
|
|
13
|
+
label: '场所窗口信息管理',
|
|
14
|
+
},
|
|
15
|
+
pages: {
|
|
16
|
+
list: {
|
|
17
|
+
role: 'list',
|
|
18
|
+
pageId: 'gxhzwplacelist',
|
|
19
|
+
title: '场所窗口信息列表',
|
|
20
|
+
iframeSrcKeyword: 'gxhzwplacelist',
|
|
21
|
+
fields: [],
|
|
22
|
+
buttons: [],
|
|
23
|
+
grids: [],
|
|
24
|
+
dialogs: [],
|
|
25
|
+
sources: [],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
dataKey: {
|
|
29
|
+
field: 'windowname',
|
|
30
|
+
label: '窗口名称',
|
|
31
|
+
availability: 'derivable',
|
|
32
|
+
generationStrategy: 'timestamp_prefix',
|
|
33
|
+
sources: [],
|
|
34
|
+
},
|
|
35
|
+
flows: {},
|
|
36
|
+
assertions: [],
|
|
37
|
+
businessRules: [],
|
|
38
|
+
unresolvedSlots: [],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 构造已确认的 CRUD 四工作流用例文档。
|
|
43
|
+
*
|
|
44
|
+
* @returns 胶水测试用例文档。
|
|
45
|
+
*/
|
|
46
|
+
function createConfirmedTestcaseDocument() {
|
|
47
|
+
return {
|
|
48
|
+
moduleId: 'zwplace',
|
|
49
|
+
moduleName: '场所窗口信息管理',
|
|
50
|
+
cases: [
|
|
51
|
+
createCase('zwplace.create', 'Create:新增场所窗口信息管理'),
|
|
52
|
+
createCase('zwplace.read', 'Read:搜索场所窗口信息管理'),
|
|
53
|
+
createCase('zwplace.update', 'Update:修改场所窗口信息管理'),
|
|
54
|
+
createCase('zwplace.delete', 'Delete:删除场所窗口信息管理'),
|
|
55
|
+
],
|
|
56
|
+
reasoningSummary: {
|
|
57
|
+
conclusion: '已确认 CRUD 用例。',
|
|
58
|
+
evidenceChain: [],
|
|
59
|
+
alternatives: [],
|
|
60
|
+
confidence: 'high',
|
|
61
|
+
risks: [],
|
|
62
|
+
needsHumanReview: false,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 构造单条已确认用例。
|
|
68
|
+
*
|
|
69
|
+
* @param caseId 用例 ID。
|
|
70
|
+
* @param title 用例标题。
|
|
71
|
+
* @returns 胶水测试用例。
|
|
72
|
+
*/
|
|
73
|
+
function createCase(caseId, title) {
|
|
74
|
+
return {
|
|
75
|
+
caseId,
|
|
76
|
+
title,
|
|
77
|
+
scenario: 'crud.single-page',
|
|
78
|
+
reviewStatus: 'confirmed',
|
|
79
|
+
evidence: [],
|
|
80
|
+
steps: ['执行动作'],
|
|
81
|
+
assertions: ['验证结果'],
|
|
82
|
+
unresolved: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
describe('testcase spec assembly contract', () => {
|
|
86
|
+
it('accepts confirmed testcase documents that match the contract CRUD workflow granularity', () => {
|
|
87
|
+
expect(() => validateGlueTestcaseDocumentForSpecAssembly(createConfirmedTestcaseDocument(), createContract())).not.toThrow();
|
|
88
|
+
});
|
|
89
|
+
it('rejects testcase documents that still need human review', () => {
|
|
90
|
+
const document = createConfirmedTestcaseDocument();
|
|
91
|
+
document.cases[1].reviewStatus = 'needs_review';
|
|
92
|
+
document.cases[1].unresolved = ['menu: 缺少 input.menu'];
|
|
93
|
+
expect(() => validateGlueTestcaseDocumentForSpecAssembly(document, createContract())).toThrow('glue testcase 仍有未确认用例');
|
|
94
|
+
});
|
|
95
|
+
it('rejects testcase documents that do not match the contract module', () => {
|
|
96
|
+
const document = createConfirmedTestcaseDocument();
|
|
97
|
+
document.moduleId = 'other-module';
|
|
98
|
+
expect(() => validateGlueTestcaseDocumentForSpecAssembly(document, createContract())).toThrow('glue testcase moduleId 与 contract 不一致');
|
|
99
|
+
});
|
|
100
|
+
it('rejects testcase documents missing CRUD workflow cases required by the generated spec', () => {
|
|
101
|
+
const document = createConfirmedTestcaseDocument();
|
|
102
|
+
document.cases = document.cases.filter((item) => item.caseId !== 'zwplace.update');
|
|
103
|
+
expect(() => validateGlueTestcaseDocumentForSpecAssembly(document, createContract())).toThrow('glue testcase 缺少 spec assembly 需要的用例');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vitest.config.d.ts","sourceRoot":"","sources":["../vitest.config.ts"],"names":[],"mappings":";AAEA,wBAKG"}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @epoint/ep-stage-skill
|
|
2
|
+
|
|
3
|
+
> 胶水编码链路 Agent Skill — 解析上游物料,按契约生成可执行测试脚本
|
|
4
|
+
|
|
5
|
+
## 定位
|
|
6
|
+
|
|
7
|
+
`ep-stage-skill` 是 **ep-stage 生态的 AI 驱动层**,作为 Agent Skill 嵌入胶水编码链路。它解析上游物料(PRD、code_list、HTML、Java Action),根据槽位信息契约按图索骥,获取槽位信息后组装 `stage-create --mode glue` 创建的骨架项目中的代码骨架,最终生成可以真实执行的 Playwright 测试脚本。
|
|
8
|
+
|
|
9
|
+
## 外发形式
|
|
10
|
+
|
|
11
|
+
AI Agent 可发现的 Skill 入口(Claude Code 扫 `.claude/skills/`、Codex 扫 `.agents/skills/`,均 symlink 到包内源):
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
.claude/skills/{glue-test, create-project, recording-to-glue}
|
|
15
|
+
.agents/skills/{glue-test, create-project, recording-to-glue}
|
|
16
|
+
→ packages/ep-stage-skill/codex-skill/ep-stage/<skill>/
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 链路
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
上游物料(PRD / code_list / HTML / Java Action)
|
|
23
|
+
-> 解析上游物料,提取 crud-business-module/v1 契约
|
|
24
|
+
-> 根据槽位信息契约按图索骥,获取槽位信息
|
|
25
|
+
-> 组装 stage-create glue 骨架项目中的代码骨架
|
|
26
|
+
-> 生成 CrudFlowSlots spec
|
|
27
|
+
-> 落袋到 stage-create 脚手架项目
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## CLI
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
# 可观测默认入口(推荐)
|
|
34
|
+
pnpm --filter @epoint/ep-stage-skill run:gap-pipeline -- \
|
|
35
|
+
--code-list <code_list.md>
|
|
36
|
+
|
|
37
|
+
# 生成契约
|
|
38
|
+
pnpm --filter @epoint/ep-stage-skill generate:crud-contract -- \
|
|
39
|
+
--module-id <模块ID> \
|
|
40
|
+
--docs <上游文档目录> \
|
|
41
|
+
--code-list <code_list.md> \
|
|
42
|
+
--webapp <前端 HTML 目录> \
|
|
43
|
+
--java-actions <Java Action 目录> \
|
|
44
|
+
--hints packages/ep-stage-skill/examples/<module>.module-hints.json \
|
|
45
|
+
--out output/<module>.crud.contract.json
|
|
46
|
+
|
|
47
|
+
# 生成测试脚本
|
|
48
|
+
pnpm --filter @epoint/ep-stage-skill generate:playwright-tests -- \
|
|
49
|
+
--contract output/<module>.crud.contract.json \
|
|
50
|
+
--out <glue项目>/src/tests/<name>.spec.ts \
|
|
51
|
+
--menu "一级菜单>二级菜单" \
|
|
52
|
+
--testcase <glue项目>/testcases/<module>.glue-testcase.json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`run:gap-pipeline` 的默认业务输入收口到 `code_list.md`。建议在该文件中声明:
|
|
56
|
+
|
|
57
|
+
```md
|
|
58
|
+
knowledgeRoot: /abs/path/to/knowledge-project/xxx
|
|
59
|
+
menu: 一级菜单>二级菜单
|
|
60
|
+
|
|
61
|
+
`_docs/.../spec.yaml`
|
|
62
|
+
`src/main/webapp/.../*.html`
|
|
63
|
+
`src/main/java/.../*Action.java`
|
|
64
|
+
`_docs/.../*.module-hints.json`
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
说明:
|
|
68
|
+
|
|
69
|
+
- `knowledgeRoot`:上游物料根目录,用于解析 `code_list.md` 中的相对路径。
|
|
70
|
+
- `menu` / `menuPath`:系统菜单路由,不是文件路径;缺失时链路会生成候选菜单并停在人工确认 gate。
|
|
71
|
+
- `--docs` / `--webapp` / `--java-actions` / `--hints` / `--menu` / `--project-dir`:仍保留,但定位为开发调试覆盖参数。
|
|
72
|
+
|
|
73
|
+
当前验收主线只锚定 `zwplace`,其唯一上游扎口是:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
knowledge-project/epoint-web-v9.5.2/_docs/code_list.md
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
由于主仓 `knowledge-project` 只读,仓内另提供一个“模拟交互补齐后回写”的**可写镜像**:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
packages/ep-stage-skill/examples/zwplace.observable.code_list.md
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
这个镜像不修改主仓只读 `knowledge-project/.../_docs/code_list.md`,而是把 `knowledgeRoot`、`menu`、文档物料和
|
|
86
|
+
`ModuleHints` 写入单独的可写 `code_list.md`,用于默认入口验证、交互补齐回写验证,以及只读真相源无法直接落盘时的 e2e 联调。
|
|
87
|
+
|
|
88
|
+
不要把脚手架项目中带出的说明信息当作上游本源;当前 skill 的默认入口和业务真相源仍然是 `code_list.md`。
|
|
89
|
+
|
|
90
|
+
如果后续要验证“不同系统的普通 CRUD 泛化”,应直接由用户补充第二个真实业务样本的 `code_list.md`,再复用同一条 `run:gap-pipeline -- --code-list <path>` 链路;不要把脚手架项目中的说明信息当作第二个业务样本。
|
|
91
|
+
|
|
92
|
+
当前 `run:gap-pipeline` 在 TTY 环境下已支持对默认入口缺失字段做轻量交互补齐:
|
|
93
|
+
|
|
94
|
+
- `material-inventory` gate:补 `knowledgeRoot`、`moduleId`、`webappDir`、`javaActionsDir`、`hintsPath`、`menu`
|
|
95
|
+
- `menu` gate:补 `menu`
|
|
96
|
+
|
|
97
|
+
若目标 `code_list.md` 是可写文件,补齐结果会按当前格式回写;若目标位于主仓只读
|
|
98
|
+
`knowledge-project/...`,补齐结果只对本次运行生效,不会写回受保护物料。
|
|
99
|
+
|
|
100
|
+
真实系统 E2E 约束:
|
|
101
|
+
|
|
102
|
+
- 禁止无头模式作为真实系统验收方式;真实系统验证必须使用 `--headless false`。
|
|
103
|
+
- 必须通过 `packages/ep-stage-skill/codex-skill/ep-stage` 对应 skill / `run:gap-pipeline` 入口执行,不接受绕开 skill 的自由式 Playwright 回放作为当前验收证据。
|
|
104
|
+
- 运行过程中需要人为观察页面、登录、弹窗和业务副作用;trace / report 负责补证,不替代人工观察。
|
|
105
|
+
|
|
106
|
+
当链路已走到 Playwright / glue-report 尾段但真实系统环境不可用时,`playwright-execution` trace 会把失败归类为
|
|
107
|
+
`environment_unavailable`,并尽量补充 `.env` 中 `LOGIN_SYSTEM_URL` 的轻量环境预检证据(例如 `curl -I: Empty reply from server`),
|
|
108
|
+
避免把登录环境空响应误判成 stage-glue 代码缺陷。
|
|
109
|
+
|
|
110
|
+
## 开发
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pnpm build
|
|
114
|
+
pnpm test
|
|
115
|
+
pnpm typecheck
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Gap Inference
|
|
119
|
+
|
|
120
|
+
`ep-stage-skill` 会先生成 CRUD + Export 可覆盖范围,再对当前模块的页面按钮、行操作和弹窗动作做 coverage diff。
|
|
121
|
+
|
|
122
|
+
- CRUD + Export 已覆盖动作不会进入 gap。
|
|
123
|
+
- 只有按钮文本不足以生成测试。
|
|
124
|
+
- `ModuleHints.customWorkflows` 可以补充自定义工作流的业务意图和断言预期。
|
|
125
|
+
- 真实页面定位补证由 `e2e/glue-code-mvp` 的 gap-executor 试点 runner 执行。
|
|
126
|
+
|
|
127
|
+
## 生态关系
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
ep-stage-skill(AI 驱动 / 解析 + 组装)
|
|
131
|
+
├── 消费 stage-core(定位器、自动填充)
|
|
132
|
+
├── 消费 stage-create glue 骨架(skeletons)
|
|
133
|
+
└── 产出测试脚本 → 落袋到 stage-create 项目
|
|
134
|
+
```
|