@pzy560117/opentest 0.1.9 → 0.1.11
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/assets/manifest.json +12 -1
- package/assets/skills/opentest/references/api-testing.md +77 -0
- package/assets/skills/opentest/references/codex-harness-coverage-heuristics.md +17 -1
- package/assets/skills/opentest/references/complete-testing-workflow.md +27 -0
- package/assets/skills/opentest/references/desktop-gui-testing.md +52 -0
- package/assets/skills/opentest/references/matrix-format.md +12 -2
- package/assets/skills/opentest/references/opentest-driven-development.md +10 -0
- package/assets/skills/opentest/references/test-asset-layout.md +64 -0
- package/assets/skills/opentest/references/test-surfaces.md +101 -0
- package/assets/skills/opentest/references/web-browser-testing.md +40 -0
- package/assets/skills/opentest/templates/acceptance-template.md +3 -1
- package/assets/skills/opentest/templates/api-acceptance-template.md +44 -0
- package/assets/skills/opentest/templates/desktop-gui-acceptance-template.md +43 -0
- package/assets/skills/opentest/templates/matrix-template.md +12 -11
- package/assets/skills/opentest/templates/plan-template.md +2 -2
- package/assets/skills/opentest/templates/web-acceptance-template.md +27 -0
- package/assets/skills/opentest-accept/SKILL.md +15 -6
- package/assets/skills/opentest-api/SKILL.md +25 -0
- package/assets/skills/opentest-author/SKILL.md +7 -5
- package/assets/skills/opentest-desktop-gui/SKILL.md +24 -0
- package/assets/skills/opentest-plan/SKILL.md +15 -9
- package/assets/skills/opentest-run/SKILL.md +14 -8
- package/assets/skills/opentest-web-browser/SKILL.md +26 -0
- package/assets/skills-zh/opentest/references/api-testing.md +77 -0
- package/assets/skills-zh/opentest/references/codex-harness-coverage-heuristics.md +17 -1
- package/assets/skills-zh/opentest/references/complete-testing-workflow.md +27 -0
- package/assets/skills-zh/opentest/references/desktop-gui-testing.md +52 -0
- package/assets/skills-zh/opentest/references/matrix-format.md +12 -2
- package/assets/skills-zh/opentest/references/opentest-driven-development.md +10 -0
- package/assets/skills-zh/opentest/references/test-asset-layout.md +64 -0
- package/assets/skills-zh/opentest/references/test-surfaces.md +101 -0
- package/assets/skills-zh/opentest/references/web-browser-testing.md +40 -0
- package/assets/skills-zh/opentest/templates/acceptance-template.md +3 -1
- package/assets/skills-zh/opentest/templates/api-acceptance-template.md +44 -0
- package/assets/skills-zh/opentest/templates/desktop-gui-acceptance-template.md +43 -0
- package/assets/skills-zh/opentest/templates/matrix-template.md +12 -11
- package/assets/skills-zh/opentest/templates/plan-template.md +2 -2
- package/assets/skills-zh/opentest/templates/web-acceptance-template.md +27 -0
- package/assets/skills-zh/opentest-accept/SKILL.md +14 -5
- package/assets/skills-zh/opentest-api/SKILL.md +25 -0
- package/assets/skills-zh/opentest-author/SKILL.md +7 -5
- package/assets/skills-zh/opentest-desktop-gui/SKILL.md +24 -0
- package/assets/skills-zh/opentest-plan/SKILL.md +13 -7
- package/assets/skills-zh/opentest-run/SKILL.md +13 -7
- package/assets/skills-zh/opentest-web-browser/SKILL.md +26 -0
- package/package.json +1 -1
- package/scripts/smoke-test.js +309 -1
package/scripts/smoke-test.js
CHANGED
|
@@ -182,7 +182,7 @@ function assertDefaultPytestContracts() {
|
|
|
182
182
|
assert(stateScript.includes('test_framework|'), '[PYTEST] state script must allow test_framework field updates');
|
|
183
183
|
assert(detectScript.includes('default_test_framework: pytest'), '[PYTEST] detect summary must report pytest as default framework');
|
|
184
184
|
assert(detectScript.includes('pytest_command:'), '[PYTEST] detect summary must report pytest command status');
|
|
185
|
-
assert(englishAuthor.includes('
|
|
185
|
+
assert(englishAuthor.includes('default to pytest'), '[PYTEST] English author skill must default missing framework to pytest');
|
|
186
186
|
assert(chineseAuthor.includes('默认使用 pytest'), '[PYTEST] Chinese author skill must default missing framework to pytest');
|
|
187
187
|
assert(englishRun.includes('python -m pytest'), '[PYTEST] English run skill must document pytest command');
|
|
188
188
|
assert(chineseRun.includes('python -m pytest'), '[PYTEST] Chinese run skill must document pytest command');
|
|
@@ -192,6 +192,308 @@ function assertDefaultPytestContracts() {
|
|
|
192
192
|
assert(chineseMatrix.includes('覆盖维度') && chineseMatrix.includes('框架/命令') && chineseMatrix.includes('缺口/阻塞'), '[COVERAGE] Chinese matrix template must include coverage, command, and gap columns');
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
function assertRequirementFirstAcceptanceContracts() {
|
|
196
|
+
const englishWorkflow = readFileSync('assets/skills/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
197
|
+
const chineseWorkflow = readFileSync('assets/skills-zh/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
198
|
+
const englishDriven = readFileSync('assets/skills/opentest/references/opentest-driven-development.md', 'utf8');
|
|
199
|
+
const chineseDriven = readFileSync('assets/skills-zh/opentest/references/opentest-driven-development.md', 'utf8');
|
|
200
|
+
const englishMatrixFormat = readFileSync('assets/skills/opentest/references/matrix-format.md', 'utf8');
|
|
201
|
+
const chineseMatrixFormat = readFileSync('assets/skills-zh/opentest/references/matrix-format.md', 'utf8');
|
|
202
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
203
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
204
|
+
const englishAuthor = readFileSync('assets/skills/opentest-author/SKILL.md', 'utf8');
|
|
205
|
+
const chineseAuthor = readFileSync('assets/skills-zh/opentest-author/SKILL.md', 'utf8');
|
|
206
|
+
const englishMatrix = readFileSync('assets/skills/opentest/templates/matrix-template.md', 'utf8');
|
|
207
|
+
const chineseMatrix = readFileSync('assets/skills-zh/opentest/templates/matrix-template.md', 'utf8');
|
|
208
|
+
|
|
209
|
+
assert(englishDriven.includes('Requirement-First Contract'), '[REQFIRST] English driven-development reference must define requirement-first contract');
|
|
210
|
+
assert(chineseDriven.includes('需求先行契约'), '[REQFIRST] Chinese driven-development reference must define requirement-first contract');
|
|
211
|
+
assert(englishWorkflow.includes('Requirement-First Acceptance'), '[REQFIRST] English workflow must include requirement-first acceptance gate');
|
|
212
|
+
assert(chineseWorkflow.includes('需求先行验收'), '[REQFIRST] Chinese workflow must include requirement-first acceptance gate');
|
|
213
|
+
assert(englishMatrixFormat.includes('Requirement source') && englishMatrixFormat.includes('Do not use a function name'), '[REQFIRST] English matrix format must require requirement source and reject implementation-derived sources');
|
|
214
|
+
assert(chineseMatrixFormat.includes('需求来源') && chineseMatrixFormat.includes('不要把函数名'), '[REQFIRST] Chinese matrix format must require requirement source and reject implementation-derived sources');
|
|
215
|
+
assert(englishMatrix.includes('Requirement source') && englishMatrix.includes('REQ-001'), '[REQFIRST] English matrix template must include requirement source examples');
|
|
216
|
+
assert(chineseMatrix.includes('需求来源') && chineseMatrix.includes('REQ-001'), '[REQFIRST] Chinese matrix template must include requirement source examples');
|
|
217
|
+
assert(englishPlan.includes('current code only for project facts') && englishPlan.includes('Do not drop or narrow acceptance'), '[REQFIRST] English plan skill must prevent implementation-derived acceptance');
|
|
218
|
+
assert(chinesePlan.includes('读取当前代码只用于发现项目事实') && chinesePlan.includes('不得因为当前代码没有对应函数'), '[REQFIRST] Chinese plan skill must prevent implementation-derived acceptance');
|
|
219
|
+
assert(englishAuthor.includes('Missing implementation means evidence stays pending'), '[REQFIRST] English author skill must keep requirements when implementation is missing');
|
|
220
|
+
assert(chineseAuthor.includes('实现缺失只表示证据 pending'), '[REQFIRST] Chinese author skill must keep requirements when implementation is missing');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function assertTestSurfaceContracts() {
|
|
224
|
+
const manifestText = readFileSync('assets/manifest.json', 'utf8');
|
|
225
|
+
const englishSurfaces = readRequiredText('assets/skills/opentest/references/test-surfaces.md', '[SURFACE] missing English test-surfaces reference');
|
|
226
|
+
const chineseSurfaces = readRequiredText('assets/skills-zh/opentest/references/test-surfaces.md', '[SURFACE] missing Chinese test-surfaces reference');
|
|
227
|
+
const englishMatrixFormat = readFileSync('assets/skills/opentest/references/matrix-format.md', 'utf8');
|
|
228
|
+
const chineseMatrixFormat = readFileSync('assets/skills-zh/opentest/references/matrix-format.md', 'utf8');
|
|
229
|
+
const englishWorkflow = readFileSync('assets/skills/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
230
|
+
const chineseWorkflow = readFileSync('assets/skills-zh/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
231
|
+
const englishHeuristics = readFileSync('assets/skills/opentest/references/codex-harness-coverage-heuristics.md', 'utf8');
|
|
232
|
+
const chineseHeuristics = readFileSync('assets/skills-zh/opentest/references/codex-harness-coverage-heuristics.md', 'utf8');
|
|
233
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
234
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
235
|
+
const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
|
|
236
|
+
const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
|
|
237
|
+
const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
|
|
238
|
+
const chineseAccept = readFileSync('assets/skills-zh/opentest-accept/SKILL.md', 'utf8');
|
|
239
|
+
const englishMatrix = readFileSync('assets/skills/opentest/templates/matrix-template.md', 'utf8');
|
|
240
|
+
const chineseMatrix = readFileSync('assets/skills-zh/opentest/templates/matrix-template.md', 'utf8');
|
|
241
|
+
const englishPlanTemplate = readFileSync('assets/skills/opentest/templates/plan-template.md', 'utf8');
|
|
242
|
+
const chinesePlanTemplate = readFileSync('assets/skills-zh/opentest/templates/plan-template.md', 'utf8');
|
|
243
|
+
const englishAcceptance = readFileSync('assets/skills/opentest/templates/acceptance-template.md', 'utf8');
|
|
244
|
+
const chineseAcceptance = readFileSync('assets/skills-zh/opentest/templates/acceptance-template.md', 'utf8');
|
|
245
|
+
const surfaces = ['web-browser', 'android-app', 'desktop-gui', 'api'];
|
|
246
|
+
|
|
247
|
+
assert(manifestText.includes('opentest/references/test-surfaces.md'), '[SURFACE] manifest must ship test-surfaces reference');
|
|
248
|
+
|
|
249
|
+
for (const surface of surfaces) {
|
|
250
|
+
assert(englishSurfaces.includes(surface), `[SURFACE] English test-surfaces missing ${surface}`);
|
|
251
|
+
assert(chineseSurfaces.includes(surface), `[SURFACE] Chinese test-surfaces missing ${surface}`);
|
|
252
|
+
assert(englishMatrixFormat.includes(surface), `[SURFACE] English matrix-format missing ${surface}`);
|
|
253
|
+
assert(chineseMatrixFormat.includes(surface), `[SURFACE] Chinese matrix-format missing ${surface}`);
|
|
254
|
+
assert(englishMatrix.includes(surface), `[SURFACE] English matrix template missing ${surface}`);
|
|
255
|
+
assert(chineseMatrix.includes(surface), `[SURFACE] Chinese matrix template missing ${surface}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
assert(englishSurfaces.includes('Do not invent a fifth primary surface'), '[SURFACE] English reference must forbid fifth primary surface');
|
|
259
|
+
assert(chineseSurfaces.includes('不要发明第五种主执行面'), '[SURFACE] Chinese reference must forbid fifth primary surface');
|
|
260
|
+
assert(englishSurfaces.includes('android-midscene-pytest') && englishSurfaces.includes('Midscene HTML report') && englishSurfaces.includes('logcat'), '[SURFACE] English Android route must require Midscene and logcat evidence');
|
|
261
|
+
assert(chineseSurfaces.includes('android-midscene-pytest') && chineseSurfaces.includes('Midscene HTML 报告') && chineseSurfaces.includes('logcat'), '[SURFACE] Chinese Android route must require Midscene and logcat evidence');
|
|
262
|
+
assert(englishSurfaces.includes('Midscene YAML runner') && englishSurfaces.includes('MIDSCENE_MCP_ANDROID_MODE=true') && englishSurfaces.includes('midscene-python'), '[SURFACE] English Android route must document YAML, MCP, and midscene-python boundaries');
|
|
263
|
+
assert(chineseSurfaces.includes('Midscene YAML runner') && chineseSurfaces.includes('MIDSCENE_MCP_ANDROID_MODE=true') && chineseSurfaces.includes('midscene-python'), '[SURFACE] Chinese Android route must document YAML, MCP, and midscene-python boundaries');
|
|
264
|
+
assert(englishSurfaces.includes('npm run test:android') && englishSurfaces.includes('midscene_run/log/ai-call.log') && englishSurfaces.includes('midscene_run/report/*.html'), '[SURFACE] English Android route must document layered run and failure artifacts');
|
|
265
|
+
assert(chineseSurfaces.includes('npm run test:android') && chineseSurfaces.includes('midscene_run/log/ai-call.log') && chineseSurfaces.includes('midscene_run/report/*.html'), '[SURFACE] Chinese Android route must document layered run and failure artifacts');
|
|
266
|
+
assert(englishSurfaces.includes('opentest-desktop-gui') && englishSurfaces.includes('@midscene/computer') && englishSurfaces.includes('deterministic read/assert changed result'), '[SURFACE] English desktop route must document opentest-desktop-gui and deterministic read-back');
|
|
267
|
+
assert(chineseSurfaces.includes('opentest-desktop-gui') && chineseSurfaces.includes('@midscene/computer') && chineseSurfaces.includes('确定性 read/assert changed result'), '[SURFACE] Chinese desktop route must document opentest-desktop-gui and deterministic read-back');
|
|
268
|
+
assert(englishSurfaces.includes('opentest-api') && englishSurfaces.includes('httpx') && englishSurfaces.includes('read-after-write'), '[SURFACE] English API route must document opentest-api and read-after-write');
|
|
269
|
+
assert(chineseSurfaces.includes('opentest-api') && chineseSurfaces.includes('httpx') && chineseSurfaces.includes('写后读'), '[SURFACE] Chinese API route must document opentest-api and read-after-write');
|
|
270
|
+
assert(englishWorkflow.includes('Execution Surfaces') && englishWorkflow.includes('android-midscene-pytest'), '[SURFACE] English workflow must include execution surface rules');
|
|
271
|
+
assert(chineseWorkflow.includes('执行面') && chineseWorkflow.includes('android-midscene-pytest'), '[SURFACE] Chinese workflow must include execution surface rules');
|
|
272
|
+
assert(englishWorkflow.includes('opentest-desktop-gui') && englishWorkflow.includes('@midscene/computer'), '[SURFACE] English workflow must include desktop GUI route');
|
|
273
|
+
assert(chineseWorkflow.includes('opentest-desktop-gui') && chineseWorkflow.includes('@midscene/computer'), '[SURFACE] Chinese workflow must include desktop GUI route');
|
|
274
|
+
assert(englishWorkflow.includes('opentest-api') && englishWorkflow.includes('httpx'), '[SURFACE] English workflow must include API route');
|
|
275
|
+
assert(chineseWorkflow.includes('opentest-api') && chineseWorkflow.includes('httpx'), '[SURFACE] Chinese workflow must include API route');
|
|
276
|
+
assert(englishHeuristics.includes('Execution Surface Selection') && englishHeuristics.includes('android-midscene-pytest'), '[SURFACE] English heuristics must include surface selection');
|
|
277
|
+
assert(chineseHeuristics.includes('执行面选择') && chineseHeuristics.includes('android-midscene-pytest'), '[SURFACE] Chinese heuristics must include surface selection');
|
|
278
|
+
assert(englishHeuristics.includes('opentest-desktop-gui') && englishHeuristics.includes('@midscene/computer'), '[SURFACE] English heuristics must include desktop GUI route');
|
|
279
|
+
assert(chineseHeuristics.includes('opentest-desktop-gui') && chineseHeuristics.includes('@midscene/computer'), '[SURFACE] Chinese heuristics must include desktop GUI route');
|
|
280
|
+
assert(englishHeuristics.includes('opentest-api') && englishHeuristics.includes('httpx'), '[SURFACE] English heuristics must include API route');
|
|
281
|
+
assert(chineseHeuristics.includes('opentest-api') && chineseHeuristics.includes('httpx'), '[SURFACE] Chinese heuristics must include API route');
|
|
282
|
+
|
|
283
|
+
for (const skillContent of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
|
|
284
|
+
assert(skillContent.includes('opentest/references/test-surfaces.md'), '[SURFACE] plan/run/accept skills must read test-surfaces reference');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
assert(englishPlan.includes('execution surface and evidence layer separately'), '[SURFACE] English plan must split surface and evidence layer');
|
|
288
|
+
assert(chinesePlan.includes('分开判定执行面和证据层级'), '[SURFACE] Chinese plan must split surface and evidence layer');
|
|
289
|
+
assert(englishRun.includes('matrix execution surface') && englishRun.includes('python -m pytest tests_py -v'), '[SURFACE] English run must route by execution surface');
|
|
290
|
+
assert(chineseRun.includes('矩阵执行面') && chineseRun.includes('python -m pytest tests_py -v'), '[SURFACE] Chinese run must route by execution surface');
|
|
291
|
+
assert(englishRun.includes('npm run test:android') && englishRun.includes('model env'), '[SURFACE] English run must gate npm run test:android behind model env/debugging');
|
|
292
|
+
assert(chineseRun.includes('npm run test:android') && chineseRun.includes('模型环境变量'), '[SURFACE] Chinese run must gate npm run test:android behind model env/debugging');
|
|
293
|
+
assert(englishAccept.includes('android-midscene-pytest') && englishAccept.includes('ADB smoke') && englishAccept.includes('midscene_run'), '[SURFACE] English accept must route Android through android-midscene-pytest');
|
|
294
|
+
assert(chineseAccept.includes('android-midscene-pytest') && chineseAccept.includes('ADB 冒烟') && chineseAccept.includes('midscene_run'), '[SURFACE] Chinese accept must route Android through android-midscene-pytest');
|
|
295
|
+
assert(englishAccept.includes('opentest-desktop-gui') && englishAccept.includes('@midscene/computer'), '[SURFACE] English accept must route desktop GUI through opentest-desktop-gui');
|
|
296
|
+
assert(chineseAccept.includes('opentest-desktop-gui') && chineseAccept.includes('@midscene/computer'), '[SURFACE] Chinese accept must route desktop GUI through opentest-desktop-gui');
|
|
297
|
+
assert(englishAccept.includes('opentest-api') && englishAccept.includes('httpx') && englishAccept.includes('cleanup/teardown'), '[SURFACE] English accept must route API through opentest-api');
|
|
298
|
+
assert(chineseAccept.includes('opentest-api') && chineseAccept.includes('httpx') && chineseAccept.includes('cleanup/teardown'), '[SURFACE] Chinese accept must route API through opentest-api');
|
|
299
|
+
|
|
300
|
+
assert(englishMatrix.includes('Execution surface') && englishMatrix.includes('Evidence layer') && englishMatrix.includes('Midscene HTML report') && englishMatrix.includes('python -m pytest tests_py -v') && englishMatrix.includes('ADB smoke') && englishMatrix.includes('midscene_run'), '[SURFACE] English matrix template must include execution surface and Android artifacts');
|
|
301
|
+
assert(chineseMatrix.includes('执行面') && chineseMatrix.includes('证据层级') && chineseMatrix.includes('Midscene HTML 报告') && chineseMatrix.includes('python -m pytest tests_py -v') && chineseMatrix.includes('ADB 冒烟') && chineseMatrix.includes('midscene_run'), '[SURFACE] Chinese matrix template must include execution surface and Android artifacts');
|
|
302
|
+
assert(englishMatrix.includes('opentest-desktop-gui') && englishMatrix.includes('@midscene/computer') && englishMatrix.includes('deterministic read-back'), '[SURFACE] English matrix template must include desktop GUI artifacts');
|
|
303
|
+
assert(chineseMatrix.includes('opentest-desktop-gui') && chineseMatrix.includes('@midscene/computer') && chineseMatrix.includes('确定性回读'), '[SURFACE] Chinese matrix template must include desktop GUI artifacts');
|
|
304
|
+
assert(englishMatrix.includes('opentest-api') && englishMatrix.includes('python -m pytest tests/api -v') && englishMatrix.includes('payload/schema assertion') && englishMatrix.includes('cleanup/teardown'), '[SURFACE] English matrix template must include API artifacts');
|
|
305
|
+
assert(chineseMatrix.includes('opentest-api') && chineseMatrix.includes('python -m pytest tests/api -v') && chineseMatrix.includes('payload/schema 断言') && chineseMatrix.includes('cleanup/teardown'), '[SURFACE] Chinese matrix template must include API artifacts');
|
|
306
|
+
assert(englishPlanTemplate.includes('| Execution surface | Acceptance mode | Evidence layer |'), '[SURFACE] English plan template must split surface and evidence layer');
|
|
307
|
+
assert(chinesePlanTemplate.includes('| 执行面 | 验收模式 | 证据层级 |'), '[SURFACE] Chinese plan template must split surface and evidence layer');
|
|
308
|
+
assert(englishAcceptance.includes('execution surface: web-browser | android-app | desktop-gui | api') && englishAcceptance.includes('evidence layer'), '[SURFACE] English acceptance template must include surface and evidence layer fields');
|
|
309
|
+
assert(chineseAcceptance.includes('执行面: web-browser | android-app | desktop-gui | api') && chineseAcceptance.includes('证据层级'), '[SURFACE] Chinese acceptance template must include surface and evidence layer fields');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function assertWebBrowserContracts() {
|
|
313
|
+
const manifestText = readFileSync('assets/manifest.json', 'utf8');
|
|
314
|
+
const englishSkill = readRequiredText('assets/skills/opentest-web-browser/SKILL.md', '[WEB] missing English web-browser skill');
|
|
315
|
+
const chineseSkill = readRequiredText('assets/skills-zh/opentest-web-browser/SKILL.md', '[WEB] missing Chinese web-browser skill');
|
|
316
|
+
const englishReference = readRequiredText('assets/skills/opentest/references/web-browser-testing.md', '[WEB] missing English web-browser reference');
|
|
317
|
+
const chineseReference = readRequiredText('assets/skills-zh/opentest/references/web-browser-testing.md', '[WEB] missing Chinese web-browser reference');
|
|
318
|
+
const englishTemplate = readRequiredText('assets/skills/opentest/templates/web-acceptance-template.md', '[WEB] missing English web acceptance template');
|
|
319
|
+
const chineseTemplate = readRequiredText('assets/skills-zh/opentest/templates/web-acceptance-template.md', '[WEB] missing Chinese web acceptance template');
|
|
320
|
+
const englishMatrix = readFileSync('assets/skills/opentest/templates/matrix-template.md', 'utf8');
|
|
321
|
+
const chineseMatrix = readFileSync('assets/skills-zh/opentest/templates/matrix-template.md', 'utf8');
|
|
322
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
323
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
324
|
+
const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
|
|
325
|
+
const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
|
|
326
|
+
const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
|
|
327
|
+
const chineseAccept = readFileSync('assets/skills-zh/opentest-accept/SKILL.md', 'utf8');
|
|
328
|
+
const allWebText = [
|
|
329
|
+
englishSkill,
|
|
330
|
+
chineseSkill,
|
|
331
|
+
englishReference,
|
|
332
|
+
chineseReference,
|
|
333
|
+
englishTemplate,
|
|
334
|
+
chineseTemplate,
|
|
335
|
+
].join('\n');
|
|
336
|
+
|
|
337
|
+
assert(manifestText.includes('opentest-web-browser/SKILL.md'), '[WEB] manifest must ship opentest-web-browser skill');
|
|
338
|
+
assert(manifestText.includes('opentest/references/web-browser-testing.md'), '[WEB] manifest must ship web-browser-testing reference');
|
|
339
|
+
assert(manifestText.includes('opentest/templates/web-acceptance-template.md'), '[WEB] manifest must ship web acceptance template');
|
|
340
|
+
|
|
341
|
+
for (const mode of ['instant-acceptance', 'durable-regression', 'visual-ai-assist']) {
|
|
342
|
+
assert(englishReference.includes(mode), `[WEB] English reference missing mode ${mode}`);
|
|
343
|
+
assert(chineseReference.includes(mode), `[WEB] Chinese reference missing mode ${mode}`);
|
|
344
|
+
assert(englishMatrix.includes(mode), `[WEB] English matrix missing mode ${mode}`);
|
|
345
|
+
assert(chineseMatrix.includes(mode), `[WEB] Chinese matrix missing mode ${mode}`);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
assert(englishSkill.includes('Playwright MCP') && englishSkill.includes('Playwright CLI') && englishSkill.includes('@playwright/test') && englishSkill.includes('Midscene'), '[WEB] English web skill must route MCP, CLI, Playwright Test, and Midscene');
|
|
349
|
+
assert(chineseSkill.includes('Playwright MCP') && chineseSkill.includes('Playwright CLI') && chineseSkill.includes('@playwright/test') && chineseSkill.includes('Midscene'), '[WEB] Chinese web skill must route MCP, CLI, Playwright Test, and Midscene');
|
|
350
|
+
assert(englishReference.includes('MCP and Playwright CLI are immediate acceptance tools') && englishReference.includes('not durable regression'), '[WEB] English reference must distinguish immediate acceptance from durable regression');
|
|
351
|
+
assert(chineseReference.includes('现场验收工具') && chineseReference.includes('不等于稳定回归'), '[WEB] Chinese reference must distinguish immediate acceptance from durable regression');
|
|
352
|
+
assert(englishReference.includes('Midscene is a supplemental AI visual UI automation layer'), '[WEB] English reference must position Midscene as supplemental');
|
|
353
|
+
assert(chineseReference.includes('Midscene 是 AI 视觉 UI 自动化补充层'), '[WEB] Chinese reference must position Midscene as supplemental');
|
|
354
|
+
assert(englishTemplate.includes('read/assert changed result') && chineseTemplate.includes('read/assert changed result'), '[WEB] web acceptance templates must require post-submit read/assert');
|
|
355
|
+
|
|
356
|
+
for (const content of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
|
|
357
|
+
assert(content.includes('opentest/references/web-browser-testing.md'), '[WEB] plan/run/accept skills must read web-browser-testing reference');
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
assert(!allWebText.includes('MetaS'), '[WEB] Web testing assets must not mention MetaS');
|
|
361
|
+
assert(!allWebText.includes('android-midscene-pytest') && !allWebText.includes('@midscene/android') && !allWebText.includes('python -m pytest tests_py -v') && !allWebText.includes('ADB'), '[WEB] Web testing assets must not include Android-specific route text');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function assertDesktopGuiContracts() {
|
|
365
|
+
const manifestText = readFileSync('assets/manifest.json', 'utf8');
|
|
366
|
+
const englishSkill = readRequiredText('assets/skills/opentest-desktop-gui/SKILL.md', '[DESKTOP] missing English desktop GUI skill');
|
|
367
|
+
const chineseSkill = readRequiredText('assets/skills-zh/opentest-desktop-gui/SKILL.md', '[DESKTOP] missing Chinese desktop GUI skill');
|
|
368
|
+
const englishReference = readRequiredText('assets/skills/opentest/references/desktop-gui-testing.md', '[DESKTOP] missing English desktop GUI reference');
|
|
369
|
+
const chineseReference = readRequiredText('assets/skills-zh/opentest/references/desktop-gui-testing.md', '[DESKTOP] missing Chinese desktop GUI reference');
|
|
370
|
+
const englishTemplate = readRequiredText('assets/skills/opentest/templates/desktop-gui-acceptance-template.md', '[DESKTOP] missing English desktop GUI template');
|
|
371
|
+
const chineseTemplate = readRequiredText('assets/skills-zh/opentest/templates/desktop-gui-acceptance-template.md', '[DESKTOP] missing Chinese desktop GUI template');
|
|
372
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
373
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
374
|
+
const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
|
|
375
|
+
const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
|
|
376
|
+
const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
|
|
377
|
+
const chineseAccept = readFileSync('assets/skills-zh/opentest-accept/SKILL.md', 'utf8');
|
|
378
|
+
const allDesktopText = [
|
|
379
|
+
englishSkill,
|
|
380
|
+
chineseSkill,
|
|
381
|
+
englishReference,
|
|
382
|
+
chineseReference,
|
|
383
|
+
englishTemplate,
|
|
384
|
+
chineseTemplate,
|
|
385
|
+
].join('\n');
|
|
386
|
+
|
|
387
|
+
assert(manifestText.includes('opentest-desktop-gui/SKILL.md'), '[DESKTOP] manifest must ship opentest-desktop-gui skill');
|
|
388
|
+
assert(manifestText.includes('opentest/references/desktop-gui-testing.md'), '[DESKTOP] manifest must ship desktop GUI reference');
|
|
389
|
+
assert(manifestText.includes('opentest/templates/desktop-gui-acceptance-template.md'), '[DESKTOP] manifest must ship desktop GUI acceptance template');
|
|
390
|
+
|
|
391
|
+
assert(englishSkill.includes('@midscene/computer') && englishSkill.includes('project GUI automation') && englishSkill.includes('deterministic read-back'), '[DESKTOP] English desktop skill must route project automation and @midscene/computer');
|
|
392
|
+
assert(chineseSkill.includes('@midscene/computer') && chineseSkill.includes('项目 GUI 自动化') && chineseSkill.includes('确定性回读'), '[DESKTOP] Chinese desktop skill must route project automation and @midscene/computer');
|
|
393
|
+
assert(englishReference.includes('Windows RDP') && englishReference.includes('Do not mark `desktop-gui` acceptance as PASS from an AI visual assertion alone'), '[DESKTOP] English reference must include RDP and no-AI-only PASS rule');
|
|
394
|
+
assert(chineseReference.includes('Windows RDP') && chineseReference.includes('不得只凭 AI 视觉断言'), '[DESKTOP] Chinese reference must include RDP and no-AI-only PASS rule');
|
|
395
|
+
assert(englishTemplate.includes('tool route: project GUI automation | @midscene/computer') && englishTemplate.includes('reopen/restart check'), '[DESKTOP] English template must include route and read-back fields');
|
|
396
|
+
assert(chineseTemplate.includes('工具路线: 项目 GUI 自动化 | @midscene/computer') && chineseTemplate.includes('重开/重启检查'), '[DESKTOP] Chinese template must include route and read-back fields');
|
|
397
|
+
|
|
398
|
+
for (const content of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
|
|
399
|
+
assert(content.includes('opentest/references/desktop-gui-testing.md'), '[DESKTOP] plan/run/accept skills must read desktop GUI reference');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
assert(!allDesktopText.includes('@midscene/android') && !allDesktopText.includes('android-midscene-pytest') && !allDesktopText.includes('ADB smoke'), '[DESKTOP] Desktop GUI assets must not include Android-specific route text');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function assertApiContracts() {
|
|
406
|
+
const manifestText = readFileSync('assets/manifest.json', 'utf8');
|
|
407
|
+
const englishSkill = readRequiredText('assets/skills/opentest-api/SKILL.md', '[API] missing English API skill');
|
|
408
|
+
const chineseSkill = readRequiredText('assets/skills-zh/opentest-api/SKILL.md', '[API] missing Chinese API skill');
|
|
409
|
+
const englishReference = readRequiredText('assets/skills/opentest/references/api-testing.md', '[API] missing English API reference');
|
|
410
|
+
const chineseReference = readRequiredText('assets/skills-zh/opentest/references/api-testing.md', '[API] missing Chinese API reference');
|
|
411
|
+
const englishTemplate = readRequiredText('assets/skills/opentest/templates/api-acceptance-template.md', '[API] missing English API template');
|
|
412
|
+
const chineseTemplate = readRequiredText('assets/skills-zh/opentest/templates/api-acceptance-template.md', '[API] missing Chinese API template');
|
|
413
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
414
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
415
|
+
const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
|
|
416
|
+
const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
|
|
417
|
+
const englishAccept = readFileSync('assets/skills/opentest-accept/SKILL.md', 'utf8');
|
|
418
|
+
const chineseAccept = readFileSync('assets/skills-zh/opentest-accept/SKILL.md', 'utf8');
|
|
419
|
+
const allApiText = [
|
|
420
|
+
englishSkill,
|
|
421
|
+
chineseSkill,
|
|
422
|
+
englishReference,
|
|
423
|
+
chineseReference,
|
|
424
|
+
englishTemplate,
|
|
425
|
+
chineseTemplate,
|
|
426
|
+
].join('\n');
|
|
427
|
+
|
|
428
|
+
assert(manifestText.includes('opentest-api/SKILL.md'), '[API] manifest must ship opentest-api skill');
|
|
429
|
+
assert(manifestText.includes('opentest/references/api-testing.md'), '[API] manifest must ship API reference');
|
|
430
|
+
assert(manifestText.includes('opentest/templates/api-acceptance-template.md'), '[API] manifest must ship API acceptance template');
|
|
431
|
+
|
|
432
|
+
assert(englishSkill.includes('pytest') && englishSkill.includes('httpx') && englishSkill.includes('jsonschema') && englishSkill.includes('read-after-write'), '[API] English API skill must route pytest/httpx/schema/read-after-write');
|
|
433
|
+
assert(chineseSkill.includes('pytest') && chineseSkill.includes('httpx') && chineseSkill.includes('jsonschema') && chineseSkill.includes('写后读'), '[API] Chinese API skill must route pytest/httpx/schema/read-after-write');
|
|
434
|
+
assert(englishReference.includes('Do not mark API acceptance as PASS from a 2xx response alone') && englishReference.includes('idempotency') && englishReference.includes('cleanup/teardown'), '[API] English reference must include no-2xx-only, idempotency, and cleanup rules');
|
|
435
|
+
assert(chineseReference.includes('不得只凭 2xx 响应') && chineseReference.includes('幂等') && chineseReference.includes('cleanup/teardown'), '[API] Chinese reference must include no-2xx-only, idempotency, and cleanup rules');
|
|
436
|
+
assert(englishTemplate.includes('tool route: project API command | pytest + httpx/requests') && englishTemplate.includes('Read-Back Contract'), '[API] English template must include route and read-back fields');
|
|
437
|
+
assert(chineseTemplate.includes('工具路线: 项目 API 命令 | pytest + httpx/requests') && chineseTemplate.includes('回读契约'), '[API] Chinese template must include route and read-back fields');
|
|
438
|
+
|
|
439
|
+
for (const content of [englishPlan, chinesePlan, englishRun, chineseRun, englishAccept, chineseAccept]) {
|
|
440
|
+
assert(content.includes('opentest/references/api-testing.md'), '[API] plan/run/accept skills must read API reference');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
assert(!allApiText.includes('@midscene/android') && !allApiText.includes('@midscene/computer') && !allApiText.includes('Playwright MCP') && !allApiText.includes('ADB smoke'), '[API] API assets must not include GUI-specific route text');
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function assertTestAssetLayoutContracts() {
|
|
447
|
+
const manifestText = readFileSync('assets/manifest.json', 'utf8');
|
|
448
|
+
const englishLayout = readRequiredText('assets/skills/opentest/references/test-asset-layout.md', '[LAYOUT] missing English test asset layout reference');
|
|
449
|
+
const chineseLayout = readRequiredText('assets/skills-zh/opentest/references/test-asset-layout.md', '[LAYOUT] missing Chinese test asset layout reference');
|
|
450
|
+
const englishWorkflow = readFileSync('assets/skills/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
451
|
+
const chineseWorkflow = readFileSync('assets/skills-zh/opentest/references/complete-testing-workflow.md', 'utf8');
|
|
452
|
+
const englishSurfaces = readFileSync('assets/skills/opentest/references/test-surfaces.md', 'utf8');
|
|
453
|
+
const chineseSurfaces = readFileSync('assets/skills-zh/opentest/references/test-surfaces.md', 'utf8');
|
|
454
|
+
const englishApi = readFileSync('assets/skills/opentest/references/api-testing.md', 'utf8');
|
|
455
|
+
const chineseApi = readFileSync('assets/skills-zh/opentest/references/api-testing.md', 'utf8');
|
|
456
|
+
const englishWeb = readFileSync('assets/skills/opentest/references/web-browser-testing.md', 'utf8');
|
|
457
|
+
const chineseWeb = readFileSync('assets/skills-zh/opentest/references/web-browser-testing.md', 'utf8');
|
|
458
|
+
const englishDesktop = readFileSync('assets/skills/opentest/references/desktop-gui-testing.md', 'utf8');
|
|
459
|
+
const chineseDesktop = readFileSync('assets/skills-zh/opentest/references/desktop-gui-testing.md', 'utf8');
|
|
460
|
+
const englishPlan = readFileSync('assets/skills/opentest-plan/SKILL.md', 'utf8');
|
|
461
|
+
const chinesePlan = readFileSync('assets/skills-zh/opentest-plan/SKILL.md', 'utf8');
|
|
462
|
+
const englishAuthor = readFileSync('assets/skills/opentest-author/SKILL.md', 'utf8');
|
|
463
|
+
const chineseAuthor = readFileSync('assets/skills-zh/opentest-author/SKILL.md', 'utf8');
|
|
464
|
+
const englishRun = readFileSync('assets/skills/opentest-run/SKILL.md', 'utf8');
|
|
465
|
+
const chineseRun = readFileSync('assets/skills-zh/opentest-run/SKILL.md', 'utf8');
|
|
466
|
+
|
|
467
|
+
assert(manifestText.includes('opentest/references/test-asset-layout.md'), '[LAYOUT] manifest must ship test asset layout reference');
|
|
468
|
+
assert(englishLayout.includes('Option B') && englishLayout.includes('standard framework skeleton'), '[LAYOUT] English layout must define Option B as default');
|
|
469
|
+
assert(chineseLayout.includes('方案 B') && chineseLayout.includes('标准测试框架骨架'), '[LAYOUT] Chinese layout must define Option B as default');
|
|
470
|
+
|
|
471
|
+
for (const requiredPath of [
|
|
472
|
+
'tests/api/',
|
|
473
|
+
'tests/web/playwright/',
|
|
474
|
+
'tests/android/tests_py/',
|
|
475
|
+
'tests/desktop/midscene/',
|
|
476
|
+
'docs/opentest/acceptance/',
|
|
477
|
+
'scripts/opentest-run-api.ps1',
|
|
478
|
+
'scripts/opentest-run-web.ps1',
|
|
479
|
+
'scripts/opentest-run-android.ps1',
|
|
480
|
+
'scripts/opentest-run-desktop.ps1',
|
|
481
|
+
]) {
|
|
482
|
+
assert(englishLayout.includes(requiredPath), `[LAYOUT] English layout missing ${requiredPath}`);
|
|
483
|
+
assert(chineseLayout.includes(requiredPath), `[LAYOUT] Chinese layout missing ${requiredPath}`);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
for (const content of [englishPlan, chinesePlan, englishAuthor, chineseAuthor, englishRun, chineseRun]) {
|
|
487
|
+
assert(content.includes('opentest/references/test-asset-layout.md'), '[LAYOUT] plan/author/run must read test asset layout reference');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
assert(englishWorkflow.includes('test-asset-layout.md') && chineseWorkflow.includes('test-asset-layout.md'), '[LAYOUT] workflow must require fixed asset layout');
|
|
491
|
+
assert(englishSurfaces.includes('do not invent directories') && chineseSurfaces.includes('不得在 author 时临场发明目录'), '[LAYOUT] test-surfaces must forbid ad hoc directories');
|
|
492
|
+
assert(englishApi.includes('tests/api/clients/') && chineseApi.includes('tests/api/clients/'), '[LAYOUT] API reference must pin client directory');
|
|
493
|
+
assert(englishWeb.includes('tests/web/playwright/') && chineseWeb.includes('tests/web/playwright/'), '[LAYOUT] web reference must pin Playwright directory');
|
|
494
|
+
assert(englishDesktop.includes('tests/desktop/midscene/') && chineseDesktop.includes('tests/desktop/midscene/'), '[LAYOUT] desktop reference must pin Midscene directory');
|
|
495
|
+
}
|
|
496
|
+
|
|
195
497
|
function assertCompleteTestingWorkflowContracts() {
|
|
196
498
|
const stateScript = readFileSync('assets/skills/opentest/scripts/opentest-state.sh', 'utf8');
|
|
197
499
|
const detectScript = readFileSync('assets/skills/opentest/scripts/opentest-detect.sh', 'utf8');
|
|
@@ -575,6 +877,12 @@ runManifestPathRelativitySelfCheck();
|
|
|
575
877
|
assertManifestStructure();
|
|
576
878
|
assertPrepublishGateCoversManifestAssets();
|
|
577
879
|
assertDefaultPytestContracts();
|
|
880
|
+
assertRequirementFirstAcceptanceContracts();
|
|
881
|
+
assertTestSurfaceContracts();
|
|
882
|
+
assertWebBrowserContracts();
|
|
883
|
+
assertDesktopGuiContracts();
|
|
884
|
+
assertApiContracts();
|
|
885
|
+
assertTestAssetLayoutContracts();
|
|
578
886
|
assertCompleteTestingWorkflowContracts();
|
|
579
887
|
assertProgressiveDisclosureContracts();
|
|
580
888
|
assertOpenTestSearchRootsCoverPlatforms();
|