@sun-asterisk/sungen 1.0.20 → 1.0.22
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/add.d.ts +3 -0
- package/dist/cli/commands/add.d.ts.map +1 -0
- package/dist/cli/commands/add.js +27 -0
- package/dist/cli/commands/add.js.map +1 -0
- package/dist/cli/commands/cache-clear.d.ts +3 -0
- package/dist/cli/commands/cache-clear.d.ts.map +1 -0
- package/dist/cli/commands/cache-clear.js +24 -0
- package/dist/cli/commands/cache-clear.js.map +1 -0
- package/dist/cli/commands/full.d.ts +3 -0
- package/dist/cli/commands/full.d.ts.map +1 -0
- package/dist/cli/commands/full.js +37 -0
- package/dist/cli/commands/full.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +3 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +53 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +20 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/live-scan.d.ts +3 -0
- package/dist/cli/commands/live-scan.d.ts.map +1 -0
- package/dist/cli/commands/{live-scan-command.js → live-scan.js} +8 -15
- package/dist/cli/commands/live-scan.js.map +1 -0
- package/dist/cli/commands/makeauth.d.ts +3 -0
- package/dist/cli/commands/makeauth.d.ts.map +1 -0
- package/dist/cli/commands/makeauth.js +76 -0
- package/dist/cli/commands/makeauth.js.map +1 -0
- package/dist/cli/commands/map.d.ts +3 -0
- package/dist/cli/commands/map.d.ts.map +1 -0
- package/dist/cli/commands/map.js +93 -0
- package/dist/cli/commands/map.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +3 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +43 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/index.js +29 -442
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/types.d.ts +9 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +7 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/utils.d.ts +6 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cli/utils.js +101 -0
- package/dist/cli/utils.js.map +1 -0
- package/dist/core/live-scanner/element-finder.d.ts.map +1 -1
- package/dist/core/live-scanner/element-finder.js +138 -22
- package/dist/core/live-scanner/element-finder.js.map +1 -1
- package/dist/core/live-scanner/matrix-reader.d.ts.map +1 -1
- package/dist/core/live-scanner/matrix-reader.js +2 -40
- package/dist/core/live-scanner/matrix-reader.js.map +1 -1
- package/dist/core/live-scanner/matrix-writer.d.ts.map +1 -1
- package/dist/core/live-scanner/matrix-writer.js +14 -4
- package/dist/core/live-scanner/matrix-writer.js.map +1 -1
- package/dist/core/live-scanner/step-replayer.d.ts.map +1 -1
- package/dist/core/live-scanner/step-replayer.js +7 -0
- package/dist/core/live-scanner/step-replayer.js.map +1 -1
- package/dist/core/validator/selector-validator.d.ts.map +1 -1
- package/dist/core/validator/selector-validator.js +2 -1
- package/dist/core/validator/selector-validator.js.map +1 -1
- package/dist/generators/scaffold-generator/index.d.ts +2 -1
- package/dist/generators/scaffold-generator/index.d.ts.map +1 -1
- package/dist/generators/scaffold-generator/index.js +21 -1
- package/dist/generators/scaffold-generator/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -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/page-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/assertion-patterns.js +95 -58
- package/dist/generators/test-generator/patterns/assertion-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/form-patterns.d.ts +0 -2
- package/dist/generators/test-generator/patterns/form-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/form-patterns.js +34 -47
- package/dist/generators/test-generator/patterns/form-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/index.d.ts +3 -1
- package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/index.js +20 -3
- package/dist/generators/test-generator/patterns/index.js.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts +0 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/interaction-patterns.js +44 -85
- package/dist/generators/test-generator/patterns/interaction-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts +7 -0
- package/dist/generators/test-generator/patterns/legacy-patterns.d.ts.map +1 -0
- package/dist/generators/test-generator/patterns/legacy-patterns.js +98 -0
- package/dist/generators/test-generator/patterns/legacy-patterns.js.map +1 -0
- package/dist/generators/test-generator/patterns/navigation-patterns.d.ts +0 -2
- package/dist/generators/test-generator/patterns/navigation-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/navigation-patterns.js +14 -42
- package/dist/generators/test-generator/patterns/navigation-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/setup-patterns.d.ts +0 -1
- package/dist/generators/test-generator/patterns/setup-patterns.d.ts.map +1 -1
- package/dist/generators/test-generator/patterns/setup-patterns.js +23 -35
- package/dist/generators/test-generator/patterns/setup-patterns.js.map +1 -1
- package/dist/generators/test-generator/patterns/types.d.ts +18 -3
- package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +0 -15
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +4 -106
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/{executor/test-generator.d.ts → generators/test-generator/types.d.ts} +4 -25
- package/dist/generators/test-generator/types.d.ts.map +1 -0
- package/dist/generators/test-generator/types.js +106 -0
- package/dist/generators/test-generator/types.js.map +1 -0
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +8 -17
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +10 -18
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/orchestrator/cache-manager.d.ts +1 -23
- package/dist/orchestrator/cache-manager.d.ts.map +1 -1
- package/dist/orchestrator/cache-manager.js +1 -87
- package/dist/orchestrator/cache-manager.js.map +1 -1
- package/dist/orchestrator/pipeline.d.ts +11 -28
- package/dist/orchestrator/pipeline.d.ts.map +1 -1
- package/dist/orchestrator/pipeline.js +52 -371
- package/dist/orchestrator/pipeline.js.map +1 -1
- package/dist/orchestrator/reporter.d.ts +1 -1
- package/dist/orchestrator/reporter.d.ts.map +1 -1
- package/dist/orchestrator/screen-manager.js +1 -1
- package/dist/orchestrator/screen-manager.js.map +1 -1
- package/dist/utils/feature-finder.d.ts +9 -0
- package/dist/utils/feature-finder.d.ts.map +1 -0
- package/dist/utils/feature-finder.js +67 -0
- package/dist/utils/feature-finder.js.map +1 -0
- package/dist/utils/screen-paths.d.ts +10 -0
- package/dist/utils/screen-paths.d.ts.map +1 -0
- package/dist/utils/screen-paths.js +73 -0
- package/dist/utils/screen-paths.js.map +1 -0
- package/dist/utils/selector-loader.d.ts +6 -0
- package/dist/utils/selector-loader.d.ts.map +1 -0
- package/dist/utils/selector-loader.js +20 -0
- package/dist/utils/selector-loader.js.map +1 -0
- package/dist/utils/selector-types.d.ts +7 -0
- package/dist/utils/selector-types.d.ts.map +1 -0
- package/dist/utils/selector-types.js +19 -0
- package/dist/utils/selector-types.js.map +1 -0
- package/dist/utils/test-data-loader.d.ts +6 -0
- package/dist/utils/test-data-loader.d.ts.map +1 -0
- package/dist/utils/test-data-loader.js +20 -0
- package/dist/utils/test-data-loader.js.map +1 -0
- package/dist/utils/yaml-io.d.ts +14 -0
- package/dist/utils/yaml-io.d.ts.map +1 -0
- package/dist/utils/yaml-io.js +72 -0
- package/dist/utils/yaml-io.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/commands/add.ts +25 -0
- package/src/cli/commands/cache-clear.ts +22 -0
- package/src/cli/commands/full.ts +35 -0
- package/src/cli/commands/generate.ts +55 -0
- package/src/cli/commands/init.ts +17 -0
- package/src/cli/commands/{live-scan-command.ts → live-scan.ts} +8 -17
- package/src/cli/commands/makeauth.ts +77 -0
- package/src/cli/commands/map.ts +97 -0
- package/src/cli/commands/validate.ts +43 -0
- package/src/cli/index.ts +32 -473
- package/src/cli/types.ts +9 -0
- package/src/cli/utils.ts +106 -0
- package/src/core/live-scanner/element-finder.ts +142 -21
- package/src/core/live-scanner/matrix-reader.ts +2 -8
- package/src/core/live-scanner/matrix-writer.ts +14 -4
- package/src/core/live-scanner/step-replayer.ts +7 -0
- package/src/core/validator/selector-validator.ts +3 -2
- package/src/generators/scaffold-generator/index.ts +23 -2
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role-with-data.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/checked-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/column-cell-assertion.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/count-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-filter-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-role-variable-assertion.hbs +4 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/disabled-with-variable-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/empty-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/enabled-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/focused-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/have-text-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-dialog-heading-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-filter-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-role-variable-assertion.hbs +4 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/hidden-with-variable-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/is-hidden-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/list-item-count-assertion.hbs +2 -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/page-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-dialog-heading-assertion.hbs +2 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-locator-variable-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +4 -3
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-value-assertion.hbs +2 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-variable-assertion.hbs +1 -0
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs +1 -1
- package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/wait-for-element-with-text.hbs +1 -1
- package/src/generators/test-generator/patterns/assertion-patterns.ts +102 -62
- package/src/generators/test-generator/patterns/form-patterns.ts +38 -60
- package/src/generators/test-generator/patterns/index.ts +22 -4
- package/src/generators/test-generator/patterns/interaction-patterns.ts +47 -107
- package/src/generators/test-generator/patterns/legacy-patterns.ts +104 -0
- package/src/generators/test-generator/patterns/navigation-patterns.ts +27 -69
- package/src/generators/test-generator/patterns/setup-patterns.ts +23 -41
- package/src/generators/test-generator/patterns/types.ts +26 -9
- package/src/generators/test-generator/step-mapper.ts +4 -124
- package/src/generators/test-generator/types.ts +131 -0
- package/src/generators/test-generator/utils/data-resolver.ts +8 -13
- package/src/generators/test-generator/utils/selector-resolver.ts +15 -17
- package/src/orchestrator/cache-manager.ts +1 -107
- package/src/orchestrator/pipeline.ts +58 -433
- package/src/orchestrator/reporter.ts +1 -1
- package/src/orchestrator/screen-manager.ts +1 -1
- package/src/utils/feature-finder.ts +33 -0
- package/src/utils/screen-paths.ts +37 -0
- package/src/utils/selector-loader.ts +23 -0
- package/src/utils/selector-types.ts +17 -0
- package/src/utils/test-data-loader.ts +23 -0
- package/src/utils/yaml-io.ts +33 -0
- package/dist/cli/commands/auto-tag-command.d.ts +0 -8
- package/dist/cli/commands/auto-tag-command.d.ts.map +0 -1
- package/dist/cli/commands/auto-tag-command.js +0 -104
- package/dist/cli/commands/auto-tag-command.js.map +0 -1
- package/dist/cli/commands/live-scan-command.d.ts +0 -9
- package/dist/cli/commands/live-scan-command.d.ts.map +0 -1
- package/dist/cli/commands/live-scan-command.js.map +0 -1
- package/dist/executor/playwright/playwright-generator.d.ts +0 -33
- package/dist/executor/playwright/playwright-generator.d.ts.map +0 -1
- package/dist/executor/playwright/playwright-generator.js +0 -136
- package/dist/executor/playwright/playwright-generator.js.map +0 -1
- package/dist/executor/test-generator.d.ts.map +0 -1
- package/dist/executor/test-generator.js +0 -30
- package/dist/executor/test-generator.js.map +0 -1
- package/dist/generators/cli.d.ts +0 -7
- package/dist/generators/cli.d.ts.map +0 -1
- package/dist/generators/cli.js +0 -570
- package/dist/generators/cli.js.map +0 -1
- package/dist/input/cli-adapter.d.ts +0 -75
- package/dist/input/cli-adapter.d.ts.map +0 -1
- package/dist/input/cli-adapter.js +0 -218
- package/dist/input/cli-adapter.js.map +0 -1
- package/dist/input/config-adapter.d.ts +0 -25
- package/dist/input/config-adapter.d.ts.map +0 -1
- package/dist/input/config-adapter.js +0 -70
- package/dist/input/config-adapter.js.map +0 -1
- package/dist/input/input-adapter.d.ts +0 -28
- package/dist/input/input-adapter.d.ts.map +0 -1
- package/dist/input/input-adapter.js +0 -17
- package/dist/input/input-adapter.js.map +0 -1
- package/dist/input/vscode-adapter.d.ts +0 -62
- package/dist/input/vscode-adapter.d.ts.map +0 -1
- package/dist/input/vscode-adapter.js +0 -64
- package/dist/input/vscode-adapter.js.map +0 -1
- package/dist/tools/auto-tagger.d.ts +0 -107
- package/dist/tools/auto-tagger.d.ts.map +0 -1
- package/dist/tools/auto-tagger.js +0 -502
- package/dist/tools/auto-tagger.js.map +0 -1
- package/src/cli/commands/auto-tag-command.ts +0 -80
- package/src/executor/playwright/playwright-generator.ts +0 -125
- package/src/executor/test-generator.ts +0 -90
- package/src/generators/cli.ts +0 -640
- package/src/input/cli-adapter.ts +0 -233
- package/src/input/config-adapter.ts +0 -71
- package/src/input/input-adapter.ts +0 -32
- package/src/input/vscode-adapter.ts +0 -90
- package/src/tools/auto-tagger.ts +0 -572
|
@@ -50,17 +50,19 @@ export async function findElement(
|
|
|
50
50
|
try {
|
|
51
51
|
playwrightName = await result.locator.evaluate((el) => {
|
|
52
52
|
// computedRole/computedLabel not available in all browsers, fallback to aria
|
|
53
|
-
|
|
53
|
+
const raw = (el as any).computedName
|
|
54
54
|
|| el.getAttribute('aria-label')
|
|
55
55
|
|| el.textContent?.trim()?.substring(0, 100)
|
|
56
56
|
|| '';
|
|
57
|
+
return raw.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
57
58
|
});
|
|
58
59
|
// Better approach: use Playwright's accessibility snapshot
|
|
59
60
|
const ariaSnapshot = await result.locator.ariaSnapshot();
|
|
60
61
|
// Parse accessible name from snapshot (format: "- role \"name\"" or "- role \"name\": ...")
|
|
61
|
-
|
|
62
|
+
// Regex handles escaped quotes (\") inside the name string
|
|
63
|
+
const nameMatch = ariaSnapshot?.match(/"((?:[^"\\]|\\.)*)"/);
|
|
62
64
|
if (nameMatch) {
|
|
63
|
-
playwrightName = nameMatch[1];
|
|
65
|
+
playwrightName = unescapeAriaSnapshot(nameMatch[1]);
|
|
64
66
|
}
|
|
65
67
|
} catch {
|
|
66
68
|
playwrightName = attrs.accessibleName || gherkinRef;
|
|
@@ -103,7 +105,7 @@ async function cascadingSearch(
|
|
|
103
105
|
// ② getByRole — exact role match
|
|
104
106
|
const roles = getRoleFallbacks(gherkinType);
|
|
105
107
|
if (roles.length > 0) {
|
|
106
|
-
const exactResult = await tryRole(page, roles[0], namePattern, nth);
|
|
108
|
+
const exactResult = await tryRole(page, roles[0], gherkinRef, namePattern, nth);
|
|
107
109
|
if (exactResult) {
|
|
108
110
|
return {
|
|
109
111
|
...exactResult,
|
|
@@ -114,7 +116,7 @@ async function cascadingSearch(
|
|
|
114
116
|
|
|
115
117
|
// ③ getByRole — fallback roles
|
|
116
118
|
for (let i = 1; i < roles.length; i++) {
|
|
117
|
-
const fallbackResult = await tryRole(page, roles[i], namePattern, nth);
|
|
119
|
+
const fallbackResult = await tryRole(page, roles[i], gherkinRef, namePattern, nth);
|
|
118
120
|
if (fallbackResult) {
|
|
119
121
|
return {
|
|
120
122
|
...fallbackResult,
|
|
@@ -126,16 +128,16 @@ async function cascadingSearch(
|
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
// ④ getByLabel — for form elements
|
|
129
|
-
const labelResult = await tryLabel(page, namePattern, nth);
|
|
131
|
+
const labelResult = await tryLabel(page, gherkinRef, namePattern, nth);
|
|
130
132
|
if (labelResult) return labelResult;
|
|
131
133
|
|
|
132
134
|
// ⑤ getByPlaceholder — for input fields
|
|
133
|
-
const placeholderResult = await tryPlaceholder(page, namePattern, nth);
|
|
135
|
+
const placeholderResult = await tryPlaceholder(page, gherkinRef, namePattern, nth);
|
|
134
136
|
if (placeholderResult) return placeholderResult;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
139
|
// ⑥ getByText — final fallback
|
|
138
|
-
const textResult = await tryText(page, namePattern, nth);
|
|
140
|
+
const textResult = await tryText(page, gherkinRef, namePattern, nth);
|
|
139
141
|
if (textResult) return textResult;
|
|
140
142
|
|
|
141
143
|
return null;
|
|
@@ -171,13 +173,36 @@ async function tryTestId(page: Page, ref: string, nth: number): Promise<FindResu
|
|
|
171
173
|
return null;
|
|
172
174
|
}
|
|
173
175
|
|
|
174
|
-
// ② ③ getByRole
|
|
176
|
+
// ② ③ getByRole — exact string first, then regex fallback
|
|
175
177
|
async function tryRole(
|
|
176
178
|
page: Page,
|
|
177
179
|
role: string,
|
|
180
|
+
gherkinRef: string,
|
|
178
181
|
namePattern: RegExp,
|
|
179
182
|
nth: number
|
|
180
183
|
): Promise<FindResult | null> {
|
|
184
|
+
// Step 1: Exact string match (prevents short refs matching longer names)
|
|
185
|
+
try {
|
|
186
|
+
const exactLocator = page.getByRole(role as any, { name: gherkinRef, exact: true });
|
|
187
|
+
const exactCount = await exactLocator.count();
|
|
188
|
+
if (exactCount > 0) {
|
|
189
|
+
const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
|
|
190
|
+
if (await target.isVisible({ timeout: 3000 })) {
|
|
191
|
+
return {
|
|
192
|
+
locator: target,
|
|
193
|
+
selectorType: 'role',
|
|
194
|
+
selectorValue: role,
|
|
195
|
+
role: role,
|
|
196
|
+
matchMethod: 'exact_role',
|
|
197
|
+
warning: null,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
// Exact match not found, continue to regex
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Step 2: Regex fallback (substring match)
|
|
181
206
|
try {
|
|
182
207
|
const locator = page.getByRole(role as any, { name: namePattern });
|
|
183
208
|
const count = await locator.count();
|
|
@@ -204,8 +229,30 @@ async function tryRole(
|
|
|
204
229
|
return null;
|
|
205
230
|
}
|
|
206
231
|
|
|
207
|
-
// ④ getByLabel
|
|
208
|
-
async function tryLabel(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
232
|
+
// ④ getByLabel — exact string first, then regex fallback
|
|
233
|
+
async function tryLabel(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
234
|
+
// Step 1: Exact string match
|
|
235
|
+
try {
|
|
236
|
+
const exactLocator = page.getByLabel(gherkinRef, { exact: true });
|
|
237
|
+
const exactCount = await exactLocator.count();
|
|
238
|
+
if (exactCount > 0) {
|
|
239
|
+
const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
|
|
240
|
+
if (await target.isVisible({ timeout: 3000 })) {
|
|
241
|
+
return {
|
|
242
|
+
locator: target,
|
|
243
|
+
selectorType: 'label',
|
|
244
|
+
selectorValue: '', // Will be filled from attrs
|
|
245
|
+
role: '',
|
|
246
|
+
matchMethod: 'label',
|
|
247
|
+
warning: null,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
// Exact match not found, continue to regex
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Step 2: Regex fallback
|
|
209
256
|
try {
|
|
210
257
|
const locator = page.getByLabel(namePattern);
|
|
211
258
|
const count = await locator.count();
|
|
@@ -228,19 +275,42 @@ async function tryLabel(page: Page, namePattern: RegExp, nth: number): Promise<F
|
|
|
228
275
|
return null;
|
|
229
276
|
}
|
|
230
277
|
|
|
231
|
-
// ⑤ getByPlaceholder
|
|
232
|
-
async function tryPlaceholder(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
278
|
+
// ⑤ getByPlaceholder — exact string first, then regex fallback
|
|
279
|
+
async function tryPlaceholder(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
280
|
+
// Step 1: Exact string match
|
|
281
|
+
try {
|
|
282
|
+
const exactLocator = page.getByPlaceholder(gherkinRef, { exact: true });
|
|
283
|
+
const exactCount = await exactLocator.count();
|
|
284
|
+
if (exactCount > 0) {
|
|
285
|
+
const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
|
|
286
|
+
if (await target.isVisible({ timeout: 3000 })) {
|
|
287
|
+
const rawPlaceholder = await target.getAttribute('placeholder');
|
|
288
|
+
return {
|
|
289
|
+
locator: target,
|
|
290
|
+
selectorType: 'placeholder',
|
|
291
|
+
selectorValue: sanitizeText(rawPlaceholder || ''),
|
|
292
|
+
role: '',
|
|
293
|
+
matchMethod: 'placeholder',
|
|
294
|
+
warning: null,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
// Exact match not found, continue to regex
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Step 2: Regex fallback
|
|
233
303
|
try {
|
|
234
304
|
const locator = page.getByPlaceholder(namePattern);
|
|
235
305
|
const count = await locator.count();
|
|
236
306
|
if (count > 0) {
|
|
237
307
|
const target = nth > 0 ? locator.nth(nth) : locator.first();
|
|
238
308
|
if (await target.isVisible({ timeout: 3000 })) {
|
|
239
|
-
const
|
|
309
|
+
const rawPlaceholder = await target.getAttribute('placeholder');
|
|
240
310
|
return {
|
|
241
311
|
locator: target,
|
|
242
312
|
selectorType: 'placeholder',
|
|
243
|
-
selectorValue:
|
|
313
|
+
selectorValue: sanitizeText(rawPlaceholder || ''),
|
|
244
314
|
role: '',
|
|
245
315
|
matchMethod: 'placeholder',
|
|
246
316
|
warning: null,
|
|
@@ -253,8 +323,30 @@ async function tryPlaceholder(page: Page, namePattern: RegExp, nth: number): Pro
|
|
|
253
323
|
return null;
|
|
254
324
|
}
|
|
255
325
|
|
|
256
|
-
// ⑥ getByText
|
|
257
|
-
async function tryText(page: Page, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
326
|
+
// ⑥ getByText — exact string first, then regex fallback
|
|
327
|
+
async function tryText(page: Page, gherkinRef: string, namePattern: RegExp, nth: number): Promise<FindResult | null> {
|
|
328
|
+
// Step 1: Exact string match
|
|
329
|
+
try {
|
|
330
|
+
const exactLocator = page.getByText(gherkinRef, { exact: true });
|
|
331
|
+
const exactCount = await exactLocator.count();
|
|
332
|
+
if (exactCount > 0) {
|
|
333
|
+
const target = nth > 0 ? exactLocator.nth(nth) : exactLocator.first();
|
|
334
|
+
if (await target.isVisible({ timeout: 3000 })) {
|
|
335
|
+
return {
|
|
336
|
+
locator: target,
|
|
337
|
+
selectorType: 'text',
|
|
338
|
+
selectorValue: '', // Will be filled from attrs
|
|
339
|
+
role: '',
|
|
340
|
+
matchMethod: 'text_only',
|
|
341
|
+
warning: null,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} catch {
|
|
346
|
+
// Exact match not found, continue to regex
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Step 2: Regex fallback
|
|
258
350
|
try {
|
|
259
351
|
const locator = page.getByText(namePattern);
|
|
260
352
|
const count = await locator.count();
|
|
@@ -286,21 +378,25 @@ async function extractElementAttributes(locator: Locator): Promise<{
|
|
|
286
378
|
}> {
|
|
287
379
|
try {
|
|
288
380
|
return await locator.evaluate((el) => {
|
|
381
|
+
// Inline sanitizer — browser context can't access Node functions
|
|
382
|
+
const clean = (s: string | null | undefined): string =>
|
|
383
|
+
(s || '').replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
384
|
+
|
|
289
385
|
// Find associated label
|
|
290
386
|
let label: string | null = null;
|
|
291
387
|
if (el.id) {
|
|
292
388
|
const labelEl = el.ownerDocument.querySelector(`label[for="${el.id}"]`);
|
|
293
|
-
if (labelEl) label = labelEl.textContent
|
|
389
|
+
if (labelEl) label = clean(labelEl.textContent) || null;
|
|
294
390
|
}
|
|
295
391
|
if (!label && el.closest('label')) {
|
|
296
|
-
label = el.closest('label')?.textContent
|
|
392
|
+
label = clean(el.closest('label')?.textContent) || null;
|
|
297
393
|
}
|
|
298
394
|
|
|
299
395
|
return {
|
|
300
396
|
testid: el.getAttribute('data-testid'),
|
|
301
397
|
tag: el.tagName.toLowerCase(),
|
|
302
|
-
accessibleName: el.getAttribute('aria-label') || el.textContent?.trim()?.substring(0, 100)
|
|
303
|
-
placeholder: el.getAttribute('placeholder'),
|
|
398
|
+
accessibleName: clean(el.getAttribute('aria-label') || el.textContent?.trim()?.substring(0, 100)),
|
|
399
|
+
placeholder: clean(el.getAttribute('placeholder')) || null,
|
|
304
400
|
label,
|
|
305
401
|
};
|
|
306
402
|
});
|
|
@@ -328,6 +424,31 @@ function buildUnresolvedElement(gherkinRef: string, gherkinType: string): LiveEl
|
|
|
328
424
|
};
|
|
329
425
|
}
|
|
330
426
|
|
|
427
|
+
/**
|
|
428
|
+
* Normalize a DOM text value for YAML output:
|
|
429
|
+
* collapse real newlines/tabs/carriage-returns into spaces, then deduplicate whitespace.
|
|
430
|
+
* Runs in both browser evaluate() and Node context.
|
|
431
|
+
*/
|
|
432
|
+
function sanitizeText(str: string): string {
|
|
433
|
+
return str.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Unescape a string extracted from Playwright's ariaSnapshot() output.
|
|
438
|
+
* ariaSnapshot encodes special chars as literal escape sequences:
|
|
439
|
+
* \n → newline, \t → tab, \\ → backslash, \" → quote
|
|
440
|
+
* We unescape them then normalize whitespace.
|
|
441
|
+
*/
|
|
442
|
+
function unescapeAriaSnapshot(str: string): string {
|
|
443
|
+
return str
|
|
444
|
+
.replace(/\\n/g, ' ')
|
|
445
|
+
.replace(/\\t/g, ' ')
|
|
446
|
+
.replace(/\\"/g, '"')
|
|
447
|
+
.replace(/\\\\/g, '\\')
|
|
448
|
+
.replace(/\s+/g, ' ')
|
|
449
|
+
.trim();
|
|
450
|
+
}
|
|
451
|
+
|
|
331
452
|
function escapeRegex(str: string): string {
|
|
332
453
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
333
454
|
}
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* Merges elements across scenarios (first match wins).
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
8
|
-
import * as yaml from 'yaml';
|
|
7
|
+
import { readYamlIfExists } from '../../utils/yaml-io';
|
|
9
8
|
import { LiveElement, LiveScanResult } from './types';
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -13,12 +12,7 @@ import { LiveElement, LiveScanResult } from './types';
|
|
|
13
12
|
* Returns null if file doesn't exist.
|
|
14
13
|
*/
|
|
15
14
|
export function readMatrix(filePath: string): LiveScanResult | null {
|
|
16
|
-
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
21
|
-
const parsed = yaml.parse(content);
|
|
15
|
+
const parsed = readYamlIfExists<any>(filePath);
|
|
22
16
|
|
|
23
17
|
if (!parsed || !parsed.scenarios) {
|
|
24
18
|
return null;
|
|
@@ -7,6 +7,16 @@ import * as fs from 'fs';
|
|
|
7
7
|
import * as yaml from 'yaml';
|
|
8
8
|
import { LiveScanResult } from './types';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Sanitize a string value before YAML serialization:
|
|
12
|
+
* collapse newlines/tabs/carriage-returns into spaces to prevent
|
|
13
|
+
* broken escape sequences (e.g. \\n) in QUOTE_DOUBLE output.
|
|
14
|
+
*/
|
|
15
|
+
function sanitizeForYaml(value: string | null): string | null {
|
|
16
|
+
if (!value) return value;
|
|
17
|
+
return value.replace(/[\n\r\t]/g, ' ').replace(/\s+/g, ' ').trim() || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export function writeMatrix(result: LiveScanResult, outputPath: string): void {
|
|
11
21
|
const output: any = {
|
|
12
22
|
screen: result.screen,
|
|
@@ -31,13 +41,13 @@ export function writeMatrix(result: LiveScanResult, outputPath: string): void {
|
|
|
31
41
|
scenarioData.elements[elementKey] = {
|
|
32
42
|
gherkin_type: element.gherkinType,
|
|
33
43
|
selector_type: element.selectorType,
|
|
34
|
-
selector_value: element.selectorValue,
|
|
44
|
+
selector_value: sanitizeForYaml(element.selectorValue),
|
|
35
45
|
role: element.role,
|
|
36
|
-
name: element.name,
|
|
46
|
+
name: sanitizeForYaml(element.name),
|
|
37
47
|
testid: element.testid,
|
|
38
48
|
tag: element.tag,
|
|
39
|
-
placeholder: element.placeholder,
|
|
40
|
-
label: element.label,
|
|
49
|
+
placeholder: sanitizeForYaml(element.placeholder),
|
|
50
|
+
label: sanitizeForYaml(element.label),
|
|
41
51
|
context: element.context,
|
|
42
52
|
match_method: element.matchMethod,
|
|
43
53
|
exact: element.exact,
|
|
@@ -100,6 +100,12 @@ export async function replaySteps(
|
|
|
100
100
|
const key = conflictKeys.has(baseKey) ? `${baseKey}--${normalizedType}` : baseKey;
|
|
101
101
|
const nth = step.nth || 0;
|
|
102
102
|
|
|
103
|
+
// Skip column-type elements — they use header text matching, no DOM lookup needed
|
|
104
|
+
if (normalizedType === 'column') {
|
|
105
|
+
console.log(` ⏭️ [${step.selectorRef}] column → skipped (table header match)`);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
103
109
|
// Skip if element already resolved in existing scan (non-force mode)
|
|
104
110
|
if (existingElements && existingElements[key] && existingElements[key].matchMethod !== 'unresolved') {
|
|
105
111
|
elements[key] = existingElements[key];
|
|
@@ -279,6 +285,7 @@ function normalizeElementType(elementType: string, action: string): string {
|
|
|
279
285
|
if (t === 'label') return 'label';
|
|
280
286
|
if (t === 'uploader') return 'uploader';
|
|
281
287
|
if (t === 'element') return 'element';
|
|
288
|
+
if (t === 'column' || t === 'columnheader') return 'column';
|
|
282
289
|
if (t === 'logo' || t === 'image' || t === 'img' || t === 'icon') return 'img';
|
|
283
290
|
if (t === 'dialog' || t === 'modal') return 'dialog';
|
|
284
291
|
if (t === 'heading' || t === 'header') return 'heading';
|
|
@@ -8,10 +8,11 @@ import * as path from 'path';
|
|
|
8
8
|
import yaml from 'yaml';
|
|
9
9
|
import { ValidationIssue } from './index';
|
|
10
10
|
import { SelectorResolver } from '../../generators/test-generator/utils/selector-resolver';
|
|
11
|
+
import { VALID_SELECTOR_TYPES, SelectorType } from '../../utils/selector-types';
|
|
11
12
|
|
|
12
13
|
interface SelectorEntry {
|
|
13
14
|
selector?: string;
|
|
14
|
-
type?:
|
|
15
|
+
type?: SelectorType;
|
|
15
16
|
value?: string;
|
|
16
17
|
name?: string;
|
|
17
18
|
nth?: number;
|
|
@@ -19,7 +20,7 @@ interface SelectorEntry {
|
|
|
19
20
|
|
|
20
21
|
type SelectorFile = Record<string, SelectorEntry>;
|
|
21
22
|
|
|
22
|
-
const VALID_TYPES =
|
|
23
|
+
const VALID_TYPES = VALID_SELECTOR_TYPES;
|
|
23
24
|
|
|
24
25
|
export class SelectorValidator {
|
|
25
26
|
private screenName: string;
|
|
@@ -8,10 +8,11 @@ import path from 'path';
|
|
|
8
8
|
import yaml from 'yaml';
|
|
9
9
|
import { glob } from 'glob';
|
|
10
10
|
import { SelectorResolver } from '../test-generator/utils/selector-resolver';
|
|
11
|
+
import { SelectorType } from '../../utils/selector-types';
|
|
11
12
|
|
|
12
13
|
export interface ScaffoldElement {
|
|
13
14
|
locator: string;
|
|
14
|
-
type:
|
|
15
|
+
type: SelectorType;
|
|
15
16
|
value: string;
|
|
16
17
|
name?: string; // For role type (accessible name), or label text
|
|
17
18
|
nth: number;
|
|
@@ -176,6 +177,9 @@ export class ScaffoldGenerator {
|
|
|
176
177
|
if (/^element\b/.test(lowerText) || /^\d*\s*element\b/.test(lowerText)) {
|
|
177
178
|
return 'element';
|
|
178
179
|
}
|
|
180
|
+
if (/^(column|columnheader)\b/.test(lowerText) || /^\d*\s*(column|columnheader)\b/.test(lowerText)) {
|
|
181
|
+
return 'column';
|
|
182
|
+
}
|
|
179
183
|
if (/^(logo|image|img|icon)\b/.test(lowerText) || /^\d*\s*(logo|image|img|icon)\b/.test(lowerText)) {
|
|
180
184
|
return 'img';
|
|
181
185
|
}
|
|
@@ -395,9 +399,19 @@ export class ScaffoldGenerator {
|
|
|
395
399
|
};
|
|
396
400
|
|
|
397
401
|
case 'see':
|
|
402
|
+
// Column type: used for table column cell assertions, no DOM selector needed
|
|
403
|
+
if (targetType === 'column') {
|
|
404
|
+
return {
|
|
405
|
+
locator: '',
|
|
406
|
+
type: 'column',
|
|
407
|
+
value: element.rawText,
|
|
408
|
+
nth,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
398
412
|
// For assertions - respect targetType for role-based elements
|
|
399
413
|
if (targetType === 'img' || targetType === 'button' || targetType === 'link' ||
|
|
400
|
-
targetType === 'checkbox' || targetType === 'radio' || targetType === 'heading' || targetType === 'dialog') {
|
|
414
|
+
targetType === 'checkbox' || targetType === 'radio' || targetType === 'heading' || targetType === 'dialog' || targetType === 'dropdown') {
|
|
401
415
|
const seeRoleValue = this.getRoleValue(targetType);
|
|
402
416
|
return {
|
|
403
417
|
locator: '',
|
|
@@ -469,6 +483,8 @@ export class ScaffoldGenerator {
|
|
|
469
483
|
return 'heading';
|
|
470
484
|
case 'dialog':
|
|
471
485
|
return 'dialog';
|
|
486
|
+
case 'dropdown':
|
|
487
|
+
return 'button';
|
|
472
488
|
default:
|
|
473
489
|
return 'button'; // Default to button
|
|
474
490
|
}
|
|
@@ -643,6 +659,11 @@ export class ScaffoldGenerator {
|
|
|
643
659
|
const enriched: ScaffoldResult = { ...scaffold };
|
|
644
660
|
|
|
645
661
|
for (const [key, scaffoldElement] of Object.entries(enriched)) {
|
|
662
|
+
// Column-type elements use header text matching, skip live-scan enrichment
|
|
663
|
+
if (scaffoldElement.type === 'column') continue;
|
|
664
|
+
// Target elements (empty value) are matched by data value at runtime, skip enrichment
|
|
665
|
+
if (!scaffoldElement.value && !scaffoldElement.name) continue;
|
|
666
|
+
|
|
646
667
|
// Try exact key first, then base key without --N suffix or --type suffix
|
|
647
668
|
let liveElement = elements[key];
|
|
648
669
|
if (!liveElement && key.includes('--')) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
await page.getByRole('{{role}}').filter({ hasText: '{{escapeQuotes dataValue}}' }).waitFor({ state: '{{state}}' });
|
package/src/generators/test-generator/adapters/playwright/templates/steps/actions/wait-for-role.hbs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
await page.getByRole('{{role}}').waitFor({ state: '{{state}}' });
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeChecked();
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
const {{columnIndexVar}} = (await page.getByRole('columnheader').allTextContents()).findIndex(h => h.includes('{{columnName}}'));
|
|
3
|
+
await expect(page.getByRole('row').nth({{rowNth}}).getByRole('cell').nth({{columnIndexVar}})).toHaveText('{{dataValue}}');
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toContainText('{{expectedText}}');
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toHaveCount({{expectedCount}});
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeDisabled();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeDisabled();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
1
2
|
{{#if name}}
|
|
2
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText:
|
|
3
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
|
|
3
4
|
{{else}}
|
|
4
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText:
|
|
5
|
-
{{/if}}
|
|
5
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
|
|
6
|
+
{{/if}}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeDisabled();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeEmpty();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeEnabled();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeFocused();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toHaveText('{{expectedText}}');
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeHidden();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
1
2
|
{{#if name}}
|
|
2
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText:
|
|
3
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
|
|
3
4
|
{{else}}
|
|
4
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText:
|
|
5
|
-
{{/if}}
|
|
5
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
|
|
6
|
+
{{/if}}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect(page.getByText('{{escapeQuotes selectorRef}}').filter({ hasText: {{#if (eq selectorValue "")}}/.*{{escapeRegex dataValue}}$/{{else}}'{{escapeQuotes dataValue}}'{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeHidden();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}.getByRole('listitem')).toHaveCount({{expectedCount}});
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeChecked({ checked: false });
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator}}).toBeVisible();
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect({{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}).toBeVisible();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
1
2
|
{{#if name}}
|
|
2
3
|
{{#if dataValue}}
|
|
3
|
-
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText:
|
|
4
|
+
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
|
|
4
5
|
{{else}}
|
|
5
6
|
await expect(page.getByRole('{{role}}', { name: '{{escapeQuotes name}}'{{#if exact}}, exact: true{{/if}} }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
|
|
6
7
|
{{/if}}
|
|
7
8
|
{{else}}
|
|
8
|
-
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText:
|
|
9
|
-
{{/if}}
|
|
9
|
+
await expect(page.getByRole('{{role}}'{{#if exact}}, { exact: true }{{/if}}).filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{#if (gt nth 0)}}.nth({{subtract nth 1}}){{/if}}).toBeVisible();
|
|
10
|
+
{{/if}}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
await
|
|
1
|
+
await page.waitForLoadState('networkidle');
|
|
2
|
+
await expect(page.getByText('{{escapeQuotes value}}').filter({ hasText: /^{{escapeRegex dataValue}}$/ })).toBeVisible();
|
package/src/generators/test-generator/adapters/playwright/templates/steps/navigation/navigation.hbs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
await page.goto('{{#if baseURL}}{{baseURL}}{{/if}}{{path}}');
|
|
1
|
+
await page.goto('{{#if baseURL}}{{baseURL}}{{/if}}{{path}}', { waitUntil: 'networkidle' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
await {{> locator-base}}.filter({ hasText:
|
|
1
|
+
await {{> locator-base}}.filter({ hasText: /^{{escapeRegex dataValue}}$/ }){{> locator-nth}}.waitFor({ state: '{{state}}' });
|