@sun-asterisk/sungen 3.2.24 → 3.2.26
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/capabilities/context-router.d.ts.map +1 -1
- package/dist/capabilities/context-router.js +15 -7
- package/dist/capabilities/context-router.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +23 -4
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.d.ts.map +1 -1
- package/dist/cli/commands/capability.js +6 -48
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/changed.d.ts +14 -0
- package/dist/cli/commands/changed.d.ts.map +1 -0
- package/dist/cli/commands/changed.js +128 -0
- package/dist/cli/commands/changed.js.map +1 -0
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +25 -1
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.js +1 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/results-merge.d.ts +19 -0
- package/dist/cli/commands/results-merge.d.ts.map +1 -0
- package/dist/cli/commands/results-merge.js +191 -0
- package/dist/cli/commands/results-merge.js.map +1 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +100 -12
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/index.js +4 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/exporters/api-catalog-loader.d.ts.map +1 -1
- package/dist/exporters/api-catalog-loader.js +10 -3
- package/dist/exporters/api-catalog-loader.js.map +1 -1
- package/dist/exporters/api-testcase-formatter.d.ts +9 -0
- package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
- package/dist/exporters/api-testcase-formatter.js +55 -3
- package/dist/exporters/api-testcase-formatter.js.map +1 -1
- package/dist/exporters/csv-exporter.d.ts.map +1 -1
- package/dist/exporters/csv-exporter.js +10 -1
- package/dist/exporters/csv-exporter.js.map +1 -1
- package/dist/exporters/json-exporter.d.ts.map +1 -1
- package/dist/exporters/json-exporter.js +6 -1
- package/dist/exporters/json-exporter.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +14 -1
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/export.js +1 -1
- package/dist/exporters/matrix/export.js.map +1 -1
- package/dist/exporters/matrix/map-loader.d.ts.map +1 -1
- package/dist/exporters/matrix/map-loader.js +5 -0
- package/dist/exporters/matrix/map-loader.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +5 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +4 -1
- package/dist/exporters/matrix/render-xlsx.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +18 -0
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/exporters/playwright-report-parser.d.ts +17 -2
- package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
- package/dist/exporters/playwright-report-parser.js +68 -8
- package/dist/exporters/playwright-report-parser.js.map +1 -1
- package/dist/exporters/results-merge.d.ts +46 -0
- package/dist/exporters/results-merge.d.ts.map +1 -0
- package/dist/exporters/results-merge.js +148 -0
- package/dist/exporters/results-merge.js.map +1 -0
- package/dist/exporters/selector-key-resolver.d.ts +4 -0
- package/dist/exporters/selector-key-resolver.d.ts.map +1 -1
- package/dist/exporters/selector-key-resolver.js +101 -1
- package/dist/exporters/selector-key-resolver.js.map +1 -1
- package/dist/exporters/types.d.ts +8 -1
- package/dist/exporters/types.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.js +5 -4
- package/dist/exporters/xlsx-report-builder.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +2 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +52 -1
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +20 -10
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +2 -11
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/imports.hbs +3 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/date-picker-unsupported.hbs +4 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/lifecycle-missing-app-id.hbs +5 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/matches-format-assertion.hbs +15 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-filtered-assertion.hbs +5 -2
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +185 -26
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +2 -11
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +17 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +6 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +18 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +5 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/matches-format-assertion.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +4 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/recipe-expect-text.hbs +1 -1
- package/dist/generators/test-generator/code-generator.d.ts +6 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +80 -7
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +60 -6
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +59 -5
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/expect-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/expect-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/expect-patterns.js +36 -2
- package/dist/generators/test-generator/patterns/expect-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +19 -12
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +58 -38
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +23 -0
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/unsupported-step-code.d.ts +18 -0
- package/dist/generators/test-generator/patterns/unsupported-step-code.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/unsupported-step-code.js +23 -0
- package/dist/generators/test-generator/patterns/unsupported-step-code.js.map +1 -0
- package/dist/generators/test-generator/recipe-expander.js +9 -1
- package/dist/generators/test-generator/recipe-expander.js.map +1 -1
- package/dist/generators/test-generator/reset-tier.d.ts +68 -0
- package/dist/generators/test-generator/reset-tier.d.ts.map +1 -0
- package/dist/generators/test-generator/reset-tier.js +94 -0
- package/dist/generators/test-generator/reset-tier.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +39 -0
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +144 -5
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +2 -10
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +16 -2
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/utils/format-pattern.d.ts +35 -0
- package/dist/generators/test-generator/utils/format-pattern.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/format-pattern.js +82 -0
- package/dist/generators/test-generator/utils/format-pattern.js.map +1 -0
- package/dist/generators/test-generator/utils/js-literal-scanner.d.ts +42 -0
- package/dist/generators/test-generator/utils/js-literal-scanner.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/js-literal-scanner.js +142 -0
- package/dist/generators/test-generator/utils/js-literal-scanner.js.map +1 -0
- package/dist/generators/test-generator/utils/mask-refs-for-matching.d.ts +18 -0
- package/dist/generators/test-generator/utils/mask-refs-for-matching.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/mask-refs-for-matching.js +25 -0
- package/dist/generators/test-generator/utils/mask-refs-for-matching.js.map +1 -0
- package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts +9 -1
- package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/runtime-data-transformer.js +124 -63
- package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +20 -1
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/spec-syntax-check.d.ts +14 -0
- package/dist/generators/test-generator/utils/spec-syntax-check.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/spec-syntax-check.js +26 -0
- package/dist/generators/test-generator/utils/spec-syntax-check.js.map +1 -0
- package/dist/harness/annotation-overrides.d.ts +0 -12
- package/dist/harness/annotation-overrides.d.ts.map +1 -1
- package/dist/harness/annotation-overrides.js +9 -5
- package/dist/harness/annotation-overrides.js.map +1 -1
- package/dist/harness/audit.d.ts +7 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +78 -10
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability-plan.d.ts +2 -1
- package/dist/harness/capability-plan.d.ts.map +1 -1
- package/dist/harness/capability-plan.js +8 -3
- package/dist/harness/capability-plan.js.map +1 -1
- package/dist/harness/capability.d.ts +11 -0
- package/dist/harness/capability.d.ts.map +1 -1
- package/dist/harness/capability.js +8 -0
- package/dist/harness/capability.js.map +1 -1
- package/dist/harness/catalog/drivers.yaml +5 -0
- package/dist/harness/flow-contract.d.ts +18 -1
- package/dist/harness/flow-contract.d.ts.map +1 -1
- package/dist/harness/flow-contract.js +72 -9
- package/dist/harness/flow-contract.js.map +1 -1
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +5 -1
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/quality-gates.d.ts +12 -1
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +62 -7
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/run-manifest.d.ts +58 -0
- package/dist/harness/run-manifest.d.ts.map +1 -0
- package/dist/harness/run-manifest.js +264 -0
- package/dist/harness/run-manifest.js.map +1 -0
- package/dist/harness/spec-branches.d.ts +88 -0
- package/dist/harness/spec-branches.d.ts.map +1 -0
- package/dist/harness/spec-branches.js +280 -0
- package/dist/harness/spec-branches.js.map +1 -0
- package/dist/harness/spec-coverage.d.ts +1 -1
- package/dist/harness/spec-coverage.js +4 -4
- package/dist/harness/spec-coverage.js.map +1 -1
- package/dist/harness/viewpoint-baseline.d.ts +9 -0
- package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
- package/dist/harness/viewpoint-baseline.js +33 -3
- package/dist/harness/viewpoint-baseline.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts +1 -1
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +88 -9
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/lockstep-version.d.ts +22 -0
- package/dist/orchestrator/lockstep-version.d.ts.map +1 -0
- package/dist/orchestrator/lockstep-version.js +58 -0
- package/dist/orchestrator/lockstep-version.js.map +1 -0
- package/dist/orchestrator/project-deps-sync.d.ts +39 -0
- package/dist/orchestrator/project-deps-sync.d.ts.map +1 -0
- package/dist/orchestrator/project-deps-sync.js +175 -0
- package/dist/orchestrator/project-deps-sync.js.map +1 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +5 -2
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +9 -0
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +9 -2
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +109 -0
- package/dist/orchestrator/templates/ai-src/config/claude.md +1 -1
- package/dist/orchestrator/templates/ai-src/config/copilot.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-design/SKILL.md +49 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +14 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +110 -6
- package/dist/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +8 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +40 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +15 -0
- package/dist/orchestrator/templates/env.appium.example +10 -0
- package/dist/orchestrator/templates/specs-api.d.ts +4 -2
- package/dist/orchestrator/templates/specs-api.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-api.js +233 -10
- package/dist/orchestrator/templates/specs-api.js.map +1 -1
- package/dist/orchestrator/templates/specs-api.ts +214 -11
- package/dist/orchestrator/templates/specs-regex-escape.d.ts +13 -0
- package/dist/orchestrator/templates/specs-regex-escape.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-regex-escape.js +19 -0
- package/dist/orchestrator/templates/specs-regex-escape.js.map +1 -0
- package/dist/orchestrator/templates/specs-regex-escape.ts +16 -0
- package/dist/orchestrator/templates/specs-test-data.ts +53 -6
- package/dist/orchestrator/templates/wdio.conf.ts +28 -9
- package/package.json +8 -6
- package/src/capabilities/context-router.ts +13 -5
- package/src/cli/commands/audit.ts +22 -3
- package/src/cli/commands/capability.ts +4 -38
- package/src/cli/commands/changed.ts +104 -0
- package/src/cli/commands/delivery.ts +27 -2
- package/src/cli/commands/generate.ts +1 -1
- package/src/cli/commands/results-merge.ts +153 -0
- package/src/cli/commands/update.ts +72 -13
- package/src/cli/index.ts +4 -0
- package/src/exporters/api-catalog-loader.ts +10 -2
- package/src/exporters/api-testcase-formatter.ts +59 -3
- package/src/exporters/csv-exporter.ts +11 -2
- package/src/exporters/json-exporter.ts +7 -2
- package/src/exporters/matrix/build.ts +13 -1
- package/src/exporters/matrix/export.ts +1 -1
- package/src/exporters/matrix/map-loader.ts +5 -0
- package/src/exporters/matrix/render-csv.ts +5 -1
- package/src/exporters/matrix/render-xlsx.ts +4 -1
- package/src/exporters/matrix/types.ts +18 -0
- package/src/exporters/playwright-report-parser.ts +68 -9
- package/src/exporters/results-merge.ts +150 -0
- package/src/exporters/selector-key-resolver.ts +81 -1
- package/src/exporters/types.ts +8 -1
- package/src/exporters/xlsx-report-builder.ts +5 -4
- package/src/generators/gherkin-parser/index.ts +55 -1
- package/src/generators/test-generator/adapters/adapter-interface.ts +23 -1
- package/src/generators/test-generator/adapters/appium/appium-adapter.ts +2 -2
- package/src/generators/test-generator/adapters/appium/templates/imports.hbs +3 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/date-picker-unsupported.hbs +4 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/lifecycle-missing-app-id.hbs +5 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/matches-format-assertion.hbs +15 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-filtered-assertion.hbs +5 -2
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +185 -26
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +17 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/attribute-assertion.hbs +6 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-value-assertion.hbs +18 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +5 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/matches-format-assertion.hbs +5 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +4 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/recipe-expect-text.hbs +1 -1
- package/src/generators/test-generator/code-generator.ts +86 -7
- package/src/generators/test-generator/diagnostics.ts +60 -6
- package/src/generators/test-generator/patterns/expect-patterns.ts +37 -2
- package/src/generators/test-generator/patterns/index.ts +58 -33
- package/src/generators/test-generator/patterns/types.ts +36 -0
- package/src/generators/test-generator/patterns/unsupported-step-code.ts +19 -0
- package/src/generators/test-generator/recipe-expander.ts +9 -1
- package/src/generators/test-generator/reset-tier.ts +93 -0
- package/src/generators/test-generator/step-mapper.ts +149 -6
- package/src/generators/test-generator/template-engine.ts +18 -3
- package/src/generators/test-generator/utils/format-pattern.ts +79 -0
- package/src/generators/test-generator/utils/js-literal-scanner.ts +132 -0
- package/src/generators/test-generator/utils/mask-refs-for-matching.ts +21 -0
- package/src/generators/test-generator/utils/runtime-data-transformer.ts +126 -76
- package/src/generators/test-generator/utils/selector-resolver.ts +22 -1
- package/src/generators/test-generator/utils/spec-syntax-check.ts +22 -0
- package/src/harness/annotation-overrides.ts +10 -5
- package/src/harness/audit.ts +82 -12
- package/src/harness/capability-plan.ts +10 -5
- package/src/harness/capability.ts +16 -0
- package/src/harness/catalog/drivers.yaml +5 -0
- package/src/harness/flow-contract.ts +87 -9
- package/src/harness/parse.ts +5 -1
- package/src/harness/quality-gates.ts +64 -6
- package/src/harness/run-manifest.ts +254 -0
- package/src/harness/spec-branches.ts +346 -0
- package/src/harness/spec-coverage.ts +4 -4
- package/src/harness/viewpoint-baseline.ts +41 -6
- package/src/harness/viewpoint-ledger.ts +82 -9
- package/src/index.ts +1 -0
- package/src/orchestrator/lockstep-version.ts +46 -0
- package/src/orchestrator/project-deps-sync.ts +175 -0
- package/src/orchestrator/project-initializer.ts +5 -2
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +9 -0
- package/src/orchestrator/templates/ai-src/commands/delivery.md +9 -2
- package/src/orchestrator/templates/ai-src/commands/run-test.md +109 -0
- package/src/orchestrator/templates/ai-src/config/claude.md +1 -1
- package/src/orchestrator/templates/ai-src/config/copilot.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-api-design/SKILL.md +49 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +14 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +110 -6
- package/src/orchestrator/templates/ai-src/skills/sungen-locale/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +8 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +40 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +15 -0
- package/src/orchestrator/templates/env.appium.example +10 -0
- package/src/orchestrator/templates/specs-api.ts +214 -11
- package/src/orchestrator/templates/specs-regex-escape.ts +16 -0
- package/src/orchestrator/templates/specs-test-data.ts +53 -6
- package/src/orchestrator/templates/wdio.conf.ts +28 -9
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal left-to-right lexer that segments generated JS into the four contexts a
|
|
4
|
+
* post-processor must tell apart: string/template literals, regex literals,
|
|
5
|
+
* comments, and everything else.
|
|
6
|
+
*
|
|
7
|
+
* WHY this exists instead of a regex pass per context: independent global regexes
|
|
8
|
+
* have no idea where a literal actually STARTS. `String.replace` retries at every
|
|
9
|
+
* offset, so a pattern that wants "quote … marker … quote" happily pairs the
|
|
10
|
+
* CLOSING quote of one literal with the OPENING quote of the next and rewrites the
|
|
11
|
+
* code in between. Field report (3.2.23, every version 2.0.0+):
|
|
12
|
+
*
|
|
13
|
+
* await page.getByText('Tìm thấy').filter({ hasText: /^§marker§$/ }).waitFor({ state: 'visible' });
|
|
14
|
+
*
|
|
15
|
+
* The marker sits in a REGEX literal, but the string-literal pass matched from the
|
|
16
|
+
* `'` after `thấy` to the `'` before `visible` and emitted
|
|
17
|
+
* `getByText('Tìm thấy`)` … `state: `visible' })` — the whole .spec.ts stopped
|
|
18
|
+
* parsing. Scanning once, in order, makes that class of fault unrepresentable: a
|
|
19
|
+
* quote can only ever open a literal when the scanner is not already inside one.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately NOT a full JS parser — it only needs to find literal boundaries:
|
|
22
|
+
* - `${…}` inside a template literal is body text, not nested code (matches what
|
|
23
|
+
* the previous passes did, and generated templates never nest a literal there).
|
|
24
|
+
* - A `'`/`"` literal must close on its own line; an unterminated one is treated
|
|
25
|
+
* as ordinary code so a stray apostrophe (prose in a comment) cannot desync the
|
|
26
|
+
* rest of the file. Backticks may span lines, but an unterminated one to EOF is
|
|
27
|
+
* likewise demoted to code.
|
|
28
|
+
* - A `/` opens a regex only in expression position and only when it closes on the
|
|
29
|
+
* same line. Both guards keep a division (or a stray slash) from swallowing the
|
|
30
|
+
* literals after it.
|
|
31
|
+
*/
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.scanSegments = scanSegments;
|
|
34
|
+
/** Chars that, immediately before a `/`, make it division or a member access — never a regex. */
|
|
35
|
+
const NOT_REGEX_PREFIX = /[\w$)\]]/;
|
|
36
|
+
const REGEX_FLAGS = /[dgimsuvy]/;
|
|
37
|
+
/** Index just past the closing quote, or -1 when the literal never closes (see module note). */
|
|
38
|
+
function scanQuoted(code, start, quote) {
|
|
39
|
+
const spansLines = quote === '`';
|
|
40
|
+
for (let i = start + 1; i < code.length; i++) {
|
|
41
|
+
const c = code[i];
|
|
42
|
+
if (c === '\\') {
|
|
43
|
+
i++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (c === quote)
|
|
47
|
+
return i + 1;
|
|
48
|
+
if (c === '\n' && !spansLines)
|
|
49
|
+
return -1;
|
|
50
|
+
}
|
|
51
|
+
return -1;
|
|
52
|
+
}
|
|
53
|
+
/** Index just past the regex's flags, or -1 when it is not a single-line regex literal. */
|
|
54
|
+
function scanRegex(code, start) {
|
|
55
|
+
// Expression-position guard: skip back over spaces/tabs to the last significant char.
|
|
56
|
+
let p = start - 1;
|
|
57
|
+
while (p >= 0 && (code[p] === ' ' || code[p] === '\t'))
|
|
58
|
+
p--;
|
|
59
|
+
if (p >= 0 && NOT_REGEX_PREFIX.test(code[p]))
|
|
60
|
+
return -1;
|
|
61
|
+
let inClass = false;
|
|
62
|
+
for (let i = start + 1; i < code.length; i++) {
|
|
63
|
+
const c = code[i];
|
|
64
|
+
if (c === '\n')
|
|
65
|
+
return -1;
|
|
66
|
+
if (c === '\\') {
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (inClass) {
|
|
71
|
+
if (c === ']')
|
|
72
|
+
inClass = false;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (c === '[') {
|
|
76
|
+
inClass = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (c === '/') {
|
|
80
|
+
let j = i + 1;
|
|
81
|
+
while (j < code.length && REGEX_FLAGS.test(code[j]))
|
|
82
|
+
j++;
|
|
83
|
+
return j;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return -1;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Split `code` into ordered segments. Concatenating every `text` reproduces the
|
|
90
|
+
* input byte for byte — callers rewrite only the segments they care about.
|
|
91
|
+
*/
|
|
92
|
+
function scanSegments(code) {
|
|
93
|
+
const out = [];
|
|
94
|
+
let codeStart = 0;
|
|
95
|
+
let i = 0;
|
|
96
|
+
const flushCode = (end) => {
|
|
97
|
+
if (end > codeStart)
|
|
98
|
+
out.push({ kind: 'code', text: code.slice(codeStart, end) });
|
|
99
|
+
};
|
|
100
|
+
const take = (kind, end) => {
|
|
101
|
+
flushCode(i);
|
|
102
|
+
out.push({ kind, text: code.slice(i, end) });
|
|
103
|
+
i = codeStart = end;
|
|
104
|
+
};
|
|
105
|
+
while (i < code.length) {
|
|
106
|
+
const c = code[i];
|
|
107
|
+
// Comments first: a `//` or `/*` reached in code position can never be a regex,
|
|
108
|
+
// and consuming them keeps an apostrophe in prose from opening a literal.
|
|
109
|
+
if (c === '/' && code[i + 1] === '/') {
|
|
110
|
+
const nl = code.indexOf('\n', i);
|
|
111
|
+
take('comment', nl === -1 ? code.length : nl);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (c === '/' && code[i + 1] === '*') {
|
|
115
|
+
const close = code.indexOf('*/', i + 2);
|
|
116
|
+
take('comment', close === -1 ? code.length : close + 2);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (c === '\'' || c === '"' || c === '`') {
|
|
120
|
+
const end = scanQuoted(code, i, c);
|
|
121
|
+
if (end !== -1) {
|
|
122
|
+
take('string', end);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
i++; // unterminated → ordinary code
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (c === '/') {
|
|
129
|
+
const end = scanRegex(code, i);
|
|
130
|
+
if (end !== -1) {
|
|
131
|
+
take('regex', end);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
i++; // division or stray slash → ordinary code
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
flushCode(code.length);
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=js-literal-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"js-literal-scanner.js","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/js-literal-scanner.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;AAqDH,oCAiDC;AA5FD,iGAAiG;AACjG,MAAM,gBAAgB,GAAG,UAAU,CAAC;AACpC,MAAM,WAAW,GAAG,YAAY,CAAC;AAEjC,gGAAgG;AAChG,SAAS,UAAU,CAAC,IAAY,EAAE,KAAa,EAAE,KAAa;IAC5D,MAAM,UAAU,GAAG,KAAK,KAAK,GAAG,CAAC;IACjC,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAAC,CAAC,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QAClC,IAAI,CAAC,KAAK,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,2FAA2F;AAC3F,SAAS,SAAS,CAAC,IAAY,EAAE,KAAa;IAC5C,sFAAsF;IACtF,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;IAClB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;QAAE,CAAC,EAAE,CAAC;IAC5D,IAAI,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC;IAExD,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAAC,CAAC,EAAE,CAAC;YAAC,SAAS;QAAC,CAAC;QAClC,IAAI,OAAO,EAAE,CAAC;YAAC,IAAI,CAAC,KAAK,GAAG;gBAAE,OAAO,GAAG,KAAK,CAAC;YAAC,SAAS;QAAC,CAAC;QAC1D,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAAC,OAAO,GAAG,IAAI,CAAC;YAAC,SAAS;QAAC,CAAC;QAC5C,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAE,CAAC,EAAE,CAAC;YACzD,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC;IAEV,MAAM,SAAS,GAAG,CAAC,GAAW,EAAQ,EAAE;QACtC,IAAI,GAAG,GAAG,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,IAAiB,EAAE,GAAW,EAAQ,EAAE;QACpD,SAAS,CAAC,CAAC,CAAC,CAAC;QACb,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC,GAAG,SAAS,GAAG,GAAG,CAAC;IACtB,CAAC,CAAC;IAEF,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAElB,gFAAgF;QAChF,0EAA0E;QAC1E,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACjC,IAAI,CAAC,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9C,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YACxC,IAAI,CAAC,SAAS,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACzC,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACnC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YAClD,CAAC,EAAE,CAAC,CAAC,+BAA+B;YACpC,SAAS;QACX,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC/B,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;gBAAC,SAAS;YAAC,CAAC;YACjD,CAAC,EAAE,CAAC,CAAC,0CAA0C;YAC/C,SAAS;QACX,CAAC;QAED,CAAC,EAAE,CAAC;IACN,CAAC;IAED,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mask the CONTENT of selector refs `[...]` and data placeholders `{{...}}` before verb matching,
|
|
3
|
+
* keeping the delimiters. A step's verb/keywords come from the SENTENCE — never from a selector or
|
|
4
|
+
* variable NAME — but matchers scan `step.text` with substring checks (e.g. `includes('click')`),
|
|
5
|
+
* so a data ref like `{{double_click_guard_account.email}}` would spuriously satisfy the click
|
|
6
|
+
* matcher and pre-empt fill. The content is replaced with an inert placeholder (`~` — carries no
|
|
7
|
+
* verb/keyword/digit substring) rather than emptied, so structural matchers that require a NON-EMPTY
|
|
8
|
+
* ref survive too — e.g. `expect {{a}} is {{b}}` matches `\{\{[^}]+\}\}`, and `in [X] table` /
|
|
9
|
+
* `/\bto\s+\[/` keep their delimiters. The resolver/generator always receives the ORIGINAL step, so
|
|
10
|
+
* value extraction and codegen are unaffected.
|
|
11
|
+
*
|
|
12
|
+
* Lives in `utils/` rather than in `patterns/index.ts` so the Gherkin parser can reuse it for
|
|
13
|
+
* state-clause extraction (SG-E021) without importing the pattern registry — which would pull the
|
|
14
|
+
* whole capability graph into the parser and close a require cycle. `patterns/index.ts` re-exports
|
|
15
|
+
* it, so its historical import path still resolves.
|
|
16
|
+
*/
|
|
17
|
+
export declare function maskRefsForMatching(text: string): string;
|
|
18
|
+
//# sourceMappingURL=mask-refs-for-matching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-refs-for-matching.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/mask-refs-for-matching.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIxD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maskRefsForMatching = maskRefsForMatching;
|
|
4
|
+
/**
|
|
5
|
+
* Mask the CONTENT of selector refs `[...]` and data placeholders `{{...}}` before verb matching,
|
|
6
|
+
* keeping the delimiters. A step's verb/keywords come from the SENTENCE — never from a selector or
|
|
7
|
+
* variable NAME — but matchers scan `step.text` with substring checks (e.g. `includes('click')`),
|
|
8
|
+
* so a data ref like `{{double_click_guard_account.email}}` would spuriously satisfy the click
|
|
9
|
+
* matcher and pre-empt fill. The content is replaced with an inert placeholder (`~` — carries no
|
|
10
|
+
* verb/keyword/digit substring) rather than emptied, so structural matchers that require a NON-EMPTY
|
|
11
|
+
* ref survive too — e.g. `expect {{a}} is {{b}}` matches `\{\{[^}]+\}\}`, and `in [X] table` /
|
|
12
|
+
* `/\bto\s+\[/` keep their delimiters. The resolver/generator always receives the ORIGINAL step, so
|
|
13
|
+
* value extraction and codegen are unaffected.
|
|
14
|
+
*
|
|
15
|
+
* Lives in `utils/` rather than in `patterns/index.ts` so the Gherkin parser can reuse it for
|
|
16
|
+
* state-clause extraction (SG-E021) without importing the pattern registry — which would pull the
|
|
17
|
+
* whole capability graph into the parser and close a require cycle. `patterns/index.ts` re-exports
|
|
18
|
+
* it, so its historical import path still resolves.
|
|
19
|
+
*/
|
|
20
|
+
function maskRefsForMatching(text) {
|
|
21
|
+
return text
|
|
22
|
+
.replace(/\{\{[^}]*\}\}/g, '{{~}}')
|
|
23
|
+
.replace(/\[[^\]]*\]/g, '[~]');
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=mask-refs-for-matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mask-refs-for-matching.js","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/mask-refs-for-matching.ts"],"names":[],"mappings":";;AAgBA,kDAIC;AApBD;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,OAAO,IAAI;SACR,OAAO,CAAC,gBAAgB,EAAE,OAAO,CAAC;SAClC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Replace __SUNGEN_TD$…$__ markers with testData.get() calls in generated code.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* The code is scanned ONCE into literal/regex/comment/code segments and each
|
|
5
|
+
* segment is rewritten for the context it is actually in. This replaced four
|
|
6
|
+
* independent global-regex passes whose ordering was the defect: the string pass
|
|
7
|
+
* ran first and, finding no marker inside a genuine literal, re-matched from that
|
|
8
|
+
* literal's CLOSING quote — pairing it with the OPENING quote of the next literal
|
|
9
|
+
* and rewriting the regex literal between them into a broken backtick template
|
|
10
|
+
* (`getByText('Tìm thấy`)` … `state: `visible' })`, a .spec.ts that would not
|
|
11
|
+
* parse at all). See js-literal-scanner.ts for the full field report.
|
|
4
12
|
*/
|
|
5
13
|
export declare function transformToRuntimeData(code: string, accessor?: string): string;
|
|
6
14
|
export declare function hasRuntimeDataMarkers(code: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-data-transformer.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/runtime-data-transformer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime-data-transformer.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/runtime-data-transformer.ts"],"names":[],"mappings":"AA0CA;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAmB,GAAG,MAAM,CAG1F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.transformToRuntimeData = transformToRuntimeData;
|
|
4
4
|
exports.hasRuntimeDataMarkers = hasRuntimeDataMarkers;
|
|
5
|
+
const js_literal_scanner_1 = require("./js-literal-scanner");
|
|
5
6
|
/**
|
|
6
7
|
* Wire format of a runtime test-data marker: `__SUNGEN_TD$<key>$__`.
|
|
7
8
|
*
|
|
@@ -18,12 +19,12 @@ exports.hasRuntimeDataMarkers = hasRuntimeDataMarkers;
|
|
|
18
19
|
* swallowed one `_` of the `___` run and decoding produced `get('code_')` plus
|
|
19
20
|
* a detached `ACCESS_TOKEN`. `$` is also identifier-safe — the whole marker
|
|
20
21
|
* still parses as ONE bare JS token, so it survives the bare-identifier
|
|
21
|
-
* (numeric) positions
|
|
22
|
+
* (numeric) positions the code context handles.
|
|
22
23
|
*
|
|
23
|
-
* Single source of truth: every
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Single source of truth: every context below is built from these constants.
|
|
25
|
+
* Invariant: every marker producer goes through DataResolver.encodeMarker and
|
|
26
|
+
* every consumer through this module — a drifting hand-copied char class is what
|
|
27
|
+
* let the suffix bug hide.
|
|
27
28
|
*/
|
|
28
29
|
const MARKER_KEY = '[A-Za-z0-9_-]+';
|
|
29
30
|
// Templates that embed a value into a regex literal run it through the escapeRegex
|
|
@@ -31,82 +32,142 @@ const MARKER_KEY = '[A-Za-z0-9_-]+';
|
|
|
31
32
|
// arrive here spelled `__SUNGEN_TD\$key\$__`. `\\\\?` accepts that optional backslash
|
|
32
33
|
// before each delimiter; the replacement consumes it, so no escape leaks to output.
|
|
33
34
|
const DELIM = '\\\\?\\$';
|
|
34
|
-
/** Marker with no capture group — for "contains a marker"
|
|
35
|
+
/** Marker with no capture group — for "contains a marker" probes. */
|
|
35
36
|
const MARKER = `__SUNGEN_TD${DELIM}${MARKER_KEY}${DELIM}__`;
|
|
36
37
|
/** Marker capturing the encoded key. */
|
|
37
38
|
const MARKER_CAP = `__SUNGEN_TD${DELIM}(${MARKER_KEY})${DELIM}__`;
|
|
38
39
|
const MARKER_PATTERN = new RegExp(MARKER);
|
|
39
|
-
|
|
40
|
-
const RE_COMMENT_LINE = new RegExp(`^(\\s*)\\/\\/(.*)${MARKER_CAP}(.*)$`, 'gm');
|
|
41
|
-
// Pass 1: a quoted string literal containing at least one marker. Covers ', " and
|
|
42
|
-
// backtick containers; `\\.` lets an ESCAPED quote (`'it\'s {{x}}'`) sit inside the
|
|
43
|
-
// body instead of terminating the literal early. The single-char branch excludes `\`
|
|
44
|
-
// so every backslash is consumed by exactly ONE branch — an ambiguous `(?!\1).`
|
|
45
|
-
// alternative enumerates 2^n segmentations when a marker-less escape-heavy literal
|
|
46
|
-
// (escapeQuotes output: multi-line Flutter content-desc) fails to match, hanging
|
|
47
|
-
// the generate run. `\n` exclusion just makes the dot's no-newline behavior explicit.
|
|
48
|
-
const RE_STRING_LITERAL = new RegExp('([\'"`])((?:\\\\.|(?!\\1)[^\\\\\\n])*?' + MARKER + '(?:\\\\.|(?!\\1)[^\\\\\\n])*)\\1', 'g');
|
|
49
|
-
// Pass 2: a single-line regex literal containing at least one marker.
|
|
50
|
-
const RE_REGEX_LITERAL = new RegExp(`\\/((?:[^/\\\\\\n]|\\\\.)*?${MARKER}(?:[^/\\\\\\n]|\\\\.)*)\\/([gimsuy]*)`, 'g');
|
|
51
|
-
// Whole-literal probe: the body is EXACTLY one marker (bare accessor call, no template).
|
|
40
|
+
/** Whole-literal probe: the body is EXACTLY one marker (bare accessor call, no template). */
|
|
52
41
|
const RE_WHOLE_MARKER = new RegExp(`^${MARKER_CAP}$`);
|
|
53
|
-
|
|
42
|
+
/** Every marker occurrence, capturing the key. */
|
|
54
43
|
const RE_MARKER_G = new RegExp(MARKER_CAP, 'g');
|
|
55
44
|
/**
|
|
56
45
|
* Replace __SUNGEN_TD$…$__ markers with testData.get() calls in generated code.
|
|
57
|
-
*
|
|
46
|
+
*
|
|
47
|
+
* The code is scanned ONCE into literal/regex/comment/code segments and each
|
|
48
|
+
* segment is rewritten for the context it is actually in. This replaced four
|
|
49
|
+
* independent global-regex passes whose ordering was the defect: the string pass
|
|
50
|
+
* ran first and, finding no marker inside a genuine literal, re-matched from that
|
|
51
|
+
* literal's CLOSING quote — pairing it with the OPENING quote of the next literal
|
|
52
|
+
* and rewriting the regex literal between them into a broken backtick template
|
|
53
|
+
* (`getByText('Tìm thấy`)` … `state: `visible' })`, a .spec.ts that would not
|
|
54
|
+
* parse at all). See js-literal-scanner.ts for the full field report.
|
|
58
55
|
*/
|
|
59
56
|
function transformToRuntimeData(code, accessor = 'testData') {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// — e.g. a URL `https://careerforum.aki-inc.jp/` in a selector name — is NOT mistaken
|
|
64
|
-
// for a comment. Before this anchor, such a URL preceding a marker on the same line
|
|
65
|
-
// made Pass 0 strip the marker to its bare key, so Pass 1 never wrapped it in
|
|
66
|
-
// testData.get() (silent: `toHaveAttribute('href', 'official_site_url')`). Generated
|
|
67
|
-
// comments are always full-line, so anchoring loses nothing.
|
|
68
|
-
code = code.replace(RE_COMMENT_LINE, (_, indent, before, enc, after) => `${indent}//${before}${decodeKey(enc)}${after}`);
|
|
69
|
-
// Pass 1: String literal context — a literal may carry SEVERAL markers
|
|
70
|
-
// ('/{{code}}/car-search?{{prefill}}' compiles to two markers in ONE literal).
|
|
71
|
-
// Match the whole quoted literal that contains at least one marker, then
|
|
72
|
-
// interpolate EVERY marker inside it. The old shape (one marker + lazy
|
|
73
|
-
// prefix/suffix) swallowed trailing markers into its suffix verbatim; they
|
|
74
|
-
// escaped the quote context (the literal had become a backtick template) and
|
|
75
|
-
// Pass 3's numeric catch-all emitted them as literal
|
|
76
|
-
// `Number(testData.get(...))` TEXT inside the template — a compiling spec
|
|
77
|
-
// navigating to a garbage URL.
|
|
78
|
-
// 'marker' → testData.get('key')
|
|
79
|
-
// 'a__m1__b__m2__c' → `a${testData.get('k1')}b${testData.get('k2')}c`
|
|
80
|
-
code = code.replace(RE_STRING_LITERAL, (_, _quote, body) => {
|
|
81
|
-
const whole = RE_WHOLE_MARKER.exec(body);
|
|
82
|
-
if (whole)
|
|
83
|
-
return `${accessor}.get('${decodeKey(whole[1])}')`;
|
|
84
|
-
return `\`${interpolateMarkers(body, accessor)}\``;
|
|
85
|
-
});
|
|
86
|
-
// Pass 2: Regex literal context — /…$marker$…/ → new RegExp(`…`). Same
|
|
87
|
-
// several-markers-per-literal rule as Pass 1 (/{{min}}-{{max}} items/).
|
|
88
|
-
// Only matches within a single line (no newlines in the body).
|
|
89
|
-
code = code.replace(RE_REGEX_LITERAL, (_, body, flags) => {
|
|
90
|
-
const flagStr = flags ? `, '${flags}'` : '';
|
|
91
|
-
const whole = RE_WHOLE_MARKER.exec(body);
|
|
92
|
-
if (whole)
|
|
93
|
-
return `new RegExp(${accessor}.get('${decodeKey(whole[1])}')${flagStr})`;
|
|
94
|
-
return `new RegExp(\`${interpolateMarkers(body, accessor)}\`${flagStr})`;
|
|
95
|
-
});
|
|
96
|
-
// Pass 3: Bare-identifier context — any marker left after the string/regex passes
|
|
97
|
-
// sits as a bare token in a numeric position (e.g. `toHaveCount(__marker__)` from the
|
|
98
|
-
// table/list count templates). testData.get() returns a string, so coerce with Number().
|
|
99
|
-
code = code.replace(RE_MARKER_G, (_, enc) => `Number(${accessor}.get('${decodeKey(enc)}'))`);
|
|
100
|
-
return code;
|
|
57
|
+
if (!MARKER_PATTERN.test(code))
|
|
58
|
+
return code;
|
|
59
|
+
return (0, js_literal_scanner_1.scanSegments)(code).map((seg) => transformSegment(seg, accessor)).join('');
|
|
101
60
|
}
|
|
102
61
|
function hasRuntimeDataMarkers(code) {
|
|
103
62
|
return MARKER_PATTERN.test(code);
|
|
104
63
|
}
|
|
64
|
+
function transformSegment(seg, accessor) {
|
|
65
|
+
if (!MARKER_PATTERN.test(seg.text))
|
|
66
|
+
return seg.text;
|
|
67
|
+
switch (seg.kind) {
|
|
68
|
+
// Decode to the plain key: a marker in a comment documents the ref, it is not code.
|
|
69
|
+
case 'comment':
|
|
70
|
+
return seg.text.replace(RE_MARKER_G, (_, enc) => decodeKey(enc));
|
|
71
|
+
case 'string':
|
|
72
|
+
return transformStringLiteral(seg.text, accessor);
|
|
73
|
+
case 'regex':
|
|
74
|
+
return transformRegexLiteral(seg.text, accessor);
|
|
75
|
+
// Bare-token position (e.g. `toHaveCount(__marker__)` from the table/list count
|
|
76
|
+
// templates). testData.get() returns a string, so coerce with Number().
|
|
77
|
+
case 'code':
|
|
78
|
+
return seg.text.replace(RE_MARKER_G, (_, enc) => `Number(${accessor}.get('${decodeKey(enc)}'))`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 'marker' → testData.get('key')
|
|
83
|
+
* 'a__m1__b__m2__c' → `a${testData.get('k1')}b${testData.get('k2')}c`
|
|
84
|
+
*
|
|
85
|
+
* A literal may carry SEVERAL markers ('/{{code}}/car-search?{{prefill}}' compiles
|
|
86
|
+
* to two markers in ONE literal), so every marker inside it is interpolated.
|
|
87
|
+
*/
|
|
88
|
+
function transformStringLiteral(text, accessor) {
|
|
89
|
+
const quote = text[0];
|
|
90
|
+
const body = text.slice(1, -1);
|
|
91
|
+
const whole = RE_WHOLE_MARKER.exec(body);
|
|
92
|
+
if (whole)
|
|
93
|
+
return `${accessor}.get('${decodeKey(whole[1])}')`;
|
|
94
|
+
return `\`${interpolateMarkers(escapeForTemplate(body, quote === '`'), accessor)}\``;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* /…$marker$…/flags → new RegExp(`…`, 'flags'). Same several-markers rule as above.
|
|
98
|
+
*
|
|
99
|
+
* Two regex-only twists on top of the string path:
|
|
100
|
+
* - The runtime VALUE is literal text (test-data holds data, not patterns), so every
|
|
101
|
+
* accessor is wrapped in the runtime escapeRegExp helper — a value containing
|
|
102
|
+
* `( [ $ . * +` must not throw a SyntaxError or silently widen the match. The helper
|
|
103
|
+
* lives in the synced specs/regex-escape.ts; the generator imports it when the
|
|
104
|
+
* transformed body references it. Templates that intend PATTERN semantics (attribute
|
|
105
|
+
* `pattern:`) emit a string container instead of a regex literal, so they skip this.
|
|
106
|
+
* - Marker-less SEGMENTS get their backslashes doubled for the template context: regex
|
|
107
|
+
* source text like a hand-written `\s*` (or escapeRegex output `\)`) means one thing
|
|
108
|
+
* in a /…/ literal but loses its backslash when the template cooks one escape level —
|
|
109
|
+
* the constructed RegExp would read `s*` / a bare `)`. Segments are escaped AFTER the
|
|
110
|
+
* markers are cut out, so an escapeRegex-spelled marker delimiter (`\$`) is never
|
|
111
|
+
* double-escaped into something the marker regex can no longer see.
|
|
112
|
+
*/
|
|
113
|
+
function transformRegexLiteral(text, accessor) {
|
|
114
|
+
// Flags never contain `/`, so the last slash always closes the pattern.
|
|
115
|
+
const close = text.lastIndexOf('/');
|
|
116
|
+
const body = text.slice(1, close);
|
|
117
|
+
const flags = text.slice(close + 1);
|
|
118
|
+
const flagStr = flags ? `, '${flags}'` : '';
|
|
119
|
+
const whole = RE_WHOLE_MARKER.exec(body);
|
|
120
|
+
if (whole)
|
|
121
|
+
return `new RegExp(escapeRegExp(${accessor}.get('${decodeKey(whole[1])}'))${flagStr})`;
|
|
122
|
+
return `new RegExp(\`${interpolateMarkersInRegexBody(body, accessor)}\`${flagStr})`;
|
|
123
|
+
}
|
|
105
124
|
function decodeKey(encoded) {
|
|
106
125
|
return encoded.replace(/_D_/g, '.');
|
|
107
126
|
}
|
|
108
|
-
/** Replace every marker in a
|
|
127
|
+
/** Replace every marker in a body with a `${accessor.get('key')}` interpolation. */
|
|
109
128
|
function interpolateMarkers(body, accessor) {
|
|
110
129
|
return body.replace(RE_MARKER_G, (_, enc) => `\${${accessor}.get('${decodeKey(enc)}')}`);
|
|
111
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Regex-body variant: markers are cut out FIRST, each accessor is wrapped in the
|
|
133
|
+
* runtime escapeRegExp helper, and only the marker-less segments between them are
|
|
134
|
+
* re-escaped for the template context (backslashes doubled, backtick/`${` neutralized).
|
|
135
|
+
*/
|
|
136
|
+
function interpolateMarkersInRegexBody(body, accessor) {
|
|
137
|
+
let out = '';
|
|
138
|
+
let last = 0;
|
|
139
|
+
for (const m of body.matchAll(RE_MARKER_G)) {
|
|
140
|
+
out += escapeRegexSegmentForTemplate(body.slice(last, m.index)) +
|
|
141
|
+
`\${escapeRegExp(${accessor}.get('${decodeKey(m[1])}'))}`;
|
|
142
|
+
last = m.index + m[0].length;
|
|
143
|
+
}
|
|
144
|
+
return out + escapeRegexSegmentForTemplate(body.slice(last));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Regex pattern text moving into a template literal: the template layer cooks one
|
|
148
|
+
* level of escapes BEFORE RegExp ever sees the string, so `\)` arrives as a bare `)`
|
|
149
|
+
* (SyntaxError: unmatched paren) and `\.` as a match-anything dot. Double the
|
|
150
|
+
* backslashes and neutralize the template's own metacharacters so the constructed
|
|
151
|
+
* RegExp source equals the original pattern text.
|
|
152
|
+
*/
|
|
153
|
+
const escapeRegexSegmentForTemplate = (segment) => segment.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
154
|
+
/**
|
|
155
|
+
* Both rewrites move a body into a backtick template, where a raw backtick or `${`
|
|
156
|
+
* would be read as syntax rather than text — a `'…'` selector value or a regex
|
|
157
|
+
* pattern is allowed to contain either (escapeQuotes/escapeRegex escape neither).
|
|
158
|
+
* Escape before interpolating so the `${…}` this module inserts is the only live one.
|
|
159
|
+
* An already-backtick container needs no pass: its body was valid template text.
|
|
160
|
+
*
|
|
161
|
+
* PRECONDITION: the body must already have its backslashes DOUBLED — which every caller
|
|
162
|
+
* satisfies, because every dynamic value reaches a literal through escapeQuotes or
|
|
163
|
+
* escapeRegex (template-engine.ts) and both double `\` before anything else. An unpaired
|
|
164
|
+
* backslash immediately before a backtick would make the pass below emit `\\\``, i.e. an
|
|
165
|
+
* escaped backslash followed by a LIVE backtick, ending the template early. If you
|
|
166
|
+
* hand-write a backslash into a .hbs template, keep it paired.
|
|
167
|
+
*/
|
|
168
|
+
function escapeForTemplate(body, alreadyTemplate) {
|
|
169
|
+
if (alreadyTemplate)
|
|
170
|
+
return body;
|
|
171
|
+
return body.replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
172
|
+
}
|
|
112
173
|
//# sourceMappingURL=runtime-data-transformer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-data-transformer.js","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/runtime-data-transformer.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"runtime-data-transformer.js","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/runtime-data-transformer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector-resolver.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-resolver.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"selector-resolver.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -141,6 +141,22 @@ class SelectorResolver {
|
|
|
141
141
|
* - Legacy format: "login:email_field" or "login.email_field" (with screen prefix)
|
|
142
142
|
*/
|
|
143
143
|
resolveSelector(selectorRef, featureName, elementType, nth) {
|
|
144
|
+
// A [Reference] is a selectors.yaml KEY, looked up verbatim (generateKey only lowercases and
|
|
145
|
+
// normalizes whitespace) — it is never interpolated. Embedding a {{var}} in it is therefore
|
|
146
|
+
// unsupported, and silence was the harmful part: with no matching entry the ref fell through
|
|
147
|
+
// to auto-infer and produced getByRole(..., { name: '{{var}}' }) — an accessible name that can
|
|
148
|
+
// never match — so the run failed far from the cause. Fail here instead, naming the two
|
|
149
|
+
// supported ways to target dynamic text. Browser-storage keys legitimately embed vars but are
|
|
150
|
+
// not selectors and never reach this method (see driver-ui storage-patterns).
|
|
151
|
+
const templateVarInRef = /\{\{\s*([^}]+?)\s*\}\}/.exec(selectorRef);
|
|
152
|
+
if (templateVarInRef) {
|
|
153
|
+
throw new Error(`Selector reference "[${selectorRef}]" embeds a template variable ({{${templateVarInRef[1]}}}). ` +
|
|
154
|
+
`A [Reference] is a selectors.yaml key and is matched verbatim, not interpolated. ` +
|
|
155
|
+
`To target text that varies (locale, @cases column), keep the reference static and put the ` +
|
|
156
|
+
`variable in the entry instead — e.g. "confirm answer": { type: role, value: button, name: "{{${templateVarInRef[1]}}}" } ` +
|
|
157
|
+
`used as [Confirm Answer] button. To pick an element by its text inside a container, use ` +
|
|
158
|
+
`\`with {{${templateVarInRef[1]}}}\` (e.g. User click [Answer List] item with {{${templateVarInRef[1]}}}).`);
|
|
159
|
+
}
|
|
144
160
|
const contextName = featureName || this.featureName;
|
|
145
161
|
// Check if it's legacy format (contains : or has dot with screen prefix)
|
|
146
162
|
// Legacy: "login:email_field" or "login.email_field"
|
|
@@ -469,7 +485,9 @@ class SelectorResolver {
|
|
|
469
485
|
...(iv ? { iosSelector: { strategy: iv.strategy, value: iv.value, name: iv.name } } : {}),
|
|
470
486
|
});
|
|
471
487
|
}
|
|
472
|
-
// If type is 'locator', use locator field (or value as fallback) as the CSS locator directly
|
|
488
|
+
// If type is 'locator', use locator field (or value as fallback) as the CSS locator directly.
|
|
489
|
+
// `exact` travels along: a locator LIST filtered by a test-data value (hasText) matches by
|
|
490
|
+
// substring by default, and `exact: true` in the YAML opts into the anchored full-text match.
|
|
473
491
|
if (type === 'locator') {
|
|
474
492
|
const locatorValue = locator && locator.trim() ? locator : value;
|
|
475
493
|
return withExtras({
|
|
@@ -477,6 +495,7 @@ class SelectorResolver {
|
|
|
477
495
|
value: locatorValue,
|
|
478
496
|
locator: locatorValue,
|
|
479
497
|
nth,
|
|
498
|
+
exact,
|
|
480
499
|
});
|
|
481
500
|
}
|
|
482
501
|
// If custom locator is provided and type is not 'locator', use it as CSS selector
|