@sun-asterisk/sungen 1.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/LICENSE +21 -0
- package/README.md +490 -0
- package/bin/sungen.js +12 -0
- package/dist/cli/commands/auto-tag-command.d.ts +8 -0
- package/dist/cli/commands/auto-tag-command.d.ts.map +1 -0
- package/dist/cli/commands/auto-tag-command.js +104 -0
- package/dist/cli/commands/auto-tag-command.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +196 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/ai-providers.yaml +56 -0
- package/dist/config/config-loader.d.ts +51 -0
- package/dist/config/config-loader.d.ts.map +1 -0
- package/dist/config/config-loader.js +216 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/config/config-schema.d.ts +121 -0
- package/dist/config/config-schema.d.ts.map +1 -0
- package/dist/config/config-schema.js +7 -0
- package/dist/config/config-schema.js.map +1 -0
- package/dist/config/default.config.yaml +101 -0
- package/dist/config/framework.config.yaml +52 -0
- package/dist/config/routes.yaml +31 -0
- package/dist/core/selector-base/annotation-handler.d.ts +45 -0
- package/dist/core/selector-base/annotation-handler.d.ts.map +1 -0
- package/dist/core/selector-base/annotation-handler.js +102 -0
- package/dist/core/selector-base/annotation-handler.js.map +1 -0
- package/dist/core/selector-base/base-generator.d.ts +49 -0
- package/dist/core/selector-base/base-generator.d.ts.map +1 -0
- package/dist/core/selector-base/base-generator.js +214 -0
- package/dist/core/selector-base/base-generator.js.map +1 -0
- package/dist/core/selector-base/gherkin-parser.d.ts +24 -0
- package/dist/core/selector-base/gherkin-parser.d.ts.map +1 -0
- package/dist/core/selector-base/gherkin-parser.js +42 -0
- package/dist/core/selector-base/gherkin-parser.js.map +1 -0
- package/dist/core/selector-mapper/priority-mapper.d.ts +74 -0
- package/dist/core/selector-mapper/priority-mapper.d.ts.map +1 -0
- package/dist/core/selector-mapper/priority-mapper.js +477 -0
- package/dist/core/selector-mapper/priority-mapper.js.map +1 -0
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts +91 -0
- package/dist/core/ui-scanner/heuristics/base-heuristic.d.ts.map +1 -0
- package/dist/core/ui-scanner/heuristics/base-heuristic.js +175 -0
- package/dist/core/ui-scanner/heuristics/base-heuristic.js.map +1 -0
- package/dist/core/ui-scanner/react-scanner.d.ts +32 -0
- package/dist/core/ui-scanner/react-scanner.d.ts.map +1 -0
- package/dist/core/ui-scanner/react-scanner.js +163 -0
- package/dist/core/ui-scanner/react-scanner.js.map +1 -0
- package/dist/core/ui-scanner/scanner-interface.d.ts +94 -0
- package/dist/core/ui-scanner/scanner-interface.d.ts.map +1 -0
- package/dist/core/ui-scanner/scanner-interface.js +33 -0
- package/dist/core/ui-scanner/scanner-interface.js.map +1 -0
- package/dist/core/ui-scanner/strict-scanner.d.ts +81 -0
- package/dist/core/ui-scanner/strict-scanner.d.ts.map +1 -0
- package/dist/core/ui-scanner/strict-scanner.js +511 -0
- package/dist/core/ui-scanner/strict-scanner.js.map +1 -0
- package/dist/executor/playwright/playwright-generator.d.ts +33 -0
- package/dist/executor/playwright/playwright-generator.d.ts.map +1 -0
- package/dist/executor/playwright/playwright-generator.js +136 -0
- package/dist/executor/playwright/playwright-generator.js.map +1 -0
- package/dist/executor/test-generator.d.ts +63 -0
- package/dist/executor/test-generator.d.ts.map +1 -0
- package/dist/executor/test-generator.js +30 -0
- package/dist/executor/test-generator.js.map +1 -0
- package/dist/external/ai-provider.d.ts +60 -0
- package/dist/external/ai-provider.d.ts.map +1 -0
- package/dist/external/ai-provider.js +30 -0
- package/dist/external/ai-provider.js.map +1 -0
- package/dist/external/anthropic-provider.d.ts +29 -0
- package/dist/external/anthropic-provider.d.ts.map +1 -0
- package/dist/external/anthropic-provider.js +85 -0
- package/dist/external/anthropic-provider.js.map +1 -0
- package/dist/generators/cache/cache-manager.d.ts +66 -0
- package/dist/generators/cache/cache-manager.d.ts.map +1 -0
- package/dist/generators/cache/cache-manager.js +286 -0
- package/dist/generators/cache/cache-manager.js.map +1 -0
- package/dist/generators/cli.d.ts +7 -0
- package/dist/generators/cli.d.ts.map +1 -0
- package/dist/generators/cli.js +570 -0
- package/dist/generators/cli.js.map +1 -0
- package/dist/generators/dsl-writer/index.d.ts +33 -0
- package/dist/generators/dsl-writer/index.d.ts.map +1 -0
- package/dist/generators/dsl-writer/index.js +226 -0
- package/dist/generators/dsl-writer/index.js.map +1 -0
- package/dist/generators/gherkin-parser/index.d.ts +47 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -0
- package/dist/generators/gherkin-parser/index.js +149 -0
- package/dist/generators/gherkin-parser/index.js.map +1 -0
- package/dist/generators/gherkin-parser/selector-extractor.d.ts +37 -0
- package/dist/generators/gherkin-parser/selector-extractor.d.ts.map +1 -0
- package/dist/generators/gherkin-parser/selector-extractor.js +108 -0
- package/dist/generators/gherkin-parser/selector-extractor.js.map +1 -0
- package/dist/generators/scaffold-generator/index.d.ts +111 -0
- package/dist/generators/scaffold-generator/index.d.ts.map +1 -0
- package/dist/generators/scaffold-generator/index.js +408 -0
- package/dist/generators/scaffold-generator/index.js.map +1 -0
- package/dist/generators/selector-mapper/ai-mapper.d.ts +56 -0
- package/dist/generators/selector-mapper/ai-mapper.d.ts.map +1 -0
- package/dist/generators/selector-mapper/ai-mapper.js +457 -0
- package/dist/generators/selector-mapper/ai-mapper.js.map +1 -0
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts +67 -0
- package/dist/generators/selector-mapper/hybrid-mapper.d.ts.map +1 -0
- package/dist/generators/selector-mapper/hybrid-mapper.js +349 -0
- package/dist/generators/selector-mapper/hybrid-mapper.js.map +1 -0
- package/dist/generators/selector-mapper/index.d.ts +8 -0
- package/dist/generators/selector-mapper/index.d.ts.map +1 -0
- package/dist/generators/selector-mapper/index.js +12 -0
- package/dist/generators/selector-mapper/index.js.map +1 -0
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts +125 -0
- package/dist/generators/selector-mapper/intelligent-mapper.d.ts.map +1 -0
- package/dist/generators/selector-mapper/intelligent-mapper.js +391 -0
- package/dist/generators/selector-mapper/intelligent-mapper.js.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +49 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-interface.js +7 -0
- package/dist/generators/test-generator/adapters/adapter-interface.js.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-registry.d.ts +29 -0
- package/dist/generators/test-generator/adapters/adapter-registry.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-registry.js +50 -0
- package/dist/generators/test-generator/adapters/adapter-registry.js.map +1 -0
- package/dist/generators/test-generator/adapters/index.d.ts +4 -0
- package/dist/generators/test-generator/adapters/index.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/index.js +13 -0
- package/dist/generators/test-generator/adapters/index.js.map +1 -0
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +23 -0
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js +38 -0
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/before-each.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/scenario.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/clear-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/double-click-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/hover-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/press-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/active-state-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/ai-response-assertion-selector.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/ai-response-assertion-simple.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/application-running.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-visible-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/check-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/checkbox.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/checked-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-auth.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-browser-state.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/clear-database.hbs +4 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/clear.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/click-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/click.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/contain-text-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/contains-text-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/count-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/count-greater-than.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/count-less-than.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/disabled-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/displayed-containing-text.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/displayed-with-text.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/double-click-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/empty-assertion-advanced.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/empty-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/enabled-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/error-message-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/fill-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/fill.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/focused-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/generic-message-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-attribute.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-class.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-count.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-image-src.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-link.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-placeholder.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/has-value.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/have-text-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/hover-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/html5-validation-check.hbs +4 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/is-checked.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/is-editable.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/is-focused.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/is-hidden.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/is-unchecked.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/locator.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/login.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/message-assertion-body.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/message-assertion-selector.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/message-count-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-timeout.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/not-checked-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/not-visible-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/not-visible.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/notification-assertion.hbs +4 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/press-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/press-enter.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/redirect-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/route-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/screen-navigation.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/scroll-bottom-assertion.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/select-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/select.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/application-running.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-auth.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-browser-state.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/clear-database.hbs +4 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/setup/user-login-todo.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/text-matches-pattern.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/uncheck-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/user-login-todo.hbs +6 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/visibility-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/visible-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/wait-for-element.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/wait-timeout.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/wait.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +19 -0
- package/dist/generators/test-generator/ai-step-mapper.d.ts +27 -0
- package/dist/generators/test-generator/ai-step-mapper.d.ts.map +1 -0
- package/dist/generators/test-generator/ai-step-mapper.js +204 -0
- package/dist/generators/test-generator/ai-step-mapper.js.map +1 -0
- package/dist/generators/test-generator/code-generator.d.ts +52 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -0
- package/dist/generators/test-generator/code-generator.js +191 -0
- package/dist/generators/test-generator/code-generator.js.map +1 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.js +173 -0
- package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/form-patterns.d.ts +8 -0
- package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/form-patterns.js +110 -0
- package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/index.d.ts +45 -0
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/index.js +106 -0
- package/dist/generators/test-generator/patterns/index.js.map +1 -0
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/interaction-patterns.js +100 -0
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +8 -0
- package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/navigation-patterns.js +92 -0
- package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/setup-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/setup-patterns.js +84 -0
- package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/types.d.ts +38 -0
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/types.js +3 -0
- package/dist/generators/test-generator/patterns/types.js.map +1 -0
- package/dist/generators/test-generator/step-mapper-old.d.ts +180 -0
- package/dist/generators/test-generator/step-mapper-old.d.ts.map +1 -0
- package/dist/generators/test-generator/step-mapper-old.js +752 -0
- package/dist/generators/test-generator/step-mapper-old.js.map +1 -0
- package/dist/generators/test-generator/step-mapper-refactored.d.ts +47 -0
- package/dist/generators/test-generator/step-mapper-refactored.d.ts.map +1 -0
- package/dist/generators/test-generator/step-mapper-refactored.js +182 -0
- package/dist/generators/test-generator/step-mapper-refactored.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +66 -0
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -0
- package/dist/generators/test-generator/step-mapper.js +248 -0
- package/dist/generators/test-generator/step-mapper.js.map +1 -0
- package/dist/generators/test-generator/template-engine.d.ts +33 -0
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -0
- package/dist/generators/test-generator/template-engine.js +129 -0
- package/dist/generators/test-generator/template-engine.js.map +1 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts +39 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/data-resolver.js +162 -0
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -0
- package/dist/generators/test-generator/utils/path-inference.d.ts +49 -0
- package/dist/generators/test-generator/utils/path-inference.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/path-inference.js +286 -0
- package/dist/generators/test-generator/utils/path-inference.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +93 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-resolver.js +408 -0
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -0
- package/dist/generators/types.d.ts +118 -0
- package/dist/generators/types.d.ts.map +1 -0
- package/dist/generators/types.js +48 -0
- package/dist/generators/types.js.map +1 -0
- package/dist/generators/ui-model-builder/deep-scanner.d.ts +121 -0
- package/dist/generators/ui-model-builder/deep-scanner.d.ts.map +1 -0
- package/dist/generators/ui-model-builder/deep-scanner.js +1113 -0
- package/dist/generators/ui-model-builder/deep-scanner.js.map +1 -0
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts +110 -0
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.d.ts.map +1 -0
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js +608 -0
- package/dist/generators/ui-model-builder/enhanced-deep-scanner.js.map +1 -0
- package/dist/generators/ui-model-builder/react-scanner.d.ts +107 -0
- package/dist/generators/ui-model-builder/react-scanner.d.ts.map +1 -0
- package/dist/generators/ui-model-builder/react-scanner.js +797 -0
- package/dist/generators/ui-model-builder/react-scanner.js.map +1 -0
- package/dist/input/cli-adapter.d.ts +63 -0
- package/dist/input/cli-adapter.d.ts.map +1 -0
- package/dist/input/cli-adapter.js +173 -0
- package/dist/input/cli-adapter.js.map +1 -0
- package/dist/input/config-adapter.d.ts +25 -0
- package/dist/input/config-adapter.d.ts.map +1 -0
- package/dist/input/config-adapter.js +70 -0
- package/dist/input/config-adapter.js.map +1 -0
- package/dist/input/input-adapter.d.ts +28 -0
- package/dist/input/input-adapter.d.ts.map +1 -0
- package/dist/input/input-adapter.js +17 -0
- package/dist/input/input-adapter.js.map +1 -0
- package/dist/input/vscode-adapter.d.ts +62 -0
- package/dist/input/vscode-adapter.d.ts.map +1 -0
- package/dist/input/vscode-adapter.js +64 -0
- package/dist/input/vscode-adapter.js.map +1 -0
- package/dist/orchestrator/cache-manager.d.ts +37 -0
- package/dist/orchestrator/cache-manager.d.ts.map +1 -0
- package/dist/orchestrator/cache-manager.js +148 -0
- package/dist/orchestrator/cache-manager.js.map +1 -0
- package/dist/orchestrator/pipeline.d.ts +73 -0
- package/dist/orchestrator/pipeline.d.ts.map +1 -0
- package/dist/orchestrator/pipeline.js +607 -0
- package/dist/orchestrator/pipeline.js.map +1 -0
- package/dist/orchestrator/project-initializer.d.ts +51 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -0
- package/dist/orchestrator/project-initializer.js +326 -0
- package/dist/orchestrator/project-initializer.js.map +1 -0
- package/dist/orchestrator/reporter.d.ts +15 -0
- package/dist/orchestrator/reporter.d.ts.map +1 -0
- package/dist/orchestrator/reporter.js +30 -0
- package/dist/orchestrator/reporter.js.map +1 -0
- package/dist/orchestrator/screen-manager.d.ts +47 -0
- package/dist/orchestrator/screen-manager.d.ts.map +1 -0
- package/dist/orchestrator/screen-manager.js +271 -0
- package/dist/orchestrator/screen-manager.js.map +1 -0
- package/dist/tools/auto-tagger.d.ts +107 -0
- package/dist/tools/auto-tagger.d.ts.map +1 -0
- package/dist/tools/auto-tagger.js +502 -0
- package/dist/tools/auto-tagger.js.map +1 -0
- package/package.json +73 -0
- package/src/cli/commands/auto-tag-command.ts +80 -0
- package/src/cli/index.ts +205 -0
- package/src/config/ai-providers.yaml +56 -0
- package/src/config/config-loader.ts +248 -0
- package/src/config/config-schema.ts +148 -0
- package/src/config/default.config.yaml +101 -0
- package/src/config/framework.config.yaml +52 -0
- package/src/config/routes.yaml +31 -0
- package/src/core/selector-base/annotation-handler.ts +127 -0
- package/src/core/selector-base/base-generator.ts +234 -0
- package/src/core/selector-base/gherkin-parser.ts +57 -0
- package/src/core/selector-mapper/priority-mapper.ts +607 -0
- package/src/core/ui-scanner/heuristics/base-heuristic.ts +216 -0
- package/src/core/ui-scanner/react-scanner.ts +156 -0
- package/src/core/ui-scanner/scanner-interface.ts +133 -0
- package/src/core/ui-scanner/strict-scanner.ts +629 -0
- package/src/executor/playwright/playwright-generator.ts +125 -0
- package/src/executor/test-generator.ts +90 -0
- package/src/external/ai-provider.ts +90 -0
- package/src/external/anthropic-provider.ts +114 -0
- package/src/generators/README.md +410 -0
- package/src/generators/cache/cache-manager.ts +322 -0
- package/src/generators/cli.ts +640 -0
- package/src/generators/dsl-writer/index.ts +253 -0
- package/src/generators/gherkin-parser/index.ts +155 -0
- package/src/generators/gherkin-parser/selector-extractor.ts +142 -0
- package/src/generators/scaffold-generator/index.ts +524 -0
- package/src/generators/selector-mapper/ai-mapper.ts +528 -0
- package/src/generators/selector-mapper/hybrid-mapper.ts +427 -0
- package/src/generators/selector-mapper/index.ts +10 -0
- package/src/generators/selector-mapper/intelligent-mapper.ts +530 -0
- package/src/generators/test-generator/adapters/adapter-interface.ts +49 -0
- package/src/generators/test-generator/adapters/adapter-registry.ts +56 -0
- package/src/generators/test-generator/adapters/index.ts +9 -0
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +40 -0
- package/src/generators/test-generator/adapters/playwright/templates/before-each.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +5 -0
- package/src/generators/test-generator/adapters/playwright/templates/scenario.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/clear-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/double-click-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/hover-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/press-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-visible-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/route-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-timeout.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/setup/application-running.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-auth.hbs +6 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-browser-state.hbs +6 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/setup/clear-database.hbs +4 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/setup/user-login-todo.hbs +6 -0
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +19 -0
- package/src/generators/test-generator/ai-step-mapper.ts +224 -0
- package/src/generators/test-generator/code-generator.ts +235 -0
- package/src/generators/test-generator/patterns/assertion-patterns.ts +183 -0
- package/src/generators/test-generator/patterns/form-patterns.ts +124 -0
- package/src/generators/test-generator/patterns/index.ts +97 -0
- package/src/generators/test-generator/patterns/interaction-patterns.ts +119 -0
- package/src/generators/test-generator/patterns/navigation-patterns.ts +110 -0
- package/src/generators/test-generator/patterns/setup-patterns.ts +94 -0
- package/src/generators/test-generator/patterns/types.ts +41 -0
- package/src/generators/test-generator/step-mapper.ts +254 -0
- package/src/generators/test-generator/template-engine.ts +160 -0
- package/src/generators/test-generator/utils/data-resolver.ts +147 -0
- package/src/generators/test-generator/utils/path-inference.ts +344 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +480 -0
- package/src/generators/types.ts +226 -0
- package/src/generators/ui-model-builder/deep-scanner.ts +1244 -0
- package/src/generators/ui-model-builder/enhanced-deep-scanner.ts +731 -0
- package/src/generators/ui-model-builder/react-scanner.ts +959 -0
- package/src/input/cli-adapter.ts +185 -0
- package/src/input/config-adapter.ts +71 -0
- package/src/input/input-adapter.ts +32 -0
- package/src/input/vscode-adapter.ts +90 -0
- package/src/orchestrator/cache-manager.ts +138 -0
- package/src/orchestrator/pipeline.ts +713 -0
- package/src/orchestrator/project-initializer.ts +315 -0
- package/src/orchestrator/reporter.ts +36 -0
- package/src/orchestrator/screen-manager.ts +268 -0
- package/src/tools/auto-tagger.ts +572 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# Selector DSL Generator Framework
|
|
2
|
+
|
|
3
|
+
> **AI-Native QA Framework** for multi-platform E2E testing with automated selector discovery
|
|
4
|
+
|
|
5
|
+
## 🎯 Overview
|
|
6
|
+
|
|
7
|
+
This framework enables:
|
|
8
|
+
- **AI-powered selector generation** from source code (no manual mapping!)
|
|
9
|
+
- **Multi-platform support** (Web, Android, iOS, Flutter, Compose, SwiftUI)
|
|
10
|
+
- **Gherkin-compatible** element references `[screen.element]`
|
|
11
|
+
- **Framework-agnostic** architecture (Playwright, Appium, Flutter Driver, etc.)
|
|
12
|
+
- **Cache-first** approach to minimize AI API costs
|
|
13
|
+
- **Override mechanism** for manual fine-tuning
|
|
14
|
+
|
|
15
|
+
## 🏗️ Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Gherkin Test Scenarios
|
|
19
|
+
↓
|
|
20
|
+
[screen.element] References
|
|
21
|
+
↓
|
|
22
|
+
Selector DSL (YAML) ← AI-generated + Manual overrides
|
|
23
|
+
↓
|
|
24
|
+
Executor Adapter (Playwright/Appium/etc.)
|
|
25
|
+
↓
|
|
26
|
+
Actual UI Tests
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 📁 Directory Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
qa/
|
|
33
|
+
├── generators/ # Core framework code
|
|
34
|
+
│ ├── types.ts # TypeScript types
|
|
35
|
+
│ ├── ui-model-builder/ # Source code scanners
|
|
36
|
+
│ │ └── react-scanner.ts
|
|
37
|
+
│ ├── selector-mapper/ # AI mapping engine
|
|
38
|
+
│ │ └── ai-mapper.ts
|
|
39
|
+
│ ├── dsl-writer/ # YAML writer/loader
|
|
40
|
+
│ ├── cache/ # Cache management
|
|
41
|
+
│ └── cli.ts # Command-line interface
|
|
42
|
+
├── helpers/
|
|
43
|
+
│ └── selector-loader.ts # Executor adapters
|
|
44
|
+
├── selectors/
|
|
45
|
+
│ ├── screens/ # Generated selector DSL files
|
|
46
|
+
│ │ ├── auth-login.yaml
|
|
47
|
+
│ │ ├── auth-login.override.yaml # Manual overrides
|
|
48
|
+
│ │ └── ...
|
|
49
|
+
│ └── .cache/ # AI response cache
|
|
50
|
+
├── ui-models/ # Extracted UI models
|
|
51
|
+
└── specs/ # Test files
|
|
52
|
+
└── login-dsl.spec.ts # Example tests
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## 🚀 Quick Start
|
|
56
|
+
|
|
57
|
+
### 1. Discover Screens
|
|
58
|
+
|
|
59
|
+
Scan your application and extract UI models:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Discover all screens
|
|
63
|
+
npm run qa:dsl:discover -- --all --verbose
|
|
64
|
+
|
|
65
|
+
# Discover specific screen
|
|
66
|
+
npm run qa:dsl:discover -- --screen auth-login
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Output:** `qa/ui-models/auth-login.json`
|
|
70
|
+
|
|
71
|
+
### 2. Generate Selectors
|
|
72
|
+
|
|
73
|
+
Use AI to map element IDs to CSS selectors:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Generate for all screens
|
|
77
|
+
npm run qa:dsl:generate -- --all --provider anthropic
|
|
78
|
+
|
|
79
|
+
# Generate for specific screen
|
|
80
|
+
npm run qa:dsl:generate -- --screen auth-login --provider google
|
|
81
|
+
|
|
82
|
+
# Force re-generation (skip cache)
|
|
83
|
+
npm run qa:dsl:generate -- --all --force
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**Output:** `qa/selectors/screens/auth-login.yaml`
|
|
87
|
+
|
|
88
|
+
### 3. Validate Selectors
|
|
89
|
+
|
|
90
|
+
Check if generated selectors are valid:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm run qa:dsl:validate -- --all
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 4. View Statistics
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm run qa:dsl:info
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Output:
|
|
103
|
+
```
|
|
104
|
+
📊 Cache Statistics:
|
|
105
|
+
Screens cached: 4
|
|
106
|
+
Cache entries: 4
|
|
107
|
+
Total size: 5.02 KB
|
|
108
|
+
|
|
109
|
+
📁 Selector Files:
|
|
110
|
+
Total screens: 7
|
|
111
|
+
- auth-login: 5 selectors
|
|
112
|
+
- auth-register: 7 selectors
|
|
113
|
+
- chat: 2 selectors
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 5. Clear Cache
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Clear specific screen
|
|
120
|
+
npm run qa:dsl:cache-clear -- --screen auth-login
|
|
121
|
+
|
|
122
|
+
# Clear all cache
|
|
123
|
+
npm run qa:dsl:cache-clear -- --all
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 📝 Writing Tests
|
|
127
|
+
|
|
128
|
+
### Using Selector Loader (Recommended)
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import { test, expect } from '@playwright/test';
|
|
132
|
+
import { createPlaywrightSelectors } from '../helpers/selector-loader';
|
|
133
|
+
|
|
134
|
+
test('login test', async ({ page }) => {
|
|
135
|
+
await page.goto('http://localhost:3000/auth/login');
|
|
136
|
+
|
|
137
|
+
// Create Playwright helper
|
|
138
|
+
const pw = createPlaywrightSelectors(page);
|
|
139
|
+
|
|
140
|
+
// Use DSL selectors
|
|
141
|
+
await pw.fill('[auth-login.email]', 'test@example.com', 'auth-login');
|
|
142
|
+
await pw.fill('[auth-login.password]', 'password123', 'auth-login');
|
|
143
|
+
await pw.click('[auth-login.submit]', 'auth-login');
|
|
144
|
+
|
|
145
|
+
// Verify
|
|
146
|
+
expect(page.url()).toContain('/chat');
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Using Raw Selector Strings
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { getSelector } from '../helpers/selector-loader';
|
|
154
|
+
|
|
155
|
+
test('login test', async ({ page }) => {
|
|
156
|
+
await page.goto('http://localhost:3000/auth/login');
|
|
157
|
+
|
|
158
|
+
// Get raw selector string
|
|
159
|
+
const emailSelector = await getSelector('[auth-login.email]', 'auth-login');
|
|
160
|
+
|
|
161
|
+
// Use with Playwright directly
|
|
162
|
+
await page.fill(emailSelector, 'test@example.com');
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## 🔧 Manual Override
|
|
167
|
+
|
|
168
|
+
If AI-generated selectors are incorrect, create an override file:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# This will be done automatically by the framework when needed
|
|
172
|
+
# Or create manually:
|
|
173
|
+
touch qa/selectors/screens/auth-login.override.yaml
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Override file format:**
|
|
177
|
+
|
|
178
|
+
```yaml
|
|
179
|
+
# qa/selectors/screens/auth-login.override.yaml
|
|
180
|
+
|
|
181
|
+
"[auth-login.submit]":
|
|
182
|
+
selector: "button[type='submit']"
|
|
183
|
+
type: "button"
|
|
184
|
+
description: "Login submit button (manually fixed)"
|
|
185
|
+
discoveryMethod: manual
|
|
186
|
+
locatorType: css
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The override will automatically merge with the base file, taking precedence.
|
|
190
|
+
|
|
191
|
+
## 🌍 Multi-Platform Support
|
|
192
|
+
|
|
193
|
+
### Folder Structure for Multi-Platform
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
qa/selectors/
|
|
197
|
+
├── web/
|
|
198
|
+
│ └── screens/
|
|
199
|
+
│ └── login.yaml
|
|
200
|
+
├── android/
|
|
201
|
+
│ └── screens/
|
|
202
|
+
│ └── login.yaml
|
|
203
|
+
└── ios/
|
|
204
|
+
└── screens/
|
|
205
|
+
└── login.yaml
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Platform-Specific Selectors
|
|
209
|
+
|
|
210
|
+
**Web (Playwright):**
|
|
211
|
+
```yaml
|
|
212
|
+
"[login.email]":
|
|
213
|
+
selector: "input[name='email']"
|
|
214
|
+
locatorType: css
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Android (Appium):**
|
|
218
|
+
```yaml
|
|
219
|
+
"[login.email]":
|
|
220
|
+
selector: "com.example:id/email_input"
|
|
221
|
+
locatorType: resource-id
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**iOS (Appium):**
|
|
225
|
+
```yaml
|
|
226
|
+
"[login.email]":
|
|
227
|
+
selector: "emailTextField"
|
|
228
|
+
locatorType: accessibility-id
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Flutter:**
|
|
232
|
+
```yaml
|
|
233
|
+
"[login.email]":
|
|
234
|
+
selector: "emailInput"
|
|
235
|
+
locatorType: key
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 🤖 AI Providers
|
|
239
|
+
|
|
240
|
+
The framework supports multiple AI providers:
|
|
241
|
+
|
|
242
|
+
### Anthropic (Claude)
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
246
|
+
npm run qa:dsl:generate -- --provider anthropic --model claude-3-5-haiku-20241022
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Google (Gemini)
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
export GEMINI_API_KEY=AIza...
|
|
253
|
+
npm run qa:dsl:generate -- --provider google --model gemini-2.0-flash-exp
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### OpenAI (Future)
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
export OPENAI_API_KEY=sk-...
|
|
260
|
+
npm run qa:dsl:generate -- --provider openai --model gpt-4o-mini
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## 💰 Cost Optimization
|
|
264
|
+
|
|
265
|
+
### Cache Strategy
|
|
266
|
+
|
|
267
|
+
The framework automatically caches AI responses based on:
|
|
268
|
+
- UI Model content hash
|
|
269
|
+
- Element IDs list
|
|
270
|
+
- Screen ID
|
|
271
|
+
|
|
272
|
+
**Cache hit = $0 cost!**
|
|
273
|
+
|
|
274
|
+
### Token Usage
|
|
275
|
+
|
|
276
|
+
Typical usage per screen:
|
|
277
|
+
- Small screen (2-5 elements): ~600-800 tokens
|
|
278
|
+
- Medium screen (5-10 elements): ~800-1200 tokens
|
|
279
|
+
- Large screen (10+ elements): ~1200-2000 tokens
|
|
280
|
+
|
|
281
|
+
**Cost example (Claude Haiku):**
|
|
282
|
+
- 1000 tokens ≈ $0.0005
|
|
283
|
+
- 100 screens ≈ $0.05 - $0.10 (one-time generation)
|
|
284
|
+
- Subsequent runs = $0 (cached)
|
|
285
|
+
|
|
286
|
+
## 🔍 Troubleshooting
|
|
287
|
+
|
|
288
|
+
### Selectors not found
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
# Re-discover screens
|
|
292
|
+
npm run qa:dsl:discover -- --all --force
|
|
293
|
+
|
|
294
|
+
# Re-generate selectors
|
|
295
|
+
npm run qa:dsl:generate -- --all --force
|
|
296
|
+
|
|
297
|
+
# Check generated selectors
|
|
298
|
+
cat qa/selectors/screens/auth-login.yaml
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### AI-generated selectors are incorrect
|
|
302
|
+
|
|
303
|
+
Create an override file:
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
# qa/selectors/screens/auth-login.override.yaml
|
|
307
|
+
"[auth-login.email]":
|
|
308
|
+
selector: "#email-address" # Fixed selector
|
|
309
|
+
type: "input"
|
|
310
|
+
description: "Email input (manually corrected)"
|
|
311
|
+
discoveryMethod: manual
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Cache issues
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Clear cache for specific screen
|
|
318
|
+
npm run qa:dsl:cache-clear -- --screen auth-login
|
|
319
|
+
|
|
320
|
+
# Clear all cache
|
|
321
|
+
npm run qa:dsl:cache-clear -- --all
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## 🎓 Best Practices
|
|
325
|
+
|
|
326
|
+
### 1. Use Meaningful Element IDs
|
|
327
|
+
|
|
328
|
+
**Good:**
|
|
329
|
+
```
|
|
330
|
+
[login.email-input]
|
|
331
|
+
[login.password-input]
|
|
332
|
+
[login.submit-button]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
**Bad:**
|
|
336
|
+
```
|
|
337
|
+
[login.e1]
|
|
338
|
+
[login.e2]
|
|
339
|
+
[login.e3]
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 2. Add `data-testid` Attributes
|
|
343
|
+
|
|
344
|
+
```tsx
|
|
345
|
+
<input
|
|
346
|
+
name="email"
|
|
347
|
+
data-testid="login-email-input" // Helps AI generate better selectors
|
|
348
|
+
placeholder="Email"
|
|
349
|
+
/>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 3. Use Override Files for Flaky Selectors
|
|
353
|
+
|
|
354
|
+
If a selector is unstable, override it with a more robust one.
|
|
355
|
+
|
|
356
|
+
### 4. Commit Generated Files to Git
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
git add qa/selectors/screens/*.yaml
|
|
360
|
+
git add qa/ui-models/*.json
|
|
361
|
+
git commit -m "chore: update selector DSL"
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Do NOT commit:**
|
|
365
|
+
- `qa/selectors/.cache/` (gitignored)
|
|
366
|
+
|
|
367
|
+
## 📊 Workflow
|
|
368
|
+
|
|
369
|
+
```mermaid
|
|
370
|
+
graph LR
|
|
371
|
+
A[Write Code] --> B[Discover Screens]
|
|
372
|
+
B --> C[Generate Selectors]
|
|
373
|
+
C --> D[Review Generated Selectors]
|
|
374
|
+
D --> E{Need Override?}
|
|
375
|
+
E -->|Yes| F[Create Override File]
|
|
376
|
+
E -->|No| G[Write Tests]
|
|
377
|
+
F --> G
|
|
378
|
+
G --> H[Run Tests]
|
|
379
|
+
H --> I{Tests Pass?}
|
|
380
|
+
I -->|No| J[Fix Selectors]
|
|
381
|
+
J --> F
|
|
382
|
+
I -->|Yes| K[Commit & Deploy]
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## 🚧 Roadmap
|
|
386
|
+
|
|
387
|
+
- [x] React/Next.js scanner
|
|
388
|
+
- [x] Playwright executor adapter
|
|
389
|
+
- [x] Cache layer
|
|
390
|
+
- [x] Override mechanism
|
|
391
|
+
- [x] CLI tools
|
|
392
|
+
- [ ] Vue.js scanner
|
|
393
|
+
- [ ] Angular scanner
|
|
394
|
+
- [ ] Appium executor adapter
|
|
395
|
+
- [ ] Flutter Driver executor
|
|
396
|
+
- [ ] Runtime discovery (Vision AI)
|
|
397
|
+
- [ ] Selector health monitoring
|
|
398
|
+
- [ ] Auto-healing selectors
|
|
399
|
+
|
|
400
|
+
## 📚 API Reference
|
|
401
|
+
|
|
402
|
+
See [types.ts](./types.ts) for complete API documentation.
|
|
403
|
+
|
|
404
|
+
## 🤝 Contributing
|
|
405
|
+
|
|
406
|
+
This is an internal framework. For questions or feature requests, contact the QA team.
|
|
407
|
+
|
|
408
|
+
## 📄 License
|
|
409
|
+
|
|
410
|
+
Proprietary - Internal Use Only
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Cache Manager
|
|
4
|
+
* Manages caching of UI models and selector mappings to reduce AI API calls
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as crypto from 'crypto';
|
|
10
|
+
import { UIModel, SelectorDSL, CacheEntry } from '../types';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Cache Configuration
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
export interface CacheConfig {
|
|
17
|
+
cachePath: string;
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
expiryMs?: number; // Cache expiry in milliseconds (default: no expiry)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Cache Manager Class
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
export class CacheManager {
|
|
27
|
+
private config: CacheConfig;
|
|
28
|
+
|
|
29
|
+
constructor(config: CacheConfig) {
|
|
30
|
+
this.config = config;
|
|
31
|
+
|
|
32
|
+
// Ensure cache directory exists
|
|
33
|
+
if (config.enabled) {
|
|
34
|
+
fs.mkdirSync(config.cachePath, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Generate cache key from UI model and element IDs
|
|
40
|
+
*/
|
|
41
|
+
generateCacheKey(
|
|
42
|
+
screenId: string,
|
|
43
|
+
uiModel: UIModel,
|
|
44
|
+
elementIds: string[]
|
|
45
|
+
): string {
|
|
46
|
+
// Create content for hash
|
|
47
|
+
const content = JSON.stringify({
|
|
48
|
+
screenId,
|
|
49
|
+
elements: uiModel.elements,
|
|
50
|
+
elementIds: elementIds.sort() // Sort for consistent hash
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Generate SHA-256 hash
|
|
54
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
55
|
+
|
|
56
|
+
return hash;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get cache file path
|
|
61
|
+
*/
|
|
62
|
+
private getCachePath(screenId: string, hash: string): string {
|
|
63
|
+
const screenDir = path.join(this.config.cachePath, screenId);
|
|
64
|
+
return path.join(screenDir, `${hash}.json`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if cache exists and is valid
|
|
69
|
+
*/
|
|
70
|
+
has(screenId: string, hash: string): boolean {
|
|
71
|
+
if (!this.config.enabled) return false;
|
|
72
|
+
|
|
73
|
+
const cachePath = this.getCachePath(screenId, hash);
|
|
74
|
+
|
|
75
|
+
if (!fs.existsSync(cachePath)) return false;
|
|
76
|
+
|
|
77
|
+
// Check expiry if configured
|
|
78
|
+
if (this.config.expiryMs) {
|
|
79
|
+
const stats = fs.statSync(cachePath);
|
|
80
|
+
const age = Date.now() - stats.mtimeMs;
|
|
81
|
+
|
|
82
|
+
if (age > this.config.expiryMs) {
|
|
83
|
+
// Cache expired, delete it
|
|
84
|
+
fs.unlinkSync(cachePath);
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get cached selectors
|
|
94
|
+
*/
|
|
95
|
+
get(screenId: string, hash: string): CacheEntry | null {
|
|
96
|
+
if (!this.config.enabled) return null;
|
|
97
|
+
|
|
98
|
+
const cachePath = this.getCachePath(screenId, hash);
|
|
99
|
+
|
|
100
|
+
if (!this.has(screenId, hash)) return null;
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
const content = fs.readFileSync(cachePath, 'utf-8');
|
|
104
|
+
return JSON.parse(content) as CacheEntry;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`Failed to read cache: ${cachePath}`, error);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Save selectors to cache
|
|
113
|
+
*/
|
|
114
|
+
set(
|
|
115
|
+
screenId: string,
|
|
116
|
+
hash: string,
|
|
117
|
+
selectors: SelectorDSL,
|
|
118
|
+
metadata: {
|
|
119
|
+
aiModel?: string;
|
|
120
|
+
tokenCost?: number;
|
|
121
|
+
framework: string;
|
|
122
|
+
}
|
|
123
|
+
): void {
|
|
124
|
+
if (!this.config.enabled) return;
|
|
125
|
+
|
|
126
|
+
const cachePath = this.getCachePath(screenId, hash);
|
|
127
|
+
const screenDir = path.dirname(cachePath);
|
|
128
|
+
|
|
129
|
+
// Ensure screen directory exists
|
|
130
|
+
fs.mkdirSync(screenDir, { recursive: true });
|
|
131
|
+
|
|
132
|
+
// Create cache entry
|
|
133
|
+
const cacheEntry: CacheEntry = {
|
|
134
|
+
screenId,
|
|
135
|
+
hash,
|
|
136
|
+
selectors,
|
|
137
|
+
metadata: {
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
aiModel: metadata.aiModel,
|
|
140
|
+
tokenCost: metadata.tokenCost,
|
|
141
|
+
framework: metadata.framework
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// Write to cache
|
|
146
|
+
fs.writeFileSync(cachePath, JSON.stringify(cacheEntry, null, 2), 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Invalidate cache for a screen
|
|
151
|
+
*/
|
|
152
|
+
invalidate(screenId: string): number {
|
|
153
|
+
if (!this.config.enabled) return 0;
|
|
154
|
+
|
|
155
|
+
const screenDir = path.join(this.config.cachePath, screenId);
|
|
156
|
+
|
|
157
|
+
if (!fs.existsSync(screenDir)) return 0;
|
|
158
|
+
|
|
159
|
+
// Delete all cache files in screen directory
|
|
160
|
+
const files = fs.readdirSync(screenDir);
|
|
161
|
+
let deletedCount = 0;
|
|
162
|
+
|
|
163
|
+
for (const file of files) {
|
|
164
|
+
if (file.endsWith('.json')) {
|
|
165
|
+
fs.unlinkSync(path.join(screenDir, file));
|
|
166
|
+
deletedCount++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Remove directory if empty
|
|
171
|
+
if (deletedCount > 0) {
|
|
172
|
+
try {
|
|
173
|
+
fs.rmdirSync(screenDir);
|
|
174
|
+
} catch {
|
|
175
|
+
// Directory might not be empty, ignore
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return deletedCount;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Clear all cache
|
|
184
|
+
*/
|
|
185
|
+
clearAll(): number {
|
|
186
|
+
if (!this.config.enabled) return 0;
|
|
187
|
+
|
|
188
|
+
if (!fs.existsSync(this.config.cachePath)) return 0;
|
|
189
|
+
|
|
190
|
+
let deletedCount = 0;
|
|
191
|
+
|
|
192
|
+
// Get all screen directories
|
|
193
|
+
const screenDirs = fs.readdirSync(this.config.cachePath);
|
|
194
|
+
|
|
195
|
+
for (const screenDir of screenDirs) {
|
|
196
|
+
const screenPath = path.join(this.config.cachePath, screenDir);
|
|
197
|
+
const stat = fs.statSync(screenPath);
|
|
198
|
+
|
|
199
|
+
if (stat.isDirectory()) {
|
|
200
|
+
const count = this.invalidate(screenDir);
|
|
201
|
+
deletedCount += count;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return deletedCount;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get cache statistics
|
|
210
|
+
*/
|
|
211
|
+
getStats(): {
|
|
212
|
+
totalScreens: number;
|
|
213
|
+
totalEntries: number;
|
|
214
|
+
totalSize: number;
|
|
215
|
+
oldestEntry?: string;
|
|
216
|
+
newestEntry?: string;
|
|
217
|
+
} {
|
|
218
|
+
if (!this.config.enabled || !fs.existsSync(this.config.cachePath)) {
|
|
219
|
+
return {
|
|
220
|
+
totalScreens: 0,
|
|
221
|
+
totalEntries: 0,
|
|
222
|
+
totalSize: 0
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let totalEntries = 0;
|
|
227
|
+
let totalSize = 0;
|
|
228
|
+
let oldestTime = Infinity;
|
|
229
|
+
let newestTime = 0;
|
|
230
|
+
|
|
231
|
+
const screenDirs = fs.readdirSync(this.config.cachePath);
|
|
232
|
+
const totalScreens = screenDirs.filter(dir => {
|
|
233
|
+
const stat = fs.statSync(path.join(this.config.cachePath, dir));
|
|
234
|
+
return stat.isDirectory();
|
|
235
|
+
}).length;
|
|
236
|
+
|
|
237
|
+
for (const screenDir of screenDirs) {
|
|
238
|
+
const screenPath = path.join(this.config.cachePath, screenDir);
|
|
239
|
+
const stat = fs.statSync(screenPath);
|
|
240
|
+
|
|
241
|
+
if (!stat.isDirectory()) continue;
|
|
242
|
+
|
|
243
|
+
const files = fs.readdirSync(screenPath);
|
|
244
|
+
|
|
245
|
+
for (const file of files) {
|
|
246
|
+
if (!file.endsWith('.json')) continue;
|
|
247
|
+
|
|
248
|
+
const filePath = path.join(screenPath, file);
|
|
249
|
+
const fileStat = fs.statSync(filePath);
|
|
250
|
+
|
|
251
|
+
totalEntries++;
|
|
252
|
+
totalSize += fileStat.size;
|
|
253
|
+
|
|
254
|
+
if (fileStat.mtimeMs < oldestTime) {
|
|
255
|
+
oldestTime = fileStat.mtimeMs;
|
|
256
|
+
}
|
|
257
|
+
if (fileStat.mtimeMs > newestTime) {
|
|
258
|
+
newestTime = fileStat.mtimeMs;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
totalScreens,
|
|
265
|
+
totalEntries,
|
|
266
|
+
totalSize,
|
|
267
|
+
oldestEntry: oldestTime !== Infinity ? new Date(oldestTime).toISOString() : undefined,
|
|
268
|
+
newestEntry: newestTime !== 0 ? new Date(newestTime).toISOString() : undefined
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* List all cached screens
|
|
274
|
+
*/
|
|
275
|
+
listScreens(): string[] {
|
|
276
|
+
if (!this.config.enabled || !fs.existsSync(this.config.cachePath)) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const screenDirs = fs.readdirSync(this.config.cachePath);
|
|
281
|
+
|
|
282
|
+
return screenDirs.filter(dir => {
|
|
283
|
+
const stat = fs.statSync(path.join(this.config.cachePath, dir));
|
|
284
|
+
return stat.isDirectory();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Get all cache entries for a screen
|
|
290
|
+
*/
|
|
291
|
+
getScreenEntries(screenId: string): CacheEntry[] {
|
|
292
|
+
if (!this.config.enabled) return [];
|
|
293
|
+
|
|
294
|
+
const screenDir = path.join(this.config.cachePath, screenId);
|
|
295
|
+
|
|
296
|
+
if (!fs.existsSync(screenDir)) return [];
|
|
297
|
+
|
|
298
|
+
const files = fs.readdirSync(screenDir);
|
|
299
|
+
const entries: CacheEntry[] = [];
|
|
300
|
+
|
|
301
|
+
for (const file of files) {
|
|
302
|
+
if (!file.endsWith('.json')) continue;
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
const content = fs.readFileSync(path.join(screenDir, file), 'utf-8');
|
|
306
|
+
entries.push(JSON.parse(content));
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.error(`Failed to read cache entry: ${file}`, error);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return entries;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ============================================================================
|
|
317
|
+
// Factory Function
|
|
318
|
+
// ============================================================================
|
|
319
|
+
|
|
320
|
+
export function createCacheManager(config: CacheConfig): CacheManager {
|
|
321
|
+
return new CacheManager(config);
|
|
322
|
+
}
|