@sun-asterisk/sungen 1.0.24 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +198 -74
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +5 -3
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +110 -35
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.js +5 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/frame-enter-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/frame-exit-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/scroll-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +11 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +11 -2
- package/dist/generators/test-generator/code-generator.d.ts +0 -1
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +10 -47
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.js +2 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +4 -1
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +17 -5
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.js +47 -0
- package/dist/generators/test-generator/patterns/keyboard-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/scope-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/scope-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/scope-patterns.js +36 -0
- package/dist/generators/test-generator/patterns/scope-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.js +25 -0
- package/dist/generators/test-generator/patterns/scroll-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/table-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/table-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/table-patterns.js +192 -0
- package/dist/generators/test-generator/patterns/table-patterns.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +5 -3
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +38 -27
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +4 -1
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/types.d.ts +7 -24
- package/dist/generators/test-generator/types.d.ts.map +1 -1
- package/dist/generators/test-generator/types.js +2 -101
- package/dist/generators/test-generator/types.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +14 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +37 -11
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +12 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +72 -160
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/screen-manager.d.ts +1 -32
- package/dist/orchestrator/screen-manager.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +55 -216
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/orchestrator/templates/ai-rules.md +189 -0
- package/dist/orchestrator/templates/gitignore +16 -0
- package/dist/orchestrator/templates/playwright.config.d.ts +10 -0
- package/dist/orchestrator/templates/playwright.config.d.ts.map +1 -0
- package/dist/orchestrator/templates/playwright.config.js +77 -0
- package/dist/orchestrator/templates/playwright.config.js.map +1 -0
- package/dist/orchestrator/templates/playwright.config.ts +80 -0
- package/dist/orchestrator/templates/readme.md +197 -0
- package/dist/utils/selector-types.d.ts +1 -1
- package/dist/utils/selector-types.d.ts.map +1 -1
- package/dist/utils/selector-types.js +3 -0
- package/dist/utils/selector-types.js.map +1 -1
- package/docs/gherkin standards/gherkin-core-standard.md +377 -0
- package/docs/gherkin standards/gherkin-core-standard.vi.md +303 -0
- package/docs/gherkin-dictionary.md +1071 -0
- package/docs/makeauth.md +225 -0
- package/package.json +4 -3
- package/src/cli/commands/add.ts +5 -3
- package/src/cli/commands/generate.ts +90 -38
- package/src/cli/index.ts +5 -16
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/frame-enter-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/frame-exit-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/keyboard-global-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/scroll-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-filter.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-cell-by-index.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-column-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs +11 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +11 -2
- package/src/generators/test-generator/code-generator.ts +11 -59
- package/src/generators/test-generator/patterns/assertion-patterns.ts +2 -0
- package/src/generators/test-generator/patterns/index.ts +12 -3
- package/src/generators/test-generator/patterns/interaction-patterns.ts +1 -1
- package/src/generators/test-generator/patterns/keyboard-patterns.ts +51 -0
- package/src/generators/test-generator/patterns/scope-patterns.ts +40 -0
- package/src/generators/test-generator/patterns/scroll-patterns.ts +27 -0
- package/src/generators/test-generator/patterns/table-patterns.ts +232 -0
- package/src/generators/test-generator/step-mapper.ts +42 -27
- package/src/generators/test-generator/template-engine.ts +3 -1
- package/src/generators/test-generator/types.ts +7 -112
- package/src/generators/test-generator/utils/selector-resolver.ts +70 -25
- package/src/orchestrator/project-initializer.ts +75 -160
- package/src/orchestrator/screen-manager.ts +61 -233
- package/src/orchestrator/templates/ai-rules.md +189 -0
- package/src/orchestrator/templates/gitignore +16 -0
- package/src/orchestrator/templates/playwright.config.ts +80 -0
- package/src/orchestrator/templates/readme.md +197 -0
- package/src/utils/selector-types.ts +3 -0
- package/dist/cli/commands/cache-clear.d.ts +0 -3
- package/dist/cli/commands/cache-clear.d.ts.map +0 -1
- package/dist/cli/commands/cache-clear.js +0 -24
- package/dist/cli/commands/cache-clear.js.map +0 -1
- package/dist/cli/commands/full.d.ts +0 -3
- package/dist/cli/commands/full.d.ts.map +0 -1
- package/dist/cli/commands/full.js +0 -37
- package/dist/cli/commands/full.js.map +0 -1
- package/dist/cli/commands/live-scan.d.ts +0 -3
- package/dist/cli/commands/live-scan.d.ts.map +0 -1
- package/dist/cli/commands/live-scan.js +0 -78
- package/dist/cli/commands/live-scan.js.map +0 -1
- package/dist/cli/commands/map.d.ts +0 -3
- package/dist/cli/commands/map.d.ts.map +0 -1
- package/dist/cli/commands/map.js +0 -93
- package/dist/cli/commands/map.js.map +0 -1
- package/dist/cli/commands/validate.d.ts +0 -3
- package/dist/cli/commands/validate.d.ts.map +0 -1
- package/dist/cli/commands/validate.js +0 -43
- package/dist/cli/commands/validate.js.map +0 -1
- package/dist/cli/utils.d.ts +0 -6
- package/dist/cli/utils.d.ts.map +0 -1
- package/dist/cli/utils.js +0 -101
- package/dist/cli/utils.js.map +0 -1
- package/dist/config/config-loader.d.ts +0 -51
- package/dist/config/config-loader.d.ts.map +0 -1
- package/dist/config/config-loader.js +0 -216
- package/dist/config/config-loader.js.map +0 -1
- package/dist/config/config-schema.d.ts +0 -121
- package/dist/config/config-schema.d.ts.map +0 -1
- package/dist/config/config-schema.js +0 -7
- package/dist/config/config-schema.js.map +0 -1
- package/dist/core/live-scanner/config-reader.d.ts +0 -10
- package/dist/core/live-scanner/config-reader.d.ts.map +0 -1
- package/dist/core/live-scanner/config-reader.js +0 -87
- package/dist/core/live-scanner/config-reader.js.map +0 -1
- package/dist/core/live-scanner/element-finder.d.ts +0 -20
- package/dist/core/live-scanner/element-finder.d.ts.map +0 -1
- package/dist/core/live-scanner/element-finder.js +0 -481
- package/dist/core/live-scanner/element-finder.js.map +0 -1
- package/dist/core/live-scanner/index.d.ts +0 -8
- package/dist/core/live-scanner/index.d.ts.map +0 -1
- package/dist/core/live-scanner/index.js +0 -33
- package/dist/core/live-scanner/index.js.map +0 -1
- package/dist/core/live-scanner/matrix-reader.d.ts +0 -17
- package/dist/core/live-scanner/matrix-reader.d.ts.map +0 -1
- package/dist/core/live-scanner/matrix-reader.js +0 -60
- package/dist/core/live-scanner/matrix-reader.js.map +0 -1
- package/dist/core/live-scanner/matrix-writer.d.ts +0 -7
- package/dist/core/live-scanner/matrix-writer.d.ts.map +0 -1
- package/dist/core/live-scanner/matrix-writer.js +0 -103
- package/dist/core/live-scanner/matrix-writer.js.map +0 -1
- package/dist/core/live-scanner/role-fallback.d.ts +0 -15
- package/dist/core/live-scanner/role-fallback.d.ts.map +0 -1
- package/dist/core/live-scanner/role-fallback.js +0 -46
- package/dist/core/live-scanner/role-fallback.js.map +0 -1
- package/dist/core/live-scanner/scanner.d.ts +0 -22
- package/dist/core/live-scanner/scanner.d.ts.map +0 -1
- package/dist/core/live-scanner/scanner.js +0 -303
- package/dist/core/live-scanner/scanner.js.map +0 -1
- package/dist/core/live-scanner/step-replayer.d.ts +0 -26
- package/dist/core/live-scanner/step-replayer.d.ts.map +0 -1
- package/dist/core/live-scanner/step-replayer.js +0 -473
- package/dist/core/live-scanner/step-replayer.js.map +0 -1
- package/dist/core/live-scanner/types.d.ts +0 -52
- package/dist/core/live-scanner/types.d.ts.map +0 -1
- package/dist/core/live-scanner/types.js +0 -14
- package/dist/core/live-scanner/types.js.map +0 -1
- package/dist/core/selector-base/annotation-handler.d.ts +0 -45
- package/dist/core/selector-base/annotation-handler.d.ts.map +0 -1
- package/dist/core/selector-base/annotation-handler.js +0 -102
- package/dist/core/selector-base/annotation-handler.js.map +0 -1
- package/dist/core/selector-base/base-generator.d.ts +0 -49
- package/dist/core/selector-base/base-generator.d.ts.map +0 -1
- package/dist/core/selector-base/base-generator.js +0 -214
- package/dist/core/selector-base/base-generator.js.map +0 -1
- package/dist/core/selector-base/gherkin-parser.d.ts +0 -24
- package/dist/core/selector-base/gherkin-parser.d.ts.map +0 -1
- package/dist/core/selector-base/gherkin-parser.js +0 -42
- package/dist/core/selector-base/gherkin-parser.js.map +0 -1
- package/dist/core/selector-mapper/priority-mapper.d.ts +0 -74
- package/dist/core/selector-mapper/priority-mapper.d.ts.map +0 -1
- package/dist/core/selector-mapper/priority-mapper.js +0 -477
- package/dist/core/selector-mapper/priority-mapper.js.map +0 -1
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts +0 -91
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts.map +0 -1
- package/dist/core/ui-scanner/heuristics/base-heuristic.js +0 -175
- package/dist/core/ui-scanner/heuristics/base-heuristic.js.map +0 -1
- package/dist/core/ui-scanner/react-scanner.d.ts +0 -32
- package/dist/core/ui-scanner/react-scanner.d.ts.map +0 -1
- package/dist/core/ui-scanner/react-scanner.js +0 -163
- package/dist/core/ui-scanner/react-scanner.js.map +0 -1
- package/dist/core/ui-scanner/scanner-interface.d.ts +0 -94
- package/dist/core/ui-scanner/scanner-interface.d.ts.map +0 -1
- package/dist/core/ui-scanner/scanner-interface.js +0 -33
- package/dist/core/ui-scanner/scanner-interface.js.map +0 -1
- package/dist/core/ui-scanner/strict-scanner.d.ts +0 -81
- package/dist/core/ui-scanner/strict-scanner.d.ts.map +0 -1
- package/dist/core/ui-scanner/strict-scanner.js +0 -511
- package/dist/core/ui-scanner/strict-scanner.js.map +0 -1
- package/dist/core/validator/data-validator.d.ts +0 -38
- package/dist/core/validator/data-validator.d.ts.map +0 -1
- package/dist/core/validator/data-validator.js +0 -212
- package/dist/core/validator/data-validator.js.map +0 -1
- package/dist/core/validator/feature-validator.d.ts +0 -27
- package/dist/core/validator/feature-validator.d.ts.map +0 -1
- package/dist/core/validator/feature-validator.js +0 -182
- package/dist/core/validator/feature-validator.js.map +0 -1
- package/dist/core/validator/index.d.ts +0 -46
- package/dist/core/validator/index.d.ts.map +0 -1
- package/dist/core/validator/index.js +0 -17
- package/dist/core/validator/index.js.map +0 -1
- package/dist/core/validator/screen-validator.d.ts +0 -35
- package/dist/core/validator/screen-validator.d.ts.map +0 -1
- package/dist/core/validator/screen-validator.js +0 -195
- package/dist/core/validator/screen-validator.js.map +0 -1
- package/dist/core/validator/selector-validator.d.ts +0 -36
- package/dist/core/validator/selector-validator.d.ts.map +0 -1
- package/dist/core/validator/selector-validator.js +0 -210
- package/dist/core/validator/selector-validator.js.map +0 -1
- package/dist/external/ai-provider.d.ts +0 -60
- package/dist/external/ai-provider.d.ts.map +0 -1
- package/dist/external/ai-provider.js +0 -30
- package/dist/external/ai-provider.js.map +0 -1
- package/dist/external/anthropic-provider.d.ts +0 -29
- package/dist/external/anthropic-provider.d.ts.map +0 -1
- package/dist/external/anthropic-provider.js +0 -85
- package/dist/external/anthropic-provider.js.map +0 -1
- package/dist/generators/cache/cache-manager.d.ts +0 -66
- package/dist/generators/cache/cache-manager.d.ts.map +0 -1
- package/dist/generators/cache/cache-manager.js +0 -286
- package/dist/generators/cache/cache-manager.js.map +0 -1
- package/dist/generators/dsl-writer/index.d.ts +0 -33
- package/dist/generators/dsl-writer/index.d.ts.map +0 -1
- package/dist/generators/dsl-writer/index.js +0 -226
- package/dist/generators/dsl-writer/index.js.map +0 -1
- package/dist/generators/scaffold-generator/index.d.ts +0 -162
- package/dist/generators/scaffold-generator/index.d.ts.map +0 -1
- package/dist/generators/scaffold-generator/index.js +0 -877
- package/dist/generators/scaffold-generator/index.js.map +0 -1
- package/dist/generators/selector-mapper/ai-mapper.d.ts +0 -56
- package/dist/generators/selector-mapper/ai-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/ai-mapper.js +0 -457
- package/dist/generators/selector-mapper/ai-mapper.js.map +0 -1
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts +0 -67
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/hybrid-mapper.js +0 -349
- package/dist/generators/selector-mapper/hybrid-mapper.js.map +0 -1
- package/dist/generators/selector-mapper/index.d.ts +0 -8
- package/dist/generators/selector-mapper/index.d.ts.map +0 -1
- package/dist/generators/selector-mapper/index.js +0 -12
- package/dist/generators/selector-mapper/index.js.map +0 -1
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts +0 -125
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts.map +0 -1
- package/dist/generators/selector-mapper/intelligent-mapper.js +0 -391
- package/dist/generators/selector-mapper/intelligent-mapper.js.map +0 -1
- package/dist/generators/test-generator/ai-step-mapper.d.ts +0 -27
- package/dist/generators/test-generator/ai-step-mapper.d.ts.map +0 -1
- package/dist/generators/test-generator/ai-step-mapper.js +0 -204
- package/dist/generators/test-generator/ai-step-mapper.js.map +0 -1
- package/dist/generators/test-generator/auth-setup-generator.d.ts +0 -18
- package/dist/generators/test-generator/auth-setup-generator.d.ts.map +0 -1
- package/dist/generators/test-generator/auth-setup-generator.js +0 -82
- package/dist/generators/test-generator/auth-setup-generator.js.map +0 -1
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +0 -7
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +0 -1
- package/dist/generators/test-generator/patterns/legacy-patterns.js +0 -98
- package/dist/generators/test-generator/patterns/legacy-patterns.js.map +0 -1
- package/dist/generators/test-generator/templates/auth-setup.ts.hbs +0 -36
- package/dist/generators/ui-model-builder/deep-scanner.d.ts +0 -121
- package/dist/generators/ui-model-builder/deep-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/deep-scanner.js +0 -1113
- package/dist/generators/ui-model-builder/deep-scanner.js.map +0 -1
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts +0 -110
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js +0 -608
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js.map +0 -1
- package/dist/generators/ui-model-builder/react-scanner.d.ts +0 -107
- package/dist/generators/ui-model-builder/react-scanner.d.ts.map +0 -1
- package/dist/generators/ui-model-builder/react-scanner.js +0 -797
- package/dist/generators/ui-model-builder/react-scanner.js.map +0 -1
- package/dist/orchestrator/cache-manager.d.ts +0 -15
- package/dist/orchestrator/cache-manager.d.ts.map +0 -1
- package/dist/orchestrator/cache-manager.js +0 -62
- package/dist/orchestrator/cache-manager.js.map +0 -1
- package/dist/orchestrator/pipeline.d.ts +0 -56
- package/dist/orchestrator/pipeline.d.ts.map +0 -1
- package/dist/orchestrator/pipeline.js +0 -298
- package/dist/orchestrator/pipeline.js.map +0 -1
- package/dist/orchestrator/reporter.d.ts +0 -15
- package/dist/orchestrator/reporter.d.ts.map +0 -1
- package/dist/orchestrator/reporter.js +0 -30
- package/dist/orchestrator/reporter.js.map +0 -1
- package/src/cli/commands/cache-clear.ts +0 -22
- package/src/cli/commands/full.ts +0 -35
- package/src/cli/commands/live-scan.ts +0 -82
- package/src/cli/commands/map.ts +0 -97
- package/src/cli/commands/validate.ts +0 -43
- package/src/cli/utils.ts +0 -106
- package/src/config/ai-providers.yaml +0 -56
- package/src/config/config-loader.ts +0 -248
- package/src/config/config-schema.ts +0 -148
- package/src/config/default.config.yaml +0 -107
- package/src/config/framework.config.yaml +0 -52
- package/src/config/routes.yaml +0 -31
- package/src/core/live-scanner/config-reader.ts +0 -57
- package/src/core/live-scanner/element-finder.ts +0 -534
- package/src/core/live-scanner/index.ts +0 -7
- package/src/core/live-scanner/matrix-reader.ts +0 -65
- package/src/core/live-scanner/matrix-writer.ts +0 -77
- package/src/core/live-scanner/role-fallback.ts +0 -44
- package/src/core/live-scanner/scanner.ts +0 -321
- package/src/core/live-scanner/step-replayer.ts +0 -503
- package/src/core/live-scanner/types.ts +0 -58
- package/src/core/selector-base/annotation-handler.ts +0 -127
- package/src/core/selector-base/base-generator.ts +0 -234
- package/src/core/selector-base/gherkin-parser.ts +0 -57
- package/src/core/selector-mapper/priority-mapper.ts +0 -607
- package/src/core/ui-scanner/heuristics/base-heuristic.ts +0 -216
- package/src/core/ui-scanner/react-scanner.ts +0 -156
- package/src/core/ui-scanner/scanner-interface.ts +0 -133
- package/src/core/ui-scanner/strict-scanner.ts +0 -629
- package/src/core/validator/data-validator.ts +0 -202
- package/src/core/validator/feature-validator.ts +0 -176
- package/src/core/validator/index.ts +0 -57
- package/src/core/validator/screen-validator.ts +0 -209
- package/src/core/validator/selector-validator.ts +0 -209
- package/src/external/ai-provider.ts +0 -90
- package/src/external/anthropic-provider.ts +0 -114
- package/src/generators/README.md +0 -410
- package/src/generators/cache/cache-manager.ts +0 -322
- package/src/generators/dsl-writer/index.ts +0 -253
- package/src/generators/scaffold-generator/index.ts +0 -1029
- package/src/generators/selector-mapper/ai-mapper.ts +0 -528
- package/src/generators/selector-mapper/hybrid-mapper.ts +0 -427
- package/src/generators/selector-mapper/index.ts +0 -10
- package/src/generators/selector-mapper/intelligent-mapper.ts +0 -530
- package/src/generators/test-generator/ai-step-mapper.ts +0 -224
- package/src/generators/test-generator/auth-setup-generator.ts +0 -59
- package/src/generators/test-generator/patterns/legacy-patterns.ts +0 -104
- package/src/generators/test-generator/templates/auth-setup.ts.hbs +0 -36
- package/src/generators/ui-model-builder/deep-scanner.ts +0 -1244
- package/src/generators/ui-model-builder/enhanced-deep-scanner.ts +0 -731
- package/src/generators/ui-model-builder/react-scanner.ts +0 -959
- package/src/orchestrator/cache-manager.ts +0 -32
- package/src/orchestrator/pipeline.ts +0 -354
- package/src/orchestrator/reporter.ts +0 -36
|
@@ -3,7 +3,6 @@ import path from 'path';
|
|
|
3
3
|
import { ParsedFeature, ParsedScenario, ParsedStep } from '../gherkin-parser';
|
|
4
4
|
import { StepMapper } from './step-mapper';
|
|
5
5
|
import { TestGeneratorAdapter, adapterRegistry } from './adapters';
|
|
6
|
-
import { AuthSetupGenerator } from './auth-setup-generator';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Extract auth role from tags
|
|
@@ -41,26 +40,6 @@ function getEffectiveAuthRole(
|
|
|
41
40
|
return featureRole;
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* Detect all auth roles across feature
|
|
46
|
-
* Returns unique roles found in feature-level and scenario-level tags
|
|
47
|
-
*/
|
|
48
|
-
function detectAuthRoles(feature: ParsedFeature): string[] {
|
|
49
|
-
const roles = new Set<string>();
|
|
50
|
-
|
|
51
|
-
// Feature-level tags
|
|
52
|
-
const featureTags = feature.tags || [];
|
|
53
|
-
const featureRole = extractAuthRole(featureTags);
|
|
54
|
-
if (featureRole) roles.add(featureRole);
|
|
55
|
-
|
|
56
|
-
// Scenario-level tags
|
|
57
|
-
for (const scenario of feature.scenarios) {
|
|
58
|
-
const effectiveRole = getEffectiveAuthRole(scenario.tags, featureTags);
|
|
59
|
-
if (effectiveRole) roles.add(effectiveRole);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return Array.from(roles);
|
|
63
|
-
}
|
|
64
43
|
|
|
65
44
|
/**
|
|
66
45
|
* Check if tags contain @manual
|
|
@@ -100,7 +79,6 @@ export class CodeGenerator {
|
|
|
100
79
|
private stepMapper: StepMapper;
|
|
101
80
|
private adapter: TestGeneratorAdapter;
|
|
102
81
|
private screenName?: string;
|
|
103
|
-
private authSetupGenerator: AuthSetupGenerator;
|
|
104
82
|
private options: any;
|
|
105
83
|
// Steps registry built per feature during generateTestCode(); used by countSteps()
|
|
106
84
|
private stepsRegistry = new Map<string, ParsedScenario>();
|
|
@@ -109,8 +87,6 @@ export class CodeGenerator {
|
|
|
109
87
|
this.options = options;
|
|
110
88
|
this.screenName = options.screenName;
|
|
111
89
|
this.stepMapper = new StepMapper(options);
|
|
112
|
-
this.authSetupGenerator = new AuthSetupGenerator();
|
|
113
|
-
|
|
114
90
|
// Get adapter from registry (default: playwright)
|
|
115
91
|
const frameworkName = options.framework || 'playwright';
|
|
116
92
|
this.adapter = adapterRegistry.getAdapter(frameworkName);
|
|
@@ -214,6 +190,17 @@ export class CodeGenerator {
|
|
|
214
190
|
featureName = this.featureNameToFileName(feature.name).replace('.spec.ts', '');
|
|
215
191
|
}
|
|
216
192
|
|
|
193
|
+
// Derive screen name from source file path when not explicitly set
|
|
194
|
+
// qa/screens/{screenName}/features/{featureName}.feature -> screenName
|
|
195
|
+
if (!this.screenName && feature.sourceFile) {
|
|
196
|
+
const sourceDir = path.dirname(feature.sourceFile);
|
|
197
|
+
const parts = sourceDir.split(path.sep);
|
|
198
|
+
const screensIndex = parts.indexOf('screens');
|
|
199
|
+
if (screensIndex >= 0 && screensIndex < parts.length - 2) {
|
|
200
|
+
this.stepMapper.setScreenContext(parts[screensIndex + 1]);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
217
204
|
// Set feature context for data resolution and navigation
|
|
218
205
|
this.stepMapper.setFeatureContext(featureName, feature.path);
|
|
219
206
|
|
|
@@ -408,41 +395,6 @@ export class CodeGenerator {
|
|
|
408
395
|
);
|
|
409
396
|
}
|
|
410
397
|
|
|
411
|
-
// Collect all auth roles across all features
|
|
412
|
-
const allRoles = new Set<string>();
|
|
413
|
-
for (const feature of features) {
|
|
414
|
-
const roles = detectAuthRoles(feature);
|
|
415
|
-
roles.forEach(role => allRoles.add(role));
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Generate auth setup if any roles detected
|
|
419
|
-
if (allRoles.size > 0) {
|
|
420
|
-
const setupFile = path.join(outputDir, 'auth.setup.ts');
|
|
421
|
-
const setupExists = fs.existsSync(setupFile);
|
|
422
|
-
|
|
423
|
-
const generated = await this.authSetupGenerator.generateIfNeeded({
|
|
424
|
-
roles: Array.from(allRoles),
|
|
425
|
-
outputDir,
|
|
426
|
-
verbose: this.options.verbose
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
// If setup already exists, check for new roles
|
|
430
|
-
if (!generated && setupExists) {
|
|
431
|
-
const setupContent = fs.readFileSync(setupFile, 'utf-8');
|
|
432
|
-
const newRoles = Array.from(allRoles).filter(role =>
|
|
433
|
-
!setupContent.includes(`authenticate as ${role}`)
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
if (newRoles.length > 0) {
|
|
437
|
-
console.warn(
|
|
438
|
-
`⚠ New auth role(s) detected: ${newRoles.join(', ')}\n` +
|
|
439
|
-
` Update specs/auth.setup.ts manually to add setup for these roles\n` +
|
|
440
|
-
` Or delete auth.setup.ts to regenerate from scratch`
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
398
|
// Generate tests
|
|
447
399
|
const results: GeneratedTest[] = [];
|
|
448
400
|
const generationErrors: Array<{ feature: string; error: any }> = [];
|
|
@@ -6,7 +6,10 @@ import { formPatterns } from './form-patterns';
|
|
|
6
6
|
import { interactionPatterns } from './interaction-patterns';
|
|
7
7
|
import { assertionPatterns } from './assertion-patterns';
|
|
8
8
|
import { setupPatterns } from './setup-patterns';
|
|
9
|
-
import {
|
|
9
|
+
import { keyboardPatterns } from './keyboard-patterns';
|
|
10
|
+
import { scrollPatterns } from './scroll-patterns';
|
|
11
|
+
import { scopePatterns } from './scope-patterns';
|
|
12
|
+
import { tablePatterns } from './table-patterns';
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Pattern Registry - manages all step patterns
|
|
@@ -27,7 +30,10 @@ export class PatternRegistry {
|
|
|
27
30
|
this.patterns.push(...formPatterns);
|
|
28
31
|
this.patterns.push(...interactionPatterns);
|
|
29
32
|
this.patterns.push(...assertionPatterns);
|
|
30
|
-
this.patterns.push(...
|
|
33
|
+
this.patterns.push(...keyboardPatterns);
|
|
34
|
+
this.patterns.push(...scrollPatterns);
|
|
35
|
+
this.patterns.push(...scopePatterns);
|
|
36
|
+
this.patterns.push(...tablePatterns);
|
|
31
37
|
|
|
32
38
|
// Sort by priority (higher first)
|
|
33
39
|
this.patterns.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
@@ -111,5 +117,8 @@ export { navigationPatterns } from './navigation-patterns';
|
|
|
111
117
|
export { formPatterns } from './form-patterns';
|
|
112
118
|
export { interactionPatterns } from './interaction-patterns';
|
|
113
119
|
export { assertionPatterns } from './assertion-patterns';
|
|
114
|
-
export {
|
|
120
|
+
export { keyboardPatterns } from './keyboard-patterns';
|
|
121
|
+
export { scrollPatterns } from './scroll-patterns';
|
|
122
|
+
export { scopePatterns } from './scope-patterns';
|
|
123
|
+
export { tablePatterns } from './table-patterns';
|
|
115
124
|
export * from './types';
|
|
@@ -68,7 +68,7 @@ export const interactionPatterns: StepPattern[] = [
|
|
|
68
68
|
comment: `${actionMethod.charAt(0).toUpperCase() + actionMethod.slice(1)} ${step.selectorRef} with ${step.dataRef}`,
|
|
69
69
|
};
|
|
70
70
|
},
|
|
71
|
-
priority: 15
|
|
71
|
+
priority: 14, // Below click-element-with-text (15) so known selectors use proper locator
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
name: 'click-element-with-text',
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard Patterns
|
|
3
|
+
* Handles: press Key key, press Key on [Target] type
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StepPattern } from './types';
|
|
7
|
+
|
|
8
|
+
export const keyboardPatterns: StepPattern[] = [
|
|
9
|
+
{
|
|
10
|
+
name: 'press-key-global',
|
|
11
|
+
matcher: (step) => {
|
|
12
|
+
const text = step.text.toLowerCase();
|
|
13
|
+
return /\bpress(?:es)?\s+\w+\s+key\b/.test(text) && !text.includes(' on ');
|
|
14
|
+
},
|
|
15
|
+
resolver: (step, context) => {
|
|
16
|
+
// Extract key name: "User press Escape key" → "Escape"
|
|
17
|
+
const match = step.text.match(/press(?:es)?\s+(\w+)\s+key/i);
|
|
18
|
+
const key = match ? match[1] : 'Enter';
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
templateName: 'keyboard-global-action',
|
|
22
|
+
data: { key },
|
|
23
|
+
comment: `Press ${key} key`,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
priority: 12,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'press-key-on-element',
|
|
30
|
+
matcher: (step) => {
|
|
31
|
+
const text = step.text.toLowerCase();
|
|
32
|
+
return /\bpress(?:es)?\s+\w+\s+on\b/.test(text) && !!step.selectorRef;
|
|
33
|
+
},
|
|
34
|
+
resolver: (step, context) => {
|
|
35
|
+
// Extract key: "User press Enter on [Search] field" → "Enter"
|
|
36
|
+
const match = step.text.match(/press(?:es)?\s+(\w+)\s+on/i);
|
|
37
|
+
const key = match ? match[1] : 'Enter';
|
|
38
|
+
|
|
39
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
40
|
+
step.selectorRef!, context.featureName, step.elementType, step.nth
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
templateName: 'press-action',
|
|
45
|
+
data: { ...resolved, key },
|
|
46
|
+
comment: `Press ${key} on ${step.selectorRef}`,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
priority: 12,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope Patterns
|
|
3
|
+
* Handles: switch to [Target] frame, switch to [main] frame
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StepPattern } from './types';
|
|
7
|
+
|
|
8
|
+
export const scopePatterns: StepPattern[] = [
|
|
9
|
+
{
|
|
10
|
+
name: 'switch-to-frame',
|
|
11
|
+
matcher: (step) => {
|
|
12
|
+
return /\bswitch(?:es)?\s+to\b/i.test(step.text) &&
|
|
13
|
+
(step.elementType === 'frame' || step.elementType === 'iframe');
|
|
14
|
+
},
|
|
15
|
+
resolver: (step, context) => {
|
|
16
|
+
const selectorRef = step.selectorRef || '';
|
|
17
|
+
|
|
18
|
+
// "switch to [main] frame" → reset to page context
|
|
19
|
+
if (selectorRef.toLowerCase() === 'main') {
|
|
20
|
+
return {
|
|
21
|
+
templateName: 'frame-exit-action',
|
|
22
|
+
data: {},
|
|
23
|
+
comment: 'Exit frame scope, return to main page',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// "switch to [Payment] frame" → enter frame scope
|
|
28
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
29
|
+
selectorRef, context.featureName, 'frame', step.nth
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
templateName: 'frame-enter-action',
|
|
34
|
+
data: { ...resolved, frameName: selectorRef },
|
|
35
|
+
comment: `Switch to ${selectorRef} frame`,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
priority: 11,
|
|
39
|
+
},
|
|
40
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scroll Patterns
|
|
3
|
+
* Handles: scroll to [Target] type
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StepPattern } from './types';
|
|
7
|
+
|
|
8
|
+
export const scrollPatterns: StepPattern[] = [
|
|
9
|
+
{
|
|
10
|
+
name: 'scroll-to-element',
|
|
11
|
+
matcher: (step) => {
|
|
12
|
+
return /\bscroll(?:s)?\s+to\b/i.test(step.text) && !!step.selectorRef;
|
|
13
|
+
},
|
|
14
|
+
resolver: (step, context) => {
|
|
15
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
16
|
+
step.selectorRef!, context.featureName, step.elementType, step.nth
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
templateName: 'scroll-action',
|
|
21
|
+
data: { ...resolved },
|
|
22
|
+
comment: `Scroll to ${step.selectorRef}`,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
priority: 8,
|
|
26
|
+
},
|
|
27
|
+
];
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table Patterns
|
|
3
|
+
* Handles: table row assertions, table cell lookups, actions in table rows
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { StepPattern } from './types';
|
|
7
|
+
|
|
8
|
+
export const tablePatterns: StepPattern[] = [
|
|
9
|
+
// "User see [Users] table has {{count}} rows" — must have "rows" AFTER {{data}}
|
|
10
|
+
{
|
|
11
|
+
name: 'table-row-count',
|
|
12
|
+
matcher: (step) => {
|
|
13
|
+
return /\btable\s+has\b/i.test(step.text) &&
|
|
14
|
+
/\}\}\s*rows?\b/i.test(step.text) &&
|
|
15
|
+
!!step.dataRef;
|
|
16
|
+
},
|
|
17
|
+
resolver: (step, context) => {
|
|
18
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
19
|
+
step.selectorRef!, context.featureName, 'table', step.nth
|
|
20
|
+
);
|
|
21
|
+
const count = context.dataResolver.resolveData(step.dataRef!, context.featureName);
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
templateName: 'table-row-count',
|
|
25
|
+
data: { ...resolved, expectedCount: count },
|
|
26
|
+
comment: `Assert ${step.selectorRef} table has ${count} rows`,
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
priority: 16,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// "User see [Users] table has [Email] column"
|
|
33
|
+
{
|
|
34
|
+
name: 'table-column-exists',
|
|
35
|
+
matcher: (step) => {
|
|
36
|
+
return /\btable\s+has\b/i.test(step.text) &&
|
|
37
|
+
/\bcolumn\b/i.test(step.text);
|
|
38
|
+
},
|
|
39
|
+
resolver: (step, context) => {
|
|
40
|
+
// Extract column name from second [bracket] reference
|
|
41
|
+
const brackets = step.text.match(/\[([^\]]+)\]/g) || [];
|
|
42
|
+
const columnName = brackets.length >= 2
|
|
43
|
+
? brackets[1].replace(/[\[\]]/g, '')
|
|
44
|
+
: 'Unknown';
|
|
45
|
+
|
|
46
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
47
|
+
step.selectorRef!, context.featureName, 'table', step.nth
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
templateName: 'table-column-exists',
|
|
52
|
+
data: { ...resolved, columnName },
|
|
53
|
+
comment: `Assert ${step.selectorRef} table has ${columnName} column`,
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
priority: 16,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// "User see [Users] table is empty"
|
|
60
|
+
{
|
|
61
|
+
name: 'table-is-empty',
|
|
62
|
+
matcher: (step) => {
|
|
63
|
+
return /\btable\s+is\s+empty\b/i.test(step.text);
|
|
64
|
+
},
|
|
65
|
+
resolver: (step, context) => {
|
|
66
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
67
|
+
step.selectorRef!, context.featureName, 'table', step.nth
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
templateName: 'table-empty',
|
|
72
|
+
data: { ...resolved },
|
|
73
|
+
comment: `Assert ${step.selectorRef} table is empty`,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
priority: 16,
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
// "User see [Users] table row with {{name}} has [Status] with {{value}}"
|
|
80
|
+
{
|
|
81
|
+
name: 'table-cell-by-filter',
|
|
82
|
+
matcher: (step) => {
|
|
83
|
+
return /\btable\s+row\s+with\b/i.test(step.text) &&
|
|
84
|
+
/\bhas\b/i.test(step.text);
|
|
85
|
+
},
|
|
86
|
+
resolver: (step, context) => {
|
|
87
|
+
// Extract: [Table] table row with {{filter}} has [Col] with {{value}}
|
|
88
|
+
const brackets = step.text.match(/\[([^\]]+)\]/g) || [];
|
|
89
|
+
const tableName = brackets[0]?.replace(/[\[\]]/g, '') || '';
|
|
90
|
+
const columnName = brackets.length >= 2
|
|
91
|
+
? brackets[1].replace(/[\[\]]/g, '')
|
|
92
|
+
: '';
|
|
93
|
+
|
|
94
|
+
// Extract data refs: first is filter, second is cell value
|
|
95
|
+
const dataRefs = step.text.match(/\{\{([^}]+)\}\}/g) || [];
|
|
96
|
+
const filterRef = dataRefs[0]?.replace(/\{\{|\}\}/g, '') || '';
|
|
97
|
+
const valueRef = dataRefs.length >= 2
|
|
98
|
+
? dataRefs[1].replace(/\{\{|\}\}/g, '')
|
|
99
|
+
: '';
|
|
100
|
+
|
|
101
|
+
const filterValue = filterRef
|
|
102
|
+
? context.dataResolver.resolveData(filterRef, context.featureName)
|
|
103
|
+
: '';
|
|
104
|
+
const cellValue = valueRef
|
|
105
|
+
? context.dataResolver.resolveData(valueRef, context.featureName)
|
|
106
|
+
: '';
|
|
107
|
+
|
|
108
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
109
|
+
tableName, context.featureName, 'table', step.nth
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
templateName: 'table-cell-by-filter',
|
|
114
|
+
data: { ...resolved, filterValue, columnName, cellValue },
|
|
115
|
+
comment: `Assert ${tableName} table row with ${filterRef} has ${columnName} = ${valueRef}`,
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
priority: 17,
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
// "User see [Users] table row 1 [Name] cell with {{value}}"
|
|
122
|
+
{
|
|
123
|
+
name: 'table-cell-by-index',
|
|
124
|
+
matcher: (step) => {
|
|
125
|
+
return /\btable\s+row\s+\d+\b/i.test(step.text) &&
|
|
126
|
+
/\bcell\b/i.test(step.text);
|
|
127
|
+
},
|
|
128
|
+
resolver: (step, context) => {
|
|
129
|
+
const brackets = step.text.match(/\[([^\]]+)\]/g) || [];
|
|
130
|
+
const tableName = brackets[0]?.replace(/[\[\]]/g, '') || '';
|
|
131
|
+
const columnName = brackets.length >= 2
|
|
132
|
+
? brackets[1].replace(/[\[\]]/g, '')
|
|
133
|
+
: '';
|
|
134
|
+
|
|
135
|
+
const rowMatch = step.text.match(/\brow\s+(\d+)\b/i);
|
|
136
|
+
const rowIndex = rowMatch ? parseInt(rowMatch[1], 10) : 1;
|
|
137
|
+
|
|
138
|
+
const cellValue = step.dataRef
|
|
139
|
+
? context.dataResolver.resolveData(step.dataRef, context.featureName)
|
|
140
|
+
: '';
|
|
141
|
+
|
|
142
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
143
|
+
tableName, context.featureName, 'table', step.nth
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
templateName: 'table-cell-by-index',
|
|
148
|
+
data: { ...resolved, rowIndex, columnName, cellValue },
|
|
149
|
+
comment: `Assert ${tableName} table row ${rowIndex} ${columnName} cell = ${step.dataRef}`,
|
|
150
|
+
};
|
|
151
|
+
},
|
|
152
|
+
priority: 17,
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
// "User see [Users] table has row with {{name}}"
|
|
156
|
+
{
|
|
157
|
+
name: 'table-row-exists',
|
|
158
|
+
matcher: (step) => {
|
|
159
|
+
return /\btable\s+has\s+row\s+with\b/i.test(step.text) && !!step.dataRef;
|
|
160
|
+
},
|
|
161
|
+
resolver: (step, context) => {
|
|
162
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
163
|
+
step.selectorRef!, context.featureName, 'table', step.nth
|
|
164
|
+
);
|
|
165
|
+
const filterValue = context.dataResolver.resolveData(step.dataRef!, context.featureName);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
templateName: 'table-row-exists',
|
|
169
|
+
data: { ...resolved, filterValue },
|
|
170
|
+
comment: `Assert ${step.selectorRef} table has row with ${step.dataRef}`,
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
priority: 18,
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
// "User see [Users] table has no row with {{name}}"
|
|
177
|
+
{
|
|
178
|
+
name: 'table-row-not-exists',
|
|
179
|
+
matcher: (step) => {
|
|
180
|
+
return /\btable\s+has\s+no\s+row\s+with\b/i.test(step.text) && !!step.dataRef;
|
|
181
|
+
},
|
|
182
|
+
resolver: (step, context) => {
|
|
183
|
+
const resolved = context.selectorResolver.resolveSelector(
|
|
184
|
+
step.selectorRef!, context.featureName, 'table', step.nth
|
|
185
|
+
);
|
|
186
|
+
const filterValue = context.dataResolver.resolveData(step.dataRef!, context.featureName);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
templateName: 'table-row-not-exists',
|
|
190
|
+
data: { ...resolved, filterValue },
|
|
191
|
+
comment: `Assert ${step.selectorRef} table has no row with ${step.dataRef}`,
|
|
192
|
+
};
|
|
193
|
+
},
|
|
194
|
+
priority: 19,
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// "User click [Edit] in [Users] table row with {{name}}"
|
|
198
|
+
{
|
|
199
|
+
name: 'table-action-in-row',
|
|
200
|
+
matcher: (step) => {
|
|
201
|
+
return /\bin\b.*\btable\s+row\s+with\b/i.test(step.text);
|
|
202
|
+
},
|
|
203
|
+
resolver: (step, context) => {
|
|
204
|
+
const brackets = step.text.match(/\[([^\]]+)\]/g) || [];
|
|
205
|
+
const elementName = brackets[0]?.replace(/[\[\]]/g, '') || '';
|
|
206
|
+
const tableName = brackets.length >= 2
|
|
207
|
+
? brackets[1].replace(/[\[\]]/g, '')
|
|
208
|
+
: '';
|
|
209
|
+
|
|
210
|
+
const dataRefs = step.text.match(/\{\{([^}]+)\}\}/g) || [];
|
|
211
|
+
const filterRef = dataRefs[0]?.replace(/\{\{|\}\}/g, '') || '';
|
|
212
|
+
const filterValue = filterRef
|
|
213
|
+
? context.dataResolver.resolveData(filterRef, context.featureName)
|
|
214
|
+
: '';
|
|
215
|
+
|
|
216
|
+
const tableResolved = context.selectorResolver.resolveSelector(
|
|
217
|
+
tableName, context.featureName, 'table', 0
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Determine action
|
|
221
|
+
const actionMatch = step.text.match(/\b(click|check|uncheck)\b/i);
|
|
222
|
+
const action = actionMatch ? actionMatch[1].toLowerCase() : 'click';
|
|
223
|
+
|
|
224
|
+
return {
|
|
225
|
+
templateName: 'table-action-in-row',
|
|
226
|
+
data: { ...tableResolved, elementName, filterValue, action },
|
|
227
|
+
comment: `${action} ${elementName} in ${tableName} table row with ${filterRef}`,
|
|
228
|
+
};
|
|
229
|
+
},
|
|
230
|
+
priority: 17,
|
|
231
|
+
},
|
|
232
|
+
];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { ParsedStep } from '../gherkin-parser';
|
|
2
|
-
import { AIStepMapper } from './ai-step-mapper';
|
|
3
2
|
import { TemplateEngine } from './template-engine';
|
|
4
3
|
import { PatternRegistry, PatternContext } from './patterns';
|
|
5
4
|
import { SelectorResolver } from './utils/selector-resolver';
|
|
@@ -18,8 +17,6 @@ export interface MappedStep {
|
|
|
18
17
|
*/
|
|
19
18
|
export class StepMapper {
|
|
20
19
|
private stepCounter: number = 0;
|
|
21
|
-
private aiMapper: AIStepMapper | null = null;
|
|
22
|
-
private useAI: boolean = false;
|
|
23
20
|
private verbose: boolean = false;
|
|
24
21
|
private templateEngine: TemplateEngine;
|
|
25
22
|
private patternRegistry: PatternRegistry;
|
|
@@ -31,9 +28,9 @@ export class StepMapper {
|
|
|
31
28
|
private featurePath?: string;
|
|
32
29
|
private currentScenarioSteps?: ParsedStep[];
|
|
33
30
|
private inDialogScope: boolean = false;
|
|
31
|
+
private inFrameScope: boolean = false;
|
|
34
32
|
|
|
35
|
-
constructor(options: {
|
|
36
|
-
this.useAI = options.useAI ?? false;
|
|
33
|
+
constructor(options: { verbose?: boolean; baseURL?: string; featureName?: string; screenName?: string; featurePath?: string } = {}) {
|
|
37
34
|
this.verbose = options.verbose ?? false;
|
|
38
35
|
this.baseURL = options.baseURL || null; // null means path-only navigation
|
|
39
36
|
this.featureName = options.featureName;
|
|
@@ -46,18 +43,8 @@ export class StepMapper {
|
|
|
46
43
|
this.selectorResolver = new SelectorResolver(undefined, options.screenName);
|
|
47
44
|
this.dataResolver = new DataResolver(undefined, options.screenName);
|
|
48
45
|
|
|
49
|
-
if (this.
|
|
50
|
-
|
|
51
|
-
this.aiMapper = new AIStepMapper(this.verbose);
|
|
52
|
-
if (this.verbose) {
|
|
53
|
-
console.log(` [StepMapper] AI fallback enabled (${this.patternRegistry.getPatternCount()} patterns loaded)`);
|
|
54
|
-
}
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.warn('[StepMapper] AI mapper initialization failed:', error);
|
|
57
|
-
this.useAI = false;
|
|
58
|
-
}
|
|
59
|
-
} else if (this.verbose) {
|
|
60
|
-
console.log(` [StepMapper] Dictionary mode (${this.patternRegistry.getPatternCount()} patterns loaded)`);
|
|
46
|
+
if (this.verbose) {
|
|
47
|
+
console.log(` [StepMapper] ${this.patternRegistry.getPatternCount()} patterns loaded`);
|
|
61
48
|
}
|
|
62
49
|
}
|
|
63
50
|
|
|
@@ -70,13 +57,23 @@ export class StepMapper {
|
|
|
70
57
|
this.selectorResolver.setFeatureContext(featureName);
|
|
71
58
|
}
|
|
72
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Update screen context (used in --all mode to set per-feature screen name)
|
|
62
|
+
*/
|
|
63
|
+
setScreenContext(screenName: string): void {
|
|
64
|
+
this.screenName = screenName;
|
|
65
|
+
this.selectorResolver.setScreenContext(screenName);
|
|
66
|
+
this.dataResolver.setScreenContext(screenName);
|
|
67
|
+
}
|
|
68
|
+
|
|
73
69
|
/**
|
|
74
70
|
* Set scenario context for path variable resolution
|
|
75
71
|
*/
|
|
76
72
|
setScenarioContext(steps: ParsedStep[]): void {
|
|
77
73
|
this.currentScenarioSteps = steps;
|
|
78
|
-
// Reset dialog scope at the start of each new scenario
|
|
74
|
+
// Reset dialog and frame scope at the start of each new scenario
|
|
79
75
|
this.inDialogScope = false;
|
|
76
|
+
this.inFrameScope = false;
|
|
80
77
|
this.templateEngine.resetBaseContext();
|
|
81
78
|
}
|
|
82
79
|
|
|
@@ -87,6 +84,32 @@ export class StepMapper {
|
|
|
87
84
|
mapStep(step: ParsedStep): MappedStep | Promise<MappedStep> {
|
|
88
85
|
this.stepCounter++;
|
|
89
86
|
|
|
87
|
+
// Frame scope directives — intercept before pattern matching
|
|
88
|
+
if (/\bswitch(?:es)?\s+to\b/i.test(step.text) &&
|
|
89
|
+
(step.elementType === 'frame' || step.elementType === 'iframe')) {
|
|
90
|
+
const selectorRef = step.selectorRef || '';
|
|
91
|
+
|
|
92
|
+
if (selectorRef.toLowerCase() === 'main') {
|
|
93
|
+
// Exit frame scope
|
|
94
|
+
this.inFrameScope = false;
|
|
95
|
+
this.templateEngine.setBaseContext({ inFrame: false });
|
|
96
|
+
return { code: '// Back to main page context', comment: 'Exit frame scope' };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Enter frame scope
|
|
100
|
+
this.inFrameScope = true;
|
|
101
|
+
let frameSelector = selectorRef;
|
|
102
|
+
try {
|
|
103
|
+
const resolved = this.selectorResolver.resolveSelector(selectorRef, this.featureName, 'frame', 0);
|
|
104
|
+
frameSelector = resolved.value || selectorRef;
|
|
105
|
+
} catch {
|
|
106
|
+
// Use selectorRef as-is
|
|
107
|
+
}
|
|
108
|
+
this.templateEngine.setBaseContext({ inFrame: true, frameSelector });
|
|
109
|
+
const code = `const frame = page.frameLocator('${frameSelector}');`;
|
|
110
|
+
return { code, comment: `Switch to ${selectorRef} frame` };
|
|
111
|
+
}
|
|
112
|
+
|
|
90
113
|
// Dialog scope directives — intercept before pattern matching
|
|
91
114
|
if (/\buse dialog\b/i.test(step.text)) {
|
|
92
115
|
this.inDialogScope = true;
|
|
@@ -142,15 +165,7 @@ export class StepMapper {
|
|
|
142
165
|
return mappedStep;
|
|
143
166
|
}
|
|
144
167
|
|
|
145
|
-
//
|
|
146
|
-
if (this.useAI && this.aiMapper) {
|
|
147
|
-
if (this.verbose) {
|
|
148
|
-
console.log(` → AI fallback for: ${step.text.substring(0, 50)}...`);
|
|
149
|
-
}
|
|
150
|
-
return this.aiMapper.mapStep(step);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// No pattern matched and no AI - return generic code with comment
|
|
168
|
+
// No pattern matched - return TODO comment
|
|
154
169
|
return {
|
|
155
170
|
code: `// TODO: Implement step: ${step.text}`,
|
|
156
171
|
comment: `Unrecognized step pattern: ${step.text}`,
|
|
@@ -112,8 +112,10 @@ export class TemplateEngine {
|
|
|
112
112
|
}
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
// Returns the Playwright root object — scoped to dialog
|
|
115
|
+
// Returns the Playwright root object — scoped to dialog or frame when active
|
|
116
116
|
Handlebars.registerHelper('pageRoot', function(this: any) {
|
|
117
|
+
// Frame scope takes precedence (frame > dialog > page)
|
|
118
|
+
if (this.inFrame) return 'frame';
|
|
117
119
|
if (!this.inDialog) return 'page';
|
|
118
120
|
const partial = Handlebars.partials['dialog-root'];
|
|
119
121
|
if (partial) {
|