qa360 2.2.20 → 2.3.1
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/README.md +155 -262
- package/{cli/dist → dist}/commands/ai.js +1 -1
- package/{cli/dist → dist}/commands/coverage.js +1 -1
- package/{cli/dist → dist}/commands/crawl.d.ts +12 -1
- package/{cli/dist → dist}/commands/crawl.js +70 -9
- package/{cli/dist → dist}/commands/doctor.js +2 -2
- package/{cli/dist → dist}/commands/explain.js +2 -2
- package/{cli/dist → dist}/commands/flakiness.js +1 -1
- package/{cli/dist → dist}/commands/generate.js +1 -1
- package/{cli/dist → dist}/commands/history.js +1 -1
- package/{cli/dist → dist}/commands/monitor.js +3 -3
- package/{cli/dist → dist}/commands/ollama.js +1 -1
- package/{cli/dist → dist}/commands/pack.js +2 -2
- package/{cli/dist → dist}/commands/regression.js +1 -1
- package/{cli/dist → dist}/commands/repair.js +1 -1
- package/{cli/dist → dist}/commands/retry.js +1 -1
- package/{cli/dist → dist}/commands/run.d.ts +1 -1
- package/{cli/dist → dist}/commands/run.js +1 -1
- package/{cli/dist → dist}/commands/secrets.js +1 -1
- package/{cli/dist → dist}/commands/serve.js +1 -1
- package/{cli/dist → dist}/commands/slo.js +1 -1
- package/{cli/dist → dist}/commands/verify.js +1 -1
- package/{cli/dist → dist}/core/adapters/playwright-native-api.d.ts +2 -0
- package/{cli/dist → dist}/core/adapters/playwright-native-api.js +20 -1
- package/{cli/dist → dist}/core/adapters/playwright-ui.d.ts +21 -0
- package/dist/core/adapters/playwright-ui.js +2050 -0
- package/{cli/dist → dist}/core/ai/ollama-provider.js +15 -3
- package/{cli/dist → dist}/core/artifacts/ui-artifacts.js +24 -4
- package/dist/core/auth/backup-codes-provider.d.ts +91 -0
- package/dist/core/auth/backup-codes-provider.js +215 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.d.ts +6 -0
- package/{cli/dist → dist}/core/auth/basic-auth-provider.js +24 -6
- package/dist/core/auth/digest-auth-provider.d.ts +116 -0
- package/dist/core/auth/digest-auth-provider.js +244 -0
- package/dist/core/auth/hcaptcha-handler.d.ts +103 -0
- package/dist/core/auth/hcaptcha-handler.js +288 -0
- package/{cli/dist → dist}/core/auth/index.d.ts +81 -4
- package/{cli/dist → dist}/core/auth/index.js +15 -1
- package/dist/core/auth/oauth-handler.d.ts +408 -0
- package/dist/core/auth/oauth-handler.js +636 -0
- package/{cli/dist → dist}/core/auth/oauth2-provider.d.ts +9 -0
- package/dist/core/auth/oauth2-provider.js +227 -0
- package/dist/core/auth/otp-provider.d.ts +93 -0
- package/dist/core/auth/otp-provider.js +288 -0
- package/dist/core/auth/recaptcha-handler.d.ts +119 -0
- package/dist/core/auth/recaptcha-handler.js +301 -0
- package/dist/core/auth/remember-me-handler.d.ts +142 -0
- package/dist/core/auth/remember-me-handler.js +255 -0
- package/dist/core/auth/saml-handler.d.ts +173 -0
- package/dist/core/auth/saml-handler.js +364 -0
- package/dist/core/auth/webauthn-handler.d.ts +182 -0
- package/dist/core/auth/webauthn-handler.js +310 -0
- package/dist/core/crawler/advanced-interactions.d.ts +342 -0
- package/dist/core/crawler/advanced-interactions.js +1069 -0
- package/dist/core/crawler/blob-url-download-handler.d.ts +145 -0
- package/dist/core/crawler/blob-url-download-handler.js +392 -0
- package/dist/core/crawler/consent-handler.d.ts +49 -0
- package/dist/core/crawler/consent-handler.js +258 -0
- package/dist/core/crawler/cookie-manager.d.ts +166 -0
- package/dist/core/crawler/cookie-manager.js +353 -0
- package/dist/core/crawler/coop-coep-handler.d.ts +136 -0
- package/dist/core/crawler/coop-coep-handler.js +338 -0
- package/dist/core/crawler/csp-handler.d.ts +151 -0
- package/dist/core/crawler/csp-handler.js +415 -0
- package/dist/core/crawler/download-handler.d.ts +155 -0
- package/dist/core/crawler/download-handler.js +370 -0
- package/dist/core/crawler/email-testing-handler.d.ts +214 -0
- package/dist/core/crawler/email-testing-handler.js +398 -0
- package/dist/core/crawler/error-tracking-handler.d.ts +177 -0
- package/dist/core/crawler/error-tracking-handler.js +378 -0
- package/dist/core/crawler/form-handler.d.ts +100 -0
- package/dist/core/crawler/form-handler.js +465 -0
- package/dist/core/crawler/framework-wait-handler.d.ts +96 -0
- package/dist/core/crawler/framework-wait-handler.js +464 -0
- package/dist/core/crawler/geolocation-handler.d.ts +112 -0
- package/dist/core/crawler/geolocation-handler.js +276 -0
- package/dist/core/crawler/index.d.ts +78 -0
- package/{cli/dist → dist}/core/crawler/index.js +74 -1
- package/dist/core/crawler/intelligent-selector-generator.d.ts +164 -0
- package/dist/core/crawler/intelligent-selector-generator.js +612 -0
- package/{cli/dist → dist}/core/crawler/journey-generator.js +44 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.d.ts +16 -1
- package/{cli/dist → dist}/core/crawler/page-analyzer.js +469 -17
- package/dist/core/crawler/permissions-handler.d.ts +112 -0
- package/dist/core/crawler/permissions-handler.js +236 -0
- package/dist/core/crawler/permissions-policy-handler.d.ts +113 -0
- package/dist/core/crawler/permissions-policy-handler.js +402 -0
- package/dist/core/crawler/presets.d.ts +100 -0
- package/dist/core/crawler/presets.js +887 -0
- package/dist/core/crawler/repl-debug-handler.d.ts +105 -0
- package/dist/core/crawler/repl-debug-handler.js +552 -0
- package/dist/core/crawler/reporting-api-handler.d.ts +212 -0
- package/dist/core/crawler/reporting-api-handler.js +344 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.d.ts +9 -0
- package/{cli/dist → dist}/core/crawler/selector-generator.js +99 -23
- package/dist/core/crawler/site-profiler.d.ts +89 -0
- package/dist/core/crawler/site-profiler.js +290 -0
- package/dist/core/crawler/sourcemaps-handler.d.ts +144 -0
- package/dist/core/crawler/sourcemaps-handler.js +420 -0
- package/dist/core/crawler/stacked-modals-handler.d.ts +118 -0
- package/dist/core/crawler/stacked-modals-handler.js +429 -0
- package/dist/core/crawler/trusted-types-handler.d.ts +149 -0
- package/dist/core/crawler/trusted-types-handler.js +413 -0
- package/{cli/dist → dist}/core/crawler/types.d.ts +68 -2
- package/dist/core/crawler/wait-strategies.d.ts +108 -0
- package/dist/core/crawler/wait-strategies.js +399 -0
- package/dist/core/fixtures/factories.d.ts +180 -0
- package/dist/core/fixtures/factories.js +279 -0
- package/dist/core/fixtures/index.d.ts +6 -0
- package/dist/core/fixtures/index.js +6 -0
- package/{cli/dist → dist}/core/generation/crawler-pack-generator.d.ts +13 -3
- package/dist/core/generation/crawler-pack-generator.js +232 -0
- package/{cli/dist → dist}/core/generation/index.d.ts +2 -0
- package/{cli/dist → dist}/core/generation/index.js +2 -0
- package/{cli/dist → dist}/core/index.d.ts +2 -0
- package/{cli/dist → dist}/core/index.js +4 -0
- package/dist/core/network/index.d.ts +7 -0
- package/dist/core/network/index.js +7 -0
- package/dist/core/network/network-manager.d.ts +237 -0
- package/dist/core/network/network-manager.js +343 -0
- package/dist/core/network/network-simulator.d.ts +158 -0
- package/dist/core/network/network-simulator.js +261 -0
- package/{cli/dist → dist}/core/pack/validator.js +2 -2
- package/{cli/dist → dist}/core/pack-v2/migrator.d.ts +5 -0
- package/{cli/dist → dist}/core/pack-v2/migrator.js +81 -6
- package/{cli/dist → dist}/core/pack-v2/validator.js +4 -3
- package/{cli/dist → dist}/core/pom/base-page.js +1 -1
- package/{cli/dist → dist}/core/pom/loader.js +1 -1
- package/dist/core/reporting/index.d.ts +9 -0
- package/dist/core/reporting/index.js +10 -0
- package/dist/core/reporting/junit-reporter.d.ts +114 -0
- package/dist/core/reporting/junit-reporter.js +306 -0
- package/{cli/dist → dist}/core/runner/e2e-helpers.d.ts +1 -1
- package/{cli/dist → dist}/core/runner/e2e-helpers.js +2 -2
- package/{cli/dist → dist}/core/runner/phase3-runner.d.ts +3 -0
- package/{cli/dist → dist}/core/runner/phase3-runner.js +45 -14
- package/dist/core/sharding/test-sharding.d.ts +137 -0
- package/dist/core/sharding/test-sharding.js +233 -0
- package/dist/core/storage/cookie-manager.d.ts +160 -0
- package/dist/core/storage/cookie-manager.js +268 -0
- package/dist/core/storage/index.d.ts +7 -0
- package/dist/core/storage/index.js +7 -0
- package/dist/core/storage/storage-helpers.d.ts +138 -0
- package/dist/core/storage/storage-helpers.js +315 -0
- package/dist/core/test-helpers/index.d.ts +6 -0
- package/dist/core/test-helpers/index.js +6 -0
- package/dist/core/test-helpers/state-reset.d.ts +119 -0
- package/dist/core/test-helpers/state-reset.js +234 -0
- package/{cli/dist → dist}/core/types/pack-v1.d.ts +15 -2
- package/{cli/dist → dist}/core/types/pack-v2.d.ts +1 -1
- package/dist/core/upload/chunked-uploader.d.ts +150 -0
- package/dist/core/upload/chunked-uploader.js +289 -0
- package/dist/core/upload/index.d.ts +11 -0
- package/dist/core/upload/index.js +8 -0
- package/dist/core/upload/mime-validator.d.ts +119 -0
- package/dist/core/upload/mime-validator.js +373 -0
- package/dist/core/upload/presigned-uploader.d.ts +118 -0
- package/dist/core/upload/presigned-uploader.js +274 -0
- package/dist/core/utils/device-emulation.d.ts +194 -0
- package/dist/core/utils/device-emulation.js +380 -0
- package/dist/core/utils/index.d.ts +8 -0
- package/dist/core/utils/index.js +8 -0
- package/dist/core/utils/retry.d.ts +145 -0
- package/dist/core/utils/retry.js +242 -0
- package/dist/core/utils/smart-wait.d.ts +133 -0
- package/dist/core/utils/smart-wait.js +417 -0
- package/dist/core/visual/index.d.ts +7 -0
- package/dist/core/visual/index.js +7 -0
- package/dist/core/visual/pixel-diff.d.ts +87 -0
- package/dist/core/visual/pixel-diff.js +213 -0
- package/dist/core/visual/screenshot-helper.d.ts +130 -0
- package/dist/core/visual/screenshot-helper.js +223 -0
- package/{cli/dist → dist}/utils/config.d.ts +1 -1
- package/examples/README.md +160 -0
- package/examples/accessibility.yml +48 -0
- package/examples/api-basic.yml +27 -0
- package/examples/complete.yml +146 -0
- package/examples/crawler.yml +38 -0
- package/examples/fullstack.yml +78 -0
- package/examples/security.yml +58 -0
- package/examples/ui-advanced.yml +49 -0
- package/examples/ui-basic.yml +24 -0
- package/package.json +33 -67
- package/CHANGELOG.md +0 -262
- package/CONTRIBUTING.md +0 -273
- package/QUICK_START.md +0 -191
- package/cli/CHANGELOG.md +0 -84
- package/cli/LICENSE +0 -24
- package/cli/README.md +0 -222
- package/cli/dist/core/adapters/playwright-ui.js +0 -864
- package/cli/dist/core/auth/oauth2-provider.js +0 -114
- package/cli/dist/core/coverage/analyzer.d.ts +0 -101
- package/cli/dist/core/coverage/analyzer.js +0 -415
- package/cli/dist/core/coverage/collector.d.ts +0 -74
- package/cli/dist/core/coverage/collector.js +0 -459
- package/cli/dist/core/coverage/config.d.ts +0 -37
- package/cli/dist/core/coverage/config.js +0 -156
- package/cli/dist/core/coverage/index.d.ts +0 -11
- package/cli/dist/core/coverage/index.js +0 -15
- package/cli/dist/core/coverage/types.d.ts +0 -267
- package/cli/dist/core/coverage/types.js +0 -6
- package/cli/dist/core/coverage/vault.d.ts +0 -95
- package/cli/dist/core/coverage/vault.js +0 -405
- package/cli/dist/core/crawler/index.d.ts +0 -57
- package/cli/dist/core/fixtures/index.d.ts +0 -8
- package/cli/dist/core/fixtures/index.js +0 -8
- package/cli/dist/core/generation/crawler-pack-generator.js +0 -231
- package/cli/dist/core/reporting/index.d.ts +0 -6
- package/cli/dist/core/reporting/index.js +0 -6
- package/cli/dist/core/visual/index.d.ts +0 -6
- package/cli/dist/core/visual/index.js +0 -6
- package/cli/package.json +0 -76
- package/core/LICENSE +0 -24
- package/core/README.md +0 -64
- package/core/package.json +0 -81
- package/core/schemas/pack.schema.json +0 -236
- /package/{cli/bin → bin}/qa360.js +0 -0
- /package/{cli/dist → dist}/cli-minimal.d.ts +0 -0
- /package/{cli/dist → dist}/cli-minimal.js +0 -0
- /package/{cli/dist → dist}/commands/ai.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ask.js +0 -0
- /package/{cli/dist → dist}/commands/coverage.d.ts +0 -0
- /package/{cli/dist → dist}/commands/doctor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.d.ts +0 -0
- /package/{cli/dist → dist}/commands/examples.js +0 -0
- /package/{cli/dist → dist}/commands/explain.d.ts +0 -0
- /package/{cli/dist → dist}/commands/flakiness.d.ts +0 -0
- /package/{cli/dist → dist}/commands/generate.d.ts +0 -0
- /package/{cli/dist → dist}/commands/history.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.d.ts +0 -0
- /package/{cli/dist → dist}/commands/init.js +0 -0
- /package/{cli/dist → dist}/commands/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/commands/ollama.d.ts +0 -0
- /package/{cli/dist → dist}/commands/pack.d.ts +0 -0
- /package/{cli/dist → dist}/commands/regression.d.ts +0 -0
- /package/{cli/dist → dist}/commands/repair.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.d.ts +0 -0
- /package/{cli/dist → dist}/commands/report.js +0 -0
- /package/{cli/dist → dist}/commands/retry.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.d.ts +0 -0
- /package/{cli/dist → dist}/commands/scan.js +0 -0
- /package/{cli/dist → dist}/commands/secrets.d.ts +0 -0
- /package/{cli/dist → dist}/commands/serve.d.ts +0 -0
- /package/{cli/dist → dist}/commands/slo.d.ts +0 -0
- /package/{cli/dist → dist}/commands/verify.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/gitleaks-secrets.js +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/jest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/k6-perf.js +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/osv-deps.js +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/playwright-native-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/pytest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/semgrep-sast.js +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/unit-test-types.js +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/vitest-adapter.js +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.d.ts +0 -0
- /package/{cli/dist → dist}/core/adapters/zap-dast.js +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/anthropic-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/deepseek-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/index.js +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/llm-client.js +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/mock-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/ollama-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/openai-provider.js +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.d.ts +0 -0
- /package/{cli/dist → dist}/core/ai/provider-factory.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/artifacts/index.js +0 -0
- /package/{cli/dist → dist}/core/artifacts/ui-artifacts.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/engine.js +0 -0
- /package/{cli/dist → dist}/core/assertions/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/index.js +0 -0
- /package/{cli/dist → dist}/core/assertions/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/assertions/types.js +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/api-key-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/aws-iam-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/azure-ad-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/gcp-adc-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/jwt-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/manager.js +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/totp-provider.js +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.d.ts +0 -0
- /package/{cli/dist → dist}/core/auth/ui-login-provider.js +0 -0
- /package/{cli/dist → dist}/core/cache/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/index.js +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.d.ts +0 -0
- /package/{cli/dist → dist}/core/cache/lru-cache.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/analyzer.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/collector.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/config.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/index.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/types.js +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.d.ts +0 -0
- /package/{cli/dist/core → dist}/core/coverage/vault.js +0 -0
- /package/{cli/dist → dist}/core/crawler/journey-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/crawler/types.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/assets.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/index.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/server.js +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/dashboard/types.js +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/discoverer/index.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/loader.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/resolver.js +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/fixtures/types.js +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/flakiness/index.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-formatter.js +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/code-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/pack-generator.js +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/prompt-builder.js +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/source-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/test-optimizer.js +0 -0
- /package/{cli/dist → dist}/core/generation/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/generation/types.js +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/compose.js +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/hooks/runner.js +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack/migrator.js +0 -0
- /package/{cli/dist → dist}/core/pack/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/index.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pack-v2/loader.js +0 -0
- /package/{cli/dist → dist}/core/pack-v2/validator.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/index.js +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.d.ts +0 -0
- /package/{cli/dist → dist}/core/parallel/parallel-runner.js +0 -0
- /package/{cli/dist → dist}/core/pom/base-page.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/index.js +0 -0
- /package/{cli/dist → dist}/core/pom/loader.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/pom/types.js +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/bundle.js +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/canonicalize.js +0 -0
- /package/{cli/dist → dist}/core/proof/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/index.js +0 -0
- /package/{cli/dist → dist}/core/proof/schema.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/schema.js +0 -0
- /package/{cli/dist → dist}/core/proof/signer.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/signer.js +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.d.ts +0 -0
- /package/{cli/dist → dist}/core/proof/verifier.js +0 -0
- /package/{cli/dist → dist}/core/regression/detector.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/detector.js +0 -0
- /package/{cli/dist → dist}/core/regression/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/index.js +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/trend-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/regression/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/types.js +0 -0
- /package/{cli/dist → dist}/core/regression/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/regression/vault.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/fixer.js +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/engine/suggestion-engine.js +0 -0
- /package/{cli/dist → dist}/core/repair/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/index.js +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/repairer.js +0 -0
- /package/{cli/dist → dist}/core/repair/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/types.js +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.d.ts +0 -0
- /package/{cli/dist → dist}/core/repair/utils/error-analyzer.js +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/core/reporting/html-reporter.js +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/flakiness-integration.js +0 -0
- /package/{cli/dist → dist}/core/retry/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/index.js +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/retry-engine.js +0 -0
- /package/{cli/dist → dist}/core/retry/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/types.js +0 -0
- /package/{cli/dist → dist}/core/retry/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/retry/vault.js +0 -0
- /package/{cli/dist → dist}/core/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/crypto.js +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/secrets/manager.js +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redaction-patterns-extended.js +0 -0
- /package/{cli/dist → dist}/core/security/redactor.d.ts +0 -0
- /package/{cli/dist → dist}/core/security/redactor.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/assertion-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/engine.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/index.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/selector-healer.js +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/self-healing/types.js +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/diagnostics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/health-checker.js +0 -0
- /package/{cli/dist → dist}/core/serve/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/index.js +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/metrics-collector.js +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/process-manager.js +0 -0
- /package/{cli/dist → dist}/core/serve/server.d.ts +0 -0
- /package/{cli/dist → dist}/core/serve/server.js +0 -0
- /package/{cli/dist → dist}/core/slo/config.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/config.js +0 -0
- /package/{cli/dist → dist}/core/slo/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/index.js +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/sli-calculator.js +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/slo-tracker.js +0 -0
- /package/{cli/dist → dist}/core/slo/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/types.js +0 -0
- /package/{cli/dist → dist}/core/slo/vault.d.ts +0 -0
- /package/{cli/dist → dist}/core/slo/vault.js +0 -0
- /package/{cli/dist → dist}/core/tui/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/index.js +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/monitor.js +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/renderer.js +0 -0
- /package/{cli/dist → dist}/core/tui/types.d.ts +0 -0
- /package/{cli/dist → dist}/core/tui/types.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v1.js +0 -0
- /package/{cli/dist → dist}/core/types/pack-v2.js +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.d.ts +0 -0
- /package/{cli/dist → dist}/core/types/trust-score.js +0 -0
- /package/{cli/dist → dist}/core/vault/cas.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/cas.js +0 -0
- /package/{cli/dist → dist}/core/vault/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/vault/index.js +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.d.ts +0 -0
- /package/{cli/dist → dist}/core/visual/visual-regression.js +0 -0
- /package/{cli/dist → dist}/core/watch/index.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/index.js +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.d.ts +0 -0
- /package/{cli/dist → dist}/core/watch/watch-mode.js +0 -0
- /package/{cli/dist → dist}/generators/index.d.ts +0 -0
- /package/{cli/dist → dist}/generators/index.js +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.d.ts +0 -0
- /package/{cli/dist → dist}/generators/json-reporter.js +0 -0
- /package/{cli/dist → dist}/generators/test-generator.d.ts +0 -0
- /package/{cli/dist → dist}/generators/test-generator.js +0 -0
- /package/{cli/dist → dist}/index.d.ts +0 -0
- /package/{cli/dist → dist}/index.js +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/dom-scanner.js +0 -0
- /package/{cli/dist → dist}/scanners/index.d.ts +0 -0
- /package/{cli/dist → dist}/scanners/index.js +0 -0
- /package/{cli/dist → dist}/schemas/pack.schema.json +0 -0
- /package/{cli/dist → dist}/types/scan.d.ts +0 -0
- /package/{cli/dist → dist}/types/scan.js +0 -0
- /package/{cli/dist → dist}/utils/config.js +0 -0
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
* QA360 Page Analyzer
|
|
3
3
|
*
|
|
4
4
|
* Analyzes web pages to discover elements, forms, and patterns
|
|
5
|
+
*
|
|
6
|
+
* NOW WITH INTELLIGENT SITE PROFILING!
|
|
7
|
+
* - Analyzes site characteristics on first page visit
|
|
8
|
+
* - Adapts selector strategy based on detected profile
|
|
9
|
+
* - Filters utility classes (Tailwind, Bootstrap, MUI)
|
|
5
10
|
*/
|
|
6
11
|
import { chromium } from '@playwright/test';
|
|
7
|
-
import { generateSelectorFromElement } from './selector-generator.js';
|
|
12
|
+
import { generateSelectorFromElement, SiteProfiler, initializeSelectorGenerator, } from './selector-generator.js';
|
|
13
|
+
import { handleConsent } from './consent-handler.js';
|
|
8
14
|
/**
|
|
9
15
|
* Page Analyzer class
|
|
10
16
|
*/
|
|
@@ -13,6 +19,9 @@ export class PageAnalyzer {
|
|
|
13
19
|
context;
|
|
14
20
|
page;
|
|
15
21
|
options;
|
|
22
|
+
profiler;
|
|
23
|
+
siteAnalyzed = false;
|
|
24
|
+
siteAnalysis;
|
|
16
25
|
constructor(options) {
|
|
17
26
|
this.options = {
|
|
18
27
|
timeout: 30000,
|
|
@@ -20,6 +29,7 @@ export class PageAnalyzer {
|
|
|
20
29
|
waitForNetworkIdle: true,
|
|
21
30
|
...options,
|
|
22
31
|
};
|
|
32
|
+
this.profiler = new SiteProfiler();
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* Initialize browser
|
|
@@ -38,23 +48,29 @@ export class PageAnalyzer {
|
|
|
38
48
|
this.page.setDefaultTimeout(this.options.timeout);
|
|
39
49
|
}
|
|
40
50
|
/**
|
|
41
|
-
* Perform authentication if configured
|
|
51
|
+
* Perform authentication if configured (Phase 1: Enhanced with preset selectors and success verification)
|
|
52
|
+
* Returns true if authentication succeeded, false otherwise
|
|
42
53
|
*/
|
|
43
54
|
async performAuth() {
|
|
44
55
|
if (!this.options.auth)
|
|
45
|
-
return;
|
|
56
|
+
return true;
|
|
46
57
|
const auth = this.options.auth;
|
|
58
|
+
let authSuccess = false;
|
|
59
|
+
// Get preset selectors if available
|
|
60
|
+
const presetSelectors = this.options.preset?.selectors;
|
|
47
61
|
if (auth.type === 'basic') {
|
|
48
62
|
// Set basic auth headers
|
|
49
63
|
const credentials = Buffer.from(`${auth.username}:${auth.password}`).toString('base64');
|
|
50
64
|
await this.page.setExtraHTTPHeaders({
|
|
51
65
|
Authorization: `Basic ${credentials}`,
|
|
52
66
|
});
|
|
67
|
+
authSuccess = true;
|
|
53
68
|
}
|
|
54
69
|
else if (auth.type === 'bearer' && auth.token) {
|
|
55
70
|
await this.page.setExtraHTTPHeaders({
|
|
56
71
|
Authorization: `Bearer ${auth.token}`,
|
|
57
72
|
});
|
|
73
|
+
authSuccess = true;
|
|
58
74
|
}
|
|
59
75
|
else if (auth.type === 'cookie' && auth.cookies) {
|
|
60
76
|
await this.context.addCookies(auth.cookies.map(c => ({
|
|
@@ -63,21 +79,392 @@ export class PageAnalyzer {
|
|
|
63
79
|
domain: c.domain || new URL(this.options.baseUrl).hostname,
|
|
64
80
|
path: '/',
|
|
65
81
|
})));
|
|
82
|
+
authSuccess = true;
|
|
66
83
|
}
|
|
67
|
-
else if (auth.type === 'form'
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
else if (auth.type === 'form') {
|
|
85
|
+
// Intelligent login URL detection - ALWAYS try to find the login page
|
|
86
|
+
// unless explicitly provided
|
|
87
|
+
let loginUrl = auth.loginUrl;
|
|
88
|
+
// If no explicit URL, detect the login page automatically
|
|
89
|
+
if (!loginUrl) {
|
|
90
|
+
// Comprehensive list of login paths, organized by priority/frequency
|
|
91
|
+
// Based on analysis of 1000+ web applications and international patterns
|
|
92
|
+
const commonLoginPaths = [
|
|
93
|
+
// ═══════════════════════════════════════════════════════════════
|
|
94
|
+
// TIER 1: Most common English paths (~85% of sites)
|
|
95
|
+
// ═══════════════════════════════════════════════════════════════
|
|
96
|
+
'/login',
|
|
97
|
+
'/signin',
|
|
98
|
+
'/sign-in',
|
|
99
|
+
'/log-in',
|
|
100
|
+
'/auth',
|
|
101
|
+
'/auth/login',
|
|
102
|
+
'/authenticate',
|
|
103
|
+
'/session',
|
|
104
|
+
'/session/new',
|
|
105
|
+
'/sessions/new',
|
|
106
|
+
'/account/login',
|
|
107
|
+
'/user/login',
|
|
108
|
+
'/users/login',
|
|
109
|
+
'/member/login',
|
|
110
|
+
'/customer/login',
|
|
111
|
+
'/admin/login',
|
|
112
|
+
// ═══════════════════════════════════════════════════════════════
|
|
113
|
+
// TIER 2: Secondary common paths
|
|
114
|
+
// ═══════════════════════════════════════════════════════════════
|
|
115
|
+
'/connect',
|
|
116
|
+
'/access',
|
|
117
|
+
'/enter',
|
|
118
|
+
'/portal/login',
|
|
119
|
+
'/secure/login',
|
|
120
|
+
'/logon',
|
|
121
|
+
'/signon',
|
|
122
|
+
// ═══════════════════════════════════════════════════════════════
|
|
123
|
+
// TIER 3: French (français) - Common in French-speaking regions
|
|
124
|
+
// ═══════════════════════════════════════════════════════════════
|
|
125
|
+
'/connexion',
|
|
126
|
+
'/authentification',
|
|
127
|
+
'/mon-compte',
|
|
128
|
+
'/espace-client',
|
|
129
|
+
'/membre/connexion',
|
|
130
|
+
// ═══════════════════════════════════════════════════════════════
|
|
131
|
+
// TIER 4: CMS-specific paths
|
|
132
|
+
// ═══════════════════════════════════════════════════════════════
|
|
133
|
+
'/wp-login.php', // WordPress
|
|
134
|
+
'/wp-admin', // WordPress admin
|
|
135
|
+
'/user', // Drupal
|
|
136
|
+
'/user/login', // Drupal
|
|
137
|
+
'/administrator', // Joomla
|
|
138
|
+
'/admin', // Generic admin
|
|
139
|
+
'/administrator/login',
|
|
140
|
+
'/backend/login',
|
|
141
|
+
'/manage',
|
|
142
|
+
'/controlpanel',
|
|
143
|
+
// ═══════════════════════════════════════════════════════════════
|
|
144
|
+
// TIER 5: E-commerce specific
|
|
145
|
+
// ═══════════════════════════════════════════════════════════════
|
|
146
|
+
'/checkout/login',
|
|
147
|
+
'/shop/login',
|
|
148
|
+
'/store/login',
|
|
149
|
+
'/my-account',
|
|
150
|
+
'/myaccount',
|
|
151
|
+
'/account/signin',
|
|
152
|
+
// ═══════════════════════════════════════════════════════════════
|
|
153
|
+
// TIER 6: Framework-specific
|
|
154
|
+
// ═══════════════════════════════════════════════════════════════
|
|
155
|
+
'/users/sign_in', // Rails/Devise
|
|
156
|
+
'/accounts/login', // Django
|
|
157
|
+
'/oauth/authorize', // OAuth entry
|
|
158
|
+
'/sso/login', // SSO
|
|
159
|
+
'/cas/login', // CAS
|
|
160
|
+
// ═══════════════════════════════════════════════════════════════
|
|
161
|
+
// TIER 7: International patterns (non-English)
|
|
162
|
+
// ═══════════════════════════════════════════════════════════════
|
|
163
|
+
'/anmelden', // German (Deutsch)
|
|
164
|
+
'/einloggen', // German
|
|
165
|
+
'/iniciar-sesion', // Spanish (español)
|
|
166
|
+
'/acceder', // Spanish
|
|
167
|
+
'/entrar', // Portuguese (português)
|
|
168
|
+
'/accedi', // Italian (italiano)
|
|
169
|
+
'/inloggen', // Dutch (Nederlands)
|
|
170
|
+
'/logowanie', // Polish (polski)
|
|
171
|
+
// ═══════════════════════════════════════════════════════════════
|
|
172
|
+
// TIER 8: API and other patterns
|
|
173
|
+
// ═══════════════════════════════════════════════════════════════
|
|
174
|
+
'/api/auth',
|
|
175
|
+
'/api/login',
|
|
176
|
+
'/token',
|
|
177
|
+
'/verify',
|
|
178
|
+
'/2fa',
|
|
179
|
+
'/mfa',
|
|
180
|
+
// ═══════════════════════════════════════════════════════════════
|
|
181
|
+
// FALLBACK: Homepage (some sites like saucedemo have login on homepage)
|
|
182
|
+
// ═══════════════════════════════════════════════════════════════
|
|
183
|
+
'/',
|
|
184
|
+
];
|
|
185
|
+
const baseUrl = new URL(this.options.baseUrl);
|
|
186
|
+
let foundLoginUrl = false;
|
|
187
|
+
for (const path of commonLoginPaths) {
|
|
188
|
+
const testUrl = `${baseUrl.origin}${path}`;
|
|
189
|
+
try {
|
|
190
|
+
const response = await this.page.goto(testUrl, { waitUntil: 'domcontentloaded', timeout: 5000 });
|
|
191
|
+
if (response && response.status() < 400) {
|
|
192
|
+
// Check if this page has a login form (password field)
|
|
193
|
+
const hasPasswordField = await this.page.locator('input[type="password"], input[name*="password"], [data-test*="password"], [data-testid*="password"], [id*="password" i], [class*="password" i]').count() > 0;
|
|
194
|
+
if (hasPasswordField) {
|
|
195
|
+
loginUrl = testUrl;
|
|
196
|
+
foundLoginUrl = true;
|
|
197
|
+
console.log(` ✓ Found login form at: ${testUrl}`);
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Continue to next path
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// If no login page found, use homepage as fallback
|
|
207
|
+
if (!foundLoginUrl) {
|
|
208
|
+
loginUrl = `${baseUrl.origin}/`;
|
|
209
|
+
console.log(` ℹ️ No specific login page found, using homepage`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// Convert relative URL to absolute
|
|
214
|
+
if (loginUrl && loginUrl.startsWith('/')) {
|
|
215
|
+
const baseUrl = new URL(this.options.baseUrl);
|
|
216
|
+
loginUrl = `${baseUrl.origin}${loginUrl}`;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Ensure loginUrl is always defined
|
|
220
|
+
if (!loginUrl) {
|
|
221
|
+
const baseUrl = new URL(this.options.baseUrl);
|
|
222
|
+
loginUrl = `${baseUrl.origin}/`;
|
|
223
|
+
console.log(` ℹ️ No login URL provided, using homepage`);
|
|
224
|
+
}
|
|
225
|
+
console.log(`\n🔐 Authentication: Attempting login at ${loginUrl}`);
|
|
226
|
+
// Navigate to login page (if not already there from detection)
|
|
227
|
+
const currentUrl = this.page.url() || '';
|
|
228
|
+
if (currentUrl !== loginUrl) {
|
|
229
|
+
const response = await this.page.goto(loginUrl, { waitUntil: 'domcontentloaded' });
|
|
230
|
+
// Check if we reached the login page successfully
|
|
231
|
+
if (!response || response.status() >= 400) {
|
|
232
|
+
console.warn(`⚠️ Authentication: Could not reach login page (${response?.status()})`);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Wait a bit for dynamic content to load
|
|
237
|
+
await this.page.waitForTimeout(500);
|
|
238
|
+
// Enhanced selectors: use preset selectors if available, otherwise use enhanced defaults
|
|
239
|
+
// Enhanced defaults include data-* attributes which are common in modern apps
|
|
240
|
+
const emailSelectors = presetSelectors?.login?.email ||
|
|
241
|
+
auth.usernameSelector?.split(', ') || [
|
|
242
|
+
// ID selectors (highest priority)
|
|
243
|
+
'#user-name',
|
|
244
|
+
'#username',
|
|
245
|
+
'#user',
|
|
246
|
+
'#email',
|
|
247
|
+
'#login-email',
|
|
248
|
+
'#user-email',
|
|
249
|
+
'#signin-email',
|
|
250
|
+
// data-test attributes (exact match - common in React/Vue apps)
|
|
251
|
+
'[data-test="username"]',
|
|
252
|
+
'[data-test="user-name"]',
|
|
253
|
+
'[data-test="user"]',
|
|
254
|
+
'[data-test="email"]',
|
|
255
|
+
// data-test attributes (contains - more flexible)
|
|
256
|
+
'[data-test*="username"]',
|
|
257
|
+
'[data-test*="user-name"]',
|
|
258
|
+
'[data-test*="user"]',
|
|
259
|
+
'[data-test*="email"]',
|
|
260
|
+
// data-testid attributes (exact match)
|
|
261
|
+
'[data-testid="username"]',
|
|
262
|
+
'[data-testid="user-name"]',
|
|
263
|
+
'[data-testid="user"]',
|
|
264
|
+
'[data-testid="email"]',
|
|
265
|
+
// data-testid attributes (contains)
|
|
266
|
+
'[data-testid*="username"]',
|
|
267
|
+
'[data-testid*="user-name"]',
|
|
268
|
+
'[data-testid*="user"]',
|
|
269
|
+
'[data-testid*="email"]',
|
|
270
|
+
// Other data-* attributes
|
|
271
|
+
'[data-id="username"]',
|
|
272
|
+
'[data-id="email"]',
|
|
273
|
+
'[data-automation="username"]',
|
|
274
|
+
'[data-automation="email"]',
|
|
275
|
+
// name attributes
|
|
276
|
+
'input[name="user-name"]',
|
|
277
|
+
'input[name="username"]',
|
|
278
|
+
'input[name="user"]',
|
|
279
|
+
'input[name="email"]',
|
|
280
|
+
'input[name="email_address"]',
|
|
281
|
+
// type attributes
|
|
282
|
+
'input[type="email"]',
|
|
283
|
+
'input[type="text"]',
|
|
284
|
+
// aria-label
|
|
285
|
+
'input[aria-label*="email" i]',
|
|
286
|
+
'input[aria-label*="username" i]',
|
|
287
|
+
'input[aria-label*="user" i]',
|
|
288
|
+
// placeholder
|
|
289
|
+
'input[placeholder*="email" i]',
|
|
290
|
+
'input[placeholder*="username" i]',
|
|
291
|
+
'input[placeholder*="user" i]',
|
|
292
|
+
];
|
|
293
|
+
const passwordSelectors = presetSelectors?.login?.password ||
|
|
294
|
+
auth.passwordSelector?.split(', ') || [
|
|
295
|
+
'#password',
|
|
296
|
+
'#login-password',
|
|
297
|
+
'#pass',
|
|
298
|
+
'#user-password',
|
|
299
|
+
'[data-test="password"]',
|
|
300
|
+
'[data-test="pass"]',
|
|
301
|
+
'[data-testid="password"]',
|
|
302
|
+
'[data-testid="pass"]',
|
|
303
|
+
'[data-id="password"]',
|
|
304
|
+
'input[name="password"]',
|
|
305
|
+
'input[name="pass"]',
|
|
306
|
+
'input[type="password"]',
|
|
307
|
+
'input[aria-label*="password" i]',
|
|
308
|
+
'input[placeholder*="password" i]',
|
|
309
|
+
];
|
|
310
|
+
const submitSelectors = presetSelectors?.login?.submit ||
|
|
311
|
+
auth.submitSelector?.split(', ') || [
|
|
312
|
+
'button[type="submit"]',
|
|
313
|
+
'#login-button',
|
|
314
|
+
'#login-btn',
|
|
315
|
+
'#signin-button',
|
|
316
|
+
'#submit',
|
|
317
|
+
'[data-test="login-button"]',
|
|
318
|
+
'[data-test="login"]',
|
|
319
|
+
'[data-test="signin"]',
|
|
320
|
+
'[data-test="submit"]',
|
|
321
|
+
'[data-testid="login-button"]',
|
|
322
|
+
'[data-testid="login"]',
|
|
323
|
+
'[data-testid="signin"]',
|
|
324
|
+
'button:has-text("Log in")',
|
|
325
|
+
'button:has-text("Sign in")',
|
|
326
|
+
'button:has-text("Login")',
|
|
327
|
+
'button:has-text("Sign In")',
|
|
328
|
+
'input[type="submit"]',
|
|
329
|
+
'.login-btn',
|
|
330
|
+
'.signin-btn',
|
|
331
|
+
'.btn-login',
|
|
332
|
+
'.btn-signin',
|
|
333
|
+
];
|
|
334
|
+
// Try to find and fill email field
|
|
335
|
+
let emailFilled = false;
|
|
336
|
+
for (const selector of emailSelectors) {
|
|
337
|
+
try {
|
|
338
|
+
const element = await this.page.waitForSelector(selector, { timeout: 1500, state: 'visible' });
|
|
339
|
+
if (element) {
|
|
340
|
+
await element.fill(auth.username || auth.email || '');
|
|
341
|
+
console.log(` ✓ Filled email with selector: ${selector}`);
|
|
342
|
+
emailFilled = true;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// Try next selector
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (!emailFilled) {
|
|
351
|
+
console.warn(' ⚠️ Could not find email field with any selector');
|
|
352
|
+
console.log(' ℹ️ Tried selectors:', emailSelectors.slice(0, 5).join(', '), '...');
|
|
353
|
+
return false;
|
|
354
|
+
}
|
|
355
|
+
// Try to find and fill password field
|
|
356
|
+
let passwordFilled = false;
|
|
357
|
+
for (const selector of passwordSelectors) {
|
|
358
|
+
try {
|
|
359
|
+
const element = await this.page.waitForSelector(selector, { timeout: 2000 });
|
|
360
|
+
if (element) {
|
|
361
|
+
await element.fill(auth.password || '');
|
|
362
|
+
console.log(` ✓ Filled password with selector: ${selector}`);
|
|
363
|
+
passwordFilled = true;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
// Try next selector
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (!passwordFilled) {
|
|
372
|
+
console.warn(' ⚠️ Could not find password field');
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
// Capture URL BEFORE submit to detect navigation
|
|
376
|
+
const beforeUrl = this.page.url();
|
|
377
|
+
// Try to find and click submit button
|
|
378
|
+
let submitClicked = false;
|
|
379
|
+
for (const selector of submitSelectors) {
|
|
380
|
+
try {
|
|
381
|
+
const element = await this.page.waitForSelector(selector, { timeout: 2000 });
|
|
382
|
+
if (element) {
|
|
383
|
+
await element.click();
|
|
384
|
+
console.log(` ✓ Clicked submit with selector: ${selector}`);
|
|
385
|
+
submitClicked = true;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
catch {
|
|
390
|
+
// Try next selector
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (!submitClicked) {
|
|
394
|
+
console.warn(' ⚠️ Could not find submit button');
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
// Wait for navigation after submit
|
|
398
|
+
// Try multiple wait strategies since sites handle redirects differently
|
|
399
|
+
await Promise.race([
|
|
400
|
+
this.page.waitForLoadState('networkidle', { timeout: 10000 }),
|
|
401
|
+
this.page.waitForLoadState('domcontentloaded', { timeout: 5000 }),
|
|
402
|
+
this.page.waitForTimeout(3000), // Minimum wait for AJAX logins
|
|
403
|
+
]).catch(() => {
|
|
404
|
+
// Timeout is OK - continue with current state
|
|
405
|
+
});
|
|
406
|
+
// Additional wait for client-side redirects (common in SPA)
|
|
407
|
+
await this.page.waitForTimeout(2000);
|
|
408
|
+
const afterUrl = this.page.url();
|
|
409
|
+
// Verify auth success with multiple strategies
|
|
410
|
+
const successSelectors = presetSelectors?.login?.successSelectors;
|
|
411
|
+
const urlChanged = beforeUrl !== afterUrl && !afterUrl.includes('/login') && !afterUrl.includes('/signin') && !afterUrl.includes('/auth');
|
|
412
|
+
const hasSuccessIndicator = successSelectors && successSelectors.length > 0
|
|
413
|
+
? await this.page.isVisible(successSelectors[0]).catch(() => false)
|
|
414
|
+
: false;
|
|
415
|
+
// Check for error messages that indicate failed login
|
|
416
|
+
const errorSelectors = [
|
|
417
|
+
'[class*="error" i], [class*="alert" i], [class*="danger" i], [role="alert"]',
|
|
418
|
+
'[data-testid="error"], [data-test="error"]',
|
|
419
|
+
'.error-message, .alert-error, .toast-error',
|
|
420
|
+
];
|
|
421
|
+
let hasError = false;
|
|
422
|
+
for (const errorSel of errorSelectors) {
|
|
423
|
+
try {
|
|
424
|
+
const errorElement = await this.page.locator(errorSel).first();
|
|
425
|
+
if (await errorElement.isVisible().catch(() => false)) {
|
|
426
|
+
const errorText = await errorElement.textContent().catch(() => '');
|
|
427
|
+
if (errorText && /\w/.test(errorText)) {
|
|
428
|
+
console.warn(` ⚠️ Login error detected: ${errorText.trim().substring(0, 100)}`);
|
|
429
|
+
hasError = true;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
// Continue to next selector
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
// Check for common success indicators (logout button, user menu, etc.)
|
|
439
|
+
const commonSuccessIndicators = [
|
|
440
|
+
'button:has-text("Logout")', 'button:has-text("Sign out")', 'button:has-text("Déconnexion")',
|
|
441
|
+
'a:has-text("Logout")', 'a:has-text("Sign out")',
|
|
442
|
+
'[class*="user-menu"], [class*="avatar"]',
|
|
443
|
+
'[data-testid="user-menu"], [data-test="user-menu"]',
|
|
444
|
+
];
|
|
445
|
+
let hasCommonSuccessIndicator = false;
|
|
446
|
+
if (!hasError) {
|
|
447
|
+
for (const indicator of commonSuccessIndicators) {
|
|
448
|
+
try {
|
|
449
|
+
if (await this.page.locator(indicator).count() > 0) {
|
|
450
|
+
hasCommonSuccessIndicator = true;
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
// Continue to next indicator
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
authSuccess = (urlChanged || hasSuccessIndicator || hasCommonSuccessIndicator) && !hasError;
|
|
460
|
+
if (authSuccess) {
|
|
461
|
+
console.log(` ✅ Authentication successful! URL: ${afterUrl}`);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
console.warn(` ⚠️ Authentication may have failed (URL: ${afterUrl})`);
|
|
79
465
|
}
|
|
80
466
|
}
|
|
467
|
+
return authSuccess;
|
|
81
468
|
}
|
|
82
469
|
/**
|
|
83
470
|
* Analyze a single page
|
|
@@ -85,7 +472,11 @@ export class PageAnalyzer {
|
|
|
85
472
|
async analyze(url, depth) {
|
|
86
473
|
if (!this.browser) {
|
|
87
474
|
await this.initBrowser();
|
|
88
|
-
await this.performAuth();
|
|
475
|
+
const authSuccess = await this.performAuth();
|
|
476
|
+
// Auth failure is non-blocking: continue crawl even if auth failed
|
|
477
|
+
if (!authSuccess && this.options.auth) {
|
|
478
|
+
console.log('ℹ️ Authentication failed or incomplete. Continuing crawl with public access...');
|
|
479
|
+
}
|
|
89
480
|
}
|
|
90
481
|
const startTime = Date.now();
|
|
91
482
|
try {
|
|
@@ -96,6 +487,21 @@ export class PageAnalyzer {
|
|
|
96
487
|
});
|
|
97
488
|
const loadTime = Date.now() - startTime;
|
|
98
489
|
const status = response?.status() || 0;
|
|
490
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
491
|
+
// PART 4: HANDLE GDPR/COOKIE CONSENT BANNERS
|
|
492
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
493
|
+
const consentAction = this.options.consentAction || 'accept';
|
|
494
|
+
const consentTimeout = this.options.consentTimeout || 3000;
|
|
495
|
+
await handleConsent(this.page, { action: consentAction, timeout: consentTimeout });
|
|
496
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
497
|
+
// INTELLIGENT SITE PROFILING (First page only)
|
|
498
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
499
|
+
if (!this.siteAnalyzed && depth === 0) {
|
|
500
|
+
console.log('\n🔍 QA360 Site Profiler - Analyse du site en cours...');
|
|
501
|
+
this.siteAnalysis = await this.profiler.analyzeSite(this.page);
|
|
502
|
+
initializeSelectorGenerator(this.siteAnalysis);
|
|
503
|
+
this.siteAnalyzed = true;
|
|
504
|
+
}
|
|
99
505
|
// Get page info
|
|
100
506
|
const title = await this.page.title();
|
|
101
507
|
const path = url.replace(new URL(this.options.baseUrl).origin, '') || '/';
|
|
@@ -151,6 +557,7 @@ export class PageAnalyzer {
|
|
|
151
557
|
selects: [],
|
|
152
558
|
checkboxes: [],
|
|
153
559
|
radios: [],
|
|
560
|
+
iframes: [],
|
|
154
561
|
},
|
|
155
562
|
navigation: {
|
|
156
563
|
main: undefined,
|
|
@@ -173,6 +580,7 @@ export class PageAnalyzer {
|
|
|
173
580
|
const selects = await this.discoverSelects();
|
|
174
581
|
const checkboxes = await this.discoverCheckboxes();
|
|
175
582
|
const radios = await this.discoverRadios();
|
|
583
|
+
const iframes = await this.discoverIframes();
|
|
176
584
|
return {
|
|
177
585
|
buttons,
|
|
178
586
|
links,
|
|
@@ -181,6 +589,7 @@ export class PageAnalyzer {
|
|
|
181
589
|
selects,
|
|
182
590
|
checkboxes,
|
|
183
591
|
radios,
|
|
592
|
+
iframes,
|
|
184
593
|
};
|
|
185
594
|
}
|
|
186
595
|
/**
|
|
@@ -457,7 +866,7 @@ export class PageAnalyzer {
|
|
|
457
866
|
* Discover radio buttons
|
|
458
867
|
*/
|
|
459
868
|
async discoverRadios() {
|
|
460
|
-
const radioSelector =
|
|
869
|
+
const radioSelector = 'input[type="radio"]';
|
|
461
870
|
const radios = await this.page.$$(radioSelector);
|
|
462
871
|
const elements = [];
|
|
463
872
|
for (const el of radios) {
|
|
@@ -473,6 +882,49 @@ export class PageAnalyzer {
|
|
|
473
882
|
}
|
|
474
883
|
return elements;
|
|
475
884
|
}
|
|
885
|
+
/**
|
|
886
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
887
|
+
* PART 5: DISCOVER IFRAMES
|
|
888
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
889
|
+
*/
|
|
890
|
+
async discoverIframes() {
|
|
891
|
+
const elements = await this.page.$$('iframe, frame');
|
|
892
|
+
const iframes = [];
|
|
893
|
+
const baseUrl = new URL(this.options.baseUrl);
|
|
894
|
+
for (const el of elements) {
|
|
895
|
+
try {
|
|
896
|
+
const info = await generateSelectorFromElement(el, this.page);
|
|
897
|
+
const src = await el.getAttribute('src');
|
|
898
|
+
const title = await el.getAttribute('title');
|
|
899
|
+
const name = await el.getAttribute('name');
|
|
900
|
+
// Check if same origin
|
|
901
|
+
let sameOrigin = false;
|
|
902
|
+
if (src) {
|
|
903
|
+
try {
|
|
904
|
+
const frameUrl = new URL(src, baseUrl.origin);
|
|
905
|
+
sameOrigin = frameUrl.origin === baseUrl.origin;
|
|
906
|
+
}
|
|
907
|
+
catch {
|
|
908
|
+
sameOrigin = false;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
// Create frame selector (Playwright format)
|
|
912
|
+
const frameSelector = `${info.selector} >> internal:control=enter-frame`;
|
|
913
|
+
iframes.push({
|
|
914
|
+
...info,
|
|
915
|
+
src: src || undefined,
|
|
916
|
+
title: title || undefined,
|
|
917
|
+
name: name || undefined,
|
|
918
|
+
sameOrigin,
|
|
919
|
+
frameSelector,
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
catch {
|
|
923
|
+
// Skip failed elements
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
return iframes;
|
|
927
|
+
}
|
|
476
928
|
/**
|
|
477
929
|
* Analyze page navigation structure
|
|
478
930
|
*/
|