@sun-asterisk/sungen 3.2.29 → 3.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +2 -1
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +6 -2
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/inspect.js +1 -1
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/commands/results-merge.d.ts.map +1 -1
- package/dist/cli/commands/results-merge.js +9 -2
- package/dist/cli/commands/results-merge.js.map +1 -1
- package/dist/cli/commands/results-sanitize.d.ts +24 -0
- package/dist/cli/commands/results-sanitize.d.ts.map +1 -0
- package/dist/cli/commands/results-sanitize.js +126 -0
- package/dist/cli/commands/results-sanitize.js.map +1 -0
- package/dist/cli/commands/script-check.d.ts.map +1 -1
- package/dist/cli/commands/script-check.js +3 -1
- package/dist/cli/commands/script-check.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +3 -0
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/exporters/api-testcase-formatter.d.ts +3 -6
- package/dist/exporters/api-testcase-formatter.d.ts.map +1 -1
- package/dist/exporters/api-testcase-formatter.js +7 -10
- package/dist/exporters/api-testcase-formatter.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +4 -2
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -1
- package/dist/exporters/matrix/render-coverage-sheet.js +3 -1
- package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -1
- package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
- package/dist/exporters/matrix/render-csv.js +3 -1
- package/dist/exporters/matrix/render-csv.js.map +1 -1
- package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -1
- package/dist/exporters/matrix/render-overview-sheet.js +5 -9
- package/dist/exporters/matrix/render-overview-sheet.js.map +1 -1
- package/dist/exporters/matrix/result-totals.d.ts +23 -0
- package/dist/exporters/matrix/result-totals.d.ts.map +1 -0
- package/dist/exporters/matrix/result-totals.js +21 -0
- package/dist/exporters/matrix/result-totals.js.map +1 -0
- package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -1
- package/dist/exporters/matrix/testcase-summary-band.js +2 -6
- package/dist/exporters/matrix/testcase-summary-band.js.map +1 -1
- package/dist/exporters/qa-env-secret-denylist.js +2 -2
- package/dist/exporters/qa-env-secret-denylist.js.map +1 -1
- package/dist/exporters/report-path-sanitizer.d.ts +38 -0
- package/dist/exporters/report-path-sanitizer.d.ts.map +1 -0
- package/dist/exporters/report-path-sanitizer.js +137 -0
- package/dist/exporters/report-path-sanitizer.js.map +1 -0
- package/dist/exporters/result-variants.d.ts.map +1 -1
- package/dist/exporters/result-variants.js +2 -1
- package/dist/exporters/result-variants.js.map +1 -1
- package/dist/exporters/sensitive-key.d.ts +31 -0
- package/dist/exporters/sensitive-key.d.ts.map +1 -0
- package/dist/exporters/sensitive-key.js +50 -0
- package/dist/exporters/sensitive-key.js.map +1 -0
- package/dist/exporters/test-data-resolver.d.ts +4 -1
- package/dist/exporters/test-data-resolver.d.ts.map +1 -1
- package/dist/exporters/test-data-resolver.js +12 -2
- package/dist/exporters/test-data-resolver.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +3 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +17 -9
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/gherkin-parser/parent-scope-clause.d.ts +54 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.d.ts.map +1 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.js +109 -0
- package/dist/generators/gherkin-parser/parent-scope-clause.js.map +1 -0
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +23 -18
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts +4 -19
- package/dist/generators/test-generator/adapters/appium/appium-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/appium/appium-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
- package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +54 -23
- package/dist/generators/test-generator/adapters/index.d.ts +1 -1
- package/dist/generators/test-generator/adapters/index.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +4 -19
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
- package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
- package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +3 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +3 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +14 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +13 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
- 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/assertions/visible-with-variable-assertion.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
- package/dist/generators/test-generator/code-generator.d.ts +37 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +160 -39
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +79 -5
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +78 -4
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +24 -5
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +92 -14
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +18 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.js +40 -0
- package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts +63 -9
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +166 -28
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +4 -19
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +17 -12
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +7 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +19 -2
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts +41 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.js +61 -0
- package/dist/generators/test-generator/utils/dialog-scope-identity.js.map +1 -0
- package/dist/generators/test-generator/utils/escape-js-string.d.ts +17 -0
- package/dist/generators/test-generator/utils/escape-js-string.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/escape-js-string.js +29 -0
- package/dist/generators/test-generator/utils/escape-js-string.js.map +1 -0
- package/dist/generators/test-generator/utils/nearest-match.d.ts +24 -0
- package/dist/generators/test-generator/utils/nearest-match.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/nearest-match.js +56 -0
- package/dist/generators/test-generator/utils/nearest-match.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.d.ts +58 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.js +119 -0
- package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.d.ts +25 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.js +54 -0
- package/dist/generators/test-generator/utils/selector-entry-walk.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.d.ts +59 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.js +91 -0
- package/dist/generators/test-generator/utils/selector-nth-validation.js.map +1 -0
- package/dist/generators/test-generator/utils/selector-resolver.d.ts +30 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +195 -15
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-type-validation.d.ts +51 -0
- package/dist/generators/test-generator/utils/selector-type-validation.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/selector-type-validation.js +77 -0
- package/dist/generators/test-generator/utils/selector-type-validation.js.map +1 -0
- package/dist/harness/data-driven-lint.d.ts.map +1 -1
- package/dist/harness/data-driven-lint.js +217 -33
- package/dist/harness/data-driven-lint.js.map +1 -1
- package/dist/harness/script-check.d.ts +2 -2
- package/dist/harness/script-check.d.ts.map +1 -1
- package/dist/harness/script-check.js +186 -25
- package/dist/harness/script-check.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/orchestrator/project-initializer.d.ts +6 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +16 -0
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/report-sanitize-reporter-install.d.ts +24 -0
- package/dist/orchestrator/report-sanitize-reporter-install.d.ts.map +1 -0
- package/dist/orchestrator/report-sanitize-reporter-install.js +161 -0
- package/dist/orchestrator/report-sanitize-reporter-install.js.map +1 -0
- package/dist/orchestrator/templates/ai-src/commands/run-test.md +9 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +14 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +108 -8
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +9 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +4 -4
- package/dist/orchestrator/templates/playwright.config.ts +7 -0
- package/dist/orchestrator/templates/specs-checked-state.d.ts +83 -0
- package/dist/orchestrator/templates/specs-checked-state.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-checked-state.js +261 -0
- package/dist/orchestrator/templates/specs-checked-state.js.map +1 -0
- package/dist/orchestrator/templates/specs-checked-state.ts +324 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts +36 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js +155 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.js.map +1 -0
- package/dist/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
- package/dist/orchestrator/templates/specs-url-assert.d.ts +50 -25
- package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.js +65 -24
- package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
- package/dist/orchestrator/templates/specs-url-assert.ts +101 -28
- package/dist/utils/selector-types.d.ts +43 -1
- package/dist/utils/selector-types.d.ts.map +1 -1
- package/dist/utils/selector-types.js +51 -7
- package/dist/utils/selector-types.js.map +1 -1
- package/package.json +3 -3
- package/src/cli/commands/delivery.ts +2 -1
- package/src/cli/commands/generate.ts +5 -2
- package/src/cli/commands/inspect.ts +1 -1
- package/src/cli/commands/results-merge.ts +9 -2
- package/src/cli/commands/results-sanitize.ts +98 -0
- package/src/cli/commands/script-check.ts +3 -1
- package/src/cli/commands/update.ts +3 -0
- package/src/exporters/api-testcase-formatter.ts +5 -7
- package/src/exporters/matrix/build.ts +4 -2
- package/src/exporters/matrix/render-coverage-sheet.ts +3 -1
- package/src/exporters/matrix/render-csv.ts +3 -1
- package/src/exporters/matrix/render-overview-sheet.ts +5 -10
- package/src/exporters/matrix/result-totals.ts +37 -0
- package/src/exporters/matrix/testcase-summary-band.ts +2 -7
- package/src/exporters/qa-env-secret-denylist.ts +1 -1
- package/src/exporters/report-path-sanitizer.ts +144 -0
- package/src/exporters/result-variants.ts +2 -1
- package/src/exporters/sensitive-key.ts +48 -0
- package/src/exporters/test-data-resolver.ts +12 -2
- package/src/generators/gherkin-parser/index.ts +21 -10
- package/src/generators/gherkin-parser/parent-scope-clause.ts +130 -0
- package/src/generators/test-generator/adapters/adapter-interface.ts +25 -3
- package/src/generators/test-generator/adapters/appium/appium-adapter.ts +4 -4
- package/src/generators/test-generator/adapters/appium/templates/after-all.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/after-each.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/before-all.hbs +18 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-at-position-action.hbs +1 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/click-element-with-text.hbs +1 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/double-click-action.hbs +7 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/frame-enter-action.hbs +3 -6
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/table-paginate-action.hbs +3 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/long-press-action.hbs +4 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/gestures/pinch-zoom-action.hbs +4 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/partials/locator.hbs +9 -1
- package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +54 -23
- package/src/generators/test-generator/adapters/index.ts +1 -1
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +4 -4
- package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +19 -1
- package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +18 -0
- package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +19 -1
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/check-action.hbs +6 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-at-position-action.hbs +23 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-editor-action.hbs +7 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row-nth.hbs +3 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +3 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-paginate-action.hbs +5 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/uncheck-action.hbs +3 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/unknown-element-action.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs +18 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +32 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-element.hbs +5 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +5 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +13 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +2 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/not-checked-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/selected-assertion.hbs +14 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +13 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +3 -3
- 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/assertions/visible-with-variable-assertion.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
- package/src/generators/test-generator/code-generator.ts +176 -45
- package/src/generators/test-generator/diagnostics.ts +79 -5
- package/src/generators/test-generator/patterns/index.ts +97 -16
- package/src/generators/test-generator/patterns/with-parent-scope.ts +41 -0
- package/src/generators/test-generator/step-mapper.ts +170 -26
- package/src/generators/test-generator/template-engine.ts +21 -21
- package/src/generators/test-generator/utils/data-resolver.ts +23 -2
- package/src/generators/test-generator/utils/dialog-scope-identity.ts +71 -0
- package/src/generators/test-generator/utils/escape-js-string.ts +24 -0
- package/src/generators/test-generator/utils/nearest-match.ts +55 -0
- package/src/generators/test-generator/utils/selector-entry-fields.ts +131 -0
- package/src/generators/test-generator/utils/selector-entry-walk.ts +58 -0
- package/src/generators/test-generator/utils/selector-nth-validation.ts +99 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +245 -16
- package/src/generators/test-generator/utils/selector-type-validation.ts +87 -0
- package/src/harness/data-driven-lint.ts +192 -32
- package/src/harness/script-check.ts +186 -21
- package/src/index.ts +7 -0
- package/src/orchestrator/project-initializer.ts +17 -0
- package/src/orchestrator/report-sanitize-reporter-install.ts +109 -0
- package/src/orchestrator/templates/ai-src/commands/run-test.md +9 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +10 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +14 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +108 -8
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +1 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +9 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +4 -4
- package/src/orchestrator/templates/playwright.config.ts +7 -0
- package/src/orchestrator/templates/specs-checked-state.ts +324 -0
- package/src/orchestrator/templates/specs-report-path-sanitize-reporter.ts +142 -0
- package/src/orchestrator/templates/specs-url-assert.ts +101 -28
- package/src/utils/selector-types.ts +54 -5
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SG-W018 — an `nth:` value outside the contract (issue #720).
|
|
3
|
+
*
|
|
4
|
+
* `nth:` was the one SelectorEntry field whose VALUE nothing validated. The key is recognised
|
|
5
|
+
* (it is in CONSUMED_ENTRY_FIELDS, so SG-W004 stays quiet) and the entry's `type:` is valid (so
|
|
6
|
+
* SG-E027 stays quiet) — every check we own stopped at the key. What landed in the value went
|
|
7
|
+
* straight to two adapters that disagreed about what a valid `nth` even is:
|
|
8
|
+
*
|
|
9
|
+
* nth: -1 web → the filter vanished (`.getByRole('combobox')`, byte-identical to deleting
|
|
10
|
+
* the line), mobile → `$$('~x')[-1]`, which is `undefined` in JavaScript
|
|
11
|
+
* nth: 'last' web → dropped, mobile → `$$('~x')[last]` — a bare identifier, valid syntax and a
|
|
12
|
+
* ReferenceError at run time, so even the SG-E022 parse self-check passed it
|
|
13
|
+
* nth: 1.5 emitted verbatim into `.nth(1.5)` / `[1.5]`
|
|
14
|
+
*
|
|
15
|
+
* Zero diagnostics in every case. `SelectorEntry.nth` is typed `number?`, but YAML is parsed, not
|
|
16
|
+
* type-checked — the declared type buys nothing at the boundary. Same family as #712 (an
|
|
17
|
+
* unrecognised KEY) and #711 (an unrecognised VALUE for `type:`), one level deeper again.
|
|
18
|
+
*
|
|
19
|
+
* THE CONTRACT: an integer `>= -1`. `0..N` is the zero-based index; `-1` means the last match
|
|
20
|
+
* (Playwright's `.last()` IS `.nth(-1)`, and the appium side now renders `.at(-1)`). Anything
|
|
21
|
+
* else is ignored by the resolver — normalised to `undefined` before it can reach a template —
|
|
22
|
+
* and reported here, so "ignored" is something the author is told rather than something they
|
|
23
|
+
* discover from a strict-mode violation.
|
|
24
|
+
*
|
|
25
|
+
* A WARNING, not an error, on SG-W004's reasoning: the value is inert once dropped, the selector
|
|
26
|
+
* still resolves (it just does not filter by position), and `--strict` already turns the channel
|
|
27
|
+
* non-zero for CI.
|
|
28
|
+
*/
|
|
29
|
+
import type { DiagnosticsCollector } from '../diagnostics';
|
|
30
|
+
/** True for the values `nth:` accepts: an integer index `>= 0`, or `-1` for the last match. */
|
|
31
|
+
export declare function isValidNth(v: unknown): v is number;
|
|
32
|
+
/**
|
|
33
|
+
* The one normalisation every resolve path runs `nth` through: a valid index, or `undefined`.
|
|
34
|
+
*
|
|
35
|
+
* Returning `undefined` rather than the raw value is what makes the SG-W018 message true — and
|
|
36
|
+
* it is the half that keeps broken JavaScript out of the emitted spec even on paths this check
|
|
37
|
+
* does not walk (the legacy selector format), because a template only ever sees a real index.
|
|
38
|
+
*/
|
|
39
|
+
export declare function normalizeNth(v: unknown): number | undefined;
|
|
40
|
+
export interface InvalidNth {
|
|
41
|
+
/** Dotted path to the offending entry, e.g. `danh muc` or `greeting.android`. */
|
|
42
|
+
path: string;
|
|
43
|
+
/** The `nth:` value exactly as written, for quoting back at the author. */
|
|
44
|
+
nth: unknown;
|
|
45
|
+
}
|
|
46
|
+
/** Every entry in `file` whose `nth:` is present but outside the contract. */
|
|
47
|
+
export declare function collectInvalidNth(file: Record<string, unknown>): InvalidNth[];
|
|
48
|
+
/**
|
|
49
|
+
* SG-W018 — report every entry whose `nth:` the compiler cannot use.
|
|
50
|
+
*
|
|
51
|
+
* Runs once per selector FILE (the resolver's load is cached), so an entry named by twenty steps
|
|
52
|
+
* is reported once — the same load point and the same reason as SG-W004 and SG-E027. Silent when
|
|
53
|
+
* no diagnostics channel is attached: `generate` must not depend on diagnostics being wired.
|
|
54
|
+
*/
|
|
55
|
+
export declare function reportInvalidNth(file: Record<string, unknown>, opts: {
|
|
56
|
+
feature?: string;
|
|
57
|
+
diagnostics?: DiagnosticsCollector;
|
|
58
|
+
}): void;
|
|
59
|
+
//# sourceMappingURL=selector-nth-validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-nth-validation.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-nth-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG3D,+FAA+F;AAC/F,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE3D;AAED,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,GAAG,EAAE,OAAO,CAAC;CACd;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,EAAE,CAa7E;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,oBAAoB,CAAA;CAAE,GAC7D,IAAI,CAiBN"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SG-W018 — an `nth:` value outside the contract (issue #720).
|
|
4
|
+
*
|
|
5
|
+
* `nth:` was the one SelectorEntry field whose VALUE nothing validated. The key is recognised
|
|
6
|
+
* (it is in CONSUMED_ENTRY_FIELDS, so SG-W004 stays quiet) and the entry's `type:` is valid (so
|
|
7
|
+
* SG-E027 stays quiet) — every check we own stopped at the key. What landed in the value went
|
|
8
|
+
* straight to two adapters that disagreed about what a valid `nth` even is:
|
|
9
|
+
*
|
|
10
|
+
* nth: -1 web → the filter vanished (`.getByRole('combobox')`, byte-identical to deleting
|
|
11
|
+
* the line), mobile → `$$('~x')[-1]`, which is `undefined` in JavaScript
|
|
12
|
+
* nth: 'last' web → dropped, mobile → `$$('~x')[last]` — a bare identifier, valid syntax and a
|
|
13
|
+
* ReferenceError at run time, so even the SG-E022 parse self-check passed it
|
|
14
|
+
* nth: 1.5 emitted verbatim into `.nth(1.5)` / `[1.5]`
|
|
15
|
+
*
|
|
16
|
+
* Zero diagnostics in every case. `SelectorEntry.nth` is typed `number?`, but YAML is parsed, not
|
|
17
|
+
* type-checked — the declared type buys nothing at the boundary. Same family as #712 (an
|
|
18
|
+
* unrecognised KEY) and #711 (an unrecognised VALUE for `type:`), one level deeper again.
|
|
19
|
+
*
|
|
20
|
+
* THE CONTRACT: an integer `>= -1`. `0..N` is the zero-based index; `-1` means the last match
|
|
21
|
+
* (Playwright's `.last()` IS `.nth(-1)`, and the appium side now renders `.at(-1)`). Anything
|
|
22
|
+
* else is ignored by the resolver — normalised to `undefined` before it can reach a template —
|
|
23
|
+
* and reported here, so "ignored" is something the author is told rather than something they
|
|
24
|
+
* discover from a strict-mode violation.
|
|
25
|
+
*
|
|
26
|
+
* A WARNING, not an error, on SG-W004's reasoning: the value is inert once dropped, the selector
|
|
27
|
+
* still resolves (it just does not filter by position), and `--strict` already turns the channel
|
|
28
|
+
* non-zero for CI.
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.isValidNth = isValidNth;
|
|
32
|
+
exports.normalizeNth = normalizeNth;
|
|
33
|
+
exports.collectInvalidNth = collectInvalidNth;
|
|
34
|
+
exports.reportInvalidNth = reportInvalidNth;
|
|
35
|
+
const selector_entry_walk_1 = require("./selector-entry-walk");
|
|
36
|
+
/** True for the values `nth:` accepts: an integer index `>= 0`, or `-1` for the last match. */
|
|
37
|
+
function isValidNth(v) {
|
|
38
|
+
return typeof v === 'number' && Number.isInteger(v) && v >= -1;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The one normalisation every resolve path runs `nth` through: a valid index, or `undefined`.
|
|
42
|
+
*
|
|
43
|
+
* Returning `undefined` rather than the raw value is what makes the SG-W018 message true — and
|
|
44
|
+
* it is the half that keeps broken JavaScript out of the emitted spec even on paths this check
|
|
45
|
+
* does not walk (the legacy selector format), because a template only ever sees a real index.
|
|
46
|
+
*/
|
|
47
|
+
function normalizeNth(v) {
|
|
48
|
+
return isValidNth(v) ? v : undefined;
|
|
49
|
+
}
|
|
50
|
+
/** Every entry in `file` whose `nth:` is present but outside the contract. */
|
|
51
|
+
function collectInvalidNth(file) {
|
|
52
|
+
const out = [];
|
|
53
|
+
(0, selector_entry_walk_1.walkSelectorEntries)(file, {
|
|
54
|
+
entry(entry, path) {
|
|
55
|
+
// An ABSENT `nth:` is the common case and means "no positional filter". An explicit
|
|
56
|
+
// `nth: null` is read the same way — the resolver has always treated null as unset, and
|
|
57
|
+
// reporting it would fire on a legitimate "no index here" written out loud.
|
|
58
|
+
if (entry.nth === undefined || entry.nth === null)
|
|
59
|
+
return;
|
|
60
|
+
if (isValidNth(entry.nth))
|
|
61
|
+
return;
|
|
62
|
+
out.push({ path, nth: entry.nth });
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* SG-W018 — report every entry whose `nth:` the compiler cannot use.
|
|
69
|
+
*
|
|
70
|
+
* Runs once per selector FILE (the resolver's load is cached), so an entry named by twenty steps
|
|
71
|
+
* is reported once — the same load point and the same reason as SG-W004 and SG-E027. Silent when
|
|
72
|
+
* no diagnostics channel is attached: `generate` must not depend on diagnostics being wired.
|
|
73
|
+
*/
|
|
74
|
+
function reportInvalidNth(file, opts) {
|
|
75
|
+
const sink = opts.diagnostics;
|
|
76
|
+
if (!sink)
|
|
77
|
+
return;
|
|
78
|
+
for (const { path, nth } of collectInvalidNth(file)) {
|
|
79
|
+
// Quoted for a string so `nth: 'last'` reads back as the string it is; `String()` for a number
|
|
80
|
+
// so -2, 1.5 and .nan survive as written (JSON.stringify renders NaN as `null`, which would
|
|
81
|
+
// quote a value the author never typed).
|
|
82
|
+
const written = typeof nth === 'string' ? `"${nth}"`
|
|
83
|
+
: typeof nth === 'number' ? String(nth)
|
|
84
|
+
: JSON.stringify(nth) ?? String(nth);
|
|
85
|
+
sink.add('SG-W018', `selectors.yaml entry "${path}" declares nth: ${written}, which is not a valid index — `
|
|
86
|
+
+ `it is IGNORED, so the selector does not filter by position and a step naming it resolves `
|
|
87
|
+
+ `to every match (strict mode then fails at run time naming the DOM, never this line). `
|
|
88
|
+
+ `Use an integer >= 0 for a zero-based index, or -1 for the last match.`, { feature: opts.feature });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=selector-nth-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector-nth-validation.js","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-nth-validation.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;AAMH,gCAEC;AASD,oCAEC;AAUD,8CAaC;AASD,4CAoBC;AApED,+DAA4D;AAE5D,+FAA+F;AAC/F,SAAgB,UAAU,CAAC,CAAU;IACnC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAAC,CAAU;IACrC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvC,CAAC;AASD,8EAA8E;AAC9E,SAAgB,iBAAiB,CAAC,IAA6B;IAC7D,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,IAAA,yCAAmB,EAAC,IAAI,EAAE;QACxB,KAAK,CAAC,KAAK,EAAE,IAAI;YACf,oFAAoF;YACpF,wFAAwF;YACxF,4EAA4E;YAC5E,IAAI,KAAK,CAAC,GAAG,KAAK,SAAS,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI;gBAAE,OAAO;YAC1D,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC;gBAAE,OAAO;YAClC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;QACrC,CAAC;KACF,CAAC,CAAC;IACH,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,gBAAgB,CAC9B,IAA6B,EAC7B,IAA8D;IAE9D,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;IAC9B,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,+FAA+F;QAC/F,4FAA4F;QAC5F,yCAAyC;QACzC,MAAM,OAAO,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG;YAClD,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;gBACvC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC,SAAS,EAChB,yBAAyB,IAAI,mBAAmB,OAAO,iCAAiC;cACtF,2FAA2F;cAC3F,uFAAuF;cACvF,uEAAuE,EACzE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC"}
|
|
@@ -56,6 +56,8 @@ export interface ResolvedSelector {
|
|
|
56
56
|
attribute?: string;
|
|
57
57
|
state?: 'none';
|
|
58
58
|
};
|
|
59
|
+
checkedClass?: string;
|
|
60
|
+
checkedAttribute?: string;
|
|
59
61
|
anchor?: ResolvedSelector;
|
|
60
62
|
}
|
|
61
63
|
/**
|
|
@@ -94,7 +96,7 @@ export declare class SelectorResolver {
|
|
|
94
96
|
* Web is unaffected — there the role IS the locator (see LIST_MEMBER_ROLES).
|
|
95
97
|
*/
|
|
96
98
|
private isUnusableMobileRole;
|
|
97
|
-
/** Attach the compile-diagnostics collector (SG-W003) */
|
|
99
|
+
/** Attach the compile-diagnostics collector (SG-W003, SG-W016, SG-W030) */
|
|
98
100
|
setDiagnostics(collector: DiagnosticsCollector): void;
|
|
99
101
|
/** Override the name-from-content role list from the app profile (qa/app.yaml feedback.toast) */
|
|
100
102
|
setContentNamedRoles(roles: string[]): void;
|
|
@@ -180,9 +182,36 @@ export declare class SelectorResolver {
|
|
|
180
182
|
* "No variables" → "No variables" (unchanged)
|
|
181
183
|
*/
|
|
182
184
|
private static resolveTemplateVars;
|
|
185
|
+
/** Encode `{{var}}` references inside a table's `columns: { <col>: { header } }` map. */
|
|
186
|
+
private static resolveColumnHeaders;
|
|
187
|
+
/**
|
|
188
|
+
* Normalise `checked:` / `selected:` into the one signal consumers read (issue #730). The two
|
|
189
|
+
* spellings are an authoring convenience for the same thing — `checked:` on a toggle, `selected:`
|
|
190
|
+
* on a card/tab picker — so they collapse here rather than at every call site. Each spelling can
|
|
191
|
+
* publish the state as a class token or as a boolean attribute; one entry declares one of them.
|
|
192
|
+
*
|
|
193
|
+
* Validated at CODEGEN because every failure mode here is silent at run time: the class token
|
|
194
|
+
* lands inside `[class~="..."]`, where a quote breaks the selector and whitespace can never match
|
|
195
|
+
* (the `~=` operator matches ONE whitespace-separated token, so 'a b' matches nothing at all and
|
|
196
|
+
* the step would just time out claiming the control never changed state); an attribute name has
|
|
197
|
+
* the same exposure inside `[name="true"]`. Refused rather than warned-and-dropped, unlike
|
|
198
|
+
* `expanded:`: dropping this signal leaves the step with nothing to read, so it would fail again
|
|
199
|
+
* with the original "no on/off state" error and hide the real cause.
|
|
200
|
+
*/
|
|
201
|
+
private resolveCheckedSignal;
|
|
183
202
|
/**
|
|
184
203
|
* Resolve from new structured entry format
|
|
185
204
|
*/
|
|
205
|
+
/**
|
|
206
|
+
* An `expanded:` signal's `class` / `attribute` value is pasted into the generated spec — into a
|
|
207
|
+
* string literal, a regex, a `classList.contains()` argument. selectors.yaml is often generated
|
|
208
|
+
* from the page under test, so a value carrying a quote, a `${`, whitespace or any other character
|
|
209
|
+
* a class or attribute name cannot legitimately contain is refused (diagnostic + the field is
|
|
210
|
+
* dropped) rather than compiled into code. Dropping it leaves a working step — codegen falls back
|
|
211
|
+
* to driving/asserting `aria-expanded` — which is why this warns where the checked/selected signal,
|
|
212
|
+
* whose fallback is the failure it exists to fix, refuses outright.
|
|
213
|
+
*/
|
|
214
|
+
private validatedStateSignal;
|
|
186
215
|
private resolveFromEntry;
|
|
187
216
|
/**
|
|
188
217
|
* Resolve selector by priority chain (legacy)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selector-resolver.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-resolver.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"selector-resolver.d.ts","sourceRoot":"","sources":["../../../../src/generators/test-generator/utils/selector-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,6 +40,9 @@ const path = __importStar(require("path"));
|
|
|
40
40
|
const yaml_io_1 = require("../../../utils/yaml-io");
|
|
41
41
|
const data_resolver_1 = require("./data-resolver");
|
|
42
42
|
const app_profile_1 = require("../app-profile");
|
|
43
|
+
const selector_entry_fields_1 = require("./selector-entry-fields");
|
|
44
|
+
const selector_type_validation_1 = require("./selector-type-validation");
|
|
45
|
+
const selector_nth_validation_1 = require("./selector-nth-validation");
|
|
43
46
|
/**
|
|
44
47
|
* Roles whose accessible name comes from their own CONTENT, not from a label — so a name the
|
|
45
48
|
* compiler invented from the `[Reference]` text can never match a real element.
|
|
@@ -93,7 +96,7 @@ class SelectorResolver {
|
|
|
93
96
|
isUnusableMobileRole(r) {
|
|
94
97
|
return this.platform === 'mobile' && !!r && r.strategy === 'role' && !r.name;
|
|
95
98
|
}
|
|
96
|
-
/** Attach the compile-diagnostics collector (SG-W003) */
|
|
99
|
+
/** Attach the compile-diagnostics collector (SG-W003, SG-W016, SG-W030) */
|
|
97
100
|
setDiagnostics(collector) {
|
|
98
101
|
this.diagnostics = collector;
|
|
99
102
|
}
|
|
@@ -448,9 +451,112 @@ class SelectorResolver {
|
|
|
448
451
|
return data_resolver_1.DataResolver.encodeMarker(varName.trim());
|
|
449
452
|
});
|
|
450
453
|
}
|
|
454
|
+
/** Encode `{{var}}` references inside a table's `columns: { <col>: { header } }` map. */
|
|
455
|
+
static resolveColumnHeaders(columns) {
|
|
456
|
+
const out = {};
|
|
457
|
+
for (const [key, col] of Object.entries(columns)) {
|
|
458
|
+
out[key] = col && typeof col.header === 'string'
|
|
459
|
+
? { ...col, header: SelectorResolver.resolveTemplateVars(col.header) }
|
|
460
|
+
: col;
|
|
461
|
+
}
|
|
462
|
+
return out;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Normalise `checked:` / `selected:` into the one signal consumers read (issue #730). The two
|
|
466
|
+
* spellings are an authoring convenience for the same thing — `checked:` on a toggle, `selected:`
|
|
467
|
+
* on a card/tab picker — so they collapse here rather than at every call site. Each spelling can
|
|
468
|
+
* publish the state as a class token or as a boolean attribute; one entry declares one of them.
|
|
469
|
+
*
|
|
470
|
+
* Validated at CODEGEN because every failure mode here is silent at run time: the class token
|
|
471
|
+
* lands inside `[class~="..."]`, where a quote breaks the selector and whitespace can never match
|
|
472
|
+
* (the `~=` operator matches ONE whitespace-separated token, so 'a b' matches nothing at all and
|
|
473
|
+
* the step would just time out claiming the control never changed state); an attribute name has
|
|
474
|
+
* the same exposure inside `[name="true"]`. Refused rather than warned-and-dropped, unlike
|
|
475
|
+
* `expanded:`: dropping this signal leaves the step with nothing to read, so it would fail again
|
|
476
|
+
* with the original "no on/off state" error and hide the real cause.
|
|
477
|
+
*/
|
|
478
|
+
resolveCheckedSignal(entry, label) {
|
|
479
|
+
const signal = {};
|
|
480
|
+
// Recorded BEFORE it is thrown, every time. A pattern that resolves its selector inside a
|
|
481
|
+
// `catch {}` — several do, to fall back when a `[Ref]` simply is not in the file — would
|
|
482
|
+
// otherwise swallow the refusal whole and emit a step against an unresolved locator, with
|
|
483
|
+
// nothing anywhere naming the entry. The throw is what stops the file; the diagnostic is what
|
|
484
|
+
// survives a caller that decided not to be stopped, and what `--strict` counts.
|
|
485
|
+
const refuse = (message) => {
|
|
486
|
+
this.diagnostics?.add('SG-E031', message, { feature: this.featureName });
|
|
487
|
+
throw new Error(message);
|
|
488
|
+
};
|
|
489
|
+
for (const key of ['class', 'attribute']) {
|
|
490
|
+
const fromChecked = entry.checked?.[key]?.trim();
|
|
491
|
+
const fromSelected = entry.selected?.[key]?.trim();
|
|
492
|
+
if (fromChecked && fromSelected && fromChecked !== fromSelected) {
|
|
493
|
+
refuse(`Selector "[${label}]" declares both \`checked.${key}\` ("${fromChecked}") and ` +
|
|
494
|
+
`\`selected.${key}\` ("${fromSelected}") with different values. They are two spellings of ONE ` +
|
|
495
|
+
`signal — how the control marks its ON state — so only one can be right. Keep \`checked:\` for ` +
|
|
496
|
+
`a toggle/checkbox or \`selected:\` for a card/tab picker, and delete the other.`);
|
|
497
|
+
}
|
|
498
|
+
const value = fromChecked || fromSelected;
|
|
499
|
+
if (!value)
|
|
500
|
+
continue;
|
|
501
|
+
if (/\s/.test(value)) {
|
|
502
|
+
refuse(`Selector "[${label}]" declares checked/selected ${key} "${value}", which contains whitespace. ` +
|
|
503
|
+
`This must be ONE ${key === 'class' ? 'class token, not a class list' : 'attribute name'}: the ` +
|
|
504
|
+
`generated matcher tests a single token, so a multi-token value can never match and the step ` +
|
|
505
|
+
`would time out rather than fail clearly. Pick the one ${key} that marks the ON state ` +
|
|
506
|
+
`(e.g. '${key === 'class' ? 'border-link' : 'data-checked'}', not ` +
|
|
507
|
+
`'${key === 'class' ? 'card border-link' : 'data-checked aria-checked'}').`);
|
|
508
|
+
}
|
|
509
|
+
if (value.includes('"') || value.includes('\\')) {
|
|
510
|
+
refuse(`Selector "[${label}]" declares checked/selected ${key} "${value}", which contains a quote or ` +
|
|
511
|
+
`backslash. The value is embedded in a [${key === 'class' ? 'class~="..."' : 'name="true"'}] CSS ` +
|
|
512
|
+
`selector, which those characters would break. A ${key} carrying them is almost certainly a typo.`);
|
|
513
|
+
}
|
|
514
|
+
signal[key] = value;
|
|
515
|
+
}
|
|
516
|
+
if (signal.class && signal.attribute) {
|
|
517
|
+
refuse(`Selector "[${label}]" declares both a checked/selected \`class\` ("${signal.class}") and ` +
|
|
518
|
+
`\`attribute\` ("${signal.attribute}"). One control publishes its ON state one way — declaring ` +
|
|
519
|
+
`two lets an action drive one signal while the assertion after it reads the other. Keep the one ` +
|
|
520
|
+
`the component actually swaps.`);
|
|
521
|
+
}
|
|
522
|
+
return signal.class || signal.attribute ? signal : undefined;
|
|
523
|
+
}
|
|
451
524
|
/**
|
|
452
525
|
* Resolve from new structured entry format
|
|
453
526
|
*/
|
|
527
|
+
/**
|
|
528
|
+
* An `expanded:` signal's `class` / `attribute` value is pasted into the generated spec — into a
|
|
529
|
+
* string literal, a regex, a `classList.contains()` argument. selectors.yaml is often generated
|
|
530
|
+
* from the page under test, so a value carrying a quote, a `${`, whitespace or any other character
|
|
531
|
+
* a class or attribute name cannot legitimately contain is refused (diagnostic + the field is
|
|
532
|
+
* dropped) rather than compiled into code. Dropping it leaves a working step — codegen falls back
|
|
533
|
+
* to driving/asserting `aria-expanded` — which is why this warns where the checked/selected signal,
|
|
534
|
+
* whose fallback is the failure it exists to fix, refuses outright.
|
|
535
|
+
*/
|
|
536
|
+
validatedStateSignal(signal, field, label) {
|
|
537
|
+
// Letters, digits and the punctuation real class/attribute names use — including Tailwind
|
|
538
|
+
// arbitrary values (`bg-[#eff6ff]`, `!mt-0`, `@md:flex`, `w-[calc(100%-2rem)]`). Excluded on
|
|
539
|
+
// purpose: whitespace, quotes, backticks, backslash, `$`/`{`/`}` — the characters that could
|
|
540
|
+
// close a literal or open an interpolation in the generated code.
|
|
541
|
+
const SAFE = /^[A-Za-z0-9_\-:./[\]%#!@(),&+=*~|?]+$/;
|
|
542
|
+
const out = {};
|
|
543
|
+
for (const key of ['class', 'attribute']) {
|
|
544
|
+
const value = signal[key];
|
|
545
|
+
if (value === undefined || value === null)
|
|
546
|
+
continue;
|
|
547
|
+
const text = String(value);
|
|
548
|
+
if (SAFE.test(text)) {
|
|
549
|
+
out[key] = text;
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
const warnKey = `w030:${label}:${field}.${key}`;
|
|
553
|
+
if (!this.warnedContentNamed.has(warnKey)) { // once per entry+field, not once per step that uses it
|
|
554
|
+
this.warnedContentNamed.add(warnKey);
|
|
555
|
+
this.diagnostics?.add('SG-W030', `selector "${label}": ${field}.${key} ${JSON.stringify(text)} is not accepted as a ${key} name (no whitespace, quotes, backslash, \`$\`, \`{\` or \`}\`) — the value is ignored and the step compiles to its default form`, { feature: this.featureName });
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return out.class || out.attribute ? out : undefined;
|
|
559
|
+
}
|
|
454
560
|
resolveFromEntry(entry, originalLabel) {
|
|
455
561
|
// Default values
|
|
456
562
|
const locator = entry.locator || '';
|
|
@@ -472,9 +578,22 @@ class SelectorResolver {
|
|
|
472
578
|
: (entry.name ?? '');
|
|
473
579
|
const value = SelectorResolver.resolveTemplateVars(rawValue);
|
|
474
580
|
const name = SelectorResolver.resolveTemplateVars(rawName);
|
|
475
|
-
|
|
581
|
+
// `nth:` is the one field whose VALUE nothing used to check (#720): anything non-null was
|
|
582
|
+
// handed to the adapters, which disagreed about it — web dropped `-1` silently, mobile emitted
|
|
583
|
+
// `$$(...)[-1]`. Normalised to a real index (integer >= -1) or `undefined` HERE, so no template
|
|
584
|
+
// ever renders a value it cannot express; the out-of-contract write is reported as SG-W018 at
|
|
585
|
+
// the file load point below.
|
|
586
|
+
const nth = (0, selector_nth_validation_1.normalizeNth)(entry.nth);
|
|
476
587
|
const exact = entry.exact === true || entry.match === 'exact';
|
|
477
|
-
|
|
588
|
+
// `contenteditable: true` is the MANUAL override for a rich-text editor (#712). It was a
|
|
589
|
+
// documented, plumbed field that nothing read: the rich-text decision lives in driver-ui's
|
|
590
|
+
// fill pattern, which gates on `inputMethod` to pick `fill-editor-action`, so an author who
|
|
591
|
+
// followed the selector reference and wrote `contenteditable: true` got a plain `.fill()` and
|
|
592
|
+
// no diagnostic. Forcing the input method HERE rather than adding a second condition in the
|
|
593
|
+
// pattern keeps ONE rich-text signal on ResolvedSelector, so every consumer — current and
|
|
594
|
+
// future — reads the intent off a single field. An explicit `inputMethod` is more specific and
|
|
595
|
+
// still wins, so the two may be mixed without surprise.
|
|
596
|
+
const inputMethod = entry.inputMethod ?? (entry.contenteditable ? 'pressSequentially' : undefined);
|
|
478
597
|
// v2 fields
|
|
479
598
|
const v2Fields = {};
|
|
480
599
|
if (entry.scope)
|
|
@@ -489,8 +608,11 @@ class SelectorResolver {
|
|
|
489
608
|
v2Fields.frame = entry.frame;
|
|
490
609
|
if (entry.contenteditable)
|
|
491
610
|
v2Fields.contenteditable = true;
|
|
611
|
+
// A column's `header` is DOM text like any other selector field, so a `{{var}}` in it is a
|
|
612
|
+
// runtime reference — the same i18n escape hatch `name:`/`value:` have. Encoded here rather
|
|
613
|
+
// than at the read site so every consumer of the map gets it (issue #674).
|
|
492
614
|
if (entry.columns)
|
|
493
|
-
v2Fields.columns = entry.columns;
|
|
615
|
+
v2Fields.columns = SelectorResolver.resolveColumnHeaders(entry.columns);
|
|
494
616
|
if (entry.pagination)
|
|
495
617
|
v2Fields.pagination = entry.pagination;
|
|
496
618
|
if (typeof entry.rows === 'string' && entry.rows.trim())
|
|
@@ -499,8 +621,16 @@ class SelectorResolver {
|
|
|
499
621
|
v2Fields.attribute = entry.attribute;
|
|
500
622
|
if (entry.pattern)
|
|
501
623
|
v2Fields.pattern = entry.pattern;
|
|
502
|
-
if (entry.expanded)
|
|
503
|
-
|
|
624
|
+
if (entry.expanded) {
|
|
625
|
+
const expanded = this.validatedStateSignal(entry.expanded, 'expanded', originalLabel);
|
|
626
|
+
if (expanded || entry.expanded.state)
|
|
627
|
+
v2Fields.expanded = { ...expanded, ...(entry.expanded.state ? { state: entry.expanded.state } : {}) };
|
|
628
|
+
}
|
|
629
|
+
const checked = this.resolveCheckedSignal(entry, originalLabel);
|
|
630
|
+
if (checked?.class)
|
|
631
|
+
v2Fields.checkedClass = checked.class;
|
|
632
|
+
if (checked?.attribute)
|
|
633
|
+
v2Fields.checkedAttribute = checked.attribute;
|
|
504
634
|
// The anchor is a selector in its own right; it must not inherit the PAGE's label as its
|
|
505
635
|
// accessible name, so it resolves against its own name (or nothing).
|
|
506
636
|
if (entry.anchor)
|
|
@@ -535,7 +665,26 @@ class SelectorResolver {
|
|
|
535
665
|
// If type is 'locator', use locator field (or value as fallback) as the CSS locator directly.
|
|
536
666
|
// `exact` travels along: a locator LIST filtered by a test-data value (hasText) matches by
|
|
537
667
|
// substring by default, and `exact: true` in the YAML opts into the anchored full-text match.
|
|
538
|
-
|
|
668
|
+
//
|
|
669
|
+
// `upload` rides the SAME branch rather than getting a case of its own. A file input is
|
|
670
|
+
// addressed by CSS in practice (`input[type=file]`, an id, a testid wrapper), and the selector
|
|
671
|
+
// reference has always documented `upload` as `page.locator(value).setInputFiles()` — so the
|
|
672
|
+
// two spellings must resolve identically or teams migrating off the workaround get a silent
|
|
673
|
+
// behaviour change. It had no case at all before, so it fell through to `default:` and
|
|
674
|
+
// compiled to `getByPlaceholder('<the CSS string>')` — a locator hunting an input whose
|
|
675
|
+
// placeholder ATTRIBUTE is the literal text `input[type=file]`, which no page has. It failed
|
|
676
|
+
// at run time with no diagnostic, and the only way out was to work out for oneself that
|
|
677
|
+
// `type: locator` had to be used instead, which no page of the reference says (issue #690).
|
|
678
|
+
//
|
|
679
|
+
// Handled HERE, above the generic `locator:`-field branch below, because that branch returns
|
|
680
|
+
// strategy 'css' and drops `exact` — putting `upload` in the switch left the two spellings
|
|
681
|
+
// diverging for any entry that sets `locator:`. `withExtras` still stamps the declared
|
|
682
|
+
// `selectorType`, so a consumer that needs to tell an upload from a plain locator still can.
|
|
683
|
+
//
|
|
684
|
+
// `exact` is inert for the upload action itself (`setInputFiles` takes no text filter), but it
|
|
685
|
+
// is NOT dead: the same key reused by a filtered step (`… with {{v}}`) reaches has-text-value,
|
|
686
|
+
// which reads `exact` regardless of strategy.
|
|
687
|
+
if (type === 'locator' || type === 'upload') {
|
|
539
688
|
const locatorValue = locator && locator.trim() ? locator : value;
|
|
540
689
|
return withExtras({
|
|
541
690
|
strategy: 'locator',
|
|
@@ -647,7 +796,14 @@ class SelectorResolver {
|
|
|
647
796
|
exact,
|
|
648
797
|
});
|
|
649
798
|
default:
|
|
650
|
-
//
|
|
799
|
+
// Reached by the NON_STRATEGY_SELECTOR_TYPES (`page`/`table`/`column`/`frame`, whose
|
|
800
|
+
// consumers read the entry or `selectorType` rather than `strategy`) and by a type this
|
|
801
|
+
// compiler does not know at all — YAML is untyped at run time, so a misspelling lands
|
|
802
|
+
// here too. The placeholder result is inert for the first group and wrong for the second,
|
|
803
|
+
// but it MUST NOT throw: `page` alone reaches this branch on every page assertion.
|
|
804
|
+
// What must never arrive here is a STRATEGY type — that is the #690 defect, and
|
|
805
|
+
// tests/codegen/selector-type-dispatch.run.ts fails the build if one does (it checks the
|
|
806
|
+
// resolved strategy, so an early return above satisfies it as well as a `case` here).
|
|
651
807
|
return withExtras({
|
|
652
808
|
strategy: 'placeholder',
|
|
653
809
|
value,
|
|
@@ -661,13 +817,17 @@ class SelectorResolver {
|
|
|
661
817
|
* Returns metadata only - no framework-specific code
|
|
662
818
|
*/
|
|
663
819
|
resolveByPriority(element) {
|
|
820
|
+
// The legacy format never passes through the SG-W018 file check (that walks new-format
|
|
821
|
+
// entries), so it is normalised here instead — a template must never see an index it cannot
|
|
822
|
+
// express, whichever door the entry came through.
|
|
823
|
+
const nth = (0, selector_nth_validation_1.normalizeNth)(element.nth);
|
|
664
824
|
// Extract data-testid from locator if present
|
|
665
825
|
const testIdMatch = element.locator.match(/\[data-testid=["']([^"']+)["']\]/);
|
|
666
826
|
if (testIdMatch) {
|
|
667
827
|
return {
|
|
668
828
|
strategy: 'testid',
|
|
669
829
|
value: testIdMatch[1],
|
|
670
|
-
nth
|
|
830
|
+
nth,
|
|
671
831
|
};
|
|
672
832
|
}
|
|
673
833
|
// Check type-based strategies
|
|
@@ -677,28 +837,28 @@ class SelectorResolver {
|
|
|
677
837
|
role: 'button',
|
|
678
838
|
name: element.value,
|
|
679
839
|
value: element.value,
|
|
680
|
-
nth
|
|
840
|
+
nth,
|
|
681
841
|
};
|
|
682
842
|
}
|
|
683
843
|
if (element.type === 'placeholder' && element.value) {
|
|
684
844
|
return {
|
|
685
845
|
strategy: 'placeholder',
|
|
686
846
|
value: element.value,
|
|
687
|
-
nth
|
|
847
|
+
nth,
|
|
688
848
|
};
|
|
689
849
|
}
|
|
690
850
|
if (element.type === 'label' && element.value) {
|
|
691
851
|
return {
|
|
692
852
|
strategy: 'label',
|
|
693
853
|
value: element.value,
|
|
694
|
-
nth
|
|
854
|
+
nth,
|
|
695
855
|
};
|
|
696
856
|
}
|
|
697
857
|
if (element.type === 'text' && element.value) {
|
|
698
858
|
return {
|
|
699
859
|
strategy: 'text',
|
|
700
860
|
value: element.value,
|
|
701
|
-
nth
|
|
861
|
+
nth,
|
|
702
862
|
};
|
|
703
863
|
}
|
|
704
864
|
// Extract #id from locator if present
|
|
@@ -708,7 +868,7 @@ class SelectorResolver {
|
|
|
708
868
|
strategy: 'id',
|
|
709
869
|
value: idMatch[1],
|
|
710
870
|
locator: `#${idMatch[1]}`,
|
|
711
|
-
nth
|
|
871
|
+
nth,
|
|
712
872
|
};
|
|
713
873
|
}
|
|
714
874
|
// Fallback to CSS locator
|
|
@@ -716,7 +876,7 @@ class SelectorResolver {
|
|
|
716
876
|
strategy: 'css',
|
|
717
877
|
value: element.locator,
|
|
718
878
|
locator: element.locator,
|
|
719
|
-
nth
|
|
879
|
+
nth,
|
|
720
880
|
};
|
|
721
881
|
}
|
|
722
882
|
/**
|
|
@@ -760,6 +920,26 @@ class SelectorResolver {
|
|
|
760
920
|
Object.assign(selectors, SelectorResolver.normalizeKeys(featureSelectors));
|
|
761
921
|
}
|
|
762
922
|
}
|
|
923
|
+
// SG-W004 — a field nothing reads (#712). Reported HERE, at the one cached load point, so a
|
|
924
|
+
// table named by twenty row steps warns once rather than twenty times.
|
|
925
|
+
(0, selector_entry_fields_1.reportUnknownEntryFields)(selectors, {
|
|
926
|
+
feature: featureName,
|
|
927
|
+
diagnostics: this.diagnostics,
|
|
928
|
+
});
|
|
929
|
+
// SG-E027 — a `type:` nothing dispatches (#711). Same load point and same once-per-file
|
|
930
|
+
// reason as SG-W004 above: the two checks are the same question one level apart (an unknown
|
|
931
|
+
// KEY vs an unknown VALUE for a known key), and both want the file in hand to name the entry.
|
|
932
|
+
(0, selector_type_validation_1.reportUnknownSelectorTypes)(selectors, {
|
|
933
|
+
feature: featureName,
|
|
934
|
+
diagnostics: this.diagnostics,
|
|
935
|
+
});
|
|
936
|
+
// SG-W018 — an `nth:` value outside the contract (#720). Third of the same family at the same
|
|
937
|
+
// load point: SG-W004 asks whether anything READS the key, SG-E027 whether the `type:` VALUE
|
|
938
|
+
// dispatches, this one whether the `nth:` VALUE is an index the adapters can express.
|
|
939
|
+
(0, selector_nth_validation_1.reportInvalidNth)(selectors, {
|
|
940
|
+
feature: featureName,
|
|
941
|
+
diagnostics: this.diagnostics,
|
|
942
|
+
});
|
|
763
943
|
this.selectorCache.set(cacheKey, selectors);
|
|
764
944
|
return selectors;
|
|
765
945
|
}
|