swipium 1.5.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +171 -0
- package/README.md +173 -280
- package/THREAT_MODEL.md +223 -47
- package/dist/appMap/automationLink.js +30 -27
- package/dist/appMap/automationLink.js.map +1 -1
- package/dist/appMap/build.js +47 -21
- package/dist/appMap/build.js.map +1 -1
- package/dist/appMap/codeIndex.js +2 -2
- package/dist/appMap/codeIndex.js.map +1 -1
- package/dist/appMap/featureIndex.js +3 -3
- package/dist/appMap/featureIndex.js.map +1 -1
- package/dist/appMap/featureModel.js +2 -2
- package/dist/appMap/featureModel.js.map +1 -1
- package/dist/appMap/firstRunApply.js +2 -2
- package/dist/appMap/firstRunApply.js.map +1 -1
- package/dist/appMap/issues.js +10 -10
- package/dist/appMap/issues.js.map +1 -1
- package/dist/appMap/migrations.js +5 -5
- package/dist/appMap/migrations.js.map +1 -1
- package/dist/appMap/prelaunch.js +2 -2
- package/dist/appMap/prelaunch.js.map +1 -1
- package/dist/appMap/projectRegistry.js +77 -11
- package/dist/appMap/projectRegistry.js.map +1 -1
- package/dist/appMap/provenance.js +2 -2
- package/dist/appMap/provenance.js.map +1 -1
- package/dist/appMap/query.js +2 -2
- package/dist/appMap/query.js.map +1 -1
- package/dist/appMap/runtimeMerge.js +3 -3
- package/dist/appMap/runtimeMerge.js.map +1 -1
- package/dist/appMap/schema.js +1 -1
- package/dist/appMap/schema.js.map +1 -1
- package/dist/appMap/screenMatch.js +1 -1
- package/dist/appMap/screenMatch.js.map +1 -1
- package/dist/appMap/staticScan.js +17 -17
- package/dist/appMap/staticScan.js.map +1 -1
- package/dist/appMap/store.js +55 -7
- package/dist/appMap/store.js.map +1 -1
- package/dist/appMap/tsAstScan.js +3 -3
- package/dist/appMap/tsAstScan.js.map +1 -1
- package/dist/artifacts/bundletool.js +5 -5
- package/dist/artifacts/bundletool.js.map +1 -1
- package/dist/artifacts/resolve.js +10 -10
- package/dist/artifacts/resolve.js.map +1 -1
- package/dist/automation/capabilities.js +3 -3
- package/dist/automation/capabilities.js.map +1 -1
- package/dist/automation/gestures.js +1 -1
- package/dist/automation/gestures.js.map +1 -1
- package/dist/automation/plan.js +7 -7
- package/dist/automation/plan.js.map +1 -1
- package/dist/automation/report.js +3 -3
- package/dist/automation/report.js.map +1 -1
- package/dist/automation/selectors.js +14 -25
- package/dist/automation/selectors.js.map +1 -1
- package/dist/automation/types.js +1 -1
- package/dist/automation/types.js.map +1 -1
- package/dist/automation/waits.js +5 -5
- package/dist/automation/waits.js.map +1 -1
- package/dist/automation/webview.js +2 -2
- package/dist/automation/webview.js.map +1 -1
- package/dist/automationGen/appiumModel.js +13 -7
- package/dist/automationGen/appiumModel.js.map +1 -1
- package/dist/automationGen/ciEmitter.js +5 -5
- package/dist/automationGen/ciEmitter.js.map +1 -1
- package/dist/automationGen/identifiers.js +224 -0
- package/dist/automationGen/identifiers.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +265 -106
- package/dist/automationGen/jsEmitter.js.map +1 -1
- package/dist/automationGen/packagePatch.js +2 -2
- package/dist/automationGen/packagePatch.js.map +1 -1
- package/dist/automationGen/platformResolve.js +36 -0
- package/dist/automationGen/platformResolve.js.map +1 -0
- package/dist/automationGen/projectProfile.js +71 -26
- package/dist/automationGen/projectProfile.js.map +1 -1
- package/dist/automationGen/pythonEmitter.js +276 -105
- package/dist/automationGen/pythonEmitter.js.map +1 -1
- package/dist/automationGen/readmeEmitter.js +7 -6
- package/dist/automationGen/readmeEmitter.js.map +1 -1
- package/dist/{tools/automationGenerate.js → automationGen/run.js} +72 -113
- package/dist/automationGen/run.js.map +1 -0
- package/dist/automationGen/suitePlan.js +6 -4
- package/dist/automationGen/suitePlan.js.map +1 -1
- package/dist/automationGen/validation.js +20 -8
- package/dist/automationGen/validation.js.map +1 -1
- package/dist/build/parseBuildLog.js +2 -2
- package/dist/build/parseBuildLog.js.map +1 -1
- package/dist/build/plan.js +7 -7
- package/dist/build/plan.js.map +1 -1
- package/dist/ci/preflight.js +13 -4
- package/dist/ci/preflight.js.map +1 -1
- package/dist/cli/gc.js +74 -0
- package/dist/cli/gc.js.map +1 -0
- package/dist/cli/init.js +217 -26
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/main.js +50 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/report.js +218 -0
- package/dist/cli/report.js.map +1 -0
- package/dist/cli/scan.js +35 -14
- package/dist/cli/scan.js.map +1 -1
- package/dist/cli/suite.js +6 -6
- package/dist/cli/suite.js.map +1 -1
- package/dist/cli/verify.js +7 -7
- package/dist/cli/verify.js.map +1 -1
- package/dist/consent/consent.js +162 -5
- package/dist/consent/consent.js.map +1 -1
- package/dist/context/detect.js +45 -14
- package/dist/context/detect.js.map +1 -1
- package/dist/context/findApps.js +6 -6
- package/dist/context/findApps.js.map +1 -1
- package/dist/context/projectRoot.js +174 -19
- package/dist/context/projectRoot.js.map +1 -1
- package/dist/context/scan.js +1 -1
- package/dist/context/scan.js.map +1 -1
- package/dist/core/capabilityGroups.js +90 -0
- package/dist/core/capabilityGroups.js.map +1 -0
- package/dist/core/target.js +3 -3
- package/dist/core/target.js.map +1 -1
- package/dist/core/targetPlan.js +65 -62
- package/dist/core/targetPlan.js.map +1 -1
- package/dist/drivers/DirectDriver.js +300 -36
- package/dist/drivers/DirectDriver.js.map +1 -1
- package/dist/drivers/SimctlDriver.js +120 -7
- package/dist/drivers/SimctlDriver.js.map +1 -1
- package/dist/drivers/WdaDriver.js +350 -50
- package/dist/drivers/WdaDriver.js.map +1 -1
- package/dist/explore/candidates.js +2 -2
- package/dist/explore/candidates.js.map +1 -1
- package/dist/explore/graph.js +5 -5
- package/dist/explore/graph.js.map +1 -1
- package/dist/explore/policy.js +5 -5
- package/dist/explore/policy.js.map +1 -1
- package/dist/explore/runner.js +301 -284
- package/dist/explore/runner.js.map +1 -1
- package/dist/explore/signatures.js +1 -1
- package/dist/featureTesting/executionBootstrap.js +29 -30
- package/dist/featureTesting/executionBootstrap.js.map +1 -1
- package/dist/featureTesting/featureMap.js +2 -2
- package/dist/featureTesting/featureMap.js.map +1 -1
- package/dist/featureTesting/featureScope.js +12 -12
- package/dist/featureTesting/featureScope.js.map +1 -1
- package/dist/featureTesting/mapFeatureScope.js +7 -7
- package/dist/featureTesting/mapFeatureScope.js.map +1 -1
- package/dist/featureTesting/objectiveModel.js +10 -10
- package/dist/featureTesting/objectiveModel.js.map +1 -1
- package/dist/featureTesting/resultMerge.js +6 -6
- package/dist/featureTesting/resultMerge.js.map +1 -1
- package/dist/featureTesting/sources.js +4 -4
- package/dist/featureTesting/sources.js.map +1 -1
- package/dist/featureTesting/suiteBridge.js +1 -1
- package/dist/featureTesting/suiteBridge.js.map +1 -1
- package/dist/featureTesting/synonyms.js +1 -1
- package/dist/featureTesting/synonyms.js.map +1 -1
- package/dist/featureTesting/testCaseFactory.js +11 -11
- package/dist/featureTesting/testCaseFactory.js.map +1 -1
- package/dist/featureTesting/testPlan.js +3 -3
- package/dist/featureTesting/testPlan.js.map +1 -1
- package/dist/firstRun/authStateMachine.js +1 -1
- package/dist/firstRun/authStateMachine.js.map +1 -1
- package/dist/firstRun/classifyScreen.js +5 -5
- package/dist/firstRun/classifyScreen.js.map +1 -1
- package/dist/firstRun/firstRunPlanner.js +11 -11
- package/dist/firstRun/firstRunPlanner.js.map +1 -1
- package/dist/firstRun/firstRunRunner.js +8 -8
- package/dist/firstRun/firstRunRunner.js.map +1 -1
- package/dist/firstRun/generatedDataPolicy.js +9 -9
- package/dist/firstRun/generatedDataPolicy.js.map +1 -1
- package/dist/firstRun/inputPlanner.js +5 -5
- package/dist/firstRun/inputPlanner.js.map +1 -1
- package/dist/firstRun/onboardingStateMachine.js +1 -1
- package/dist/firstRun/onboardingStateMachine.js.map +1 -1
- package/dist/firstRun/paywallPolicy.js +3 -3
- package/dist/firstRun/paywallPolicy.js.map +1 -1
- package/dist/firstRun/types.js +1 -1
- package/dist/firstRun/types.js.map +1 -1
- package/dist/fixtures/catalog.js +33 -3
- package/dist/fixtures/catalog.js.map +1 -1
- package/dist/fixtures/load.js +50 -0
- package/dist/fixtures/load.js.map +1 -0
- package/dist/flows/discover.js +2 -2
- package/dist/flows/discover.js.map +1 -1
- package/dist/flows/generate.js +20 -10
- package/dist/flows/generate.js.map +1 -1
- package/dist/flows/pack.js +3 -3
- package/dist/flows/pack.js.map +1 -1
- package/dist/flows/paths.js +57 -0
- package/dist/flows/paths.js.map +1 -0
- package/dist/flows/repair.js +111 -23
- package/dist/flows/repair.js.map +1 -1
- package/dist/flows/run.js +153 -57
- package/dist/flows/run.js.map +1 -1
- package/dist/flows/schema.js +50 -5
- package/dist/flows/schema.js.map +1 -1
- package/dist/flows/seedExec.js +4 -4
- package/dist/flows/seedExec.js.map +1 -1
- package/dist/flows/templates.js +5 -5
- package/dist/index.js +50 -8
- package/dist/index.js.map +1 -1
- package/dist/issues/classify.js +16 -16
- package/dist/issues/classify.js.map +1 -1
- package/dist/issues/fingerprint.js +24 -4
- package/dist/issues/fingerprint.js.map +1 -1
- package/dist/issues/index.js +94 -31
- package/dist/issues/index.js.map +1 -1
- package/dist/issues/metrics.js +4 -4
- package/dist/issues/metrics.js.map +1 -1
- package/dist/issues/recurrence.js +35 -8
- package/dist/issues/recurrence.js.map +1 -1
- package/dist/issues/report.js +4 -4
- package/dist/issues/report.js.map +1 -1
- package/dist/issues/reportBridge.js +4 -4
- package/dist/issues/reportBridge.js.map +1 -1
- package/dist/issues/schema.js +2 -2
- package/dist/issues/schema.js.map +1 -1
- package/dist/issues/sourceRevision.js +2 -2
- package/dist/issues/sourceRevision.js.map +1 -1
- package/dist/issues/store.js +110 -32
- package/dist/issues/store.js.map +1 -1
- package/dist/lib/abortScope.js +48 -0
- package/dist/lib/abortScope.js.map +1 -0
- package/dist/lib/android.js +75 -7
- package/dist/lib/android.js.map +1 -1
- package/dist/lib/coordSpace.js +1 -1
- package/dist/lib/coordSpace.js.map +1 -1
- package/dist/lib/device.js +32 -7
- package/dist/lib/device.js.map +1 -1
- package/dist/lib/gestures.js +141 -0
- package/dist/lib/gestures.js.map +1 -0
- package/dist/lib/gitignore.js +4 -3
- package/dist/lib/gitignore.js.map +1 -1
- package/dist/lib/image.js +1 -1
- package/dist/lib/image.js.map +1 -1
- package/dist/lib/lockfile.js +370 -31
- package/dist/lib/lockfile.js.map +1 -1
- package/dist/lib/needsInput.js +3 -3
- package/dist/lib/needsInput.js.map +1 -1
- package/dist/lib/png.js +2 -2
- package/dist/lib/png.js.map +1 -1
- package/dist/lib/redact.js +170 -9
- package/dist/lib/redact.js.map +1 -1
- package/dist/lib/result.js +79 -10
- package/dist/lib/result.js.map +1 -1
- package/dist/lib/schemaHash.js +3 -3
- package/dist/lib/schemaHash.js.map +1 -1
- package/dist/lib/sensitive.js +3 -2
- package/dist/lib/sensitive.js.map +1 -1
- package/dist/lib/simctl.js +3 -3
- package/dist/lib/simctl.js.map +1 -1
- package/dist/lib/spawn.js +52 -10
- package/dist/lib/spawn.js.map +1 -1
- package/dist/lib/toolAnnotations.js +114 -0
- package/dist/lib/toolAnnotations.js.map +1 -0
- package/dist/lib/wda.js +294 -15
- package/dist/lib/wda.js.map +1 -1
- package/dist/mobileAudit/checks.js +12 -12
- package/dist/mobileAudit/checks.js.map +1 -1
- package/dist/mobileAudit/evidence.js +4 -4
- package/dist/mobileAudit/evidence.js.map +1 -1
- package/dist/mobileAudit/profiles.js +1 -1
- package/dist/mobileAudit/profiles.js.map +1 -1
- package/dist/mobileAudit/results.js +3 -3
- package/dist/mobileAudit/results.js.map +1 -1
- package/dist/mobileAudit/runner.js +72 -18
- package/dist/mobileAudit/runner.js.map +1 -1
- package/dist/oracle/auth.js +1 -1
- package/dist/oracle/auth.js.map +1 -1
- package/dist/oracle/failures.js +219 -36
- package/dist/oracle/failures.js.map +1 -1
- package/dist/oracle/health.js +63 -17
- package/dist/oracle/health.js.map +1 -1
- package/dist/oracle/locator.js +13 -13
- package/dist/oracle/locator.js.map +1 -1
- package/dist/oracle/record.js +3 -3
- package/dist/oracle/record.js.map +1 -1
- package/dist/orchestration/envelope.js +2 -2
- package/dist/orchestration/envelope.js.map +1 -1
- package/dist/orchestration/goal.js +4 -4
- package/dist/orchestration/goal.js.map +1 -1
- package/dist/orchestration/testThis/execute.js +62 -21
- package/dist/orchestration/testThis/execute.js.map +1 -1
- package/dist/orchestration/testThis/pipeline.js +119 -30
- package/dist/orchestration/testThis/pipeline.js.map +1 -1
- package/dist/orchestration/testThis/plan.js +162 -73
- package/dist/orchestration/testThis/plan.js.map +1 -1
- package/dist/orchestration/testThis/sessionIntent.js +72 -0
- package/dist/orchestration/testThis/sessionIntent.js.map +1 -0
- package/dist/orchestration/testThis/terminal.js +34 -16
- package/dist/orchestration/testThis/terminal.js.map +1 -1
- package/dist/orchestration/testThis/types.js +1 -1
- package/dist/orchestration/testThis/types.js.map +1 -1
- package/dist/plan/plan.js +9 -9
- package/dist/plan/plan.js.map +1 -1
- package/dist/prompts/index.js +22 -22
- package/dist/prompts/index.js.map +1 -1
- package/dist/report/export.js +392 -37
- package/dist/report/export.js.map +1 -1
- package/dist/report/findingsDedupe.js +41 -0
- package/dist/report/findingsDedupe.js.map +1 -0
- package/dist/report/policy.js +7 -4
- package/dist/report/policy.js.map +1 -1
- package/dist/report/qaLevel.js +8 -8
- package/dist/report/qaLevel.js.map +1 -1
- package/dist/report/sarifSources.js +160 -0
- package/dist/report/sarifSources.js.map +1 -0
- package/dist/report/summary.js +2 -2
- package/dist/report/summary.js.map +1 -1
- package/dist/report/testCatalog.js +4 -4
- package/dist/report/testCatalog.js.map +1 -1
- package/dist/report/toolHealth.js +124 -0
- package/dist/report/toolHealth.js.map +1 -0
- package/dist/server.js +472 -45
- package/dist/server.js.map +1 -1
- package/dist/services/automationGenerate.js +8 -2
- package/dist/services/automationGenerate.js.map +1 -1
- package/dist/services/build.js +2 -2
- package/dist/services/build.js.map +1 -1
- package/dist/{tools → services}/flowGenerate.js +29 -13
- package/dist/services/flowGenerate.js.map +1 -0
- package/dist/services/preflight.js +4 -4
- package/dist/services/preflight.js.map +1 -1
- package/dist/services/prepareAndroid.js +46 -8
- package/dist/services/prepareAndroid.js.map +1 -1
- package/dist/services/prepareIos.js +24 -9
- package/dist/services/prepareIos.js.map +1 -1
- package/dist/services/report.js +100 -45
- package/dist/services/report.js.map +1 -1
- package/dist/services/smoke.js +32 -16
- package/dist/services/smoke.js.map +1 -1
- package/dist/services/suiteGenerate.js +28 -3
- package/dist/services/suiteGenerate.js.map +1 -1
- package/dist/services/testSuiteKnowledge.js +40 -27
- package/dist/services/testSuiteKnowledge.js.map +1 -1
- package/dist/session/attach.js +270 -6
- package/dist/session/attach.js.map +1 -1
- package/dist/session/processRegistry.js +317 -48
- package/dist/session/processRegistry.js.map +1 -1
- package/dist/session/progress.js +1 -1
- package/dist/session/retention.js +201 -0
- package/dist/session/retention.js.map +1 -0
- package/dist/session/store.js +275 -48
- package/dist/session/store.js.map +1 -1
- package/dist/snapshot/overlays.js +53 -8
- package/dist/snapshot/overlays.js.map +1 -1
- package/dist/snapshot/parse.js +28 -4
- package/dist/snapshot/parse.js.map +1 -1
- package/dist/snapshot/present.js +11 -5
- package/dist/snapshot/present.js.map +1 -1
- package/dist/snapshot/settle.js +39 -9
- package/dist/snapshot/settle.js.map +1 -1
- package/dist/state/consent.js +99 -0
- package/dist/state/consent.js.map +1 -0
- package/dist/state/profile.js +46 -2
- package/dist/state/profile.js.map +1 -1
- package/dist/suite/compile.js +9 -5
- package/dist/suite/compile.js.map +1 -1
- package/dist/suite/lint.js +4 -4
- package/dist/suite/lint.js.map +1 -1
- package/dist/suite/pom.js +50 -41
- package/dist/suite/pom.js.map +1 -1
- package/dist/suite/secretGuard.js +266 -0
- package/dist/suite/secretGuard.js.map +1 -0
- package/dist/suite/testcase.js +9 -7
- package/dist/suite/testcase.js.map +1 -1
- package/dist/testSuite/exporter.js +4 -4
- package/dist/testSuite/exporter.js.map +1 -1
- package/dist/testSuite/generator.js +13 -9
- package/dist/testSuite/generator.js.map +1 -1
- package/dist/testSuite/history.js +1 -1
- package/dist/testSuite/history.js.map +1 -1
- package/dist/testSuite/issueLinks.js +3 -3
- package/dist/testSuite/issueLinks.js.map +1 -1
- package/dist/testSuite/lint.js +4 -4
- package/dist/testSuite/lint.js.map +1 -1
- package/dist/testSuite/merge.js +5 -5
- package/dist/testSuite/merge.js.map +1 -1
- package/dist/testSuite/schema.js +5 -5
- package/dist/testSuite/schema.js.map +1 -1
- package/dist/testSuite/store.js +3 -3
- package/dist/testSuite/store.js.map +1 -1
- package/dist/testSuite/traceability.js +2 -2
- package/dist/testSuite/traceability.js.map +1 -1
- package/dist/tools/act.js +794 -164
- package/dist/tools/act.js.map +1 -1
- package/dist/tools/agent.js +451 -128
- package/dist/tools/agent.js.map +1 -1
- package/dist/tools/appControl.js +69 -19
- package/dist/tools/appControl.js.map +1 -1
- package/dist/tools/appMap.js +188 -130
- package/dist/tools/appMap.js.map +1 -1
- package/dist/tools/build.js +32 -42
- package/dist/tools/build.js.map +1 -1
- package/dist/tools/bundletool.js +21 -31
- package/dist/tools/bundletool.js.map +1 -1
- package/dist/tools/clearOverlay.js +55 -12
- package/dist/tools/clearOverlay.js.map +1 -1
- package/dist/tools/device.js +76 -24
- package/dist/tools/device.js.map +1 -1
- package/dist/tools/doctor.js +68 -28
- package/dist/tools/doctor.js.map +1 -1
- package/dist/tools/explore.js +41 -47
- package/dist/tools/explore.js.map +1 -1
- package/dist/tools/featureTesting.js +31 -48
- package/dist/tools/featureTesting.js.map +1 -1
- package/dist/tools/firstRun.js +34 -41
- package/dist/tools/firstRun.js.map +1 -1
- package/dist/tools/flow.js +183 -103
- package/dist/tools/flow.js.map +1 -1
- package/dist/tools/flowRepair.js +25 -13
- package/dist/tools/flowRepair.js.map +1 -1
- package/dist/tools/generate.js +52 -89
- package/dist/tools/generate.js.map +1 -1
- package/dist/tools/getArtifact.js +16 -5
- package/dist/tools/getArtifact.js.map +1 -1
- package/dist/tools/health.js +15 -12
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/ios.js +45 -223
- package/dist/tools/ios.js.map +1 -1
- package/dist/tools/issues.js +251 -35
- package/dist/tools/issues.js.map +1 -1
- package/dist/tools/jobs.js +41 -16
- package/dist/tools/jobs.js.map +1 -1
- package/dist/tools/metro.js +36 -35
- package/dist/tools/metro.js.map +1 -1
- package/dist/tools/mobileAudit.js +50 -45
- package/dist/tools/mobileAudit.js.map +1 -1
- package/dist/tools/network.js +31 -14
- package/dist/tools/network.js.map +1 -1
- package/dist/tools/note.js +26 -26
- package/dist/tools/note.js.map +1 -1
- package/dist/tools/prepareIosTarget.js +10 -16
- package/dist/tools/prepareIosTarget.js.map +1 -1
- package/dist/tools/prepareTarget.js +117 -50
- package/dist/tools/prepareTarget.js.map +1 -1
- package/dist/tools/report.js +11 -22
- package/dist/tools/report.js.map +1 -1
- package/dist/tools/resolveArtifact.js +11 -15
- package/dist/tools/resolveArtifact.js.map +1 -1
- package/dist/tools/resolveTarget.js +78 -24
- package/dist/tools/resolveTarget.js.map +1 -1
- package/dist/tools/screenRecord.js +23 -21
- package/dist/tools/screenRecord.js.map +1 -1
- package/dist/tools/screenshot.js +23 -16
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/smoke.js +20 -16
- package/dist/tools/smoke.js.map +1 -1
- package/dist/tools/snapshot.js +155 -118
- package/dist/tools/snapshot.js.map +1 -1
- package/dist/tools/startSession.js +104 -116
- package/dist/tools/startSession.js.map +1 -1
- package/dist/tools/suite.js +72 -43
- package/dist/tools/suite.js.map +1 -1
- package/dist/tools/testSuite.js +30 -20
- package/dist/tools/testSuite.js.map +1 -1
- package/dist/tools/testThis.js +24 -28
- package/dist/tools/testThis.js.map +1 -1
- package/dist/tools/visual.js +686 -210
- package/dist/tools/visual.js.map +1 -1
- package/dist/tools/wait.js +9 -38
- package/dist/tools/wait.js.map +1 -1
- package/dist/tools/wda.js +187 -57
- package/dist/tools/wda.js.map +1 -1
- package/dist/version.js +31 -22
- package/dist/version.js.map +1 -1
- package/dist/visual/ocr.js +53 -6
- package/dist/visual/ocr.js.map +1 -1
- package/dist/visual/provider.js +80 -12
- package/dist/visual/provider.js.map +1 -1
- package/docs/README.md +24 -10
- package/docs/ci-reports.md +328 -0
- package/docs/concepts.md +227 -0
- package/docs/flows.md +153 -0
- package/docs/mcp-server.md +194 -128
- package/docs/physical-devices.md +84 -0
- package/docs/tools.md +812 -152
- package/package.json +3 -2
- package/dist/tools/assertVisual.js +0 -84
- package/dist/tools/assertVisual.js.map +0 -1
- package/dist/tools/automationGenerate.js.map +0 -1
- package/dist/tools/capabilities.js +0 -179
- package/dist/tools/capabilities.js.map +0 -1
- package/dist/tools/detectContext.js +0 -41
- package/dist/tools/detectContext.js.map +0 -1
- package/dist/tools/flowGenerate.js.map +0 -1
- package/dist/tools/history.js +0 -86
- package/dist/tools/history.js.map +0 -1
- package/dist/tools/locator.js +0 -85
- package/dist/tools/locator.js.map +0 -1
- package/dist/tools/permissions.js +0 -174
- package/dist/tools/permissions.js.map +0 -1
- package/dist/tools/plan.js +0 -52
- package/dist/tools/plan.js.map +0 -1
- package/dist/tools/screenInfo.js +0 -76
- package/dist/tools/screenInfo.js.map +0 -1
- package/dist/tools/seed.js +0 -133
- package/dist/tools/seed.js.map +0 -1
- package/dist/tools/state.js +0 -217
- package/dist/tools/state.js.map +0 -1
- package/dist/tools/visualText.js +0 -106
- package/dist/tools/visualText.js.map +0 -1
|
@@ -1,17 +1,67 @@
|
|
|
1
|
-
//
|
|
1
|
+
// JS/TS WebdriverIO + Appium emitter. Pure: turns the shared Appium model into a
|
|
2
2
|
// runnable WebdriverIO POM suite (page/screen classes with locator getters + action methods, env-
|
|
3
3
|
// driven capabilities, structured waits). No XPath is ever emitted; coordinate fallbacks are marked
|
|
4
4
|
// non-release-grade. Aligns with the Appium JS quickstart (WebdriverIO) locator-strategy guidance.
|
|
5
|
+
import { defaultPlatformOf } from './platformResolve.js';
|
|
6
|
+
import { NameAllocator, UnemittableStepError, checkDirection, checkKey, className, commentSafe, isJsIdentifier, jsMemberName, pascalWords, screensOf, } from './identifiers.js';
|
|
5
7
|
const DEFAULT_TIMEOUT = 15000;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const MAX_SCROLLS = 8;
|
|
9
|
+
/** Every member BaseScreen declares. A generated field/method must never shadow one (a field named
|
|
10
|
+
* `tap` would replace the tap() helper, and in TS it is a type error). */
|
|
11
|
+
const JS_BASE_MEMBERS = [
|
|
12
|
+
'constructor',
|
|
13
|
+
'element',
|
|
14
|
+
'tap',
|
|
15
|
+
'type',
|
|
16
|
+
'typeFocused',
|
|
17
|
+
'scrollTo',
|
|
18
|
+
'scrollToText',
|
|
19
|
+
'scrollOnce',
|
|
20
|
+
'isVisible',
|
|
21
|
+
'assertVisible',
|
|
22
|
+
'assertTextVisible',
|
|
23
|
+
'textSelector',
|
|
24
|
+
'tapAt',
|
|
25
|
+
'pressKey',
|
|
26
|
+
'swipe',
|
|
27
|
+
'openUrl',
|
|
28
|
+
];
|
|
29
|
+
function methodKey(action, element) {
|
|
30
|
+
return `${action}|${element}`;
|
|
13
31
|
}
|
|
14
|
-
|
|
32
|
+
function planJsNames(model) {
|
|
33
|
+
const classes = new NameAllocator(['BaseScreen', 'TestData', 'PlatformLocator'], (s) => s.toLowerCase());
|
|
34
|
+
const instances = new NameAllocator(['testData', 'driver', 'browser', 'describe', 'it', 'expect', '$', '$$']);
|
|
35
|
+
const plan = new Map();
|
|
36
|
+
for (const screen of screensOf(model)) {
|
|
37
|
+
const cls = classes.alloc(className(screen.className));
|
|
38
|
+
const instance = instances.alloc(cls[0].toLowerCase() + cls.slice(1));
|
|
39
|
+
const members = new NameAllocator(JS_BASE_MEMBERS);
|
|
40
|
+
const fields = new Map();
|
|
41
|
+
for (const el of screen.elements)
|
|
42
|
+
if (!fields.has(el.name))
|
|
43
|
+
fields.set(el.name, members.alloc(jsMemberName(el.name)));
|
|
44
|
+
const methods = new Map();
|
|
45
|
+
for (const s of model.steps) {
|
|
46
|
+
if (s.screen !== screen.className || !s.element)
|
|
47
|
+
continue;
|
|
48
|
+
const field = fields.get(s.element);
|
|
49
|
+
if (!field) {
|
|
50
|
+
throw new UnemittableStepError(`cannot emit ${s.action} step on ${screen.className}: element ${JSON.stringify(s.element)} is not declared on that screen`);
|
|
51
|
+
}
|
|
52
|
+
const key = methodKey(s.action, s.element);
|
|
53
|
+
if (methods.has(key))
|
|
54
|
+
continue;
|
|
55
|
+
methods.set(key, members.alloc(methodBase(s.action, pascalWords(field) || 'Element')));
|
|
56
|
+
}
|
|
57
|
+
plan.set(screen.className, { cls, instance, fields, methods });
|
|
58
|
+
}
|
|
59
|
+
return plan;
|
|
60
|
+
}
|
|
61
|
+
function jsProp(obj, key) {
|
|
62
|
+
return isJsIdentifier(key) ? `${obj}.${key}` : `${obj}[${JSON.stringify(key)}]`;
|
|
63
|
+
}
|
|
64
|
+
/** Env var (SWIPIUM_TEST_PASSWORD) > a stable testData key (password). */
|
|
15
65
|
export function varToKey(v) {
|
|
16
66
|
const stripped = v.replace(/^SWIPIUM_(TEST_)?/i, '');
|
|
17
67
|
const parts = stripped
|
|
@@ -60,8 +110,11 @@ function platformLocatorLiteral(el) {
|
|
|
60
110
|
export function emitJsSuite(input) {
|
|
61
111
|
const ts = input.language === 'typescript';
|
|
62
112
|
const ext = ts ? 'ts' : 'js';
|
|
63
|
-
const t = (annotation) => (ts ? annotation : '');
|
|
64
113
|
const files = [];
|
|
114
|
+
// Plan every class/field/method name up front (H4) and validate every step is emittable (§4);
|
|
115
|
+
// generation fails loudly here rather than writing a suite with silent no-op steps.
|
|
116
|
+
const names = planJsNames(input.model);
|
|
117
|
+
const smoke = smokeTest(input.model, names);
|
|
65
118
|
files.push({ path: 'package.json', content: packageJson(input) });
|
|
66
119
|
if (ts)
|
|
67
120
|
files.push({ path: 'tsconfig.json', content: tsconfigJson() });
|
|
@@ -70,11 +123,12 @@ export function emitJsSuite(input) {
|
|
|
70
123
|
files.push({ path: `src/utils/locators.${ext}`, content: locatorsUtil(ts) });
|
|
71
124
|
files.push({ path: `src/utils/waits.${ext}`, content: waitsUtil(ts) });
|
|
72
125
|
files.push({ path: `src/screens/BaseScreen.${ext}`, content: baseScreen(ts) });
|
|
73
|
-
for (const screen of input.model
|
|
74
|
-
|
|
126
|
+
for (const screen of screensOf(input.model)) {
|
|
127
|
+
const n = names.get(screen.className);
|
|
128
|
+
files.push({ path: `src/screens/${n.cls}.${ext}`, content: screenClass(screen, n, input.model.steps, ts) });
|
|
75
129
|
}
|
|
76
130
|
files.push({ path: `src/data/testData.${ext}`, content: testData(input.model, ts) });
|
|
77
|
-
files.push({ path: `test/smoke.e2e.${ext}`, content:
|
|
131
|
+
files.push({ path: `test/smoke.e2e.${ext}`, content: smoke });
|
|
78
132
|
return files;
|
|
79
133
|
}
|
|
80
134
|
function packageJson(input) {
|
|
@@ -84,7 +138,7 @@ function packageJson(input) {
|
|
|
84
138
|
name,
|
|
85
139
|
private: true,
|
|
86
140
|
type: 'module',
|
|
87
|
-
description: 'Generated by Swipium
|
|
141
|
+
description: 'Generated by Swipium: WebdriverIO + Appium POM suite (review before committing).',
|
|
88
142
|
scripts: {
|
|
89
143
|
test: 'wdio run ./wdio.conf.' + (ts ? 'ts' : 'js'),
|
|
90
144
|
},
|
|
@@ -115,7 +169,7 @@ function tsconfigJson() {
|
|
|
115
169
|
}, null, 2) + '\n');
|
|
116
170
|
}
|
|
117
171
|
function wdioConf(ts, ext) {
|
|
118
|
-
const header = '// Generated by Swipium. WebdriverIO + Appium config
|
|
172
|
+
const header = '// Generated by Swipium. WebdriverIO + Appium config. Capabilities come from env (see src/config/capabilities).';
|
|
119
173
|
const importLine = `import { buildCapabilities } from './src/config/capabilities.js';`;
|
|
120
174
|
const typeAnno = ts ? `\nimport type { Options } from '@wdio/types';\n` : '\n';
|
|
121
175
|
const cfgType = ts ? ': WebdriverIO.Config' : '';
|
|
@@ -139,15 +193,17 @@ export const config${cfgType} = {
|
|
|
139
193
|
`;
|
|
140
194
|
}
|
|
141
195
|
function capabilities(input, ts) {
|
|
142
|
-
const
|
|
196
|
+
const primary = defaultPlatformOf(input.profile, input.model);
|
|
143
197
|
const ret = ts ? ': WebdriverIO.Capabilities' : '';
|
|
144
198
|
const appId = input.appId ?? '';
|
|
145
199
|
const lines = [];
|
|
146
|
-
lines.push('// Generated by Swipium. ALL device/app config is environment-driven
|
|
147
|
-
lines.push(
|
|
200
|
+
lines.push('// Generated by Swipium. ALL device/app config is environment-driven: no secrets, no hardcoded paths.');
|
|
201
|
+
lines.push(primary === 'ios'
|
|
202
|
+
? '// iOS (XCUITest) is the default for this suite; set SWIPIUM_PLATFORM=android to target Android (UiAutomator2).'
|
|
203
|
+
: '// Android (UiAutomator2) is the default for this suite; set SWIPIUM_PLATFORM=ios to target iOS (XCUITest).');
|
|
148
204
|
lines.push('');
|
|
149
205
|
lines.push(`export function buildCapabilities()${ret} {`);
|
|
150
|
-
lines.push(` const platform = (process.env.SWIPIUM_PLATFORM || ${JSON.stringify(
|
|
206
|
+
lines.push(` const platform = (process.env.SWIPIUM_PLATFORM || ${JSON.stringify(primary)}).toLowerCase();`);
|
|
151
207
|
lines.push(" if (platform === 'ios') {");
|
|
152
208
|
lines.push(' return {');
|
|
153
209
|
lines.push(" platformName: 'iOS',");
|
|
@@ -160,7 +216,7 @@ function capabilities(input, ts) {
|
|
|
160
216
|
lines.push(" 'appium:noReset': process.env.SWIPIUM_NO_RESET === 'true',");
|
|
161
217
|
lines.push(' };');
|
|
162
218
|
lines.push(' }');
|
|
163
|
-
lines.push(' // Android UiAutomator2
|
|
219
|
+
lines.push(' // Android UiAutomator2.');
|
|
164
220
|
lines.push(' return {');
|
|
165
221
|
lines.push(" platformName: 'Android',");
|
|
166
222
|
lines.push(" 'appium:automationName': 'UiAutomator2',");
|
|
@@ -177,7 +233,7 @@ function capabilities(input, ts) {
|
|
|
177
233
|
}
|
|
178
234
|
function locatorsUtil(ts) {
|
|
179
235
|
const typeBlock = ts
|
|
180
|
-
? `export interface PlatformLocator {\n android?: string;\n ios?: string;\n /** "x,y" coordinate fallback
|
|
236
|
+
? `export interface PlatformLocator {\n android?: string;\n ios?: string;\n /** "x,y" coordinate fallback, non-release-grade. */\n coordinate?: string;\n}\n\n`
|
|
181
237
|
: '';
|
|
182
238
|
const param = ts ? 'loc: PlatformLocator' : 'loc';
|
|
183
239
|
const ret = ts ? ': string' : '';
|
|
@@ -187,7 +243,7 @@ ${typeBlock}export function resolveSelector(${param})${ret} {
|
|
|
187
243
|
const android = typeof driver !== 'undefined' ? driver.isAndroid : true;
|
|
188
244
|
const selector = android ? loc.android : loc.ios;
|
|
189
245
|
if (!selector) {
|
|
190
|
-
throw new Error('No durable selector for this platform
|
|
246
|
+
throw new Error('No durable selector for this platform. Element relies on a coordinate fallback (non-release-grade). Add an accessibility id / resource-id / testID.');
|
|
191
247
|
}
|
|
192
248
|
return selector;
|
|
193
249
|
}
|
|
@@ -202,7 +258,7 @@ export function coordinateOf(${param})${ts ? ': [number, number] | undefined' :
|
|
|
202
258
|
function waitsUtil(ts) {
|
|
203
259
|
const elAnno = ts ? ': WebdriverIO.Element' : '';
|
|
204
260
|
const numAnno = ts ? ': number' : '';
|
|
205
|
-
return `// Generated by Swipium. Structured waits
|
|
261
|
+
return `// Generated by Swipium. Structured waits, never a bare sleep. Auto-wait before interaction
|
|
206
262
|
// (Playwright-style resilience, applied to mobile Appium).
|
|
207
263
|
export const DEFAULT_TIMEOUT = ${DEFAULT_TIMEOUT};
|
|
208
264
|
|
|
@@ -220,36 +276,92 @@ export async function waitEnabled(el${elAnno}, timeout${numAnno} = DEFAULT_TIMEO
|
|
|
220
276
|
function baseScreen(ts) {
|
|
221
277
|
const locImport = ts ? `import type { PlatformLocator } from '../utils/locators.js';\n` : '';
|
|
222
278
|
const p = (name, type) => (ts ? `${name}: ${type}` : name);
|
|
279
|
+
// H3: TS-only modifiers/annotations are gated on the TypeScript flag so the .js output parses.
|
|
280
|
+
const prot = ts ? 'protected ' : '';
|
|
281
|
+
const dirType = ts ? `: 'up' | 'down' | 'left' | 'right'` : '';
|
|
223
282
|
return `// Generated by Swipium. BaseScreen centralizes all element interaction so selectors are
|
|
224
283
|
// resolved per-platform in ONE place and tests never touch raw selectors.
|
|
225
|
-
${locImport}import { resolveSelector
|
|
226
|
-
import { waitVisible, waitEnabled
|
|
284
|
+
${locImport}import { resolveSelector } from '../utils/locators.js';
|
|
285
|
+
import { waitVisible, waitEnabled } from '../utils/waits.js';
|
|
286
|
+
|
|
287
|
+
/** Upper bound on scroll gestures while looking for an element, so never an endless loop. */
|
|
288
|
+
export const MAX_SCROLLS = ${MAX_SCROLLS};
|
|
227
289
|
|
|
228
290
|
export class BaseScreen {
|
|
229
|
-
|
|
291
|
+
${prot}async element(${p('loc', 'PlatformLocator')}) {
|
|
230
292
|
// @ts-ignore wdio global
|
|
231
293
|
return $(resolveSelector(loc));
|
|
232
294
|
}
|
|
233
295
|
|
|
234
|
-
|
|
296
|
+
${prot}async tap(${p('loc', 'PlatformLocator')}) {
|
|
235
297
|
const el = await this.element(loc);
|
|
236
298
|
await waitEnabled(await waitVisible(el));
|
|
237
299
|
await el.click();
|
|
238
300
|
}
|
|
239
301
|
|
|
240
|
-
|
|
302
|
+
${prot}async type(${p('loc', 'PlatformLocator')}, ${p('value', 'string')}) {
|
|
241
303
|
const el = await this.element(loc);
|
|
242
304
|
await waitVisible(el);
|
|
243
305
|
await el.setValue(value);
|
|
244
306
|
}
|
|
245
307
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
await
|
|
308
|
+
/** Type into whichever field currently has focus (the recording had no locator for it). */
|
|
309
|
+
async typeFocused(${p('value', 'string')}) {
|
|
310
|
+
// @ts-ignore wdio global
|
|
311
|
+
const active = await $(await driver.getActiveElement());
|
|
312
|
+
await active.addValue(value);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* One real content-scroll gesture. direction is the CONTENT direction: 'down' reveals what is below.
|
|
317
|
+
* Android: UiAutomator2 \`mobile: scrollGesture\` (returns false once the end is reached).
|
|
318
|
+
* iOS: XCUITest \`mobile: scroll\`.
|
|
319
|
+
*/
|
|
320
|
+
async scrollOnce(${p('direction', 'string')} = 'down')${ts ? ': Promise<boolean>' : ''} {
|
|
321
|
+
// @ts-ignore wdio global
|
|
322
|
+
if (driver.isAndroid) {
|
|
323
|
+
// @ts-ignore wdio global
|
|
324
|
+
const { width, height } = await driver.getWindowSize();
|
|
325
|
+
// @ts-ignore wdio global
|
|
326
|
+
const canScrollMore = await driver.execute('mobile: scrollGesture', {
|
|
327
|
+
left: Math.round(width * 0.1),
|
|
328
|
+
top: Math.round(height * 0.2),
|
|
329
|
+
width: Math.round(width * 0.8),
|
|
330
|
+
height: Math.round(height * 0.6),
|
|
331
|
+
direction,
|
|
332
|
+
percent: 0.75,
|
|
333
|
+
});
|
|
334
|
+
return canScrollMore !== false;
|
|
335
|
+
}
|
|
336
|
+
// @ts-ignore wdio global
|
|
337
|
+
await driver.execute('mobile: scroll', { direction });
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/** Scroll (bounded by maxScrolls) until the element is displayed; throws if it never appears. */
|
|
342
|
+
${prot}async scrollTo(${p('loc', 'PlatformLocator')}, ${p('direction', 'string')} = 'down', ${p('maxScrolls', 'number')} = MAX_SCROLLS) {
|
|
343
|
+
let atEnd = false;
|
|
344
|
+
for (let i = 0; i <= maxScrolls; i++) {
|
|
345
|
+
if (await this.isVisible(loc)) return;
|
|
346
|
+
if (i === maxScrolls || atEnd) break;
|
|
347
|
+
atEnd = !(await this.scrollOnce(direction));
|
|
348
|
+
}
|
|
349
|
+
throw new Error('Element not visible after scrolling ' + direction + ' (max ' + maxScrolls + ' scrolls)');
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Scroll (bounded) until an element whose text/label contains \`text\` is displayed. */
|
|
353
|
+
async scrollToText(${p('text', 'string')}, ${p('direction', 'string')} = 'down', ${p('maxScrolls', 'number')} = MAX_SCROLLS) {
|
|
354
|
+
let atEnd = false;
|
|
355
|
+
for (let i = 0; i <= maxScrolls; i++) {
|
|
356
|
+
// @ts-ignore wdio global
|
|
357
|
+
if (await $(this.textSelector(text)).isDisplayed()) return;
|
|
358
|
+
if (i === maxScrolls || atEnd) break;
|
|
359
|
+
atEnd = !(await this.scrollOnce(direction));
|
|
360
|
+
}
|
|
361
|
+
throw new Error('Text ' + JSON.stringify(text) + ' not visible after scrolling ' + direction + ' (max ' + maxScrolls + ' scrolls)');
|
|
250
362
|
}
|
|
251
363
|
|
|
252
|
-
|
|
364
|
+
${prot}async isVisible(${p('loc', 'PlatformLocator')})${ts ? ': Promise<boolean>' : ''} {
|
|
253
365
|
const el = await this.element(loc);
|
|
254
366
|
return el.isDisplayed();
|
|
255
367
|
}
|
|
@@ -259,28 +371,60 @@ export class BaseScreen {
|
|
|
259
371
|
await waitVisible(el);
|
|
260
372
|
}
|
|
261
373
|
|
|
374
|
+
/** Platform-appropriate "text contains" selector. JSON.stringify escapes backslashes and quotes. */
|
|
375
|
+
textSelector(${p('text', 'string')})${ts ? ': string' : ''} {
|
|
376
|
+
// @ts-ignore wdio global
|
|
377
|
+
if (driver.isAndroid) return 'android=new UiSelector().textContains(' + JSON.stringify(text) + ')';
|
|
378
|
+
return '-ios predicate string:label CONTAINS ' + JSON.stringify(text) + ' OR name CONTAINS ' + JSON.stringify(text);
|
|
379
|
+
}
|
|
380
|
+
|
|
262
381
|
async assertTextVisible(${p('text', 'string')}) {
|
|
263
|
-
// Non-release-grade text/OCR assertion
|
|
382
|
+
// Non-release-grade text/OCR assertion. Prefer a structured locator.
|
|
264
383
|
// @ts-ignore wdio global
|
|
265
|
-
const el = await $(
|
|
384
|
+
const el = await $(this.textSelector(text));
|
|
266
385
|
await waitVisible(el);
|
|
267
386
|
}
|
|
268
387
|
|
|
269
|
-
// Coordinate tap
|
|
388
|
+
// Coordinate tap: brittle, non-release-grade fallback. Only used when no durable locator exists.
|
|
270
389
|
async tapAt(${p('x', 'number')}, ${p('y', 'number')}) {
|
|
271
390
|
// @ts-ignore wdio global
|
|
272
|
-
await driver.action('pointer')
|
|
391
|
+
await driver.action('pointer', { parameters: { pointerType: 'touch' } })
|
|
273
392
|
.move({ x, y }).down().pause(50).up().perform();
|
|
274
393
|
}
|
|
275
394
|
|
|
276
|
-
async pressKey(${p('key', '
|
|
277
|
-
// @ts-ignore wdio global
|
|
278
|
-
if (driver.isAndroid && key === 'back') { await driver.back(); return; }
|
|
395
|
+
async pressKey(${p('key', `'back' | 'home' | 'enter'`)}) {
|
|
279
396
|
// @ts-ignore wdio global
|
|
280
|
-
|
|
397
|
+
const android = driver.isAndroid;
|
|
398
|
+
if (key === 'back') {
|
|
399
|
+
// @ts-ignore wdio global
|
|
400
|
+
if (android) { await driver.back(); return; }
|
|
401
|
+
// iOS has no system back key: swipe in from the left edge (UINavigationController back gesture).
|
|
402
|
+
// @ts-ignore wdio global
|
|
403
|
+
const { width, height } = await driver.getWindowSize();
|
|
404
|
+
// @ts-ignore wdio global
|
|
405
|
+
await driver.action('pointer', { parameters: { pointerType: 'touch' } })
|
|
406
|
+
.move({ x: 2, y: Math.round(height / 2) }).down().pause(50)
|
|
407
|
+
.move({ duration: 400, x: Math.round(width * 0.7), y: Math.round(height / 2) }).up().perform();
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (key === 'home') {
|
|
411
|
+
// @ts-ignore wdio global
|
|
412
|
+
if (android) await driver.execute('mobile: pressKey', { keycode: 3 });
|
|
413
|
+
// @ts-ignore wdio global
|
|
414
|
+
else await driver.execute('mobile: pressButton', { name: 'home' });
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
if (key === 'enter') {
|
|
418
|
+
// @ts-ignore wdio global
|
|
419
|
+
if (android) { await driver.execute('mobile: pressKey', { keycode: 66 }); return; }
|
|
420
|
+
await this.typeFocused('\\n');
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
throw new Error('Unsupported key: ' + key);
|
|
281
424
|
}
|
|
282
425
|
|
|
283
|
-
|
|
426
|
+
/** Real window-size-relative swipe. direction is the FINGER direction ('up' drags from bottom to top). */
|
|
427
|
+
async swipe(${p('direction', dirType.slice(2) || 'string')}) {
|
|
284
428
|
// @ts-ignore wdio global
|
|
285
429
|
const { width, height } = await driver.getWindowSize();
|
|
286
430
|
const cx = Math.round(width / 2), cy = Math.round(height / 2);
|
|
@@ -290,9 +434,11 @@ export class BaseScreen {
|
|
|
290
434
|
left: [Math.round(width * 0.8), cy, Math.round(width * 0.2), cy],
|
|
291
435
|
right: [Math.round(width * 0.2), cy, Math.round(width * 0.8), cy],
|
|
292
436
|
};
|
|
293
|
-
const
|
|
437
|
+
const vec = map[direction];
|
|
438
|
+
if (!vec) throw new Error('Unsupported swipe direction: ' + direction);
|
|
439
|
+
const [x1, y1, x2, y2] = vec;
|
|
294
440
|
// @ts-ignore wdio global
|
|
295
|
-
await driver.action('pointer')
|
|
441
|
+
await driver.action('pointer', { parameters: { pointerType: 'touch' } })
|
|
296
442
|
.move({ x: x1, y: y1 }).down().pause(100).move({ duration: 600, x: x2, y: y2 }).up().perform();
|
|
297
443
|
}
|
|
298
444
|
|
|
@@ -303,9 +449,8 @@ export class BaseScreen {
|
|
|
303
449
|
}
|
|
304
450
|
`;
|
|
305
451
|
}
|
|
306
|
-
/**
|
|
307
|
-
function
|
|
308
|
-
const E = pascal(element);
|
|
452
|
+
/** Base (pre-dedupe) action-method name for an (action, element) pair. */
|
|
453
|
+
function methodBase(action, E) {
|
|
309
454
|
switch (action) {
|
|
310
455
|
case 'tap':
|
|
311
456
|
return `tap${E}`;
|
|
@@ -316,22 +461,23 @@ function methodName(action, element) {
|
|
|
316
461
|
case 'assertVisible':
|
|
317
462
|
return `assert${E}Visible`;
|
|
318
463
|
default:
|
|
319
|
-
|
|
464
|
+
throw new UnemittableStepError(`cannot emit a ${action} step bound to an element: no generated action exists for it`);
|
|
320
465
|
}
|
|
321
466
|
}
|
|
322
|
-
function screenClass(screen, steps, ts
|
|
323
|
-
const locImport = ts ? `import type { PlatformLocator } from '../utils/locators.js';\n` : '';
|
|
467
|
+
function screenClass(screen, names, steps, ts) {
|
|
324
468
|
const lines = [];
|
|
325
|
-
lines.push(`// Generated by Swipium. Screen object for ${screen.pageName}${screen.screenSignature ? ` (${screen.screenSignature})` : ''}.`);
|
|
469
|
+
lines.push(`// Generated by Swipium. Screen object for ${commentSafe(screen.pageName)}${screen.screenSignature ? ` (${commentSafe(screen.screenSignature)})` : ''}.`);
|
|
326
470
|
lines.push('// Selectors are centralized here; tests call the action methods below.');
|
|
327
|
-
|
|
471
|
+
if (ts)
|
|
472
|
+
lines.push(`import type { PlatformLocator } from '../utils/locators.js';`);
|
|
328
473
|
lines.push(`import { BaseScreen } from './BaseScreen.js';`);
|
|
329
474
|
lines.push('');
|
|
330
|
-
lines.push(`export class ${
|
|
331
|
-
// Locators (centralized).
|
|
475
|
+
lines.push(`export class ${names.cls} extends BaseScreen {`);
|
|
476
|
+
// Locators (centralized). H3: `readonly` + the type annotation are TypeScript-only.
|
|
332
477
|
for (const el of screen.elements) {
|
|
333
|
-
const
|
|
334
|
-
|
|
478
|
+
const field = names.fields.get(el.name);
|
|
479
|
+
const durabilityNote = el.durability === 'durable' ? '' : ` // ${el.durability} locator${el.remediation ? `: ${commentSafe(el.remediation)}` : ''}`;
|
|
480
|
+
lines.push(` ${ts ? 'readonly ' : ''}${field}${ts ? ': PlatformLocator' : ''} = ${platformLocatorLiteral(el)};${durabilityNote}`);
|
|
335
481
|
}
|
|
336
482
|
lines.push('');
|
|
337
483
|
// Action methods for each (element, action) used in steps on this screen.
|
|
@@ -339,47 +485,47 @@ function screenClass(screen, steps, ts, t) {
|
|
|
339
485
|
for (const s of steps) {
|
|
340
486
|
if (s.screen !== screen.className || !s.element)
|
|
341
487
|
continue;
|
|
342
|
-
const
|
|
343
|
-
if (
|
|
344
|
-
continue;
|
|
345
|
-
const name = methodName(s.action, s.element);
|
|
346
|
-
if (seen.has(name))
|
|
488
|
+
const key = methodKey(s.action, s.element);
|
|
489
|
+
if (seen.has(key))
|
|
347
490
|
continue;
|
|
348
|
-
seen.add(
|
|
491
|
+
seen.add(key);
|
|
492
|
+
const name = names.methods.get(key);
|
|
493
|
+
const field = `this.${names.fields.get(s.element)}`;
|
|
349
494
|
if (s.action === 'inputText') {
|
|
350
495
|
lines.push(` async ${name}(${ts ? 'value: string' : 'value'}) {`);
|
|
351
|
-
lines.push(` await this.type(
|
|
352
|
-
lines.push(' }');
|
|
496
|
+
lines.push(` await this.type(${field}, value);`);
|
|
353
497
|
}
|
|
354
498
|
else if (s.action === 'tap') {
|
|
355
499
|
lines.push(` async ${name}() {`);
|
|
356
|
-
lines.push(` await this.tap(
|
|
357
|
-
lines.push(' }');
|
|
500
|
+
lines.push(` await this.tap(${field});`);
|
|
358
501
|
}
|
|
359
502
|
else if (s.action === 'scrollTo') {
|
|
360
|
-
lines.push(` async ${name}() {`);
|
|
361
|
-
lines.push(` await this.scrollTo(
|
|
362
|
-
lines.push(' }');
|
|
503
|
+
lines.push(` async ${name}(${ts ? "direction: string = 'down'" : "direction = 'down'"}) {`);
|
|
504
|
+
lines.push(` await this.scrollTo(${field}, direction);`);
|
|
363
505
|
}
|
|
364
|
-
else
|
|
506
|
+
else {
|
|
365
507
|
lines.push(` async ${name}() {`);
|
|
366
|
-
lines.push(` await this.assertVisible(
|
|
367
|
-
lines.push(' }');
|
|
508
|
+
lines.push(` await this.assertVisible(${field});`);
|
|
368
509
|
}
|
|
510
|
+
lines.push(' }');
|
|
369
511
|
}
|
|
370
512
|
lines.push('}');
|
|
371
513
|
lines.push('');
|
|
372
514
|
return lines.join('\n');
|
|
373
515
|
}
|
|
516
|
+
function envRef(v) {
|
|
517
|
+
return jsProp('process.env', v);
|
|
518
|
+
}
|
|
374
519
|
function testData(model, ts) {
|
|
375
520
|
const lines = [];
|
|
376
|
-
|
|
521
|
+
const key = (v) => (isJsIdentifier(varToKey(v)) ? varToKey(v) : JSON.stringify(varToKey(v)));
|
|
522
|
+
lines.push('// Generated by Swipium. Test data comes from the ENVIRONMENT. Secrets are never inlined.');
|
|
377
523
|
lines.push('export const testData = {');
|
|
378
524
|
for (const v of model.variables) {
|
|
379
|
-
lines.push(` ${
|
|
525
|
+
lines.push(` ${key(v)}: ${envRef(v)} || '',`);
|
|
380
526
|
}
|
|
381
527
|
for (const v of model.secrets) {
|
|
382
|
-
lines.push(` ${
|
|
528
|
+
lines.push(` ${key(v)}: ${envRef(v)} || '', // secret, provide via environment only`);
|
|
383
529
|
}
|
|
384
530
|
lines.push('};');
|
|
385
531
|
lines.push('');
|
|
@@ -388,61 +534,74 @@ function testData(model, ts) {
|
|
|
388
534
|
lines.push('');
|
|
389
535
|
return lines.join('\n');
|
|
390
536
|
}
|
|
391
|
-
function smokeTest(model,
|
|
537
|
+
function smokeTest(model, names) {
|
|
392
538
|
const classes = [...new Set(model.steps.map((s) => s.screen))];
|
|
393
539
|
const lines = [];
|
|
394
540
|
lines.push('// Generated by Swipium. Smoke test driving the recorded flow through the screen objects.');
|
|
395
541
|
for (const c of classes) {
|
|
396
|
-
|
|
542
|
+
const cls = names.get(c).cls;
|
|
543
|
+
lines.push(`import { ${cls} } from '../src/screens/${cls}.js';`);
|
|
397
544
|
}
|
|
398
545
|
lines.push(`import { testData } from '../src/data/testData.js';`);
|
|
399
546
|
lines.push('');
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
for (const c of classes)
|
|
404
|
-
const
|
|
405
|
-
inst.set(c, v);
|
|
406
|
-
}
|
|
407
|
-
lines.push(` it('completes the recorded flow', async () => {`);
|
|
408
|
-
for (const [c, v] of inst)
|
|
409
|
-
lines.push(` const ${v} = new ${c}();`);
|
|
547
|
+
// H3: titles come from recorded data, so always a JSON-escaped literal, never raw interpolation.
|
|
548
|
+
lines.push(`describe(${JSON.stringify(`${model.testName} smoke`)}, () => {`);
|
|
549
|
+
lines.push(` it(${JSON.stringify('completes the recorded flow')}, async () => {`);
|
|
550
|
+
for (const c of classes)
|
|
551
|
+
lines.push(` const ${names.get(c).instance} = new ${names.get(c).cls}();`);
|
|
410
552
|
for (const s of model.steps) {
|
|
411
|
-
|
|
412
|
-
lines.push(' ' + stepCall(v, s));
|
|
553
|
+
lines.push(' ' + stepCall(names.get(s.screen), s));
|
|
413
554
|
}
|
|
414
555
|
lines.push(' });');
|
|
415
556
|
lines.push('});');
|
|
416
557
|
lines.push('');
|
|
417
558
|
return lines.join('\n');
|
|
418
559
|
}
|
|
419
|
-
function
|
|
560
|
+
function dataArg(s) {
|
|
561
|
+
return s.varName ? jsProp('testData', varToKey(s.varName)) : JSON.stringify(s.text ?? '');
|
|
562
|
+
}
|
|
563
|
+
function num(n) {
|
|
564
|
+
return Number.isFinite(n) ? Math.round(n) : 0;
|
|
565
|
+
}
|
|
566
|
+
function stepCall(n, s) {
|
|
567
|
+
const v = n.instance;
|
|
420
568
|
if (s.element) {
|
|
421
|
-
const name =
|
|
422
|
-
if (s.action === 'inputText')
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
return `await ${
|
|
569
|
+
const name = n.methods.get(methodKey(s.action, s.element));
|
|
570
|
+
if (s.action === 'inputText')
|
|
571
|
+
return `await ${v}.${name}(${dataArg(s)});`;
|
|
572
|
+
if (s.action === 'scrollTo')
|
|
573
|
+
return `await ${v}.${name}(${JSON.stringify(checkDirection(s.direction ?? 'down', 'scrollTo step'))});`;
|
|
574
|
+
return `await ${v}.${name}();`;
|
|
427
575
|
}
|
|
428
576
|
// No element: generic BaseScreen helpers.
|
|
429
577
|
switch (s.action) {
|
|
430
578
|
case 'tapAt':
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
579
|
+
if (!s.coords)
|
|
580
|
+
throw new UnemittableStepError('cannot emit a coordinate tap without coordinates');
|
|
581
|
+
return `await ${v}.tapAt(${num(s.coords[0])}, ${num(s.coords[1])}); // coordinate fallback, non-release-grade`;
|
|
582
|
+
case 'inputText':
|
|
583
|
+
return `await ${v}.typeFocused(${dataArg(s)}); // focused-field input`;
|
|
436
584
|
case 'press':
|
|
437
|
-
return `await ${
|
|
585
|
+
return `await ${v}.pressKey(${JSON.stringify(checkKey(s.key))});`;
|
|
438
586
|
case 'swipe':
|
|
439
|
-
return `await ${
|
|
587
|
+
return `await ${v}.swipe(${JSON.stringify(checkDirection(s.direction ?? 'up', 'swipe step'))});`;
|
|
588
|
+
case 'scrollTo':
|
|
589
|
+
if (!s.text)
|
|
590
|
+
throw new UnemittableStepError('cannot emit a scrollTo step with neither an element nor a target text');
|
|
591
|
+
return `await ${v}.scrollToText(${JSON.stringify(s.text)}, ${JSON.stringify(checkDirection(s.direction ?? 'down', 'scrollTo step'))});`;
|
|
440
592
|
case 'openUrl':
|
|
441
|
-
|
|
593
|
+
if (!s.url)
|
|
594
|
+
throw new UnemittableStepError('cannot emit an openUrl step without a URL');
|
|
595
|
+
return `await ${v}.openUrl(${JSON.stringify(s.url)});`;
|
|
442
596
|
case 'assertVisible':
|
|
443
|
-
|
|
597
|
+
if (!s.text)
|
|
598
|
+
throw new UnemittableStepError('cannot emit a text assertion without text');
|
|
599
|
+
return `await ${v}.assertTextVisible(${JSON.stringify(s.text)});`;
|
|
600
|
+
case 'visualCheck':
|
|
601
|
+
// Visual judgement prose is not on-screen text. It's a manual checkpoint, never a failing text check.
|
|
602
|
+
return `// TODO(manual visual check, not automated): ${commentSafe(s.text ?? 'visual checkpoint')}`;
|
|
444
603
|
default:
|
|
445
|
-
|
|
604
|
+
throw new UnemittableStepError(`cannot emit step action ${JSON.stringify(s.action)}: no WebdriverIO equivalent is generated for it`);
|
|
446
605
|
}
|
|
447
606
|
}
|
|
448
607
|
//# sourceMappingURL=jsEmitter.js.map
|