@sun-asterisk/sungen 1.0.24 → 2.0.0
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 +0 -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 +1 -3
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +30 -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 +8 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +343 -32
- 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/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/package.json +2 -2
- 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 +0 -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 +33 -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 +345 -32
- package/src/orchestrator/screen-manager.ts +61 -233
- 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
|
@@ -1,503 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step Replayer
|
|
3
|
-
* Replays Gherkin steps on a live Playwright page to reveal dynamic elements.
|
|
4
|
-
* Takes a snapshot and finds elements after each action.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Page } from 'playwright';
|
|
8
|
-
import { findElement } from './element-finder';
|
|
9
|
-
import { LiveElement, ElementContext } from './types';
|
|
10
|
-
import { SelectorResolver } from '../../generators/test-generator/utils/selector-resolver';
|
|
11
|
-
|
|
12
|
-
interface ParsedStepInfo {
|
|
13
|
-
keyword: string;
|
|
14
|
-
text: string;
|
|
15
|
-
selectorRef?: string;
|
|
16
|
-
dataRef?: string;
|
|
17
|
-
elementType?: string;
|
|
18
|
-
nth?: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface ReplayResult {
|
|
22
|
-
elements: Record<string, LiveElement>;
|
|
23
|
-
errors: string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Resolve a {{dataRef}} path against test-data object.
|
|
28
|
-
* Supports dot-notation: "email.valid" → testData.email.valid
|
|
29
|
-
*/
|
|
30
|
-
function resolveDataRef(testData: Record<string, any>, dataRef: string): string {
|
|
31
|
-
const parts = dataRef.replace(/[{}]/g, '').split('.');
|
|
32
|
-
let value: any = testData;
|
|
33
|
-
for (const part of parts) {
|
|
34
|
-
value = value?.[part];
|
|
35
|
-
}
|
|
36
|
-
return typeof value === 'string' ? value : String(value ?? '');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Replay a sequence of Gherkin steps on a Playwright page,
|
|
41
|
-
* finding and interacting with elements along the way.
|
|
42
|
-
*/
|
|
43
|
-
export async function replaySteps(
|
|
44
|
-
page: Page,
|
|
45
|
-
steps: ParsedStepInfo[],
|
|
46
|
-
featurePath: string,
|
|
47
|
-
baseUrl: string,
|
|
48
|
-
existingElements?: Record<string, LiveElement>,
|
|
49
|
-
testData?: Record<string, any> | null
|
|
50
|
-
): Promise<ReplayResult> {
|
|
51
|
-
const elements: Record<string, LiveElement> = {};
|
|
52
|
-
const errors: string[] = [];
|
|
53
|
-
let currentContext: ElementContext = 'page';
|
|
54
|
-
|
|
55
|
-
// Pre-scan: detect which base keys have multiple normalized element types
|
|
56
|
-
// so we can append --type suffix (matching scaffold generator behavior)
|
|
57
|
-
// Uses normalizeElementType to match scaffold generator's extractTargetType mapping
|
|
58
|
-
// e.g. modal/dialog both normalize to 'dialog', so they won't create a false conflict
|
|
59
|
-
const typesPerKey = new Map<string, Set<string>>();
|
|
60
|
-
for (const step of steps) {
|
|
61
|
-
if (!step.selectorRef) continue;
|
|
62
|
-
const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
|
|
63
|
-
const action = detectAction(step.text);
|
|
64
|
-
const normalizedType = normalizeElementType(step.elementType || 'button', action);
|
|
65
|
-
if (!typesPerKey.has(baseKey)) {
|
|
66
|
-
typesPerKey.set(baseKey, new Set());
|
|
67
|
-
}
|
|
68
|
-
typesPerKey.get(baseKey)!.add(normalizedType);
|
|
69
|
-
}
|
|
70
|
-
const conflictKeys = new Set<string>();
|
|
71
|
-
for (const [key, types] of typesPerKey) {
|
|
72
|
-
if (types.size > 1) conflictKeys.add(key);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
for (const step of steps) {
|
|
76
|
-
try {
|
|
77
|
-
const action = detectAction(step.text);
|
|
78
|
-
|
|
79
|
-
// Handle navigation (Given User is on [x] page)
|
|
80
|
-
if (action === 'navigate') {
|
|
81
|
-
await page.goto(baseUrl + featurePath, { waitUntil: 'networkidle', timeout: 15000 });
|
|
82
|
-
await settle(page);
|
|
83
|
-
if (step.selectorRef) {
|
|
84
|
-
const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
|
|
85
|
-
const normalizedType = normalizeElementType(step.elementType || 'page', action);
|
|
86
|
-
const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
|
|
87
|
-
// Record the page element but don't search for it on the DOM
|
|
88
|
-
elements[key] = {
|
|
89
|
-
gherkinRef: step.selectorRef,
|
|
90
|
-
gherkinType: step.elementType || 'page',
|
|
91
|
-
selectorType: '',
|
|
92
|
-
selectorValue: featurePath,
|
|
93
|
-
role: '',
|
|
94
|
-
name: step.selectorRef,
|
|
95
|
-
testid: null,
|
|
96
|
-
tag: '',
|
|
97
|
-
contenteditable: false,
|
|
98
|
-
placeholder: null,
|
|
99
|
-
label: null,
|
|
100
|
-
context: 'page',
|
|
101
|
-
matchMethod: 'exact_role',
|
|
102
|
-
exact: false,
|
|
103
|
-
warning: null,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
continue;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Skip steps without element references
|
|
110
|
-
if (!step.selectorRef) continue;
|
|
111
|
-
|
|
112
|
-
const baseKey = generateElementKey(step.selectorRef, step.elementType, step.nth);
|
|
113
|
-
const elementType = step.elementType || 'button';
|
|
114
|
-
const normalizedType = normalizeElementType(elementType, action);
|
|
115
|
-
const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
|
|
116
|
-
const nth = step.nth || 0;
|
|
117
|
-
|
|
118
|
-
// Skip column-type elements — they use header text matching, no DOM lookup needed
|
|
119
|
-
if (normalizedType === 'column') {
|
|
120
|
-
console.log(` ⏭️ [${step.selectorRef}] column → skipped (table header match)`);
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Skip if element already resolved in existing scan (non-force mode)
|
|
125
|
-
if (existingElements && existingElements[key] && existingElements[key].matchMethod !== 'unresolved') {
|
|
126
|
-
elements[key] = existingElements[key];
|
|
127
|
-
(elements[key] as any).skipped = true;
|
|
128
|
-
console.log(` ⏩ [${step.selectorRef}] ${elementType} → cached (${existingElements[key].selectorType})`);
|
|
129
|
-
|
|
130
|
-
// Still execute actions for cached elements to maintain page state
|
|
131
|
-
if (action === 'click') {
|
|
132
|
-
try {
|
|
133
|
-
await executeClick(page, step.selectorRef, elementType, nth);
|
|
134
|
-
await settle(page);
|
|
135
|
-
currentContext = await detectCurrentContext(page, currentContext, step.text);
|
|
136
|
-
} catch {
|
|
137
|
-
// Click failed for cached element, continue anyway
|
|
138
|
-
}
|
|
139
|
-
} else if (action === 'fill' && testData && step.dataRef) {
|
|
140
|
-
try {
|
|
141
|
-
const value = resolveDataRef(testData, step.dataRef);
|
|
142
|
-
if (value) {
|
|
143
|
-
await executeFill(page, step.selectorRef, elementType, nth, value);
|
|
144
|
-
await settle(page);
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// Fill failed for cached element, continue anyway
|
|
148
|
-
}
|
|
149
|
-
} else if (action === 'select' && testData && step.dataRef) {
|
|
150
|
-
try {
|
|
151
|
-
const value = resolveDataRef(testData, step.dataRef);
|
|
152
|
-
if (value) {
|
|
153
|
-
await executeSelect(page, step.selectorRef, elementType, nth, value);
|
|
154
|
-
await settle(page);
|
|
155
|
-
}
|
|
156
|
-
} catch {
|
|
157
|
-
// Select failed for cached element, continue anyway
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
continue;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Find the element on the page, scoped to current context (dialog/page)
|
|
164
|
-
const element = await findElement(page, step.selectorRef, elementType, nth, currentContext);
|
|
165
|
-
element.context = currentContext;
|
|
166
|
-
|
|
167
|
-
// Record in matrix (first match wins for duplicate keys)
|
|
168
|
-
if (!elements[key]) {
|
|
169
|
-
elements[key] = element;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Execute the action if element was found
|
|
173
|
-
if (element.matchMethod !== 'unresolved') {
|
|
174
|
-
if (action === 'click') {
|
|
175
|
-
await executeClick(page, step.selectorRef, elementType, nth);
|
|
176
|
-
await settle(page);
|
|
177
|
-
currentContext = await detectCurrentContext(page, currentContext, step.text);
|
|
178
|
-
} else if (action === 'fill') {
|
|
179
|
-
if (testData && step.dataRef) {
|
|
180
|
-
const value = resolveDataRef(testData, step.dataRef);
|
|
181
|
-
if (value) {
|
|
182
|
-
try {
|
|
183
|
-
await executeFill(page, step.selectorRef, elementType, nth, value);
|
|
184
|
-
await settle(page);
|
|
185
|
-
} catch (e: any) {
|
|
186
|
-
errors.push(`Step "${step.text}": fill failed — ${e.message}`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
} else if (action === 'select') {
|
|
191
|
-
if (testData && step.dataRef) {
|
|
192
|
-
const value = resolveDataRef(testData, step.dataRef);
|
|
193
|
-
if (value) {
|
|
194
|
-
try {
|
|
195
|
-
await executeSelect(page, step.selectorRef, elementType, nth, value);
|
|
196
|
-
await settle(page);
|
|
197
|
-
} catch (e: any) {
|
|
198
|
-
errors.push(`Step "${step.text}": select failed — ${e.message}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
// Label-value detection: check if the data value appears in a sibling element
|
|
204
|
-
if (action === 'see' && normalizedType === 'text' && (elementType === 'label' || elementType === 'title' || elementType === 'caption') && testData && step.dataRef) {
|
|
205
|
-
const dataValue = resolveDataRef(testData, step.dataRef);
|
|
206
|
-
if (dataValue) {
|
|
207
|
-
try {
|
|
208
|
-
// Check if the parent container has both the label text and the data value
|
|
209
|
-
const hasLabelValue = await page.getByText(new RegExp(escapeRegex(element.gherkinRef) + '.*' + escapeRegex(dataValue))).first().isVisible({ timeout: 2000 });
|
|
210
|
-
if (hasLabelValue) {
|
|
211
|
-
element.matchMethod = 'label-value';
|
|
212
|
-
elements[key] = element;
|
|
213
|
-
}
|
|
214
|
-
} catch {
|
|
215
|
-
// Regex match failed, keep original matchMethod
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
// 'see' and 'wait' actions: just record, don't interact
|
|
220
|
-
} else {
|
|
221
|
-
// Try data-value fallback for click actions: use the resolved data value as element name
|
|
222
|
-
if (action === 'click' && testData && step.dataRef) {
|
|
223
|
-
const dataValue = resolveDataRef(testData, step.dataRef);
|
|
224
|
-
if (dataValue) {
|
|
225
|
-
// Brief wait for dynamic content (e.g. autocomplete dropdown after fill)
|
|
226
|
-
await page.waitForTimeout(1000);
|
|
227
|
-
const fallback = await findElement(page, dataValue, elementType, nth, currentContext);
|
|
228
|
-
if (fallback.matchMethod !== 'unresolved') {
|
|
229
|
-
// Preserve original gherkinRef; clear locator values since they come
|
|
230
|
-
// from test-data ({{dataRef}}) at runtime, not hardcoded from DOM.
|
|
231
|
-
// Store dataValue for logging in scanner.ts
|
|
232
|
-
fallback.gherkinRef = step.selectorRef;
|
|
233
|
-
(fallback as any).dataValue = dataValue;
|
|
234
|
-
fallback.name = '';
|
|
235
|
-
fallback.exact = false;
|
|
236
|
-
elements[key] = fallback;
|
|
237
|
-
try {
|
|
238
|
-
await executeClick(page, dataValue, elementType, nth);
|
|
239
|
-
await settle(page);
|
|
240
|
-
currentContext = await detectCurrentContext(page, currentContext, step.text);
|
|
241
|
-
} catch {
|
|
242
|
-
// Click failed, element still recorded
|
|
243
|
-
}
|
|
244
|
-
continue;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
errors.push(`Step "${step.text}": element [${step.selectorRef}] not found`);
|
|
249
|
-
// Continue scanning remaining steps — record what we can even if some elements are missing
|
|
250
|
-
}
|
|
251
|
-
} catch (error: any) {
|
|
252
|
-
errors.push(`Step "${step.text}": ${error.message}`);
|
|
253
|
-
// On navigation or critical errors, stop replaying this scenario
|
|
254
|
-
if (error.message.includes('Navigation') || error.message.includes('net::')) {
|
|
255
|
-
break;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return { elements, errors };
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function executeClick(
|
|
264
|
-
page: Page,
|
|
265
|
-
ref: string,
|
|
266
|
-
elementType: string,
|
|
267
|
-
nth: number
|
|
268
|
-
): Promise<void> {
|
|
269
|
-
const namePattern = new RegExp(escapeRegex(ref), 'i');
|
|
270
|
-
|
|
271
|
-
// Try role-based click first
|
|
272
|
-
const { getRoleFallbacks } = require('./role-fallback');
|
|
273
|
-
const roles = getRoleFallbacks(elementType);
|
|
274
|
-
|
|
275
|
-
for (const role of roles) {
|
|
276
|
-
try {
|
|
277
|
-
const locator = page.getByRole(role as any, { name: namePattern });
|
|
278
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
279
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
280
|
-
await target.click({ timeout: 5000 });
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
} catch {
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Fallback to text click
|
|
289
|
-
try {
|
|
290
|
-
const locator = page.getByText(namePattern);
|
|
291
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
292
|
-
await target.click({ timeout: 5000 });
|
|
293
|
-
} catch {
|
|
294
|
-
// Try testid as last resort
|
|
295
|
-
const normalized = ref.toLowerCase().replace(/[\s_-]+/g, '-');
|
|
296
|
-
await page.locator(`[data-testid*="${normalized}" i]`).first().click({ timeout: 5000 });
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async function executeFill(
|
|
301
|
-
page: Page,
|
|
302
|
-
ref: string,
|
|
303
|
-
elementType: string,
|
|
304
|
-
nth: number,
|
|
305
|
-
value: string
|
|
306
|
-
): Promise<void> {
|
|
307
|
-
const namePattern = new RegExp(escapeRegex(ref), 'i');
|
|
308
|
-
|
|
309
|
-
// Try placeholder first — most direct for input fields, avoids slow role attempts
|
|
310
|
-
try {
|
|
311
|
-
const locator = page.getByPlaceholder(namePattern);
|
|
312
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
313
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
314
|
-
await target.fill(value, { timeout: 5000 });
|
|
315
|
-
return;
|
|
316
|
-
}
|
|
317
|
-
} catch {
|
|
318
|
-
// continue
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Try label
|
|
322
|
-
try {
|
|
323
|
-
const locator = page.getByLabel(namePattern);
|
|
324
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
325
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
326
|
-
await target.fill(value, { timeout: 5000 });
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
} catch {
|
|
330
|
-
// continue
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// Try role-based fill (textbox, combobox, spinbutton)
|
|
334
|
-
const { getRoleFallbacks } = require('./role-fallback');
|
|
335
|
-
const roles = getRoleFallbacks(elementType);
|
|
336
|
-
|
|
337
|
-
for (const role of roles) {
|
|
338
|
-
try {
|
|
339
|
-
const locator = page.getByRole(role as any, { name: namePattern });
|
|
340
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
341
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
342
|
-
await target.fill(value, { timeout: 5000 });
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
} catch {
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Try testid as last resort
|
|
351
|
-
const normalized = ref.toLowerCase().replace(/[\s_-]+/g, '-');
|
|
352
|
-
await page.locator(`[data-testid*="${normalized}" i]`).first().fill(value, { timeout: 5000 });
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
async function executeSelect(
|
|
356
|
-
page: Page,
|
|
357
|
-
ref: string,
|
|
358
|
-
elementType: string,
|
|
359
|
-
nth: number,
|
|
360
|
-
value: string
|
|
361
|
-
): Promise<void> {
|
|
362
|
-
const namePattern = new RegExp(escapeRegex(ref), 'i');
|
|
363
|
-
|
|
364
|
-
// Try label first — most direct for select elements
|
|
365
|
-
try {
|
|
366
|
-
const locator = page.getByLabel(namePattern);
|
|
367
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
368
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
369
|
-
await target.selectOption(value, { timeout: 5000 });
|
|
370
|
-
return;
|
|
371
|
-
}
|
|
372
|
-
} catch {
|
|
373
|
-
// continue
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Try role-based select (combobox, listbox)
|
|
377
|
-
const { getRoleFallbacks } = require('./role-fallback');
|
|
378
|
-
const roles = getRoleFallbacks(elementType);
|
|
379
|
-
|
|
380
|
-
for (const role of roles) {
|
|
381
|
-
try {
|
|
382
|
-
const locator = page.getByRole(role as any, { name: namePattern });
|
|
383
|
-
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
384
|
-
if (await target.isVisible({ timeout: 3000 })) {
|
|
385
|
-
await target.selectOption(value, { timeout: 5000 });
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
} catch {
|
|
389
|
-
continue;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Try testid as last resort
|
|
394
|
-
const normalized = ref.toLowerCase().replace(/[\s_-]+/g, '-');
|
|
395
|
-
await page.locator(`[data-testid*="${normalized}" i]`).first().selectOption(value, { timeout: 5000 });
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
function detectAction(text: string): string {
|
|
399
|
-
const lower = text.toLowerCase();
|
|
400
|
-
if (/\b(is on|navigate|go to|visit|open)\b/.test(lower) && /\bpage\b/.test(lower)) return 'navigate';
|
|
401
|
-
if (/\b(click|press|tap|submit)\b/.test(lower)) return 'click';
|
|
402
|
-
if (/\b(fill|enter|type|input)\b/.test(lower)) return 'fill';
|
|
403
|
-
if (/\b(see|verify|check|expect|visible|displayed)\b/.test(lower)) return 'see';
|
|
404
|
-
if (/\b(select|choose|pick)\b/.test(lower)) return 'select';
|
|
405
|
-
if (/\b(wait)\b/.test(lower)) return 'wait';
|
|
406
|
-
return 'see';
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
async function detectCurrentContext(
|
|
410
|
-
page: Page,
|
|
411
|
-
previous: ElementContext,
|
|
412
|
-
stepText: string
|
|
413
|
-
): Promise<ElementContext> {
|
|
414
|
-
const lower = stepText.toLowerCase();
|
|
415
|
-
|
|
416
|
-
// Check if we opened a dialog/modal
|
|
417
|
-
if (/\b(dialog|modal|panel)\b/.test(lower)) {
|
|
418
|
-
return 'dialog';
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Check if a dialog is now visible on the page
|
|
422
|
-
try {
|
|
423
|
-
const dialogLocator = page.getByRole('dialog');
|
|
424
|
-
if (await dialogLocator.count() > 0) {
|
|
425
|
-
return 'dialog';
|
|
426
|
-
}
|
|
427
|
-
} catch {
|
|
428
|
-
// ignore
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Check for menu
|
|
432
|
-
if (/\b(menu|dropdown)\b/.test(lower)) {
|
|
433
|
-
return 'menu';
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
const menuLocator = page.getByRole('menu');
|
|
438
|
-
if (await menuLocator.count() > 0) {
|
|
439
|
-
return 'menu';
|
|
440
|
-
}
|
|
441
|
-
} catch {
|
|
442
|
-
// ignore
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
return previous;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
async function settle(page: Page): Promise<void> {
|
|
449
|
-
try {
|
|
450
|
-
await page.waitForLoadState('networkidle', { timeout: 5000 });
|
|
451
|
-
} catch {
|
|
452
|
-
// Timeout is acceptable — page may have long-polling connections
|
|
453
|
-
}
|
|
454
|
-
// Small extra wait for animations/transitions
|
|
455
|
-
await page.waitForTimeout(300);
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
function generateElementKey(ref: string, elementType?: string, nth?: number): string {
|
|
459
|
-
// Use the same key generation as the scaffold generator
|
|
460
|
-
// so live-scan keys match scaffold keys in the map command.
|
|
461
|
-
// Append --N suffix for nth > 0, consistent with scaffold generator format.
|
|
462
|
-
const baseKey = SelectorResolver.generateKey(ref);
|
|
463
|
-
return nth && nth > 0 ? `${baseKey}--${nth}` : baseKey;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Normalize element type to match scaffold generator's extractTargetType() mapping.
|
|
468
|
-
* e.g. modal→dialog, img/icon/logo→img, input→field, select→dropdown, etc.
|
|
469
|
-
*/
|
|
470
|
-
function normalizeElementType(elementType: string, action: string): string {
|
|
471
|
-
const t = elementType.toLowerCase();
|
|
472
|
-
if (t === 'page') return 'page';
|
|
473
|
-
if (t === 'link') return 'link';
|
|
474
|
-
if (t === 'button') return 'button';
|
|
475
|
-
if (t === 'radio') return 'radio';
|
|
476
|
-
if (t === 'dropdown' || t === 'select') return 'dropdown';
|
|
477
|
-
if (t === 'checkbox') return 'checkbox';
|
|
478
|
-
if (t === 'field' || t === 'input') return 'field';
|
|
479
|
-
if (t === 'textbox') return 'textbox';
|
|
480
|
-
if (t === 'textarea') return 'textarea';
|
|
481
|
-
if (t === 'text') return 'text';
|
|
482
|
-
if (t === 'label') return 'label';
|
|
483
|
-
if (t === 'uploader') return 'uploader';
|
|
484
|
-
if (t === 'element') return 'element';
|
|
485
|
-
if (t === 'column' || t === 'columnheader') return 'column';
|
|
486
|
-
if (t === 'logo' || t === 'image' || t === 'img' || t === 'icon') return 'img';
|
|
487
|
-
if (t === 'option' || t === 'item' || t === 'listitem') return 'option';
|
|
488
|
-
if (t === 'dialog' || t === 'modal') return 'dialog';
|
|
489
|
-
if (t === 'heading' || t === 'header') return 'heading';
|
|
490
|
-
if (t === 'title' || t === 'caption' || t === 'message') return 'text';
|
|
491
|
-
// Default based on action (matches scaffold generator)
|
|
492
|
-
switch (action) {
|
|
493
|
-
case 'click': return 'text';
|
|
494
|
-
case 'fill': return 'field';
|
|
495
|
-
case 'see': return 'text';
|
|
496
|
-
case 'select': return 'dropdown';
|
|
497
|
-
default: return 'element';
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
function escapeRegex(str: string): string {
|
|
502
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
503
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Live Scanner Types
|
|
3
|
-
* Defines the data structures for live DOM scanning and matrix file output.
|
|
4
|
-
*
|
|
5
|
-
* Selector types map directly to Playwright locator strategies:
|
|
6
|
-
* testid → page.getByTestId(value)
|
|
7
|
-
* role → page.getByRole(value, { name })
|
|
8
|
-
* label → page.getByLabel(value)
|
|
9
|
-
* placeholder → page.getByPlaceholder(value)
|
|
10
|
-
* text → page.getByText(value)
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export type MatchMethod = 'testid' | 'exact_role' | 'role_fallback' | 'label' | 'placeholder' | 'text_only' | 'contenteditable' | 'label-value' | 'unresolved';
|
|
14
|
-
|
|
15
|
-
export type SelectorType = 'testid' | 'role' | 'label' | 'placeholder' | 'text' | 'locator';
|
|
16
|
-
|
|
17
|
-
export type ElementContext = 'page' | 'dialog' | 'menu' | 'modal' | 'popup';
|
|
18
|
-
|
|
19
|
-
export interface LiveElement {
|
|
20
|
-
gherkinRef: string;
|
|
21
|
-
gherkinType: string;
|
|
22
|
-
selectorType: SelectorType | '';
|
|
23
|
-
selectorValue: string;
|
|
24
|
-
role: string;
|
|
25
|
-
name: string;
|
|
26
|
-
testid: string | null;
|
|
27
|
-
tag: string;
|
|
28
|
-
contenteditable: boolean;
|
|
29
|
-
placeholder: string | null;
|
|
30
|
-
label: string | null;
|
|
31
|
-
context: ElementContext;
|
|
32
|
-
matchMethod: MatchMethod;
|
|
33
|
-
exact: boolean;
|
|
34
|
-
warning: string | null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface LiveScanScenario {
|
|
38
|
-
auth: string | null;
|
|
39
|
-
extends: string | null;
|
|
40
|
-
path: string;
|
|
41
|
-
elements: Record<string, LiveElement>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface LiveScanResult {
|
|
45
|
-
screen: string;
|
|
46
|
-
baseUrl: string;
|
|
47
|
-
scannedAt: string;
|
|
48
|
-
scenarios: Record<string, LiveScanScenario>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface LiveScanOptions {
|
|
52
|
-
baseUrl?: string;
|
|
53
|
-
screenName: string;
|
|
54
|
-
screensDir: string;
|
|
55
|
-
headed?: boolean;
|
|
56
|
-
authDir?: string;
|
|
57
|
-
force?: boolean;
|
|
58
|
-
}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Annotation Handler
|
|
3
|
-
* Handles Gherkin annotations: selector IDs, data refs, ignore, etc.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { RuntimeConfig } from '../../config/config-schema';
|
|
7
|
-
import { ParsedScenario, ParsedStep } from './gherkin-parser';
|
|
8
|
-
|
|
9
|
-
export interface ExtractedAnnotation {
|
|
10
|
-
id: string;
|
|
11
|
-
type: 'selector' | 'data' | 'ignore';
|
|
12
|
-
value?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class AnnotationHandler {
|
|
16
|
-
private config: RuntimeConfig;
|
|
17
|
-
|
|
18
|
-
constructor(config: RuntimeConfig) {
|
|
19
|
-
this.config = config;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Extract element ID from step text
|
|
24
|
-
* Supports: [screen.element] ONLY (not data refs)
|
|
25
|
-
* Data refs <data.field> are handled separately in test-data system
|
|
26
|
-
*/
|
|
27
|
-
extractElementId(stepText: string, screenName: string): ExtractedAnnotation | null {
|
|
28
|
-
// Extract selector ID: [screen.element-name]
|
|
29
|
-
const selectorPattern = new RegExp(this.config.annotations.selectorId.pattern);
|
|
30
|
-
const selectorMatch = stepText.match(selectorPattern);
|
|
31
|
-
|
|
32
|
-
if (selectorMatch) {
|
|
33
|
-
const fullId = selectorMatch[1]; // e.g., "chat.input"
|
|
34
|
-
const [screen, element] = fullId.split('.');
|
|
35
|
-
|
|
36
|
-
// Only return if it matches the target screen
|
|
37
|
-
if (screen === screenName) {
|
|
38
|
-
return {
|
|
39
|
-
id: element,
|
|
40
|
-
type: 'selector'
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// NOTE: Data references <data.field> are NOT included in selector files
|
|
46
|
-
// They belong in qa/test-data/ directory, not qa/selectors/
|
|
47
|
-
// This is per GHERKIN_STANDARDS.md specification
|
|
48
|
-
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Check if step should be ignored
|
|
54
|
-
* Supports: # @ignore
|
|
55
|
-
*/
|
|
56
|
-
shouldIgnoreStep(step: ParsedStep): boolean {
|
|
57
|
-
const ignorePattern = new RegExp(this.config.annotations.ignore.pattern);
|
|
58
|
-
return ignorePattern.test(step.text);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Check if entire scenario should be ignored
|
|
63
|
-
* Supports: # @ignore-testcase
|
|
64
|
-
*/
|
|
65
|
-
shouldIgnoreScenario(scenario: ParsedScenario): boolean {
|
|
66
|
-
// Check scenario description
|
|
67
|
-
// @ts-ignore - Legacy parser may have description field
|
|
68
|
-
if (scenario.description) {
|
|
69
|
-
const ignorePattern = new RegExp(this.config.annotations.ignoreTestCase.pattern);
|
|
70
|
-
// @ts-ignore
|
|
71
|
-
if (ignorePattern.test(scenario.description)) {
|
|
72
|
-
return true;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Check scenario tags (if any)
|
|
77
|
-
// @ts-ignore - Legacy parser may have tags field
|
|
78
|
-
if (scenario.tags && scenario.tags.includes('@ignore')) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Check if step should be skipped in production
|
|
87
|
-
* Supports: # @skip-production
|
|
88
|
-
*/
|
|
89
|
-
shouldSkipInProduction(step: ParsedStep): boolean {
|
|
90
|
-
const skipPattern = new RegExp(this.config.annotations.skipProduction.pattern);
|
|
91
|
-
return skipPattern.test(step.text);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Extract all element IDs from step (can have multiple)
|
|
96
|
-
*/
|
|
97
|
-
extractAllElementIds(stepText: string): string[] {
|
|
98
|
-
const ids: string[] = [];
|
|
99
|
-
|
|
100
|
-
// Extract all [screen.element] patterns
|
|
101
|
-
const selectorPattern = new RegExp(this.config.annotations.selectorId.pattern, 'g');
|
|
102
|
-
let match;
|
|
103
|
-
|
|
104
|
-
while ((match = selectorPattern.exec(stepText)) !== null) {
|
|
105
|
-
ids.push(match[1]);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return ids;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Extract data references from step
|
|
113
|
-
*/
|
|
114
|
-
extractDataRefs(stepText: string): string[] {
|
|
115
|
-
const refs: string[] = [];
|
|
116
|
-
|
|
117
|
-
// Extract all <data.ref> patterns
|
|
118
|
-
const dataPattern = new RegExp(this.config.annotations.dataRef.pattern, 'g');
|
|
119
|
-
let match;
|
|
120
|
-
|
|
121
|
-
while ((match = dataPattern.exec(stepText)) !== null) {
|
|
122
|
-
refs.push(match[1]);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return refs;
|
|
126
|
-
}
|
|
127
|
-
}
|