@sun-asterisk/sungen 3.2.28 → 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/capabilities/discover.d.ts +29 -0
- package/dist/capabilities/discover.d.ts.map +1 -1
- package/dist/capabilities/discover.js +144 -10
- package/dist/capabilities/discover.js.map +1 -1
- package/dist/capabilities/registry.d.ts +18 -0
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js +25 -0
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +9 -0
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/capability.js +1 -1
- package/dist/cli/commands/capability.js.map +1 -1
- 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/dashboard/templates/index.html +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/feature-parser.d.ts +1 -1
- package/dist/exporters/feature-parser.js +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +18 -3
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/item-labels.d.ts +35 -0
- package/dist/exporters/matrix/item-labels.d.ts.map +1 -0
- package/dist/exporters/matrix/item-labels.js +90 -0
- package/dist/exporters/matrix/item-labels.js.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts +14 -0
- package/dist/exporters/matrix/render-coverage-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-coverage-sheet.js +162 -0
- package/dist/exporters/matrix/render-coverage-sheet.js.map +1 -0
- 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 +20 -0
- package/dist/exporters/matrix/render-overview-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-overview-sheet.js +32 -0
- package/dist/exporters/matrix/render-overview-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts +30 -0
- package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -0
- package/dist/exporters/matrix/render-testcase-sheet.js +156 -0
- package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -0
- package/dist/exporters/matrix/render-xlsx.d.ts +41 -31
- package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
- package/dist/exporters/matrix/render-xlsx.js +72 -425
- package/dist/exporters/matrix/render-xlsx.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 +30 -0
- package/dist/exporters/matrix/testcase-summary-band.d.ts.map +1 -0
- package/dist/exporters/matrix/testcase-summary-band.js +71 -0
- package/dist/exporters/matrix/testcase-summary-band.js.map +1 -0
- package/dist/exporters/matrix/wording.d.ts.map +1 -1
- package/dist/exporters/matrix/wording.js +13 -0
- package/dist/exporters/matrix/wording.js.map +1 -1
- package/dist/exporters/matrix/xlsx-cells.d.ts +38 -0
- package/dist/exporters/matrix/xlsx-cells.d.ts.map +1 -0
- package/dist/exporters/matrix/xlsx-cells.js +52 -0
- package/dist/exporters/matrix/xlsx-cells.js.map +1 -0
- 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/exporters/xlsx-report-builder.d.ts +12 -1
- package/dist/exporters/xlsx-report-builder.d.ts.map +1 -1
- package/dist/exporters/xlsx-report-builder.js +10 -2
- package/dist/exporters/xlsx-report-builder.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +10 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +20 -12
- 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/os-support.d.ts +53 -0
- package/dist/generators/test-generator/adapters/appium/os-support.d.ts.map +1 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js +200 -0
- package/dist/generators/test-generator/adapters/appium/os-support.js.map +1 -0
- 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/alert-fill-action.hbs +9 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- 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/hover-action.hbs +6 -2
- package/dist/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- 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/actions/unknown-element-action.hbs +9 -0
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- 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/go-back-action.hbs +21 -0
- 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/gestures/set-geolocation-action.hbs +16 -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 +62 -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 +7 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
- 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 +21 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -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-base.hbs +8 -8
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- 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 +165 -40
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/diagnostics.d.ts +116 -6
- package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
- package/dist/generators/test-generator/diagnostics.js +115 -5
- package/dist/generators/test-generator/diagnostics.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +57 -11
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +163 -21
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +8 -0
- package/dist/generators/test-generator/patterns/types.d.ts.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 +103 -10
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +266 -45
- 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 +53 -2
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +273 -27
- 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/audit.d.ts +3 -1
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +51 -28
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/capability-plan.d.ts +4 -0
- package/dist/harness/capability-plan.d.ts.map +1 -1
- package/dist/harness/capability-plan.js +32 -2
- package/dist/harness/capability-plan.js.map +1 -1
- package/dist/harness/catalog/drivers.yaml +1 -1
- package/dist/harness/catalog/universal-viewpoints.yaml +145 -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/parse.d.ts +6 -0
- package/dist/harness/parse.d.ts.map +1 -1
- package/dist/harness/parse.js +1 -1
- package/dist/harness/parse.js.map +1 -1
- package/dist/harness/repair.d.ts.map +1 -1
- package/dist/harness/repair.js +8 -1
- package/dist/harness/repair.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/harness/sensors.d.ts +48 -0
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +26 -1
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts +10 -0
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +23 -2
- package/dist/harness/viewpoint-ledger.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/delivery.md +4 -3
- 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-delivery/SKILL.md +14 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
- package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
- package/dist/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
- package/dist/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/dist/orchestrator/templates/playwright.config.ts +7 -0
- package/dist/orchestrator/templates/readme.md +1 -1
- 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-pw-shape-reporter.ts +0 -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/orchestrator/templates/wdio.conf.ts +105 -1
- 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/capabilities/discover.ts +146 -10
- package/src/capabilities/registry.ts +30 -0
- package/src/cli/commands/audit.ts +9 -0
- package/src/cli/commands/capability.ts +1 -1
- 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/dashboard/templates/index.html +1 -1
- package/src/exporters/api-testcase-formatter.ts +5 -7
- package/src/exporters/feature-parser.ts +1 -1
- package/src/exporters/matrix/build.ts +17 -3
- package/src/exporters/matrix/item-labels.ts +78 -0
- package/src/exporters/matrix/render-coverage-sheet.ts +170 -0
- package/src/exporters/matrix/render-csv.ts +3 -1
- package/src/exporters/matrix/render-overview-sheet.ts +51 -0
- package/src/exporters/matrix/render-testcase-sheet.ts +178 -0
- package/src/exporters/matrix/render-xlsx.ts +67 -448
- package/src/exporters/matrix/result-totals.ts +37 -0
- package/src/exporters/matrix/testcase-summary-band.ts +74 -0
- package/src/exporters/matrix/wording.ts +13 -0
- package/src/exporters/matrix/xlsx-cells.ts +56 -0
- 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/exporters/xlsx-report-builder.ts +16 -2
- package/src/generators/gherkin-parser/index.ts +22 -11
- 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/os-support.ts +176 -0
- 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/alert-fill-action.hbs +9 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/capture-variable.hbs +24 -1
- 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/hover-action.hbs +6 -2
- package/src/generators/test-generator/adapters/appium/templates/steps/actions/hover-element-with-text.hbs +4 -3
- 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/actions/unknown-element-action.hbs +9 -0
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/have-value-assertion.hbs +34 -1
- package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +14 -6
- 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/go-back-action.hbs +21 -0
- 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/gestures/set-geolocation-action.hbs +16 -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 +62 -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 +7 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/table-action-in-row.hbs +7 -2
- 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 +21 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/state-with-filter-assertion.hbs +20 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-empty.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-match-data.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-count.hbs +4 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-exists.hbs +12 -4
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/table-row-not-exists.hbs +14 -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-base.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/id.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator-strategies/testid.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs +8 -8
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +10 -8
- package/src/generators/test-generator/code-generator.ts +181 -46
- package/src/generators/test-generator/diagnostics.ts +117 -6
- package/src/generators/test-generator/patterns/index.ts +175 -24
- package/src/generators/test-generator/patterns/types.ts +8 -0
- package/src/generators/test-generator/patterns/with-parent-scope.ts +41 -0
- package/src/generators/test-generator/step-mapper.ts +277 -43
- 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 +333 -28
- package/src/generators/test-generator/utils/selector-type-validation.ts +87 -0
- package/src/harness/audit.ts +55 -30
- package/src/harness/capability-plan.ts +33 -1
- package/src/harness/catalog/drivers.yaml +1 -1
- package/src/harness/catalog/universal-viewpoints.yaml +145 -0
- package/src/harness/data-driven-lint.ts +192 -32
- package/src/harness/parse.ts +7 -1
- package/src/harness/repair.ts +8 -1
- package/src/harness/script-check.ts +186 -21
- package/src/harness/sensors.ts +75 -1
- package/src/harness/viewpoint-ledger.ts +26 -5
- 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/delivery.md +4 -3
- 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-delivery/SKILL.md +14 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +62 -3
- package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +126 -11
- package/src/orchestrator/templates/ai-src/skills/sungen-mobile-gestures/SKILL.md +16 -1
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +12 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +19 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +88 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +62 -5
- package/src/orchestrator/templates/ai-src/skills/sungen-test-design-techniques/SKILL.md +13 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +59 -10
- package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/group-f-mobile-native.md +419 -0
- package/src/orchestrator/templates/playwright.config.ts +7 -0
- package/src/orchestrator/templates/readme.md +1 -1
- package/src/orchestrator/templates/specs-checked-state.ts +324 -0
- package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -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/orchestrator/templates/wdio.conf.ts +105 -1
- package/src/utils/selector-types.ts +54 -5
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{{#if clickPosition}}
|
|
2
|
+
{{!-- Positioned click: coordinates are relative to the element's PADDING box (clientWidth/Height),
|
|
3
|
+
the same box `click({ position })` measures from — boundingBox() would be the border box and
|
|
4
|
+
drift by the border width. Read once, checked, then clicked, so an offset past the real size
|
|
5
|
+
fails naming that size instead of landing on a neighbour. --}}
|
|
6
|
+
{ const el = {{> locator}};
|
|
7
|
+
const __label = {{{label}}};
|
|
8
|
+
await el.waitFor({ state: 'visible' }); // the box is read once — not before the element has laid out
|
|
9
|
+
{{!-- padding box = bounding rect minus borders: clientWidth/Height would read 0 on an inline element (a link). --}}
|
|
10
|
+
const box = await el.evaluate((n) => {
|
|
11
|
+
const r = n.getBoundingClientRect(); const cs = getComputedStyle(n); const b = (p: string) => parseFloat(cs.getPropertyValue(p)) || 0;
|
|
12
|
+
return { w: r.width - b('border-left-width') - b('border-right-width'), h: r.height - b('border-top-width') - b('border-bottom-width') };
|
|
13
|
+
});
|
|
14
|
+
if (box.w <= 0 || box.h <= 0) throw new Error('[sungen] ' + __label + ': element has no layout box (hidden, detached or zero-sized)');
|
|
15
|
+
const x = {{#if (eq clickPosition.xUnit '%')}}box.w * {{clickPosition.xRatio}}{{else}}{{clickPosition.x}}{{/if}};
|
|
16
|
+
const y = {{#if (eq clickPosition.yUnit '%')}}box.h * {{clickPosition.yRatio}}{{else}}{{clickPosition.y}}{{/if}};
|
|
17
|
+
if (x >= box.w || y >= box.h) throw new Error('[sungen] ' + __label + ': click position (' + Math.round(x) + ', ' + Math.round(y) + ') lies outside the element box ' + Math.round(box.w) + 'x' + Math.round(box.h));
|
|
18
|
+
await el.click({ position: { x, y } });
|
|
19
|
+
}
|
|
20
|
+
{{else}}
|
|
21
|
+
{{!-- Unreachable through the compiler (SG-E026 replaces the step) — kept so a stray render fails loud. --}}
|
|
22
|
+
throw new Error('[sungen] click position could not be parsed');
|
|
23
|
+
{{/if}}
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/expand-action.hbs
CHANGED
|
@@ -5,20 +5,20 @@ await el.click();
|
|
|
5
5
|
{{else if expanded.class}}
|
|
6
6
|
{{!-- State signalled by a class on a descendant (e.g. an accordion chevron icon). --}}
|
|
7
7
|
{{#if (eq direction 'expand')}}
|
|
8
|
-
if (!(await el.locator('.{{expanded.class}}').count())) { await el.click(); }
|
|
9
|
-
await expect(el.locator('.{{expanded.class}}')).toBeVisible();
|
|
8
|
+
if (!(await el.locator('.{{escapeQuotes expanded.class}}').count())) { await el.click(); }
|
|
9
|
+
await expect(el.locator('.{{escapeQuotes expanded.class}}')).toBeVisible();
|
|
10
10
|
{{else}}
|
|
11
|
-
if (await el.locator('.{{expanded.class}}').count()) { await el.click(); }
|
|
12
|
-
await expect(el.locator('.{{expanded.class}}')).toHaveCount(0);
|
|
11
|
+
if (await el.locator('.{{escapeQuotes expanded.class}}').count()) { await el.click(); }
|
|
12
|
+
await expect(el.locator('.{{escapeQuotes expanded.class}}')).toHaveCount(0);
|
|
13
13
|
{{/if}}
|
|
14
14
|
{{else if expanded.attribute}}
|
|
15
15
|
{{!-- Explicit boolean attribute ('true'/'false'), custom or aria-expanded. --}}
|
|
16
16
|
{{#if (eq direction 'expand')}}
|
|
17
|
-
if (await el.getAttribute('{{expanded.attribute}}') !== 'true') { await el.click(); }
|
|
18
|
-
await expect(el).toHaveAttribute('{{expanded.attribute}}', 'true');
|
|
17
|
+
if (await el.getAttribute('{{escapeQuotes expanded.attribute}}') !== 'true') { await el.click(); }
|
|
18
|
+
await expect(el).toHaveAttribute('{{escapeQuotes expanded.attribute}}', 'true');
|
|
19
19
|
{{else}}
|
|
20
|
-
if (await el.getAttribute('{{expanded.attribute}}') !== 'false') { await el.click(); }
|
|
21
|
-
await expect(el).toHaveAttribute('{{expanded.attribute}}', 'false');
|
|
20
|
+
if (await el.getAttribute('{{escapeQuotes expanded.attribute}}') !== 'false') { await el.click(); }
|
|
21
|
+
await expect(el).toHaveAttribute('{{escapeQuotes expanded.attribute}}', 'false');
|
|
22
22
|
{{/if}}
|
|
23
23
|
{{else}}
|
|
24
24
|
{{!-- Default (zero-config): drive by aria-expanded, but assert it ONLY when the element exposes it. --}}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
const editorLocator
|
|
1
|
+
{{!-- Block-scoped, like the appium counterpart: `const editorLocator` at statement level made a
|
|
2
|
+
SECOND editor fill in the same scenario a duplicate declaration, and Playwright fails the
|
|
3
|
+
WHOLE file with one SyntaxError — every scenario in it never runs. Unreachable while
|
|
4
|
+
`contenteditable:` was dead and nothing set `inputMethod` (#712); a form with two rich-text
|
|
5
|
+
fields hits it immediately once the field works. SG-E022 is the gate that caught it. --}}
|
|
6
|
+
{ const editorLocator = {{> locator}};
|
|
2
7
|
await editorLocator.click();
|
|
3
|
-
await editorLocator.pressSequentially('{{escapeQuotes fillValue}}');
|
|
8
|
+
await editorLocator.pressSequentially('{{escapeQuotes fillValue}}'); }
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
1
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
2
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
3
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
4
|
+
{ const tableRow = {{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row'){{/if}}.nth({{{rowIndexExpr}}});
|
|
5
|
+
{{!-- `check`/`uncheck` must not emit a bare .check() here either (#675) — the row control is just
|
|
6
|
+
as likely to be an aria-pressed toggle as a standalone one. `click` stays a plain click. --}}
|
|
7
|
+
{{#if (eq action 'click')}}await {{{actionLocator}}}.click();{{else}}await setCheckedState({{{actionLocator}}}, {{#if (eq action 'check')}}true{{else}}false{{/if}}, '{{escapeQuotes elementName}}'{{> checked-opts cls=actionCheckedClass attr=actionCheckedAttribute}});{{/if}} }
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
1
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
2
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
3
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
4
|
+
{ const tableRow = {{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row'){{/if}}.filter({ hasText: '{{escapeQuotes filterValue}}' });
|
|
5
|
+
{{!-- `check`/`uncheck` must not emit a bare .check() here either (#675) — the row control is just
|
|
6
|
+
as likely to be an aria-pressed toggle as a standalone one. `click` stays a plain click. --}}
|
|
7
|
+
{{#if (eq action 'click')}}await {{{actionLocator}}}.click();{{else}}await setCheckedState({{{actionLocator}}}, {{#if (eq action 'check')}}true{{else}}false{{/if}}, '{{escapeQuotes elementName}}'{{> checked-opts cls=actionCheckedClass attr=actionCheckedAttribute}});{{/if}} }
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{{!-- The paginator is located from `page`, NOT from inside the table locator: antd/MUI/Radix all
|
|
2
|
+
render the control as a SIBLING of the <table>, so scoping it to the table would resolve 0
|
|
3
|
+
elements (issue #712). No implicit wait — the round-trip belongs to
|
|
4
|
+
`User wait for [X] table to refresh`. A disabled control fails loud: click waits for enabled. --}}
|
|
5
|
+
await page.locator('{{escapeQuotes paginationSelector}}').click();
|
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- Inverse of check-action.hbs — see there and specs/checked-state.ts for why the control is
|
|
2
|
+
inspected at run time rather than driven by a bare .uncheck() (#675). --}}
|
|
3
|
+
await setCheckedState({{> locator}}, false, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await page.getByText('{{escapeQuotes selectorValue}}').filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact legacyTail=(eq selectorValue "")}} }){{
|
|
1
|
+
await page.getByText('{{escapeQuotes selectorValue}}').filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact legacyTail=(eq selectorValue "")}} }){{> locator-nth}}.{{action}}();
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-page.hbs
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- `wait for [T] page` is a WAIT, not an oracle — but a bare `page.waitForURL(/…/)` resolves on
|
|
2
|
+
the FIRST URL sample that matches, which for a client-side router is the URL it pushed before
|
|
3
|
+
the route guard had answered. Every step after the wait then ran against a page mid-redirect,
|
|
4
|
+
so their failures pointed at the wrong thing (#677). The unanchored regex also matched a
|
|
5
|
+
neighbour: `/vi/search` resolved on `/vi/search-results`.
|
|
6
|
+
|
|
7
|
+
`waitForPage` is the third caller of the settle-and-hold core in specs/url-assert.ts, after
|
|
8
|
+
the `see [T] page` / `is on [T] page` pair #662 routed there (partials/url-assertion.hbs):
|
|
9
|
+
arrive, let the page settle, HOLD the URL, and fail naming where the user actually ended up.
|
|
10
|
+
|
|
11
|
+
Where it deliberately DIFFERS from the Then-side `expectPage`: the query is not constrained.
|
|
12
|
+
A bare page ASSERTION means a bare page; a wait for a results page legitimately lands on
|
|
13
|
+
`?q=…`, and reddening there would assert something the step never said. The helper's docstring
|
|
14
|
+
carries the full argument.
|
|
15
|
+
|
|
16
|
+
`hostname` rides separately and only for an absolute page value: it is read off `u.hostname`,
|
|
17
|
+
which never appears in `u.pathname`, so one concatenated regex cannot carry both. --}}
|
|
18
|
+
await waitForPage(page, { pathname: /^{{pathRegex}}\/?$/{{#if hostRegex}}, hostname: /^{{hostRegex}}$/{{/if}} });
|
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
{{!-- All-contain: the assertion has to SURVIVE whatever async action precedes it.
|
|
2
|
+
|
|
3
|
+
`locator.allInnerTexts()` is a one-shot DOM read — no auto-wait, no retry — and wrapping its
|
|
4
|
+
RESULT in expect() adds no waiting either, because by then it is a plain array of strings.
|
|
5
|
+
Playwright's auto-waiting only applies when the LOCATOR is handed to expect(). Placed after a
|
|
6
|
+
search click or a filter change, the old shape asserted against the PRE-action DOM and failed
|
|
7
|
+
deterministically, naming real-looking values that read as a product defect rather than as a
|
|
8
|
+
generator bug (#672). A `toBeGreaterThan(0)` guard does not help: the stale list is non-empty,
|
|
9
|
+
so the length check passes and the CONTENT check is what races.
|
|
10
|
+
|
|
11
|
+
Playwright has no locator-level "every match contains X" — `filter({ hasNotText })` matches
|
|
12
|
+
case-insensitively on normalized whitespace, which is not the `toContain` semantics this step
|
|
13
|
+
promises — so the wait is expressed with expect.poll, which retries for `expect.timeout` from
|
|
14
|
+
playwright.config.ts. Two details carry the fix:
|
|
15
|
+
|
|
16
|
+
- The loop asserts on the snapshot the poll SETTLED on. Re-reading the locator afterwards
|
|
17
|
+
reopens the very race being closed — a late render pass between the poll settling and the
|
|
18
|
+
re-read swapped the rows out again, which is how the reporter's first patch passed in
|
|
19
|
+
isolation and failed in the full suite.
|
|
20
|
+
- The poll's own rejection is swallowed: on its own it can only report
|
|
21
|
+
`toBe(true) received false`. The per-item expect() below names expected vs received, which
|
|
22
|
+
is the message a QA has to act on. --~}}{
|
|
23
|
+
const __expected_{{stepCounter}} = '{{escapeQuotes expectedText}}';
|
|
24
|
+
let __items_{{stepCounter}}: string[] = [];
|
|
25
|
+
try {
|
|
26
|
+
await expect.poll(async () => {
|
|
27
|
+
__items_{{stepCounter}} = await {{> locator}}.allInnerTexts();
|
|
28
|
+
return __items_{{stepCounter}}.length > 0 && __items_{{stepCounter}}.every((__s) => __s.includes(__expected_{{stepCounter}}));
|
|
29
|
+
}).toBe(true);
|
|
30
|
+
} catch { /* the assertions below report expected-vs-received on the settled snapshot */ }
|
|
31
|
+
expect(__items_{{stepCounter}}.length, 'Expected at least one [{{escapeQuotes selectorRef}}]').toBeGreaterThan(0);
|
|
4
32
|
for (const __t_{{stepCounter}} of __items_{{stepCounter}}) {
|
|
5
|
-
expect(__t_{{stepCounter}}).toContain(
|
|
33
|
+
expect(__t_{{stepCounter}}).toContain(__expected_{{stepCounter}});
|
|
6
34
|
}
|
|
7
35
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
{
|
|
1
|
+
{{!-- The count() below is a one-shot read, same class as #672: after a search or filter click the
|
|
2
|
+
container list may not have rendered yet, and a bare `toBeGreaterThan(0)` on a stale 0 fails
|
|
3
|
+
instantly with no retry. `not.toHaveCount(0)` IS locator-based, so it auto-waits for the list
|
|
4
|
+
to appear; count() then reads a list that is already known to exist. --~}}{
|
|
2
5
|
const {{containerVar}} = {{> locator}};
|
|
6
|
+
await expect({{containerVar}}, 'Expected at least one [{{escapeQuotes selectorRef}}]').not.toHaveCount(0);
|
|
3
7
|
const __n_{{stepCounter}} = await {{containerVar}}.count();
|
|
4
|
-
expect(__n_{{stepCounter}}, 'Expected at least one [{{escapeQuotes selectorRef}}]').toBeGreaterThan(0);
|
|
5
8
|
for (let {{containerIndexVar}} = 0; {{containerIndexVar}} < __n_{{stepCounter}}; {{containerIndexVar}}++) {
|
|
6
9
|
await expect({{#with child}}{{> locator parentLocator=(add (add (add ../containerVar ".nth(") ../containerIndexVar) ")")}}{{/with}}, 'Every [{{escapeQuotes selectorRef}}] must contain [{{escapeQuotes childRef}}]').toBeVisible();
|
|
7
10
|
}
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- `expect(locator).toBeChecked()` throws the same "Not a checkbox or radio button" (#675) on a
|
|
2
|
+
`<button aria-pressed>` as the action side did, so driving a toggle worked while ASSERTING it
|
|
3
|
+
did not. expectCheckedState reads state the same way setCheckedState drives it — an action and
|
|
4
|
+
the assertion after it can never disagree about what the control reports. --}}
|
|
5
|
+
await expectCheckedState({{> locator}}, true, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- Rooted at `page`, like the two lines below it. This line used to render `{{> locator}}` from
|
|
2
|
+
step data that carries no strategy/value at all, so it emitted `page.locator('')` — an empty
|
|
3
|
+
CSS selector, which Playwright refuses to parse. The step could not run.
|
|
4
|
+
|
|
5
|
+
Block-scoped: the column-index const is named after the [Reference], so two steps naming the
|
|
6
|
+
same column — or two non-ASCII references, which sanitize down to the same identifier — would
|
|
7
|
+
redeclare it in one scenario and the spec would not compile. The braces make each step's
|
|
8
|
+
binding its own.
|
|
9
|
+
|
|
10
|
+
Not dialog/frame scoped: this step form carries no selector entry, so there is nothing for
|
|
11
|
+
`pageRoot` to read. A column assertion inside a modal needs the row-scoped form. --~}}{ await expect(page.getByRole('columnheader', { name: '{{columnName}}', includeHidden: true })).toBeVisible();
|
|
2
12
|
const {{columnIndexVar}} = (await page.getByRole('columnheader', { includeHidden: true }).filter({ visible: true }).allTextContents()).findIndex(h => h.includes('{{columnName}}'));
|
|
3
|
-
|
|
13
|
+
expect({{columnIndexVar}}, 'Column "{{escapeQuotes columnName}}" is not among the visible headers').toBeGreaterThanOrEqual(0);
|
|
14
|
+
await expect(page.getByRole('row', { includeHidden: true }).filter({ visible: true }).nth({{rowNth}}).getByRole('cell', { includeHidden: true }).filter({ visible: true }).nth({{columnIndexVar}})).toHaveText('{{dataValue}}'); }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect({{> locator}}).toContainText('{{expectedText}}');
|
|
1
|
+
await expect({{> locator}}).toContainText('{{escapeQuotes expectedText}}');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{{#if name}}
|
|
2
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
2
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeDisabled();
|
|
3
3
|
{{else}}
|
|
4
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
4
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeDisabled();
|
|
5
5
|
{{/if}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{
|
|
1
|
+
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{> locator-nth}}).toBeDisabled();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect({{> locator}}).toHaveText('{{expectedText}}');
|
|
1
|
+
await expect({{> locator}}).toHaveText('{{escapeQuotes expectedText}}');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{{#if name}}
|
|
2
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
2
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeHidden();
|
|
3
3
|
{{else}}
|
|
4
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
4
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeHidden();
|
|
5
5
|
{{/if}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{
|
|
1
|
+
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{> locator-nth}}).toBeHidden();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- Inverse of checked-assertion.hbs — see there (#675). --}}
|
|
2
|
+
await expectCheckedState({{> locator}}, false, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
{{#if (or
|
|
1
|
+
{{#if (or checkedClass checkedAttribute)}}
|
|
2
|
+
{{!-- A DECLARED signal (issue #730) short-circuits the whole ARIA probe below: the author
|
|
3
|
+
reached for `selected:`/`checked:` precisely because this component publishes no aria-selected,
|
|
4
|
+
no aria-current and no checked state — a Tailwind card/tab picker. Probing for them first would
|
|
5
|
+
just spend the budget confirming they are absent. --}}
|
|
6
|
+
await expectCheckedState({{> locator}}, true, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
7
|
+
{{else if (or (eq role 'checkbox') (eq role 'radio') (eq role 'switch'))}}
|
|
2
8
|
{{!-- Form control: "selected" is the checked state, never aria-selected. A native checkbox/radio
|
|
3
9
|
exposes no aria-selected attribute — its state lives in the `checked` property. --}}
|
|
4
|
-
|
|
10
|
+
{{!-- "selected" on a form control IS the checked state — routed through expectCheckedState so an
|
|
11
|
+
aria-pressed toggle does not throw "Not a checkbox or radio button" (#675), and so the selector
|
|
12
|
+
that declares role: switch while the element publishes aria-pressed still reads correctly. --}}
|
|
13
|
+
await expectCheckedState({{> locator}}, true, '{{escapeQuotes selectorRef}}');
|
|
5
14
|
{{else}}
|
|
6
15
|
{{!-- Other/unknown role (tab, option, or a text/testid/css selector): probe at runtime. An ARIA
|
|
7
16
|
single-select widget exposes aria-selected → assert it; anything without it falls back to the
|
|
@@ -9,8 +18,17 @@ await expect({{> locator}}).toBeChecked();
|
|
|
9
18
|
{ const el = {{> locator}};
|
|
10
19
|
if ((await el.getAttribute('aria-selected')) !== null) {
|
|
11
20
|
await expect(el).toHaveAttribute('aria-selected', 'true');
|
|
21
|
+
} else if ((await el.getAttribute('aria-current')) !== null) {
|
|
22
|
+
{{!-- aria-current marks the CURRENT item of a navigation set (WAI-ARIA 1.1): a Next.js tab strip
|
|
23
|
+
of plain <a> links carries aria-current="page" and has neither aria-selected nor a checked
|
|
24
|
+
state, so toBeChecked() threw "Not a checkbox or radio button" on a correct step. Any value
|
|
25
|
+
but "false" ("page", "step", "true", …) means current. Probed AFTER aria-selected: a real
|
|
26
|
+
role=tab owns the stronger signal. --}}
|
|
27
|
+
await expect(el).toHaveAttribute('aria-current', /^(?!false$)./);
|
|
12
28
|
} else {
|
|
13
|
-
|
|
29
|
+
{{!-- Last resort, same as the -with-filter twin: neither aria-selected nor aria-current, so read the
|
|
30
|
+
checked/pressed state through the #675-safe path rather than toBeChecked(). --}}
|
|
31
|
+
await expectCheckedState(el, true, '{{escapeQuotes selectorRef}}');
|
|
14
32
|
}
|
|
15
33
|
}
|
|
16
34
|
{{/if}}
|
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
{{!-- Filter contract shared with the visible/hidden/contains siblings (has-text-value):
|
|
2
2
|
substring by default, `exact: true` in the selector YAML anchors. --}}
|
|
3
3
|
{{#if selectedProbe}}
|
|
4
|
+
{{#if (or checkedClass checkedAttribute)}}
|
|
5
|
+
{{!-- Declared class signal (issue #730) — short-circuits the ARIA probe, exactly as the unfiltered
|
|
6
|
+
twin selected-assertion.hbs does. Without this branch the filtered form stayed broken while the
|
|
7
|
+
unfiltered one worked, which is the inconsistency #730's second field report ran into. --}}
|
|
8
|
+
await expectCheckedState({{> locator-base}}.filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact}} }){{> locator-nth}}, true, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
9
|
+
{{else}}
|
|
4
10
|
{ const el = {{> locator-base}}.filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact}} }){{> locator-nth}};
|
|
5
11
|
if ((await el.getAttribute('aria-selected')) !== null) {
|
|
6
12
|
await expect(el).toHaveAttribute('aria-selected', 'true');
|
|
13
|
+
} else if ((await el.getAttribute('aria-current')) !== null) {
|
|
14
|
+
{{!-- aria-current marks the CURRENT item of a navigation set (WAI-ARIA 1.1): a Next.js tab strip
|
|
15
|
+
of plain <a> links carries aria-current="page" and has neither aria-selected nor a checked
|
|
16
|
+
state, so toBeChecked() threw "Not a checkbox or radio button" on a correct step. Any value
|
|
17
|
+
but "false" ("page", "step", "true", …) means current. Probed AFTER aria-selected: a real
|
|
18
|
+
role=tab owns the stronger signal. --}}
|
|
19
|
+
await expect(el).toHaveAttribute('aria-current', /^(?!false$)./);
|
|
7
20
|
} else {
|
|
8
|
-
|
|
21
|
+
{{!-- Last resort: the element publishes neither aria-selected nor aria-current. toBeChecked() used
|
|
22
|
+
to sit here and threw "Not a checkbox or radio button" on an aria-pressed toggle (#675). --}}
|
|
23
|
+
await expectCheckedState(el, true, '{{escapeQuotes selectorRef}}');
|
|
9
24
|
}
|
|
10
25
|
}
|
|
26
|
+
{{/if}}
|
|
27
|
+
{{else}}{{#if isCheckedAssertion}}
|
|
28
|
+
await expectCheckedState({{> locator-base}}.filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact}} }){{> locator-nth}}, {{checkedWant}}, '{{escapeQuotes selectorRef}}'{{> checked-opts cls=checkedClass attr=checkedAttribute}});
|
|
11
29
|
{{else}}
|
|
12
30
|
await expect({{> locator-base}}.filter({ hasText: {{> has-text-value dataValue=dataValue exact=exact}} }){{> locator-nth}}).{{{stateAssertion}}};
|
|
13
|
-
{{/if}}
|
|
31
|
+
{{/if}}{{/if}}
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
2
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
3
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
4
|
+
await expect({{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.locator('tbody').getByRole('row', { includeHidden: true }){{/if}}.filter({ visible: true })).toHaveCount(0);
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
const table = {{> locator}};
|
|
3
|
-
|
|
3
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
4
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
5
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
6
|
+
const rows = table{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.locator('tbody').getByRole('row', { includeHidden: true }){{/if}}.filter({ visible: true });
|
|
4
7
|
{{#each assertions}}
|
|
5
8
|
{{{this}}}
|
|
6
9
|
{{/each~}}
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
2
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
3
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
4
|
+
await expect({{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.locator('tbody').getByRole('row', { includeHidden: true }){{/if}}.filter({ visible: true })).toHaveCount({{expectedCount}});
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
{{~#if rowSelector}}
|
|
2
|
+
{{!-- Declared row LABEL = one positioned row. The toHaveCount(1) guard is what turns "I used the
|
|
3
|
+
row label as the row SHAPE" (div.job-row, issue #688) into a named error instead of a
|
|
4
|
+
strict-mode message pointing at the wrong line. --}}
|
|
2
5
|
{{~#if isGiven}}
|
|
3
|
-
const tableRow = {{> locator}}.locator('{{rowSelector}}');
|
|
6
|
+
const tableRow = {{> locator}}.locator('{{escapeQuotes rowSelector}}');
|
|
7
|
+
await expect(tableRow, 'row label "[{{escapeQuotes rowLabel}}]" must position exactly ONE row (its selectors.yaml entry is relative to the table) — if this selector describes what EVERY row looks like, declare it as `rows:` on the TABLE entry instead').toHaveCount(1);
|
|
4
8
|
await tableRow.filter({ hasText: '{{escapeQuotes filterValue}}' }).waitFor();
|
|
5
9
|
{{~else}}
|
|
6
|
-
const tableRow = {{> locator}}.locator('{{rowSelector}}');
|
|
10
|
+
const tableRow = {{> locator}}.locator('{{escapeQuotes rowSelector}}');
|
|
11
|
+
await expect(tableRow, 'row label "[{{escapeQuotes rowLabel}}]" must position exactly ONE row (its selectors.yaml entry is relative to the table) — if this selector describes what EVERY row looks like, declare it as `rows:` on the TABLE entry instead').toHaveCount(1);
|
|
7
12
|
await expect(tableRow).toContainText('{{escapeQuotes filterValue}}');
|
|
8
13
|
{{~/if}}
|
|
9
14
|
{{~else}}
|
|
15
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
16
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
17
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
10
18
|
{{~#if isGiven}}
|
|
11
|
-
const tableRow = {{> locator}}.getByRole('row', { includeHidden: true }).filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true });
|
|
19
|
+
const tableRow = {{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row', { includeHidden: true }){{/if}}.filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true });
|
|
12
20
|
await tableRow.waitFor();
|
|
13
21
|
{{~else}}
|
|
14
|
-
const tableRow = {{> locator}}.getByRole('row', { includeHidden: true }).filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true });
|
|
22
|
+
const tableRow = {{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row', { includeHidden: true }){{/if}}.filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true });
|
|
15
23
|
await expect(tableRow).toBeVisible();
|
|
16
24
|
{{~/if}}
|
|
17
25
|
{{~/if}}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
{{~#if rowSelector}}
|
|
2
|
+
{{!-- Declared row LABEL = one positioned row (same contract as the exists twin). The row must not
|
|
3
|
+
hold the value. Block-scoped: this step does not enter row scope, so it must not redeclare
|
|
4
|
+
the function-level tableRow the exists step binds. --}}
|
|
5
|
+
{ const tableRow = {{> locator}}.locator('{{escapeQuotes rowSelector}}');
|
|
6
|
+
await expect(tableRow, 'row label "[{{escapeQuotes rowLabel}}]" must position exactly ONE row (its selectors.yaml entry is relative to the table) — if this selector describes what EVERY row looks like, declare it as `rows:` on the TABLE entry instead').toHaveCount(1);
|
|
7
|
+
await expect(tableRow).not.toContainText('{{escapeQuotes filterValue}}'); }
|
|
8
|
+
{{~else}}
|
|
9
|
+
{{!-- Row universe: `rows:` on the table entry (what EVERY row matches — a <div> list has no
|
|
10
|
+
role=row, so the ARIA chain below is 0 elements and this assertion would be vacuous, issue #688)
|
|
11
|
+
wins; otherwise the historical ARIA chain, byte-identical. --}}
|
|
1
12
|
{{~#if isGiven}}
|
|
2
|
-
await {{> locator}}.getByRole('row', { includeHidden: true }).filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true }).waitFor({ state: 'hidden' });
|
|
13
|
+
await {{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row', { includeHidden: true }){{/if}}.filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true }).waitFor({ state: 'hidden' });
|
|
3
14
|
{{~else}}
|
|
4
|
-
await expect({{> locator}}.getByRole('row', { includeHidden: true }).filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true })).toHaveCount(0);
|
|
15
|
+
await expect({{> locator}}{{#if rows}}.locator('{{escapeQuotes rows}}'){{else}}.getByRole('row', { includeHidden: true }){{/if}}.filter({ hasText: '{{escapeQuotes filterValue}}' }).filter({ visible: true })).toHaveCount(0);
|
|
16
|
+
{{~/if}}
|
|
5
17
|
{{~/if}}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{{#if name}}
|
|
2
2
|
{{#if dataValue}}
|
|
3
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
3
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeVisible();
|
|
4
4
|
{{else}}
|
|
5
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{
|
|
5
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{> locator-nth}}).toBeVisible();
|
|
6
6
|
{{/if}}
|
|
7
7
|
{{else}}
|
|
8
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{
|
|
8
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeVisible();
|
|
9
9
|
{{/if}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect(page.getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{
|
|
1
|
+
await expect(page.getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{> locator-nth}}).toBeVisible();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await expect(page.getByText('{{escapeQuotes selectorValue}}').filter({ hasText: /.*{{escapeRegex dataValue}}$/ }){{
|
|
1
|
+
await expect(page.getByText('{{escapeQuotes selectorValue}}').filter({ hasText: /.*{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeVisible();
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/checked-opts.hbs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{{!-- The `checked:`/`selected:` signal from selectors.yaml, appended as the options argument of
|
|
2
|
+
setCheckedState/expectCheckedState (issue #730). One partial so all nine call sites carry it
|
|
3
|
+
identically, and so a site that declares nothing stays BYTE-IDENTICAL to before — the whole
|
|
4
|
+
argument disappears rather than becoming an empty object. Takes `cls`/`attr` so a caller can
|
|
5
|
+
pass a signal resolved from a DIFFERENT entry than the one it spread (table-action-in-row
|
|
6
|
+
spreads the TABLE but acts on the row's own control). A selector declares one or the other;
|
|
7
|
+
the resolver refuses both, so the two branches never collide here. --~}}
|
|
8
|
+
{{~#if cls}}, { checkedClass: '{{escapeQuotes cls}}' }{{else if attr}}, { checkedAttribute: '{{escapeQuotes attr}}' }{{/if~}}
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-base.hbs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{{#if parentLocator}}{{parentLocator}}.{{#switch strategy~}}
|
|
2
|
-
{{~#case 'testid'}}getByTestId('{{value}}'){{/case~}}
|
|
2
|
+
{{~#case 'testid'}}getByTestId('{{escapeQuotes value}}'){{/case~}}
|
|
3
3
|
{{~#case 'role'}}{{#if name}}getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{else}}getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}){{/if}}{{/case~}}
|
|
4
4
|
{{~#case 'placeholder'}}getByPlaceholder('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
5
5
|
{{~#case 'label'}}getByLabel('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
6
6
|
{{~#case 'text'}}getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
7
|
-
{{~#case 'locator'}}locator('{{value}}'){{/case~}}
|
|
8
|
-
{{~#case 'id'}}locator('{{value}}'){{/case~}}
|
|
9
|
-
{{~#default}}locator('{{value}}'){{/default~}}
|
|
7
|
+
{{~#case 'locator'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
8
|
+
{{~#case 'id'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
9
|
+
{{~#default}}locator('{{escapeQuotes value}}'){{/default~}}
|
|
10
10
|
{{~/switch}}{{else~}}
|
|
11
11
|
{{#if scope}}{{#if (eq scope "dialog")}}{{pageRoot}}.{{else}}{{pageRoot}}.getByLabel('{{escapeQuotes scope}}').{{/if}}{{#switch strategy~}}
|
|
12
|
-
{{~#case 'testid'}}getByTestId('{{value}}'){{/case~}}
|
|
12
|
+
{{~#case 'testid'}}getByTestId('{{escapeQuotes value}}'){{/case~}}
|
|
13
13
|
{{~#case 'role'}}{{#if name}}getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{else}}getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}){{/if}}{{/case~}}
|
|
14
14
|
{{~#case 'placeholder'}}getByPlaceholder('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
15
15
|
{{~#case 'label'}}getByLabel('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
16
16
|
{{~#case 'text'}}getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
17
|
-
{{~#case 'locator'}}locator('{{value}}'){{/case~}}
|
|
18
|
-
{{~#case 'id'}}locator('{{value}}'){{/case~}}
|
|
19
|
-
{{~#default}}locator('{{value}}'){{/default~}}
|
|
17
|
+
{{~#case 'locator'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
18
|
+
{{~#case 'id'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
19
|
+
{{~#default}}locator('{{escapeQuotes value}}'){{/default~}}
|
|
20
20
|
{{~/switch}}{{else}}{{#switch strategy~}}
|
|
21
21
|
{{~#case 'testid'}}{{> locator-strategies/testid}}{{/case~}}
|
|
22
22
|
{{~#case 'role'}}{{> locator-strategies/role}}{{/case~}}
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator-nth.hbs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{{#if (gte nth 0)}}.nth({{nth}}){{/if}}
|
|
1
|
+
{{#if (gte nth 0)}}.nth({{nth}}){{else if (eq nth -1)}}.last(){{/if}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
page.locator('{{selector}}')
|
|
1
|
+
page.locator('{{escapeQuotes selector}}')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{{pageRoot}}.getByTestId('{{value}}')
|
|
1
|
+
{{pageRoot}}.getByTestId('{{escapeQuotes value}}')
|
package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/locator.hbs
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
{{#if parentLocator}}{{parentLocator}}.{{#switch strategy~}}
|
|
2
|
-
{{~#case 'testid'}}getByTestId('{{value}}'){{/case~}}
|
|
2
|
+
{{~#case 'testid'}}getByTestId('{{escapeQuotes value}}'){{/case~}}
|
|
3
3
|
{{~#case 'role'}}{{#if name}}getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{else}}getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}){{/if}}{{/case~}}
|
|
4
4
|
{{~#case 'placeholder'}}getByPlaceholder('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
5
5
|
{{~#case 'label'}}getByLabel('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
6
6
|
{{~#case 'text'}}getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
7
|
-
{{~#case 'locator'}}locator('{{value}}'){{/case~}}
|
|
8
|
-
{{~#case 'id'}}locator('{{value}}'){{/case~}}
|
|
9
|
-
{{~#default}}locator('{{value}}'){{/default~}}
|
|
7
|
+
{{~#case 'locator'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
8
|
+
{{~#case 'id'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
9
|
+
{{~#default}}locator('{{escapeQuotes value}}'){{/default~}}
|
|
10
10
|
{{~/switch}}{{> locator-nth}}{{else~}}
|
|
11
11
|
{{#if scope}}{{#if (eq scope "dialog")}}{{pageRoot}}.{{else}}{{pageRoot}}.getByLabel('{{escapeQuotes scope}}').{{/if}}{{#switch strategy~}}
|
|
12
|
-
{{~#case 'testid'}}getByTestId('{{value}}'){{/case~}}
|
|
12
|
+
{{~#case 'testid'}}getByTestId('{{escapeQuotes value}}'){{/case~}}
|
|
13
13
|
{{~#case 'role'}}{{#if name}}getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{else}}getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}){{/if}}{{/case~}}
|
|
14
14
|
{{~#case 'placeholder'}}getByPlaceholder('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
15
15
|
{{~#case 'label'}}getByLabel('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
16
16
|
{{~#case 'text'}}getByText('{{escapeQuotes value}}'{{#if exact}}, { exact: true }{{/if}}){{/case~}}
|
|
17
|
-
{{~#case 'locator'}}locator('{{value}}'){{/case~}}
|
|
18
|
-
{{~#case 'id'}}locator('{{value}}'){{/case~}}
|
|
19
|
-
{{~#default}}locator('{{value}}'){{/default~}}
|
|
17
|
+
{{~#case 'locator'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
18
|
+
{{~#case 'id'}}locator('{{escapeQuotes value}}'){{/case~}}
|
|
19
|
+
{{~#default}}locator('{{escapeQuotes value}}'){{/default~}}
|
|
20
20
|
{{~/switch}}{{> locator-nth}}{{else}}{{#switch strategy~}}
|
|
21
21
|
{{~#case 'testid'}}{{> locator-strategies/testid}}{{/case~}}
|
|
22
22
|
{{~#case 'role'}}{{> locator-strategies/role}}{{/case~}}
|
|
@@ -98,6 +98,16 @@ test.describe.serial('{{featureName}}', () => {
|
|
|
98
98
|
});
|
|
99
99
|
{{/if}}
|
|
100
100
|
|
|
101
|
+
{{#if beforeAll}}
|
|
102
|
+
{{beforeAll}}
|
|
103
|
+
|
|
104
|
+
{{/if}}
|
|
105
|
+
{{#if afterAll}}
|
|
106
|
+
// User @afterAll runs BEFORE the built-in close below (Playwright runs afterAll hooks in registration
|
|
107
|
+
// order), so the shared page is still open for its cleanup steps.
|
|
108
|
+
{{afterAll}}
|
|
109
|
+
|
|
110
|
+
{{/if}}
|
|
101
111
|
test.afterAll(async () => {
|
|
102
112
|
await page.close();
|
|
103
113
|
await context.close();
|
|
@@ -112,18 +122,10 @@ test.describe.serial('{{featureName}}', () => {
|
|
|
112
122
|
{{#if screenshotOnFailure}}
|
|
113
123
|
test.use({ screenshotOnFailure: true });
|
|
114
124
|
|
|
115
|
-
{{/if}}
|
|
116
|
-
{{#if beforeAll}}
|
|
117
|
-
{{beforeAll}}
|
|
118
|
-
|
|
119
125
|
{{/if}}
|
|
120
126
|
{{#if afterEach}}
|
|
121
127
|
{{afterEach}}
|
|
122
128
|
|
|
123
|
-
{{/if}}
|
|
124
|
-
{{#if afterAll}}
|
|
125
|
-
{{afterAll}}
|
|
126
|
-
|
|
127
129
|
{{/if}}
|
|
128
130
|
{{#if authGroups}}
|
|
129
131
|
{{#each authGroups}}
|