@empline/preflight 1.0.20
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.
Potentially problematic release.
This version of @empline/preflight might be problematic. Click here for more details.
- package/README.md +540 -0
- package/dist/bin/approve.d.ts +24 -0
- package/dist/bin/approve.d.ts.map +1 -0
- package/dist/bin/approve.js +249 -0
- package/dist/bin/approve.js.map +1 -0
- package/dist/bin/audit.d.ts +64 -0
- package/dist/bin/audit.d.ts.map +1 -0
- package/dist/bin/audit.js +464 -0
- package/dist/bin/audit.js.map +1 -0
- package/dist/bin/install-hooks.d.ts +20 -0
- package/dist/bin/install-hooks.d.ts.map +1 -0
- package/dist/bin/install-hooks.js +204 -0
- package/dist/bin/install-hooks.js.map +1 -0
- package/dist/bin/preflight.d.ts +21 -0
- package/dist/bin/preflight.d.ts.map +1 -0
- package/dist/bin/preflight.js +218 -0
- package/dist/bin/preflight.js.map +1 -0
- package/dist/bin/preinstall.d.ts +15 -0
- package/dist/bin/preinstall.d.ts.map +1 -0
- package/dist/bin/preinstall.js +229 -0
- package/dist/bin/preinstall.js.map +1 -0
- package/dist/bin/review-drift.d.ts +17 -0
- package/dist/bin/review-drift.d.ts.map +1 -0
- package/dist/bin/review-drift.js +292 -0
- package/dist/bin/review-drift.js.map +1 -0
- package/dist/bin/review.d.ts +22 -0
- package/dist/bin/review.d.ts.map +1 -0
- package/dist/bin/review.js +179 -0
- package/dist/bin/review.js.map +1 -0
- package/dist/bin/submit-drift.d.ts +36 -0
- package/dist/bin/submit-drift.d.ts.map +1 -0
- package/dist/bin/submit-drift.js +534 -0
- package/dist/bin/submit-drift.js.map +1 -0
- package/dist/bin/submit.d.ts +23 -0
- package/dist/bin/submit.d.ts.map +1 -0
- package/dist/bin/submit.js +263 -0
- package/dist/bin/submit.js.map +1 -0
- package/dist/bin/watch.d.ts +27 -0
- package/dist/bin/watch.d.ts.map +1 -0
- package/dist/bin/watch.js +327 -0
- package/dist/bin/watch.js.map +1 -0
- package/dist/checks/ai/card-size-detection-validation.d.ts +22 -0
- package/dist/checks/ai/card-size-detection-validation.d.ts.map +1 -0
- package/dist/checks/ai/card-size-detection-validation.js +452 -0
- package/dist/checks/ai/card-size-detection-validation.js.map +1 -0
- package/dist/checks/ai/code-quality-ai.d.ts +17 -0
- package/dist/checks/ai/code-quality-ai.d.ts.map +1 -0
- package/dist/checks/ai/code-quality-ai.js +399 -0
- package/dist/checks/ai/code-quality-ai.js.map +1 -0
- package/dist/checks/ai/recognition-pipeline-validation.d.ts +27 -0
- package/dist/checks/ai/recognition-pipeline-validation.d.ts.map +1 -0
- package/dist/checks/ai/recognition-pipeline-validation.js +808 -0
- package/dist/checks/ai/recognition-pipeline-validation.js.map +1 -0
- package/dist/checks/ai/series-subset-hierarchy.d.ts +21 -0
- package/dist/checks/ai/series-subset-hierarchy.d.ts.map +1 -0
- package/dist/checks/ai/series-subset-hierarchy.js +373 -0
- package/dist/checks/ai/series-subset-hierarchy.js.map +1 -0
- package/dist/checks/api/api-completeness-check.d.ts +26 -0
- package/dist/checks/api/api-completeness-check.d.ts.map +1 -0
- package/dist/checks/api/api-completeness-check.js +311 -0
- package/dist/checks/api/api-completeness-check.js.map +1 -0
- package/dist/checks/api/api-contract-validation.d.ts +24 -0
- package/dist/checks/api/api-contract-validation.d.ts.map +1 -0
- package/dist/checks/api/api-contract-validation.js +219 -0
- package/dist/checks/api/api-contract-validation.js.map +1 -0
- package/dist/checks/api/pagination-validation.d.ts +21 -0
- package/dist/checks/api/pagination-validation.d.ts.map +1 -0
- package/dist/checks/api/pagination-validation.js +270 -0
- package/dist/checks/api/pagination-validation.js.map +1 -0
- package/dist/checks/api/response-consistency.d.ts +21 -0
- package/dist/checks/api/response-consistency.d.ts.map +1 -0
- package/dist/checks/api/response-consistency.js +238 -0
- package/dist/checks/api/response-consistency.js.map +1 -0
- package/dist/checks/api/response-schema-validation.d.ts +25 -0
- package/dist/checks/api/response-schema-validation.d.ts.map +1 -0
- package/dist/checks/api/response-schema-validation.js +288 -0
- package/dist/checks/api/response-schema-validation.js.map +1 -0
- package/dist/checks/api/response-time-budget.d.ts +17 -0
- package/dist/checks/api/response-time-budget.d.ts.map +1 -0
- package/dist/checks/api/response-time-budget.js +294 -0
- package/dist/checks/api/response-time-budget.js.map +1 -0
- package/dist/checks/api/variant-switching-integrity.d.ts +22 -0
- package/dist/checks/api/variant-switching-integrity.d.ts.map +1 -0
- package/dist/checks/api/variant-switching-integrity.js +306 -0
- package/dist/checks/api/variant-switching-integrity.js.map +1 -0
- package/dist/checks/architecture/admin-page-consistency.d.ts +27 -0
- package/dist/checks/architecture/admin-page-consistency.d.ts.map +1 -0
- package/dist/checks/architecture/admin-page-consistency.js +294 -0
- package/dist/checks/architecture/admin-page-consistency.js.map +1 -0
- package/dist/checks/architecture/backend-ui-coverage.d.ts +25 -0
- package/dist/checks/architecture/backend-ui-coverage.d.ts.map +1 -0
- package/dist/checks/architecture/backend-ui-coverage.js +562 -0
- package/dist/checks/architecture/backend-ui-coverage.js.map +1 -0
- package/dist/checks/architecture/component-architecture.d.ts +26 -0
- package/dist/checks/architecture/component-architecture.d.ts.map +1 -0
- package/dist/checks/architecture/component-architecture.js +513 -0
- package/dist/checks/architecture/component-architecture.js.map +1 -0
- package/dist/checks/architecture/component-consolidation-opportunities.d.ts +28 -0
- package/dist/checks/architecture/component-consolidation-opportunities.d.ts.map +1 -0
- package/dist/checks/architecture/component-consolidation-opportunities.js +338 -0
- package/dist/checks/architecture/component-consolidation-opportunities.js.map +1 -0
- package/dist/checks/architecture/orphaned-pages-detection.d.ts +34 -0
- package/dist/checks/architecture/orphaned-pages-detection.d.ts.map +1 -0
- package/dist/checks/architecture/orphaned-pages-detection.js +464 -0
- package/dist/checks/architecture/orphaned-pages-detection.js.map +1 -0
- package/dist/checks/architecture/primitive-component-enforcement.d.ts +25 -0
- package/dist/checks/architecture/primitive-component-enforcement.d.ts.map +1 -0
- package/dist/checks/architecture/primitive-component-enforcement.js +305 -0
- package/dist/checks/architecture/primitive-component-enforcement.js.map +1 -0
- package/dist/checks/architecture/shared-component-enforcement.d.ts +34 -0
- package/dist/checks/architecture/shared-component-enforcement.d.ts.map +1 -0
- package/dist/checks/architecture/shared-component-enforcement.js +725 -0
- package/dist/checks/architecture/shared-component-enforcement.js.map +1 -0
- package/dist/checks/async-cleanup-validation.d.ts +20 -0
- package/dist/checks/async-cleanup-validation.d.ts.map +1 -0
- package/dist/checks/async-cleanup-validation.js +179 -0
- package/dist/checks/async-cleanup-validation.js.map +1 -0
- package/dist/checks/auth/auth-page-consistency.d.ts +25 -0
- package/dist/checks/auth/auth-page-consistency.d.ts.map +1 -0
- package/dist/checks/auth/auth-page-consistency.js +581 -0
- package/dist/checks/auth/auth-page-consistency.js.map +1 -0
- package/dist/checks/auth/authenticated-redirect.d.ts +55 -0
- package/dist/checks/auth/authenticated-redirect.d.ts.map +1 -0
- package/dist/checks/auth/authenticated-redirect.js +389 -0
- package/dist/checks/auth/authenticated-redirect.js.map +1 -0
- package/dist/checks/auth/role-validation.d.ts +31 -0
- package/dist/checks/auth/role-validation.d.ts.map +1 -0
- package/dist/checks/auth/role-validation.js +252 -0
- package/dist/checks/auth/role-validation.js.map +1 -0
- package/dist/checks/auth/session-integrity-validation.d.ts +58 -0
- package/dist/checks/auth/session-integrity-validation.d.ts.map +1 -0
- package/dist/checks/auth/session-integrity-validation.js +402 -0
- package/dist/checks/auth/session-integrity-validation.js.map +1 -0
- package/dist/checks/auth/session-security.d.ts +67 -0
- package/dist/checks/auth/session-security.d.ts.map +1 -0
- package/dist/checks/auth/session-security.js +399 -0
- package/dist/checks/auth/session-security.js.map +1 -0
- package/dist/checks/auth/session-update-safety.d.ts +96 -0
- package/dist/checks/auth/session-update-safety.d.ts.map +1 -0
- package/dist/checks/auth/session-update-safety.js +697 -0
- package/dist/checks/auth/session-update-safety.js.map +1 -0
- package/dist/checks/auth/store-access-delegation.d.ts +33 -0
- package/dist/checks/auth/store-access-delegation.d.ts.map +1 -0
- package/dist/checks/auth/store-access-delegation.js +344 -0
- package/dist/checks/auth/store-access-delegation.js.map +1 -0
- package/dist/checks/business/business-invariants.d.ts +20 -0
- package/dist/checks/business/business-invariants.d.ts.map +1 -0
- package/dist/checks/business/business-invariants.js +174 -0
- package/dist/checks/business/business-invariants.js.map +1 -0
- package/dist/checks/business/currency-precision.d.ts +21 -0
- package/dist/checks/business/currency-precision.d.ts.map +1 -0
- package/dist/checks/business/currency-precision.js +433 -0
- package/dist/checks/business/currency-precision.js.map +1 -0
- package/dist/checks/business/idempotency-key-validation.d.ts +27 -0
- package/dist/checks/business/idempotency-key-validation.d.ts.map +1 -0
- package/dist/checks/business/idempotency-key-validation.js +275 -0
- package/dist/checks/business/idempotency-key-validation.js.map +1 -0
- package/dist/checks/business/image-metadata-injection.d.ts +19 -0
- package/dist/checks/business/image-metadata-injection.d.ts.map +1 -0
- package/dist/checks/business/image-metadata-injection.js +367 -0
- package/dist/checks/business/image-metadata-injection.js.map +1 -0
- package/dist/checks/business/image-upload-optimization.d.ts +20 -0
- package/dist/checks/business/image-upload-optimization.d.ts.map +1 -0
- package/dist/checks/business/image-upload-optimization.js +271 -0
- package/dist/checks/business/image-upload-optimization.js.map +1 -0
- package/dist/checks/business/inventory-atomicity-validation.d.ts +19 -0
- package/dist/checks/business/inventory-atomicity-validation.d.ts.map +1 -0
- package/dist/checks/business/inventory-atomicity-validation.js +257 -0
- package/dist/checks/business/inventory-atomicity-validation.js.map +1 -0
- package/dist/checks/business/order-state-machine-validation.d.ts +19 -0
- package/dist/checks/business/order-state-machine-validation.d.ts.map +1 -0
- package/dist/checks/business/order-state-machine-validation.js +289 -0
- package/dist/checks/business/order-state-machine-validation.js.map +1 -0
- package/dist/checks/business/price-calculation-validation.d.ts +20 -0
- package/dist/checks/business/price-calculation-validation.d.ts.map +1 -0
- package/dist/checks/business/price-calculation-validation.js +247 -0
- package/dist/checks/business/price-calculation-validation.js.map +1 -0
- package/dist/checks/business/price-display-validation.d.ts +22 -0
- package/dist/checks/business/price-display-validation.d.ts.map +1 -0
- package/dist/checks/business/price-display-validation.js +152 -0
- package/dist/checks/business/price-display-validation.js.map +1 -0
- package/dist/checks/business/resilient-recognition-validation.d.ts +26 -0
- package/dist/checks/business/resilient-recognition-validation.d.ts.map +1 -0
- package/dist/checks/business/resilient-recognition-validation.js +230 -0
- package/dist/checks/business/resilient-recognition-validation.js.map +1 -0
- package/dist/checks/business/store-approval-listing-filter.d.ts +19 -0
- package/dist/checks/business/store-approval-listing-filter.d.ts.map +1 -0
- package/dist/checks/business/store-approval-listing-filter.js +176 -0
- package/dist/checks/business/store-approval-listing-filter.js.map +1 -0
- package/dist/checks/business/timezone-handling.d.ts +28 -0
- package/dist/checks/business/timezone-handling.d.ts.map +1 -0
- package/dist/checks/business/timezone-handling.js +294 -0
- package/dist/checks/business/timezone-handling.js.map +1 -0
- package/dist/checks/code-hygiene/any-type-detection.d.ts +30 -0
- package/dist/checks/code-hygiene/any-type-detection.d.ts.map +1 -0
- package/dist/checks/code-hygiene/any-type-detection.js +210 -0
- package/dist/checks/code-hygiene/any-type-detection.js.map +1 -0
- package/dist/checks/code-hygiene/api-error-handling.d.ts +29 -0
- package/dist/checks/code-hygiene/api-error-handling.d.ts.map +1 -0
- package/dist/checks/code-hygiene/api-error-handling.js +285 -0
- package/dist/checks/code-hygiene/api-error-handling.js.map +1 -0
- package/dist/checks/code-hygiene/broken-template-literals.d.ts +24 -0
- package/dist/checks/code-hygiene/broken-template-literals.d.ts.map +1 -0
- package/dist/checks/code-hygiene/broken-template-literals.js +209 -0
- package/dist/checks/code-hygiene/broken-template-literals.js.map +1 -0
- package/dist/checks/code-hygiene/comment-hygiene.d.ts +26 -0
- package/dist/checks/code-hygiene/comment-hygiene.d.ts.map +1 -0
- package/dist/checks/code-hygiene/comment-hygiene.js +421 -0
- package/dist/checks/code-hygiene/comment-hygiene.js.map +1 -0
- package/dist/checks/code-hygiene/console-chars-sync.d.ts +26 -0
- package/dist/checks/code-hygiene/console-chars-sync.d.ts.map +1 -0
- package/dist/checks/code-hygiene/console-chars-sync.js +417 -0
- package/dist/checks/code-hygiene/console-chars-sync.js.map +1 -0
- package/dist/checks/code-hygiene/console-log-detection.d.ts +27 -0
- package/dist/checks/code-hygiene/console-log-detection.d.ts.map +1 -0
- package/dist/checks/code-hygiene/console-log-detection.js +204 -0
- package/dist/checks/code-hygiene/console-log-detection.js.map +1 -0
- package/dist/checks/code-hygiene/dead-code-detection.d.ts +28 -0
- package/dist/checks/code-hygiene/dead-code-detection.d.ts.map +1 -0
- package/dist/checks/code-hygiene/dead-code-detection.js +217 -0
- package/dist/checks/code-hygiene/dead-code-detection.js.map +1 -0
- package/dist/checks/code-hygiene/decorative-separators.d.ts +32 -0
- package/dist/checks/code-hygiene/decorative-separators.d.ts.map +1 -0
- package/dist/checks/code-hygiene/decorative-separators.js +251 -0
- package/dist/checks/code-hygiene/decorative-separators.js.map +1 -0
- package/dist/checks/code-hygiene/empty-catch-detection.d.ts +25 -0
- package/dist/checks/code-hygiene/empty-catch-detection.d.ts.map +1 -0
- package/dist/checks/code-hygiene/empty-catch-detection.js +184 -0
- package/dist/checks/code-hygiene/empty-catch-detection.js.map +1 -0
- package/dist/checks/code-hygiene/fix-hardcoded-emoji.d.ts +18 -0
- package/dist/checks/code-hygiene/fix-hardcoded-emoji.d.ts.map +1 -0
- package/dist/checks/code-hygiene/fix-hardcoded-emoji.js +332 -0
- package/dist/checks/code-hygiene/fix-hardcoded-emoji.js.map +1 -0
- package/dist/checks/code-hygiene/log-level-misuse.d.ts +25 -0
- package/dist/checks/code-hygiene/log-level-misuse.d.ts.map +1 -0
- package/dist/checks/code-hygiene/log-level-misuse.js +383 -0
- package/dist/checks/code-hygiene/log-level-misuse.js.map +1 -0
- package/dist/checks/code-hygiene/missing-logger-import.d.ts +16 -0
- package/dist/checks/code-hygiene/missing-logger-import.d.ts.map +1 -0
- package/dist/checks/code-hygiene/missing-logger-import.js +154 -0
- package/dist/checks/code-hygiene/missing-logger-import.js.map +1 -0
- package/dist/checks/code-hygiene/root-file-hygiene.d.ts +31 -0
- package/dist/checks/code-hygiene/root-file-hygiene.d.ts.map +1 -0
- package/dist/checks/code-hygiene/root-file-hygiene.js +285 -0
- package/dist/checks/code-hygiene/root-file-hygiene.js.map +1 -0
- package/dist/checks/code-hygiene/todo-tracking.d.ts +25 -0
- package/dist/checks/code-hygiene/todo-tracking.d.ts.map +1 -0
- package/dist/checks/code-hygiene/todo-tracking.js +205 -0
- package/dist/checks/code-hygiene/todo-tracking.js.map +1 -0
- package/dist/checks/code-hygiene/unicode-console-compatibility.d.ts +21 -0
- package/dist/checks/code-hygiene/unicode-console-compatibility.d.ts.map +1 -0
- package/dist/checks/code-hygiene/unicode-console-compatibility.js +229 -0
- package/dist/checks/code-hygiene/unicode-console-compatibility.js.map +1 -0
- package/dist/checks/code-quality/duplicate-logic-detection.d.ts +39 -0
- package/dist/checks/code-quality/duplicate-logic-detection.d.ts.map +1 -0
- package/dist/checks/code-quality/duplicate-logic-detection.js +270 -0
- package/dist/checks/code-quality/duplicate-logic-detection.js.map +1 -0
- package/dist/checks/code-quality/feature-flag-hygiene.d.ts +26 -0
- package/dist/checks/code-quality/feature-flag-hygiene.d.ts.map +1 -0
- package/dist/checks/code-quality/feature-flag-hygiene.js +353 -0
- package/dist/checks/code-quality/feature-flag-hygiene.js.map +1 -0
- package/dist/checks/code-quality/grading-config-usage.d.ts +29 -0
- package/dist/checks/code-quality/grading-config-usage.d.ts.map +1 -0
- package/dist/checks/code-quality/grading-config-usage.js +210 -0
- package/dist/checks/code-quality/grading-config-usage.js.map +1 -0
- package/dist/checks/code-quality/legacy-data-pattern-detection.d.ts +36 -0
- package/dist/checks/code-quality/legacy-data-pattern-detection.d.ts.map +1 -0
- package/dist/checks/code-quality/legacy-data-pattern-detection.js +450 -0
- package/dist/checks/code-quality/legacy-data-pattern-detection.js.map +1 -0
- package/dist/checks/code-quality/magic-number-detection.d.ts +30 -0
- package/dist/checks/code-quality/magic-number-detection.d.ts.map +1 -0
- package/dist/checks/code-quality/magic-number-detection.js +405 -0
- package/dist/checks/code-quality/magic-number-detection.js.map +1 -0
- package/dist/checks/code-quality/mock-function-detection.d.ts +32 -0
- package/dist/checks/code-quality/mock-function-detection.d.ts.map +1 -0
- package/dist/checks/code-quality/mock-function-detection.js +244 -0
- package/dist/checks/code-quality/mock-function-detection.js.map +1 -0
- package/dist/checks/code-quality/no-console-production.d.ts +26 -0
- package/dist/checks/code-quality/no-console-production.d.ts.map +1 -0
- package/dist/checks/code-quality/no-console-production.js +272 -0
- package/dist/checks/code-quality/no-console-production.js.map +1 -0
- package/dist/checks/code-quality/shared-utility-gaps.d.ts +27 -0
- package/dist/checks/code-quality/shared-utility-gaps.d.ts.map +1 -0
- package/dist/checks/code-quality/shared-utility-gaps.js +413 -0
- package/dist/checks/code-quality/shared-utility-gaps.js.map +1 -0
- package/dist/checks/code-quality/stub-script-detection.d.ts +32 -0
- package/dist/checks/code-quality/stub-script-detection.d.ts.map +1 -0
- package/dist/checks/code-quality/stub-script-detection.js +211 -0
- package/dist/checks/code-quality/stub-script-detection.js.map +1 -0
- package/dist/checks/code-quality/typescript-type-safety.d.ts +31 -0
- package/dist/checks/code-quality/typescript-type-safety.d.ts.map +1 -0
- package/dist/checks/code-quality/typescript-type-safety.js +228 -0
- package/dist/checks/code-quality/typescript-type-safety.js.map +1 -0
- package/dist/checks/component-imports.d.ts +15 -0
- package/dist/checks/component-imports.d.ts.map +1 -0
- package/dist/checks/component-imports.js +227 -0
- package/dist/checks/component-imports.js.map +1 -0
- package/dist/checks/config/env-completeness.d.ts +20 -0
- package/dist/checks/config/env-completeness.d.ts.map +1 -0
- package/dist/checks/config/env-completeness.js +193 -0
- package/dist/checks/config/env-completeness.js.map +1 -0
- package/dist/checks/coverage-gap-analysis.d.ts +21 -0
- package/dist/checks/coverage-gap-analysis.d.ts.map +1 -0
- package/dist/checks/coverage-gap-analysis.js +779 -0
- package/dist/checks/coverage-gap-analysis.js.map +1 -0
- package/dist/checks/css/dead-css-detection.d.ts +14 -0
- package/dist/checks/css/dead-css-detection.d.ts.map +1 -0
- package/dist/checks/css/dead-css-detection.js +222 -0
- package/dist/checks/css/dead-css-detection.js.map +1 -0
- package/dist/checks/css/sticky-header-validation.d.ts +19 -0
- package/dist/checks/css/sticky-header-validation.d.ts.map +1 -0
- package/dist/checks/css/sticky-header-validation.js +256 -0
- package/dist/checks/css/sticky-header-validation.js.map +1 -0
- package/dist/checks/data-integrity/cart-data-integrity.d.ts +19 -0
- package/dist/checks/data-integrity/cart-data-integrity.d.ts.map +1 -0
- package/dist/checks/data-integrity/cart-data-integrity.js +235 -0
- package/dist/checks/data-integrity/cart-data-integrity.js.map +1 -0
- package/dist/checks/data-integrity/enum-special-chars-validation.d.ts +26 -0
- package/dist/checks/data-integrity/enum-special-chars-validation.d.ts.map +1 -0
- package/dist/checks/data-integrity/enum-special-chars-validation.js +94 -0
- package/dist/checks/data-integrity/enum-special-chars-validation.js.map +1 -0
- package/dist/checks/data-integrity/notification-template-alignment.d.ts +21 -0
- package/dist/checks/data-integrity/notification-template-alignment.d.ts.map +1 -0
- package/dist/checks/data-integrity/notification-template-alignment.js +372 -0
- package/dist/checks/data-integrity/notification-template-alignment.js.map +1 -0
- package/dist/checks/data-integrity/product-data-flow-validation.d.ts +21 -0
- package/dist/checks/data-integrity/product-data-flow-validation.d.ts.map +1 -0
- package/dist/checks/data-integrity/product-data-flow-validation.js +569 -0
- package/dist/checks/data-integrity/product-data-flow-validation.js.map +1 -0
- package/dist/checks/data-integrity/store-data-integrity.d.ts +18 -0
- package/dist/checks/data-integrity/store-data-integrity.d.ts.map +1 -0
- package/dist/checks/data-integrity/store-data-integrity.js +398 -0
- package/dist/checks/data-integrity/store-data-integrity.js.map +1 -0
- package/dist/checks/data-integrity/unwired-functionality.d.ts +22 -0
- package/dist/checks/data-integrity/unwired-functionality.d.ts.map +1 -0
- package/dist/checks/data-integrity/unwired-functionality.js +550 -0
- package/dist/checks/data-integrity/unwired-functionality.js.map +1 -0
- package/dist/checks/database/block-db-push.d.ts +29 -0
- package/dist/checks/database/block-db-push.d.ts.map +1 -0
- package/dist/checks/database/block-db-push.js +138 -0
- package/dist/checks/database/block-db-push.js.map +1 -0
- package/dist/checks/database/grade-integrity.d.ts +13 -0
- package/dist/checks/database/grade-integrity.d.ts.map +1 -0
- package/dist/checks/database/grade-integrity.js +131 -0
- package/dist/checks/database/grade-integrity.js.map +1 -0
- package/dist/checks/database/migration-integrity.d.ts +26 -0
- package/dist/checks/database/migration-integrity.d.ts.map +1 -0
- package/dist/checks/database/migration-integrity.js +239 -0
- package/dist/checks/database/migration-integrity.js.map +1 -0
- package/dist/checks/database/migration-reversibility.d.ts +25 -0
- package/dist/checks/database/migration-reversibility.d.ts.map +1 -0
- package/dist/checks/database/migration-reversibility.js +277 -0
- package/dist/checks/database/migration-reversibility.js.map +1 -0
- package/dist/checks/database/migration-safety.d.ts +27 -0
- package/dist/checks/database/migration-safety.d.ts.map +1 -0
- package/dist/checks/database/migration-safety.js +243 -0
- package/dist/checks/database/migration-safety.js.map +1 -0
- package/dist/checks/database/prisma-client-db-sync.d.ts +24 -0
- package/dist/checks/database/prisma-client-db-sync.d.ts.map +1 -0
- package/dist/checks/database/prisma-client-db-sync.js +226 -0
- package/dist/checks/database/prisma-client-db-sync.js.map +1 -0
- package/dist/checks/database/prisma-drift-prevention.d.ts +29 -0
- package/dist/checks/database/prisma-drift-prevention.d.ts.map +1 -0
- package/dist/checks/database/prisma-drift-prevention.js +614 -0
- package/dist/checks/database/prisma-drift-prevention.js.map +1 -0
- package/dist/checks/database/prisma-overfetch-detection.d.ts +26 -0
- package/dist/checks/database/prisma-overfetch-detection.d.ts.map +1 -0
- package/dist/checks/database/prisma-overfetch-detection.js +666 -0
- package/dist/checks/database/prisma-overfetch-detection.js.map +1 -0
- package/dist/checks/database/prisma-precommit-guard.d.ts +25 -0
- package/dist/checks/database/prisma-precommit-guard.d.ts.map +1 -0
- package/dist/checks/database/prisma-precommit-guard.js +188 -0
- package/dist/checks/database/prisma-precommit-guard.js.map +1 -0
- package/dist/checks/database/prisma-schema-syntax.d.ts +17 -0
- package/dist/checks/database/prisma-schema-syntax.d.ts.map +1 -0
- package/dist/checks/database/prisma-schema-syntax.js +50 -0
- package/dist/checks/database/prisma-schema-syntax.js.map +1 -0
- package/dist/checks/database/prod-db-guardrail.d.ts +20 -0
- package/dist/checks/database/prod-db-guardrail.d.ts.map +1 -0
- package/dist/checks/database/prod-db-guardrail.js +184 -0
- package/dist/checks/database/prod-db-guardrail.js.map +1 -0
- package/dist/checks/database/schema-best-practices.d.ts +24 -0
- package/dist/checks/database/schema-best-practices.d.ts.map +1 -0
- package/dist/checks/database/schema-best-practices.js +393 -0
- package/dist/checks/database/schema-best-practices.js.map +1 -0
- package/dist/checks/database/schema-migration-column-sync.d.ts +33 -0
- package/dist/checks/database/schema-migration-column-sync.d.ts.map +1 -0
- package/dist/checks/database/schema-migration-column-sync.js +561 -0
- package/dist/checks/database/schema-migration-column-sync.js.map +1 -0
- package/dist/checks/database/seed-coverage-validation.d.ts +29 -0
- package/dist/checks/database/seed-coverage-validation.d.ts.map +1 -0
- package/dist/checks/database/seed-coverage-validation.js +595 -0
- package/dist/checks/database/seed-coverage-validation.js.map +1 -0
- package/dist/checks/database/soft-delete-consistency.d.ts +24 -0
- package/dist/checks/database/soft-delete-consistency.d.ts.map +1 -0
- package/dist/checks/database/soft-delete-consistency.js +273 -0
- package/dist/checks/database/soft-delete-consistency.js.map +1 -0
- package/dist/checks/database/tcg-seed-validation.d.ts +29 -0
- package/dist/checks/database/tcg-seed-validation.d.ts.map +1 -0
- package/dist/checks/database/tcg-seed-validation.js +281 -0
- package/dist/checks/database/tcg-seed-validation.js.map +1 -0
- package/dist/checks/database/transaction-integrity.d.ts +25 -0
- package/dist/checks/database/transaction-integrity.d.ts.map +1 -0
- package/dist/checks/database/transaction-integrity.js +275 -0
- package/dist/checks/database/transaction-integrity.js.map +1 -0
- package/dist/checks/database/unused-schema-detection.d.ts +28 -0
- package/dist/checks/database/unused-schema-detection.d.ts.map +1 -0
- package/dist/checks/database/unused-schema-detection.js +624 -0
- package/dist/checks/database/unused-schema-detection.js.map +1 -0
- package/dist/checks/dependencies/deprecated-packages.d.ts +17 -0
- package/dist/checks/dependencies/deprecated-packages.d.ts.map +1 -0
- package/dist/checks/dependencies/deprecated-packages.js +220 -0
- package/dist/checks/dependencies/deprecated-packages.js.map +1 -0
- package/dist/checks/dependencies/weekly-stable-updates.d.ts +27 -0
- package/dist/checks/dependencies/weekly-stable-updates.d.ts.map +1 -0
- package/dist/checks/dependencies/weekly-stable-updates.js +490 -0
- package/dist/checks/dependencies/weekly-stable-updates.js.map +1 -0
- package/dist/checks/deployment/esm-import-extensions.d.ts +23 -0
- package/dist/checks/deployment/esm-import-extensions.d.ts.map +1 -0
- package/dist/checks/deployment/esm-import-extensions.js +183 -0
- package/dist/checks/deployment/esm-import-extensions.js.map +1 -0
- package/dist/checks/deployment/pre-production-checklist-quick.d.ts +15 -0
- package/dist/checks/deployment/pre-production-checklist-quick.d.ts.map +1 -0
- package/dist/checks/deployment/pre-production-checklist-quick.js +140 -0
- package/dist/checks/deployment/pre-production-checklist-quick.js.map +1 -0
- package/dist/checks/deployment/pre-production-checklist.d.ts +18 -0
- package/dist/checks/deployment/pre-production-checklist.d.ts.map +1 -0
- package/dist/checks/deployment/pre-production-checklist.js +219 -0
- package/dist/checks/deployment/pre-production-checklist.js.map +1 -0
- package/dist/checks/deployment/production-config.d.ts +36 -0
- package/dist/checks/deployment/production-config.d.ts.map +1 -0
- package/dist/checks/deployment/production-config.js +424 -0
- package/dist/checks/deployment/production-config.js.map +1 -0
- package/dist/checks/deployment/production-env-validation.d.ts +18 -0
- package/dist/checks/deployment/production-env-validation.d.ts.map +1 -0
- package/dist/checks/deployment/production-env-validation.js +162 -0
- package/dist/checks/deployment/production-env-validation.js.map +1 -0
- package/dist/checks/deployment/rollback-compatibility.d.ts +27 -0
- package/dist/checks/deployment/rollback-compatibility.d.ts.map +1 -0
- package/dist/checks/deployment/rollback-compatibility.js +327 -0
- package/dist/checks/deployment/rollback-compatibility.js.map +1 -0
- package/dist/checks/deprecated-api-usage.d.ts +86 -0
- package/dist/checks/deprecated-api-usage.d.ts.map +1 -0
- package/dist/checks/deprecated-api-usage.js +382 -0
- package/dist/checks/deprecated-api-usage.js.map +1 -0
- package/dist/checks/drift-prevention/api-contract-consistency.d.ts +18 -0
- package/dist/checks/drift-prevention/api-contract-consistency.d.ts.map +1 -0
- package/dist/checks/drift-prevention/api-contract-consistency.js +279 -0
- package/dist/checks/drift-prevention/api-contract-consistency.js.map +1 -0
- package/dist/checks/drift-prevention/breaking-change-detection.d.ts +28 -0
- package/dist/checks/drift-prevention/breaking-change-detection.d.ts.map +1 -0
- package/dist/checks/drift-prevention/breaking-change-detection.js +364 -0
- package/dist/checks/drift-prevention/breaking-change-detection.js.map +1 -0
- package/dist/checks/drift-prevention/component-prop-consistency.d.ts +18 -0
- package/dist/checks/drift-prevention/component-prop-consistency.d.ts.map +1 -0
- package/dist/checks/drift-prevention/component-prop-consistency.js +289 -0
- package/dist/checks/drift-prevention/component-prop-consistency.js.map +1 -0
- package/dist/checks/drift-prevention/database-query-patterns.d.ts +19 -0
- package/dist/checks/drift-prevention/database-query-patterns.d.ts.map +1 -0
- package/dist/checks/drift-prevention/database-query-patterns.js +340 -0
- package/dist/checks/drift-prevention/database-query-patterns.js.map +1 -0
- package/dist/checks/drift-prevention/design-system-consistency.d.ts +18 -0
- package/dist/checks/drift-prevention/design-system-consistency.d.ts.map +1 -0
- package/dist/checks/drift-prevention/design-system-consistency.js +419 -0
- package/dist/checks/drift-prevention/design-system-consistency.js.map +1 -0
- package/dist/checks/drift-prevention/empty-state-consistency.d.ts +17 -0
- package/dist/checks/drift-prevention/empty-state-consistency.d.ts.map +1 -0
- package/dist/checks/drift-prevention/empty-state-consistency.js +257 -0
- package/dist/checks/drift-prevention/empty-state-consistency.js.map +1 -0
- package/dist/checks/drift-prevention/performance-regression-detection.d.ts +18 -0
- package/dist/checks/drift-prevention/performance-regression-detection.d.ts.map +1 -0
- package/dist/checks/drift-prevention/performance-regression-detection.js +444 -0
- package/dist/checks/drift-prevention/performance-regression-detection.js.map +1 -0
- package/dist/checks/drift-prevention/size-convention-consistency.d.ts +40 -0
- package/dist/checks/drift-prevention/size-convention-consistency.d.ts.map +1 -0
- package/dist/checks/drift-prevention/size-convention-consistency.js +219 -0
- package/dist/checks/drift-prevention/size-convention-consistency.js.map +1 -0
- package/dist/checks/drift-prevention/state-management-patterns.d.ts +18 -0
- package/dist/checks/drift-prevention/state-management-patterns.d.ts.map +1 -0
- package/dist/checks/drift-prevention/state-management-patterns.js +240 -0
- package/dist/checks/drift-prevention/state-management-patterns.js.map +1 -0
- package/dist/checks/e2e/e2e-action-outcome-validator.d.ts +21 -0
- package/dist/checks/e2e/e2e-action-outcome-validator.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-action-outcome-validator.js +292 -0
- package/dist/checks/e2e/e2e-action-outcome-validator.js.map +1 -0
- package/dist/checks/e2e/e2e-interaction-coverage-scan.d.ts +21 -0
- package/dist/checks/e2e/e2e-interaction-coverage-scan.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-interaction-coverage-scan.js +1688 -0
- package/dist/checks/e2e/e2e-interaction-coverage-scan.js.map +1 -0
- package/dist/checks/e2e/e2e-interaction-regression.d.ts +19 -0
- package/dist/checks/e2e/e2e-interaction-regression.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-interaction-regression.js +1039 -0
- package/dist/checks/e2e/e2e-interaction-regression.js.map +1 -0
- package/dist/checks/e2e/e2e-outcome-validation.d.ts +33 -0
- package/dist/checks/e2e/e2e-outcome-validation.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-outcome-validation.js +610 -0
- package/dist/checks/e2e/e2e-outcome-validation.js.map +1 -0
- package/dist/checks/e2e/e2e-performance-baseline.d.ts +14 -0
- package/dist/checks/e2e/e2e-performance-baseline.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-performance-baseline.js +289 -0
- package/dist/checks/e2e/e2e-performance-baseline.js.map +1 -0
- package/dist/checks/e2e/e2e-performance-patterns.d.ts +19 -0
- package/dist/checks/e2e/e2e-performance-patterns.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-performance-patterns.js +464 -0
- package/dist/checks/e2e/e2e-performance-patterns.js.map +1 -0
- package/dist/checks/e2e/e2e-performance-regression.d.ts +18 -0
- package/dist/checks/e2e/e2e-performance-regression.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-performance-regression.js +230 -0
- package/dist/checks/e2e/e2e-performance-regression.js.map +1 -0
- package/dist/checks/e2e/e2e-resource-monitoring.d.ts +17 -0
- package/dist/checks/e2e/e2e-resource-monitoring.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-resource-monitoring.js +368 -0
- package/dist/checks/e2e/e2e-resource-monitoring.js.map +1 -0
- package/dist/checks/e2e/e2e-test-redundancy-scan.d.ts +27 -0
- package/dist/checks/e2e/e2e-test-redundancy-scan.d.ts.map +1 -0
- package/dist/checks/e2e/e2e-test-redundancy-scan.js +477 -0
- package/dist/checks/e2e/e2e-test-redundancy-scan.js.map +1 -0
- package/dist/checks/e2e/playwright-config-validator.d.ts +25 -0
- package/dist/checks/e2e/playwright-config-validator.d.ts.map +1 -0
- package/dist/checks/e2e/playwright-config-validator.js +558 -0
- package/dist/checks/e2e/playwright-config-validator.js.map +1 -0
- package/dist/checks/environment/env-duplicates.d.ts +16 -0
- package/dist/checks/environment/env-duplicates.d.ts.map +1 -0
- package/dist/checks/environment/env-duplicates.js +166 -0
- package/dist/checks/environment/env-duplicates.js.map +1 -0
- package/dist/checks/event-listener-cleanup.d.ts +18 -0
- package/dist/checks/event-listener-cleanup.d.ts.map +1 -0
- package/dist/checks/event-listener-cleanup.js +187 -0
- package/dist/checks/event-listener-cleanup.js.map +1 -0
- package/dist/checks/file-naming-conventions.d.ts +21 -0
- package/dist/checks/file-naming-conventions.d.ts.map +1 -0
- package/dist/checks/file-naming-conventions.js +1258 -0
- package/dist/checks/file-naming-conventions.js.map +1 -0
- package/dist/checks/framework/framework-compatibility.d.ts +35 -0
- package/dist/checks/framework/framework-compatibility.d.ts.map +1 -0
- package/dist/checks/framework/framework-compatibility.js +159 -0
- package/dist/checks/framework/framework-compatibility.js.map +1 -0
- package/dist/checks/framework/turbopack-enforcement.d.ts +22 -0
- package/dist/checks/framework/turbopack-enforcement.d.ts.map +1 -0
- package/dist/checks/framework/turbopack-enforcement.js +171 -0
- package/dist/checks/framework/turbopack-enforcement.js.map +1 -0
- package/dist/checks/governance/check-ui-uniformity.d.ts +18 -0
- package/dist/checks/governance/check-ui-uniformity.d.ts.map +1 -0
- package/dist/checks/governance/check-ui-uniformity.js +127 -0
- package/dist/checks/governance/check-ui-uniformity.js.map +1 -0
- package/dist/checks/governance/codeowners-coverage.d.ts +26 -0
- package/dist/checks/governance/codeowners-coverage.d.ts.map +1 -0
- package/dist/checks/governance/codeowners-coverage.js +290 -0
- package/dist/checks/governance/codeowners-coverage.js.map +1 -0
- package/dist/checks/governance/naming-conventions.d.ts +7 -0
- package/dist/checks/governance/naming-conventions.d.ts.map +1 -0
- package/dist/checks/governance/naming-conventions.js +115 -0
- package/dist/checks/governance/naming-conventions.js.map +1 -0
- package/dist/checks/governance/seller-store-naming-consistency.d.ts +32 -0
- package/dist/checks/governance/seller-store-naming-consistency.d.ts.map +1 -0
- package/dist/checks/governance/seller-store-naming-consistency.js +241 -0
- package/dist/checks/governance/seller-store-naming-consistency.js.map +1 -0
- package/dist/checks/governance/store-seller-route-names.d.ts +17 -0
- package/dist/checks/governance/store-seller-route-names.d.ts.map +1 -0
- package/dist/checks/governance/store-seller-route-names.js +170 -0
- package/dist/checks/governance/store-seller-route-names.js.map +1 -0
- package/dist/checks/grading-config-usage.d.ts +23 -0
- package/dist/checks/grading-config-usage.d.ts.map +1 -0
- package/dist/checks/grading-config-usage.js +197 -0
- package/dist/checks/grading-config-usage.js.map +1 -0
- package/dist/checks/help-center-features-validation.d.ts +21 -0
- package/dist/checks/help-center-features-validation.d.ts.map +1 -0
- package/dist/checks/help-center-features-validation.js +529 -0
- package/dist/checks/help-center-features-validation.js.map +1 -0
- package/dist/checks/help-center-validation.d.ts +21 -0
- package/dist/checks/help-center-validation.d.ts.map +1 -0
- package/dist/checks/help-center-validation.js +325 -0
- package/dist/checks/help-center-validation.js.map +1 -0
- package/dist/checks/image/card-edge-protection.d.ts +33 -0
- package/dist/checks/image/card-edge-protection.d.ts.map +1 -0
- package/dist/checks/image/card-edge-protection.js +230 -0
- package/dist/checks/image/card-edge-protection.js.map +1 -0
- package/dist/checks/image/card-orientation-validation.d.ts +34 -0
- package/dist/checks/image/card-orientation-validation.d.ts.map +1 -0
- package/dist/checks/image/card-orientation-validation.js +519 -0
- package/dist/checks/image/card-orientation-validation.js.map +1 -0
- package/dist/checks/integrations/integrations-consolidated.d.ts +76 -0
- package/dist/checks/integrations/integrations-consolidated.d.ts.map +1 -0
- package/dist/checks/integrations/integrations-consolidated.js +493 -0
- package/dist/checks/integrations/integrations-consolidated.js.map +1 -0
- package/dist/checks/integrations/platform-feed-integrity.d.ts +75 -0
- package/dist/checks/integrations/platform-feed-integrity.d.ts.map +1 -0
- package/dist/checks/integrations/platform-feed-integrity.js +487 -0
- package/dist/checks/integrations/platform-feed-integrity.js.map +1 -0
- package/dist/checks/master-preflight.d.ts +56 -0
- package/dist/checks/master-preflight.d.ts.map +1 -0
- package/dist/checks/master-preflight.js +254 -0
- package/dist/checks/master-preflight.js.map +1 -0
- package/dist/checks/nextjs/dynamic-route-exports.d.ts +28 -0
- package/dist/checks/nextjs/dynamic-route-exports.d.ts.map +1 -0
- package/dist/checks/nextjs/dynamic-route-exports.js +201 -0
- package/dist/checks/nextjs/dynamic-route-exports.js.map +1 -0
- package/dist/checks/nextjs/essential-files-validation.d.ts +23 -0
- package/dist/checks/nextjs/essential-files-validation.d.ts.map +1 -0
- package/dist/checks/nextjs/essential-files-validation.js +355 -0
- package/dist/checks/nextjs/essential-files-validation.js.map +1 -0
- package/dist/checks/nextjs/ignore-build-errors.d.ts +15 -0
- package/dist/checks/nextjs/ignore-build-errors.d.ts.map +1 -0
- package/dist/checks/nextjs/ignore-build-errors.js +120 -0
- package/dist/checks/nextjs/ignore-build-errors.js.map +1 -0
- package/dist/checks/nextjs/metadata-api-placement.d.ts +29 -0
- package/dist/checks/nextjs/metadata-api-placement.d.ts.map +1 -0
- package/dist/checks/nextjs/metadata-api-placement.js +274 -0
- package/dist/checks/nextjs/metadata-api-placement.js.map +1 -0
- package/dist/checks/nextjs/nextjs-image-validation.d.ts +52 -0
- package/dist/checks/nextjs/nextjs-image-validation.d.ts.map +1 -0
- package/dist/checks/nextjs/nextjs-image-validation.js +253 -0
- package/dist/checks/nextjs/nextjs-image-validation.js.map +1 -0
- package/dist/checks/nextjs/nextjs16-compatibility.d.ts +39 -0
- package/dist/checks/nextjs/nextjs16-compatibility.d.ts.map +1 -0
- package/dist/checks/nextjs/nextjs16-compatibility.js +1208 -0
- package/dist/checks/nextjs/nextjs16-compatibility.js.map +1 -0
- package/dist/checks/nextjs/static-generation-check.d.ts +25 -0
- package/dist/checks/nextjs/static-generation-check.d.ts.map +1 -0
- package/dist/checks/nextjs/static-generation-check.js +178 -0
- package/dist/checks/nextjs/static-generation-check.js.map +1 -0
- package/dist/checks/observability/centralized-logging-validation.d.ts +22 -0
- package/dist/checks/observability/centralized-logging-validation.d.ts.map +1 -0
- package/dist/checks/observability/centralized-logging-validation.js +285 -0
- package/dist/checks/observability/centralized-logging-validation.js.map +1 -0
- package/dist/checks/order-number-consistency.d.ts +23 -0
- package/dist/checks/order-number-consistency.d.ts.map +1 -0
- package/dist/checks/order-number-consistency.js +288 -0
- package/dist/checks/order-number-consistency.js.map +1 -0
- package/dist/checks/organization/agent-steering-validation.d.ts +16 -0
- package/dist/checks/organization/agent-steering-validation.d.ts.map +1 -0
- package/dist/checks/organization/agent-steering-validation.js +186 -0
- package/dist/checks/organization/agent-steering-validation.js.map +1 -0
- package/dist/checks/organization/api-route-consolidation.d.ts +23 -0
- package/dist/checks/organization/api-route-consolidation.d.ts.map +1 -0
- package/dist/checks/organization/api-route-consolidation.js +364 -0
- package/dist/checks/organization/api-route-consolidation.js.map +1 -0
- package/dist/checks/organization/api-route-naming-validation.d.ts +23 -0
- package/dist/checks/organization/api-route-naming-validation.d.ts.map +1 -0
- package/dist/checks/organization/api-route-naming-validation.js +491 -0
- package/dist/checks/organization/api-route-naming-validation.js.map +1 -0
- package/dist/checks/organization/file-organization-validation.d.ts +18 -0
- package/dist/checks/organization/file-organization-validation.d.ts.map +1 -0
- package/dist/checks/organization/file-organization-validation.js +562 -0
- package/dist/checks/organization/file-organization-validation.js.map +1 -0
- package/dist/checks/organization/npm-script-bloat-prevention.d.ts +40 -0
- package/dist/checks/organization/npm-script-bloat-prevention.d.ts.map +1 -0
- package/dist/checks/organization/npm-script-bloat-prevention.js +412 -0
- package/dist/checks/organization/npm-script-bloat-prevention.js.map +1 -0
- package/dist/checks/organization/preflight-env-check.d.ts +12 -0
- package/dist/checks/organization/preflight-env-check.d.ts.map +1 -0
- package/dist/checks/organization/preflight-env-check.js +157 -0
- package/dist/checks/organization/preflight-env-check.js.map +1 -0
- package/dist/checks/organization/preflight-progress-consistency.d.ts +25 -0
- package/dist/checks/organization/preflight-progress-consistency.d.ts.map +1 -0
- package/dist/checks/organization/preflight-progress-consistency.js +227 -0
- package/dist/checks/organization/preflight-progress-consistency.js.map +1 -0
- package/dist/checks/organization/preflight-system-validation.d.ts +19 -0
- package/dist/checks/organization/preflight-system-validation.d.ts.map +1 -0
- package/dist/checks/organization/preflight-system-validation.js +487 -0
- package/dist/checks/organization/preflight-system-validation.js.map +1 -0
- package/dist/checks/organization/preflight-typescript-validation.d.ts +14 -0
- package/dist/checks/organization/preflight-typescript-validation.d.ts.map +1 -0
- package/dist/checks/organization/preflight-typescript-validation.js +43 -0
- package/dist/checks/organization/preflight-typescript-validation.js.map +1 -0
- package/dist/checks/organization/route-structure-validation.d.ts +18 -0
- package/dist/checks/organization/route-structure-validation.d.ts.map +1 -0
- package/dist/checks/organization/route-structure-validation.js +235 -0
- package/dist/checks/organization/route-structure-validation.js.map +1 -0
- package/dist/checks/organization/steering-bloat-prevention.d.ts +88 -0
- package/dist/checks/organization/steering-bloat-prevention.d.ts.map +1 -0
- package/dist/checks/organization/steering-bloat-prevention.js +1197 -0
- package/dist/checks/organization/steering-bloat-prevention.js.map +1 -0
- package/dist/checks/performance/bundle-optimization-drift.d.ts +18 -0
- package/dist/checks/performance/bundle-optimization-drift.d.ts.map +1 -0
- package/dist/checks/performance/bundle-optimization-drift.js +260 -0
- package/dist/checks/performance/bundle-optimization-drift.js.map +1 -0
- package/dist/checks/performance/bundle-size-regression.d.ts +14 -0
- package/dist/checks/performance/bundle-size-regression.d.ts.map +1 -0
- package/dist/checks/performance/bundle-size-regression.js +236 -0
- package/dist/checks/performance/bundle-size-regression.js.map +1 -0
- package/dist/checks/performance/core-web-vitals.d.ts +39 -0
- package/dist/checks/performance/core-web-vitals.d.ts.map +1 -0
- package/dist/checks/performance/core-web-vitals.js +445 -0
- package/dist/checks/performance/core-web-vitals.js.map +1 -0
- package/dist/checks/performance/mobile-performance-budget.d.ts +29 -0
- package/dist/checks/performance/mobile-performance-budget.d.ts.map +1 -0
- package/dist/checks/performance/mobile-performance-budget.js +415 -0
- package/dist/checks/performance/mobile-performance-budget.js.map +1 -0
- package/dist/checks/performance/runtime-regression.d.ts +17 -0
- package/dist/checks/performance/runtime-regression.d.ts.map +1 -0
- package/dist/checks/performance/runtime-regression.js +425 -0
- package/dist/checks/performance/runtime-regression.js.map +1 -0
- package/dist/checks/performance/unused-preload-detection.d.ts +17 -0
- package/dist/checks/performance/unused-preload-detection.d.ts.map +1 -0
- package/dist/checks/performance/unused-preload-detection.js +185 -0
- package/dist/checks/performance/unused-preload-detection.js.map +1 -0
- package/dist/checks/prisma/prisma7-compatibility.d.ts +29 -0
- package/dist/checks/prisma/prisma7-compatibility.d.ts.map +1 -0
- package/dist/checks/prisma/prisma7-compatibility.js +440 -0
- package/dist/checks/prisma/prisma7-compatibility.js.map +1 -0
- package/dist/checks/quality/component-size.d.ts +13 -0
- package/dist/checks/quality/component-size.d.ts.map +1 -0
- package/dist/checks/quality/component-size.js +104 -0
- package/dist/checks/quality/component-size.js.map +1 -0
- package/dist/checks/quality/critical-type-imports.d.ts +23 -0
- package/dist/checks/quality/critical-type-imports.d.ts.map +1 -0
- package/dist/checks/quality/critical-type-imports.js +632 -0
- package/dist/checks/quality/critical-type-imports.js.map +1 -0
- package/dist/checks/quality/development.d.ts +13 -0
- package/dist/checks/quality/development.d.ts.map +1 -0
- package/dist/checks/quality/development.js +98 -0
- package/dist/checks/quality/development.js.map +1 -0
- package/dist/checks/quality/docs-code-sync.d.ts +27 -0
- package/dist/checks/quality/docs-code-sync.d.ts.map +1 -0
- package/dist/checks/quality/docs-code-sync.js +368 -0
- package/dist/checks/quality/docs-code-sync.js.map +1 -0
- package/dist/checks/quality/duplicate-jsx-attributes.d.ts +23 -0
- package/dist/checks/quality/duplicate-jsx-attributes.d.ts.map +1 -0
- package/dist/checks/quality/duplicate-jsx-attributes.js +201 -0
- package/dist/checks/quality/duplicate-jsx-attributes.js.map +1 -0
- package/dist/checks/quality/file-size.d.ts +13 -0
- package/dist/checks/quality/file-size.d.ts.map +1 -0
- package/dist/checks/quality/file-size.js +97 -0
- package/dist/checks/quality/file-size.js.map +1 -0
- package/dist/checks/quality/file-validation.d.ts +13 -0
- package/dist/checks/quality/file-validation.d.ts.map +1 -0
- package/dist/checks/quality/file-validation.js +103 -0
- package/dist/checks/quality/file-validation.js.map +1 -0
- package/dist/checks/quality/i18n-hardcoded-strings.d.ts +28 -0
- package/dist/checks/quality/i18n-hardcoded-strings.d.ts.map +1 -0
- package/dist/checks/quality/i18n-hardcoded-strings.js +336 -0
- package/dist/checks/quality/i18n-hardcoded-strings.js.map +1 -0
- package/dist/checks/quality/lint-preflight.d.ts +70 -0
- package/dist/checks/quality/lint-preflight.d.ts.map +1 -0
- package/dist/checks/quality/lint-preflight.js +477 -0
- package/dist/checks/quality/lint-preflight.js.map +1 -0
- package/dist/checks/quality/react-namespace-import.d.ts +27 -0
- package/dist/checks/quality/react-namespace-import.d.ts.map +1 -0
- package/dist/checks/quality/react-namespace-import.js +212 -0
- package/dist/checks/quality/react-namespace-import.js.map +1 -0
- package/dist/checks/quality/strict-lint.d.ts +13 -0
- package/dist/checks/quality/strict-lint.d.ts.map +1 -0
- package/dist/checks/quality/strict-lint.js +41 -0
- package/dist/checks/quality/strict-lint.js.map +1 -0
- package/dist/checks/quality/syntax.d.ts +13 -0
- package/dist/checks/quality/syntax.d.ts.map +1 -0
- package/dist/checks/quality/syntax.js +94 -0
- package/dist/checks/quality/syntax.js.map +1 -0
- package/dist/checks/quality/unused-imports.d.ts +14 -0
- package/dist/checks/quality/unused-imports.d.ts.map +1 -0
- package/dist/checks/quality/unused-imports.js +172 -0
- package/dist/checks/quality/unused-imports.js.map +1 -0
- package/dist/checks/react/component-best-practices.d.ts +23 -0
- package/dist/checks/react/component-best-practices.d.ts.map +1 -0
- package/dist/checks/react/component-best-practices.js +273 -0
- package/dist/checks/react/component-best-practices.js.map +1 -0
- package/dist/checks/react/error-boundary-coverage.d.ts +26 -0
- package/dist/checks/react/error-boundary-coverage.d.ts.map +1 -0
- package/dist/checks/react/error-boundary-coverage.js +304 -0
- package/dist/checks/react/error-boundary-coverage.js.map +1 -0
- package/dist/checks/react/memory-leak-detection.d.ts +22 -0
- package/dist/checks/react/memory-leak-detection.d.ts.map +1 -0
- package/dist/checks/react/memory-leak-detection.js +268 -0
- package/dist/checks/react/memory-leak-detection.js.map +1 -0
- package/dist/checks/react/memory-leak-patterns.d.ts +27 -0
- package/dist/checks/react/memory-leak-patterns.d.ts.map +1 -0
- package/dist/checks/react/memory-leak-patterns.js +324 -0
- package/dist/checks/react/memory-leak-patterns.js.map +1 -0
- package/dist/checks/react/react19-compatibility.d.ts +14 -0
- package/dist/checks/react/react19-compatibility.d.ts.map +1 -0
- package/dist/checks/react/react19-compatibility.js +433 -0
- package/dist/checks/react/react19-compatibility.js.map +1 -0
- package/dist/checks/react/useeffect-loop-detector.d.ts +25 -0
- package/dist/checks/react/useeffect-loop-detector.d.ts.map +1 -0
- package/dist/checks/react/useeffect-loop-detector.js +216 -0
- package/dist/checks/react/useeffect-loop-detector.js.map +1 -0
- package/dist/checks/runtime/client-process-env-usage.d.ts +28 -0
- package/dist/checks/runtime/client-process-env-usage.d.ts.map +1 -0
- package/dist/checks/runtime/client-process-env-usage.js +190 -0
- package/dist/checks/runtime/client-process-env-usage.js.map +1 -0
- package/dist/checks/runtime/client-runtime-errors.d.ts +34 -0
- package/dist/checks/runtime/client-runtime-errors.d.ts.map +1 -0
- package/dist/checks/runtime/client-runtime-errors.js +308 -0
- package/dist/checks/runtime/client-runtime-errors.js.map +1 -0
- package/dist/checks/runtime/dev-error-monitoring-system.d.ts +22 -0
- package/dist/checks/runtime/dev-error-monitoring-system.d.ts.map +1 -0
- package/dist/checks/runtime/dev-error-monitoring-system.js +209 -0
- package/dist/checks/runtime/dev-error-monitoring-system.js.map +1 -0
- package/dist/checks/runtime/gtm-installation.d.ts +21 -0
- package/dist/checks/runtime/gtm-installation.d.ts.map +1 -0
- package/dist/checks/runtime/gtm-installation.js +341 -0
- package/dist/checks/runtime/gtm-installation.js.map +1 -0
- package/dist/checks/runtime/json-parse-safety.d.ts +22 -0
- package/dist/checks/runtime/json-parse-safety.d.ts.map +1 -0
- package/dist/checks/runtime/json-parse-safety.js +179 -0
- package/dist/checks/runtime/json-parse-safety.js.map +1 -0
- package/dist/checks/runtime/missing-public-env-import.d.ts +26 -0
- package/dist/checks/runtime/missing-public-env-import.d.ts.map +1 -0
- package/dist/checks/runtime/missing-public-env-import.js +175 -0
- package/dist/checks/runtime/missing-public-env-import.js.map +1 -0
- package/dist/checks/runtime/node-deprecations.d.ts +22 -0
- package/dist/checks/runtime/node-deprecations.d.ts.map +1 -0
- package/dist/checks/runtime/node-deprecations.js +157 -0
- package/dist/checks/runtime/node-deprecations.js.map +1 -0
- package/dist/checks/runtime/node25-compatibility.d.ts +28 -0
- package/dist/checks/runtime/node25-compatibility.d.ts.map +1 -0
- package/dist/checks/runtime/node25-compatibility.js +200 -0
- package/dist/checks/runtime/node25-compatibility.js.map +1 -0
- package/dist/checks/runtime/process-stdio-usage.d.ts +26 -0
- package/dist/checks/runtime/process-stdio-usage.d.ts.map +1 -0
- package/dist/checks/runtime/process-stdio-usage.js +179 -0
- package/dist/checks/runtime/process-stdio-usage.js.map +1 -0
- package/dist/checks/runtime/server-client-decimal.d.ts +25 -0
- package/dist/checks/runtime/server-client-decimal.d.ts.map +1 -0
- package/dist/checks/runtime/server-client-decimal.js +243 -0
- package/dist/checks/runtime/server-client-decimal.js.map +1 -0
- package/dist/checks/security/csrf-protection.d.ts +20 -0
- package/dist/checks/security/csrf-protection.d.ts.map +1 -0
- package/dist/checks/security/csrf-protection.js +249 -0
- package/dist/checks/security/csrf-protection.js.map +1 -0
- package/dist/checks/security/dependency-audit.d.ts +25 -0
- package/dist/checks/security/dependency-audit.d.ts.map +1 -0
- package/dist/checks/security/dependency-audit.js +219 -0
- package/dist/checks/security/dependency-audit.js.map +1 -0
- package/dist/checks/security/env-value-leakage.d.ts +21 -0
- package/dist/checks/security/env-value-leakage.d.ts.map +1 -0
- package/dist/checks/security/env-value-leakage.js +285 -0
- package/dist/checks/security/env-value-leakage.js.map +1 -0
- package/dist/checks/security/no-tracked-env-files.d.ts +18 -0
- package/dist/checks/security/no-tracked-env-files.d.ts.map +1 -0
- package/dist/checks/security/no-tracked-env-files.js +247 -0
- package/dist/checks/security/no-tracked-env-files.js.map +1 -0
- package/dist/checks/security/open-redirect-prevention.d.ts +19 -0
- package/dist/checks/security/open-redirect-prevention.d.ts.map +1 -0
- package/dist/checks/security/open-redirect-prevention.js +238 -0
- package/dist/checks/security/open-redirect-prevention.js.map +1 -0
- package/dist/checks/security/path-traversal-prevention.d.ts +25 -0
- package/dist/checks/security/path-traversal-prevention.d.ts.map +1 -0
- package/dist/checks/security/path-traversal-prevention.js +246 -0
- package/dist/checks/security/path-traversal-prevention.js.map +1 -0
- package/dist/checks/security/permission-security-validation.d.ts +19 -0
- package/dist/checks/security/permission-security-validation.d.ts.map +1 -0
- package/dist/checks/security/permission-security-validation.js +319 -0
- package/dist/checks/security/permission-security-validation.js.map +1 -0
- package/dist/checks/security/prod-command-detection.d.ts +17 -0
- package/dist/checks/security/prod-command-detection.d.ts.map +1 -0
- package/dist/checks/security/prod-command-detection.js +222 -0
- package/dist/checks/security/prod-command-detection.js.map +1 -0
- package/dist/checks/security/rate-limiting-validation.d.ts +19 -0
- package/dist/checks/security/rate-limiting-validation.d.ts.map +1 -0
- package/dist/checks/security/rate-limiting-validation.js +260 -0
- package/dist/checks/security/rate-limiting-validation.js.map +1 -0
- package/dist/checks/security/security-sla-enforcement.d.ts +34 -0
- package/dist/checks/security/security-sla-enforcement.d.ts.map +1 -0
- package/dist/checks/security/security-sla-enforcement.js +349 -0
- package/dist/checks/security/security-sla-enforcement.js.map +1 -0
- package/dist/checks/security/sensitive-data-exposure.d.ts +36 -0
- package/dist/checks/security/sensitive-data-exposure.d.ts.map +1 -0
- package/dist/checks/security/sensitive-data-exposure.js +540 -0
- package/dist/checks/security/sensitive-data-exposure.js.map +1 -0
- package/dist/checks/security/sql-injection-prevention.d.ts +25 -0
- package/dist/checks/security/sql-injection-prevention.d.ts.map +1 -0
- package/dist/checks/security/sql-injection-prevention.js +216 -0
- package/dist/checks/security/sql-injection-prevention.js.map +1 -0
- package/dist/checks/security/turnstile-scope-validation.d.ts +21 -0
- package/dist/checks/security/turnstile-scope-validation.d.ts.map +1 -0
- package/dist/checks/security/turnstile-scope-validation.js +237 -0
- package/dist/checks/security/turnstile-scope-validation.js.map +1 -0
- package/dist/checks/security/unvalidated-route-params.d.ts +28 -0
- package/dist/checks/security/unvalidated-route-params.d.ts.map +1 -0
- package/dist/checks/security/unvalidated-route-params.js +246 -0
- package/dist/checks/security/unvalidated-route-params.js.map +1 -0
- package/dist/checks/security/webhook-security-validation.d.ts +19 -0
- package/dist/checks/security/webhook-security-validation.d.ts.map +1 -0
- package/dist/checks/security/webhook-security-validation.js +258 -0
- package/dist/checks/security/webhook-security-validation.js.map +1 -0
- package/dist/checks/seo/missing-metadata.d.ts +26 -0
- package/dist/checks/seo/missing-metadata.d.ts.map +1 -0
- package/dist/checks/seo/missing-metadata.js +189 -0
- package/dist/checks/seo/missing-metadata.js.map +1 -0
- package/dist/checks/storage-keys-validation.d.ts +25 -0
- package/dist/checks/storage-keys-validation.d.ts.map +1 -0
- package/dist/checks/storage-keys-validation.js +312 -0
- package/dist/checks/storage-keys-validation.js.map +1 -0
- package/dist/checks/store-order-numbers.d.ts +19 -0
- package/dist/checks/store-order-numbers.d.ts.map +1 -0
- package/dist/checks/store-order-numbers.js +238 -0
- package/dist/checks/store-order-numbers.js.map +1 -0
- package/dist/checks/system/analyze-consolidation-candidates.d.ts +17 -0
- package/dist/checks/system/analyze-consolidation-candidates.d.ts.map +1 -0
- package/dist/checks/system/analyze-consolidation-candidates.js +221 -0
- package/dist/checks/system/analyze-consolidation-candidates.js.map +1 -0
- package/dist/checks/system/apply-universal-progress.d.ts +15 -0
- package/dist/checks/system/apply-universal-progress.d.ts.map +1 -0
- package/dist/checks/system/apply-universal-progress.js +292 -0
- package/dist/checks/system/apply-universal-progress.js.map +1 -0
- package/dist/checks/system/broken-preflight-detection.d.ts +30 -0
- package/dist/checks/system/broken-preflight-detection.d.ts.map +1 -0
- package/dist/checks/system/broken-preflight-detection.js +565 -0
- package/dist/checks/system/broken-preflight-detection.js.map +1 -0
- package/dist/checks/system/find-orphaned-preflights.d.ts +19 -0
- package/dist/checks/system/find-orphaned-preflights.d.ts.map +1 -0
- package/dist/checks/system/find-orphaned-preflights.js +157 -0
- package/dist/checks/system/find-orphaned-preflights.js.map +1 -0
- package/dist/checks/system/lint-preflight-consistency.d.ts +25 -0
- package/dist/checks/system/lint-preflight-consistency.d.ts.map +1 -0
- package/dist/checks/system/lint-preflight-consistency.js +374 -0
- package/dist/checks/system/lint-preflight-consistency.js.map +1 -0
- package/dist/checks/system/orphaned-scripts-detection.d.ts +24 -0
- package/dist/checks/system/orphaned-scripts-detection.d.ts.map +1 -0
- package/dist/checks/system/orphaned-scripts-detection.js +335 -0
- package/dist/checks/system/orphaned-scripts-detection.js.map +1 -0
- package/dist/checks/system/preflight-command-validation.d.ts +32 -0
- package/dist/checks/system/preflight-command-validation.d.ts.map +1 -0
- package/dist/checks/system/preflight-command-validation.js +631 -0
- package/dist/checks/system/preflight-command-validation.js.map +1 -0
- package/dist/checks/system/preflight-concurrency-support.d.ts +18 -0
- package/dist/checks/system/preflight-concurrency-support.d.ts.map +1 -0
- package/dist/checks/system/preflight-concurrency-support.js +207 -0
- package/dist/checks/system/preflight-concurrency-support.js.map +1 -0
- package/dist/checks/system/preflight-consolidation-safety.d.ts +16 -0
- package/dist/checks/system/preflight-consolidation-safety.d.ts.map +1 -0
- package/dist/checks/system/preflight-consolidation-safety.js +250 -0
- package/dist/checks/system/preflight-consolidation-safety.js.map +1 -0
- package/dist/checks/system/preflight-coverage-map.d.ts +26 -0
- package/dist/checks/system/preflight-coverage-map.d.ts.map +1 -0
- package/dist/checks/system/preflight-coverage-map.js +295 -0
- package/dist/checks/system/preflight-coverage-map.js.map +1 -0
- package/dist/checks/system/preflight-drift-detector.d.ts +28 -0
- package/dist/checks/system/preflight-drift-detector.d.ts.map +1 -0
- package/dist/checks/system/preflight-drift-detector.js +380 -0
- package/dist/checks/system/preflight-drift-detector.js.map +1 -0
- package/dist/checks/system/preflight-env-var-documentation.d.ts +25 -0
- package/dist/checks/system/preflight-env-var-documentation.d.ts.map +1 -0
- package/dist/checks/system/preflight-env-var-documentation.js +333 -0
- package/dist/checks/system/preflight-env-var-documentation.js.map +1 -0
- package/dist/checks/system/preflight-exit-code-validator.d.ts +30 -0
- package/dist/checks/system/preflight-exit-code-validator.d.ts.map +1 -0
- package/dist/checks/system/preflight-exit-code-validator.js +298 -0
- package/dist/checks/system/preflight-exit-code-validator.js.map +1 -0
- package/dist/checks/system/preflight-false-positive-tracker.d.ts +25 -0
- package/dist/checks/system/preflight-false-positive-tracker.d.ts.map +1 -0
- package/dist/checks/system/preflight-false-positive-tracker.js +262 -0
- package/dist/checks/system/preflight-false-positive-tracker.js.map +1 -0
- package/dist/checks/system/preflight-metadata-validator.d.ts +28 -0
- package/dist/checks/system/preflight-metadata-validator.d.ts.map +1 -0
- package/dist/checks/system/preflight-metadata-validator.js +220 -0
- package/dist/checks/system/preflight-metadata-validator.js.map +1 -0
- package/dist/checks/system/preflight-organization.d.ts +15 -0
- package/dist/checks/system/preflight-organization.d.ts.map +1 -0
- package/dist/checks/system/preflight-organization.js +212 -0
- package/dist/checks/system/preflight-organization.js.map +1 -0
- package/dist/checks/system/preflight-performance-optimizer.d.ts +17 -0
- package/dist/checks/system/preflight-performance-optimizer.d.ts.map +1 -0
- package/dist/checks/system/preflight-performance-optimizer.js +375 -0
- package/dist/checks/system/preflight-performance-optimizer.js.map +1 -0
- package/dist/checks/system/preflight-redundancy-detection.d.ts +28 -0
- package/dist/checks/system/preflight-redundancy-detection.d.ts.map +1 -0
- package/dist/checks/system/preflight-redundancy-detection.js +1168 -0
- package/dist/checks/system/preflight-redundancy-detection.js.map +1 -0
- package/dist/checks/system/preflight-reporting-standards.d.ts +17 -0
- package/dist/checks/system/preflight-reporting-standards.d.ts.map +1 -0
- package/dist/checks/system/preflight-reporting-standards.js +315 -0
- package/dist/checks/system/preflight-reporting-standards.js.map +1 -0
- package/dist/checks/system/preflight-runtime-health.d.ts +29 -0
- package/dist/checks/system/preflight-runtime-health.d.ts.map +1 -0
- package/dist/checks/system/preflight-runtime-health.js +346 -0
- package/dist/checks/system/preflight-runtime-health.js.map +1 -0
- package/dist/checks/system/preflight-schema-validator.d.ts +23 -0
- package/dist/checks/system/preflight-schema-validator.d.ts.map +1 -0
- package/dist/checks/system/preflight-schema-validator.js +322 -0
- package/dist/checks/system/preflight-schema-validator.js.map +1 -0
- package/dist/checks/system/preflight-test-coverage.d.ts +24 -0
- package/dist/checks/system/preflight-test-coverage.d.ts.map +1 -0
- package/dist/checks/system/preflight-test-coverage.js +242 -0
- package/dist/checks/system/preflight-test-coverage.js.map +1 -0
- package/dist/checks/system/script-path-validation.d.ts +30 -0
- package/dist/checks/system/script-path-validation.d.ts.map +1 -0
- package/dist/checks/system/script-path-validation.js +351 -0
- package/dist/checks/system/script-path-validation.js.map +1 -0
- package/dist/checks/system/stale-preflight-detection.d.ts +15 -0
- package/dist/checks/system/stale-preflight-detection.d.ts.map +1 -0
- package/dist/checks/system/stale-preflight-detection.js +200 -0
- package/dist/checks/system/stale-preflight-detection.js.map +1 -0
- package/dist/checks/system/universal-progress-reporter.d.ts +92 -0
- package/dist/checks/system/universal-progress-reporter.d.ts.map +1 -0
- package/dist/checks/system/universal-progress-reporter.js +272 -0
- package/dist/checks/system/universal-progress-reporter.js.map +1 -0
- package/dist/checks/tailwind/tailwind4-compatibility.d.ts +31 -0
- package/dist/checks/tailwind/tailwind4-compatibility.d.ts.map +1 -0
- package/dist/checks/tailwind/tailwind4-compatibility.js +490 -0
- package/dist/checks/tailwind/tailwind4-compatibility.js.map +1 -0
- package/dist/checks/tanstack/tanstack-query-compatibility.d.ts +31 -0
- package/dist/checks/tanstack/tanstack-query-compatibility.d.ts.map +1 -0
- package/dist/checks/tanstack/tanstack-query-compatibility.js +434 -0
- package/dist/checks/tanstack/tanstack-query-compatibility.js.map +1 -0
- package/dist/checks/ui/accessibility-critical.d.ts +18 -0
- package/dist/checks/ui/accessibility-critical.d.ts.map +1 -0
- package/dist/checks/ui/accessibility-critical.js +357 -0
- package/dist/checks/ui/accessibility-critical.js.map +1 -0
- package/dist/checks/ui/alert-button-gap.d.ts +26 -0
- package/dist/checks/ui/alert-button-gap.d.ts.map +1 -0
- package/dist/checks/ui/alert-button-gap.js +215 -0
- package/dist/checks/ui/alert-button-gap.js.map +1 -0
- package/dist/checks/ui/breadcrumb-consistency.d.ts +18 -0
- package/dist/checks/ui/breadcrumb-consistency.d.ts.map +1 -0
- package/dist/checks/ui/breadcrumb-consistency.js +237 -0
- package/dist/checks/ui/breadcrumb-consistency.js.map +1 -0
- package/dist/checks/ui/button-group-gap.d.ts +22 -0
- package/dist/checks/ui/button-group-gap.d.ts.map +1 -0
- package/dist/checks/ui/button-group-gap.js +194 -0
- package/dist/checks/ui/button-group-gap.js.map +1 -0
- package/dist/checks/ui/button-icon-prop.d.ts +40 -0
- package/dist/checks/ui/button-icon-prop.d.ts.map +1 -0
- package/dist/checks/ui/button-icon-prop.js +248 -0
- package/dist/checks/ui/button-icon-prop.js.map +1 -0
- package/dist/checks/ui/card-section-content-spacing.d.ts +31 -0
- package/dist/checks/ui/card-section-content-spacing.d.ts.map +1 -0
- package/dist/checks/ui/card-section-content-spacing.js +260 -0
- package/dist/checks/ui/card-section-content-spacing.js.map +1 -0
- package/dist/checks/ui/color-check.d.ts +7 -0
- package/dist/checks/ui/color-check.d.ts.map +1 -0
- package/dist/checks/ui/color-check.js +105 -0
- package/dist/checks/ui/color-check.js.map +1 -0
- package/dist/checks/ui/component-library-quality.d.ts +19 -0
- package/dist/checks/ui/component-library-quality.d.ts.map +1 -0
- package/dist/checks/ui/component-library-quality.js +231 -0
- package/dist/checks/ui/component-library-quality.js.map +1 -0
- package/dist/checks/ui/component-prop-validation.d.ts +22 -0
- package/dist/checks/ui/component-prop-validation.d.ts.map +1 -0
- package/dist/checks/ui/component-prop-validation.js +271 -0
- package/dist/checks/ui/component-prop-validation.js.map +1 -0
- package/dist/checks/ui/console-log-check.d.ts +7 -0
- package/dist/checks/ui/console-log-check.d.ts.map +1 -0
- package/dist/checks/ui/console-log-check.js +126 -0
- package/dist/checks/ui/console-log-check.js.map +1 -0
- package/dist/checks/ui/css-grid-gap-check.d.ts +24 -0
- package/dist/checks/ui/css-grid-gap-check.d.ts.map +1 -0
- package/dist/checks/ui/css-grid-gap-check.js +314 -0
- package/dist/checks/ui/css-grid-gap-check.js.map +1 -0
- package/dist/checks/ui/css-token-syntax.d.ts +22 -0
- package/dist/checks/ui/css-token-syntax.d.ts.map +1 -0
- package/dist/checks/ui/css-token-syntax.js +386 -0
- package/dist/checks/ui/css-token-syntax.js.map +1 -0
- package/dist/checks/ui/dark-mode-support.d.ts +95 -0
- package/dist/checks/ui/dark-mode-support.d.ts.map +1 -0
- package/dist/checks/ui/dark-mode-support.js +702 -0
- package/dist/checks/ui/dark-mode-support.js.map +1 -0
- package/dist/checks/ui/dashboard-section-patterns.d.ts +85 -0
- package/dist/checks/ui/dashboard-section-patterns.d.ts.map +1 -0
- package/dist/checks/ui/dashboard-section-patterns.js +1751 -0
- package/dist/checks/ui/dashboard-section-patterns.js.map +1 -0
- package/dist/checks/ui/dashboard-ui.d.ts +28 -0
- package/dist/checks/ui/dashboard-ui.d.ts.map +1 -0
- package/dist/checks/ui/dashboard-ui.js +503 -0
- package/dist/checks/ui/dashboard-ui.js.map +1 -0
- package/dist/checks/ui/dead-action-detector.d.ts +24 -0
- package/dist/checks/ui/dead-action-detector.d.ts.map +1 -0
- package/dist/checks/ui/dead-action-detector.js +457 -0
- package/dist/checks/ui/dead-action-detector.js.map +1 -0
- package/dist/checks/ui/doubled-padding-check.d.ts +21 -0
- package/dist/checks/ui/doubled-padding-check.d.ts.map +1 -0
- package/dist/checks/ui/doubled-padding-check.js +233 -0
- package/dist/checks/ui/doubled-padding-check.js.map +1 -0
- package/dist/checks/ui/dropdown-positioning-check.d.ts +26 -0
- package/dist/checks/ui/dropdown-positioning-check.d.ts.map +1 -0
- package/dist/checks/ui/dropdown-positioning-check.js +283 -0
- package/dist/checks/ui/dropdown-positioning-check.js.map +1 -0
- package/dist/checks/ui/feature-page-hero-consistency.d.ts +29 -0
- package/dist/checks/ui/feature-page-hero-consistency.d.ts.map +1 -0
- package/dist/checks/ui/feature-page-hero-consistency.js +228 -0
- package/dist/checks/ui/feature-page-hero-consistency.js.map +1 -0
- package/dist/checks/ui/filter-loading-states.d.ts +19 -0
- package/dist/checks/ui/filter-loading-states.d.ts.map +1 -0
- package/dist/checks/ui/filter-loading-states.js +193 -0
- package/dist/checks/ui/filter-loading-states.js.map +1 -0
- package/dist/checks/ui/flex-icon-text-gap.d.ts +30 -0
- package/dist/checks/ui/flex-icon-text-gap.d.ts.map +1 -0
- package/dist/checks/ui/flex-icon-text-gap.js +371 -0
- package/dist/checks/ui/flex-icon-text-gap.js.map +1 -0
- package/dist/checks/ui/form-control-layout-check.d.ts +30 -0
- package/dist/checks/ui/form-control-layout-check.d.ts.map +1 -0
- package/dist/checks/ui/form-control-layout-check.js +287 -0
- package/dist/checks/ui/form-control-layout-check.js.map +1 -0
- package/dist/checks/ui/form-field-consistency.d.ts +29 -0
- package/dist/checks/ui/form-field-consistency.d.ts.map +1 -0
- package/dist/checks/ui/form-field-consistency.js +270 -0
- package/dist/checks/ui/form-field-consistency.js.map +1 -0
- package/dist/checks/ui/gap-spacing-consistency.d.ts +35 -0
- package/dist/checks/ui/gap-spacing-consistency.d.ts.map +1 -0
- package/dist/checks/ui/gap-spacing-consistency.js +316 -0
- package/dist/checks/ui/gap-spacing-consistency.js.map +1 -0
- package/dist/checks/ui/header-action-text-color.d.ts +19 -0
- package/dist/checks/ui/header-action-text-color.d.ts.map +1 -0
- package/dist/checks/ui/header-action-text-color.js +122 -0
- package/dist/checks/ui/header-action-text-color.js.map +1 -0
- package/dist/checks/ui/header-vertical-alignment.d.ts +33 -0
- package/dist/checks/ui/header-vertical-alignment.d.ts.map +1 -0
- package/dist/checks/ui/header-vertical-alignment.js +205 -0
- package/dist/checks/ui/header-vertical-alignment.js.map +1 -0
- package/dist/checks/ui/image-component-check.d.ts +7 -0
- package/dist/checks/ui/image-component-check.d.ts.map +1 -0
- package/dist/checks/ui/image-component-check.js +92 -0
- package/dist/checks/ui/image-component-check.js.map +1 -0
- package/dist/checks/ui/inline-flex-gap-check.d.ts +26 -0
- package/dist/checks/ui/inline-flex-gap-check.d.ts.map +1 -0
- package/dist/checks/ui/inline-flex-gap-check.js +196 -0
- package/dist/checks/ui/inline-flex-gap-check.js.map +1 -0
- package/dist/checks/ui/inline-to-tailwind-check.d.ts +47 -0
- package/dist/checks/ui/inline-to-tailwind-check.d.ts.map +1 -0
- package/dist/checks/ui/inline-to-tailwind-check.js +329 -0
- package/dist/checks/ui/inline-to-tailwind-check.js.map +1 -0
- package/dist/checks/ui/input-label-gap.d.ts +34 -0
- package/dist/checks/ui/input-label-gap.d.ts.map +1 -0
- package/dist/checks/ui/input-label-gap.js +347 -0
- package/dist/checks/ui/input-label-gap.js.map +1 -0
- package/dist/checks/ui/input-width-consistency.d.ts +53 -0
- package/dist/checks/ui/input-width-consistency.d.ts.map +1 -0
- package/dist/checks/ui/input-width-consistency.js +342 -0
- package/dist/checks/ui/input-width-consistency.js.map +1 -0
- package/dist/checks/ui/js-responsive-visibility.d.ts +31 -0
- package/dist/checks/ui/js-responsive-visibility.d.ts.map +1 -0
- package/dist/checks/ui/js-responsive-visibility.js +213 -0
- package/dist/checks/ui/js-responsive-visibility.js.map +1 -0
- package/dist/checks/ui/label-description-spacing.d.ts +30 -0
- package/dist/checks/ui/label-description-spacing.d.ts.map +1 -0
- package/dist/checks/ui/label-description-spacing.js +285 -0
- package/dist/checks/ui/label-description-spacing.js.map +1 -0
- package/dist/checks/ui/layout-shift-detection.d.ts +31 -0
- package/dist/checks/ui/layout-shift-detection.d.ts.map +1 -0
- package/dist/checks/ui/layout-shift-detection.js +398 -0
- package/dist/checks/ui/layout-shift-detection.js.map +1 -0
- package/dist/checks/ui/margin-in-gap-container.d.ts +25 -0
- package/dist/checks/ui/margin-in-gap-container.d.ts.map +1 -0
- package/dist/checks/ui/margin-in-gap-container.js +619 -0
- package/dist/checks/ui/margin-in-gap-container.js.map +1 -0
- package/dist/checks/ui/mega-menu-dropdown-position.d.ts +25 -0
- package/dist/checks/ui/mega-menu-dropdown-position.d.ts.map +1 -0
- package/dist/checks/ui/mega-menu-dropdown-position.js +230 -0
- package/dist/checks/ui/mega-menu-dropdown-position.js.map +1 -0
- package/dist/checks/ui/mega-menu-scrollbar-overlap.d.ts +24 -0
- package/dist/checks/ui/mega-menu-scrollbar-overlap.d.ts.map +1 -0
- package/dist/checks/ui/mega-menu-scrollbar-overlap.js +283 -0
- package/dist/checks/ui/mega-menu-scrollbar-overlap.js.map +1 -0
- package/dist/checks/ui/mega-menu-spacing-check.d.ts +21 -0
- package/dist/checks/ui/mega-menu-spacing-check.d.ts.map +1 -0
- package/dist/checks/ui/mega-menu-spacing-check.js +244 -0
- package/dist/checks/ui/mega-menu-spacing-check.js.map +1 -0
- package/dist/checks/ui/notification-feedback-check.d.ts +37 -0
- package/dist/checks/ui/notification-feedback-check.d.ts.map +1 -0
- package/dist/checks/ui/notification-feedback-check.js +552 -0
- package/dist/checks/ui/notification-feedback-check.js.map +1 -0
- package/dist/checks/ui/overflow-clipping-detection.d.ts +17 -0
- package/dist/checks/ui/overflow-clipping-detection.d.ts.map +1 -0
- package/dist/checks/ui/overflow-clipping-detection.js +198 -0
- package/dist/checks/ui/overflow-clipping-detection.js.map +1 -0
- package/dist/checks/ui/page-layout-spacing.d.ts +29 -0
- package/dist/checks/ui/page-layout-spacing.d.ts.map +1 -0
- package/dist/checks/ui/page-layout-spacing.js +604 -0
- package/dist/checks/ui/page-layout-spacing.js.map +1 -0
- package/dist/checks/ui/path-alias-check.d.ts +7 -0
- package/dist/checks/ui/path-alias-check.d.ts.map +1 -0
- package/dist/checks/ui/path-alias-check.js +95 -0
- package/dist/checks/ui/path-alias-check.js.map +1 -0
- package/dist/checks/ui/product-image-animations.d.ts +70 -0
- package/dist/checks/ui/product-image-animations.d.ts.map +1 -0
- package/dist/checks/ui/product-image-animations.js +332 -0
- package/dist/checks/ui/product-image-animations.js.map +1 -0
- package/dist/checks/ui/search-width-consistency.d.ts +53 -0
- package/dist/checks/ui/search-width-consistency.d.ts.map +1 -0
- package/dist/checks/ui/search-width-consistency.js +276 -0
- package/dist/checks/ui/search-width-consistency.js.map +1 -0
- package/dist/checks/ui/section-spacing-check.d.ts +30 -0
- package/dist/checks/ui/section-spacing-check.d.ts.map +1 -0
- package/dist/checks/ui/section-spacing-check.js +248 -0
- package/dist/checks/ui/section-spacing-check.js.map +1 -0
- package/dist/checks/ui/sibling-spacing-check.d.ts +25 -0
- package/dist/checks/ui/sibling-spacing-check.d.ts.map +1 -0
- package/dist/checks/ui/sibling-spacing-check.js +329 -0
- package/dist/checks/ui/sibling-spacing-check.js.map +1 -0
- package/dist/checks/ui/sidebar-layout-gap.d.ts +34 -0
- package/dist/checks/ui/sidebar-layout-gap.d.ts.map +1 -0
- package/dist/checks/ui/sidebar-layout-gap.js +200 -0
- package/dist/checks/ui/sidebar-layout-gap.js.map +1 -0
- package/dist/checks/ui/skeleton-size-consistency.d.ts +50 -0
- package/dist/checks/ui/skeleton-size-consistency.d.ts.map +1 -0
- package/dist/checks/ui/skeleton-size-consistency.js +1239 -0
- package/dist/checks/ui/skeleton-size-consistency.js.map +1 -0
- package/dist/checks/ui/spacing-check.d.ts +7 -0
- package/dist/checks/ui/spacing-check.d.ts.map +1 -0
- package/dist/checks/ui/spacing-check.js +100 -0
- package/dist/checks/ui/spacing-check.js.map +1 -0
- package/dist/checks/ui/styling-standards.d.ts +71 -0
- package/dist/checks/ui/styling-standards.d.ts.map +1 -0
- package/dist/checks/ui/styling-standards.js +567 -0
- package/dist/checks/ui/styling-standards.js.map +1 -0
- package/dist/checks/ui/tailwind-consistency.d.ts +26 -0
- package/dist/checks/ui/tailwind-consistency.d.ts.map +1 -0
- package/dist/checks/ui/tailwind-consistency.js +345 -0
- package/dist/checks/ui/tailwind-consistency.js.map +1 -0
- package/dist/checks/ui/tailwind-contrast-check.d.ts +44 -0
- package/dist/checks/ui/tailwind-contrast-check.d.ts.map +1 -0
- package/dist/checks/ui/tailwind-contrast-check.js +457 -0
- package/dist/checks/ui/tailwind-contrast-check.js.map +1 -0
- package/dist/checks/ui/text-button-group-gap.d.ts +29 -0
- package/dist/checks/ui/text-button-group-gap.d.ts.map +1 -0
- package/dist/checks/ui/text-button-group-gap.js +242 -0
- package/dist/checks/ui/text-button-group-gap.js.map +1 -0
- package/dist/checks/ui/typography-check.d.ts +7 -0
- package/dist/checks/ui/typography-check.d.ts.map +1 -0
- package/dist/checks/ui/typography-check.js +114 -0
- package/dist/checks/ui/typography-check.js.map +1 -0
- package/dist/checks/ui/z-index-check.d.ts +25 -0
- package/dist/checks/ui/z-index-check.d.ts.map +1 -0
- package/dist/checks/ui/z-index-check.js +663 -0
- package/dist/checks/ui/z-index-check.js.map +1 -0
- package/dist/checks/zod/zod4-compatibility.d.ts +31 -0
- package/dist/checks/zod/zod4-compatibility.d.ts.map +1 -0
- package/dist/checks/zod/zod4-compatibility.js +412 -0
- package/dist/checks/zod/zod4-compatibility.js.map +1 -0
- package/dist/core/categories.d.ts +40 -0
- package/dist/core/categories.d.ts.map +1 -0
- package/dist/core/categories.js +153 -0
- package/dist/core/categories.js.map +1 -0
- package/dist/core/config.d.ts +87 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +176 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/types.d.ts +194 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +24 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +207 -0
- package/dist/index.js.map +1 -0
- package/dist/runner.d.ts +33 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +457 -0
- package/dist/runner.js.map +1 -0
- package/dist/shared/concurrency-config.d.ts +57 -0
- package/dist/shared/concurrency-config.d.ts.map +1 -0
- package/dist/shared/concurrency-config.js +128 -0
- package/dist/shared/concurrency-config.js.map +1 -0
- package/dist/shared/design-tokens-config.d.ts +140 -0
- package/dist/shared/design-tokens-config.d.ts.map +1 -0
- package/dist/shared/design-tokens-config.js +290 -0
- package/dist/shared/design-tokens-config.js.map +1 -0
- package/dist/shared/design-tokens.d.ts +771 -0
- package/dist/shared/design-tokens.d.ts.map +1 -0
- package/dist/shared/design-tokens.js +873 -0
- package/dist/shared/design-tokens.js.map +1 -0
- package/dist/shared/file-cache.d.ts +379 -0
- package/dist/shared/file-cache.d.ts.map +1 -0
- package/dist/shared/file-cache.js +744 -0
- package/dist/shared/file-cache.js.map +1 -0
- package/dist/shared/glob-patterns.d.ts +200 -0
- package/dist/shared/glob-patterns.d.ts.map +1 -0
- package/dist/shared/glob-patterns.js +291 -0
- package/dist/shared/glob-patterns.js.map +1 -0
- package/dist/shared/layout-constants.d.ts +101 -0
- package/dist/shared/layout-constants.d.ts.map +1 -0
- package/dist/shared/layout-constants.js +172 -0
- package/dist/shared/layout-constants.js.map +1 -0
- package/dist/utils/config-loader.d.ts +34 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +169 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/console-chars.d.ts +388 -0
- package/dist/utils/console-chars.d.ts.map +1 -0
- package/dist/utils/console-chars.js +378 -0
- package/dist/utils/console-chars.js.map +1 -0
- package/dist/utils/file-scanner.d.ts +73 -0
- package/dist/utils/file-scanner.d.ts.map +1 -0
- package/dist/utils/file-scanner.js +203 -0
- package/dist/utils/file-scanner.js.map +1 -0
- package/dist/utils/findings-writer.d.ts +32 -0
- package/dist/utils/findings-writer.d.ts.map +1 -0
- package/dist/utils/findings-writer.js +69 -0
- package/dist/utils/findings-writer.js.map +1 -0
- package/dist/utils/plugin-loader.d.ts +76 -0
- package/dist/utils/plugin-loader.d.ts.map +1 -0
- package/dist/utils/plugin-loader.js +235 -0
- package/dist/utils/plugin-loader.js.map +1 -0
- package/dist/utils/preflight-runner.d.ts +29 -0
- package/dist/utils/preflight-runner.d.ts.map +1 -0
- package/dist/utils/preflight-runner.js +131 -0
- package/dist/utils/preflight-runner.js.map +1 -0
- package/dist/utils/progress-reporter.d.ts +92 -0
- package/dist/utils/progress-reporter.d.ts.map +1 -0
- package/dist/utils/progress-reporter.js +272 -0
- package/dist/utils/progress-reporter.js.map +1 -0
- package/package.json +78 -0
- package/templates/domain-specific/trading-card-system/tcg-seed-validation.ts +197 -0
- package/templates/new-check.ts.template +205 -0
- package/templates/preflight.config.ts.template +103 -0
|
@@ -0,0 +1,1688 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* E2E Interaction Coverage Scanner
|
|
5
|
+
*
|
|
6
|
+
* Automatically discovers interactive elements in the app and verifies
|
|
7
|
+
* they have corresponding E2E test coverage with outcome verification.
|
|
8
|
+
*
|
|
9
|
+
* This goes beyond the basic critical flow check to find ALL:
|
|
10
|
+
* - Form submissions
|
|
11
|
+
* - Button clicks with side effects
|
|
12
|
+
* - Modal/dialog interactions
|
|
13
|
+
* - CRUD operations
|
|
14
|
+
* - State-changing actions
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.tags = exports.description = exports.blocking = exports.category = exports.name = exports.id = void 0;
|
|
51
|
+
const glob_1 = require("glob");
|
|
52
|
+
const fs = __importStar(require("node:fs"));
|
|
53
|
+
const path = __importStar(require("node:path"));
|
|
54
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
55
|
+
const file_cache_1 = require("../../shared/file-cache");
|
|
56
|
+
// Check metadata
|
|
57
|
+
exports.id = "e2e/e2e-interaction-coverage-scan";
|
|
58
|
+
exports.name = "E2e Interaction Coverage Scan";
|
|
59
|
+
exports.category = "e2e";
|
|
60
|
+
exports.blocking = false;
|
|
61
|
+
exports.description = "E2E Interaction Coverage Scanner";
|
|
62
|
+
exports.tags = ["e2e", "testing"];
|
|
63
|
+
function formatInteractionForReport(i) {
|
|
64
|
+
const selector = i.selectorType && i.selectorValue
|
|
65
|
+
? `${i.selectorType}:${i.selectorValue}`
|
|
66
|
+
: "(no-stable-selector)";
|
|
67
|
+
const file = i.file.replace(process.cwd() + path.sep, "");
|
|
68
|
+
const severityIcon = i.severity === "critical"
|
|
69
|
+
? "${emoji.stop}"
|
|
70
|
+
: i.severity === "high"
|
|
71
|
+
? "${emoji.warning}"
|
|
72
|
+
: i.severity === "medium"
|
|
73
|
+
? "${emoji.warning}"
|
|
74
|
+
: "${emoji.info}";
|
|
75
|
+
const sharedTag = i.isSharedComponent ? " [shared]" : "";
|
|
76
|
+
return `${severityIcon} ${i.type} ${selector}${sharedTag} @ ${file}:${i.line}`;
|
|
77
|
+
}
|
|
78
|
+
function getTopUncoveredInteractions(route, max) {
|
|
79
|
+
const uncovered = route.interactions.filter((i) => !i.hasTestCoverage);
|
|
80
|
+
// Enhancement #4: Sort by severity first, then by selector availability
|
|
81
|
+
const severityOrder = {
|
|
82
|
+
critical: 0,
|
|
83
|
+
high: 1,
|
|
84
|
+
medium: 2,
|
|
85
|
+
low: 3,
|
|
86
|
+
};
|
|
87
|
+
uncovered.sort((a, b) => {
|
|
88
|
+
// First by severity
|
|
89
|
+
const aSeverity = severityOrder[a.severity || "low"];
|
|
90
|
+
const bSeverity = severityOrder[b.severity || "low"];
|
|
91
|
+
if (aSeverity !== bSeverity)
|
|
92
|
+
return aSeverity - bSeverity;
|
|
93
|
+
// Then prefer selector-based actionable controls
|
|
94
|
+
const aHasSelector = Boolean(a.selectorType && a.selectorValue);
|
|
95
|
+
const bHasSelector = Boolean(b.selectorType && b.selectorValue);
|
|
96
|
+
if (aHasSelector !== bHasSelector)
|
|
97
|
+
return aHasSelector ? -1 : 1;
|
|
98
|
+
// Then by line number
|
|
99
|
+
return a.line - b.line;
|
|
100
|
+
});
|
|
101
|
+
return uncovered.slice(0, max);
|
|
102
|
+
}
|
|
103
|
+
function getModeFromArgsOrEnv() {
|
|
104
|
+
const rawEnv = (process.env.PREFLIGHT_INTERACTION_SCAN_MODE || "").toLowerCase();
|
|
105
|
+
const argv = process.argv.slice(2);
|
|
106
|
+
const modeArg = argv.find((a) => a.startsWith("--mode="));
|
|
107
|
+
const rawArg = modeArg ? modeArg.split("=")[1] : "";
|
|
108
|
+
const raw = (rawArg || rawEnv || "block").toLowerCase();
|
|
109
|
+
return raw === "block" ? "block" : "warn";
|
|
110
|
+
}
|
|
111
|
+
function isVerbose() {
|
|
112
|
+
return process.argv.includes("--verbose");
|
|
113
|
+
}
|
|
114
|
+
function isActionsMode() {
|
|
115
|
+
return (process.argv.includes("--actions") ||
|
|
116
|
+
/^(1|true)$/i.test(process.env.PREFLIGHT_INTERACTION_SCAN_ACTIONS ?? ""));
|
|
117
|
+
}
|
|
118
|
+
function isJsonOutput() {
|
|
119
|
+
return process.argv.includes("--json");
|
|
120
|
+
}
|
|
121
|
+
function isQuietMode() {
|
|
122
|
+
return process.argv.includes("--quiet") || process.argv.includes("-q");
|
|
123
|
+
}
|
|
124
|
+
function showHelp() {
|
|
125
|
+
console.log(`
|
|
126
|
+
E2E Interaction Coverage Scanner
|
|
127
|
+
|
|
128
|
+
Usage: npx tsx e2e-interaction-coverage-scan.ts [options]
|
|
129
|
+
|
|
130
|
+
Options:
|
|
131
|
+
--mode=warn|block Set mode (default: block)
|
|
132
|
+
- warn: Report issues but don't fail
|
|
133
|
+
- block: Fail if coverage thresholds not met
|
|
134
|
+
|
|
135
|
+
--actions Enable actions mode (stricter selector-based checks)
|
|
136
|
+
Requires specific click/check/fill patterns for actionable controls
|
|
137
|
+
|
|
138
|
+
Actions mode enhancements:
|
|
139
|
+
- Detects buttons, toggles, selects, menus, tabs, dialogs
|
|
140
|
+
- Tracks form input .fill() coverage
|
|
141
|
+
- Assigns severity levels (critical/high/medium/low)
|
|
142
|
+
- Cross-references shared component library
|
|
143
|
+
- Generates suggested test code snippets
|
|
144
|
+
|
|
145
|
+
--verbose Show detailed output including:
|
|
146
|
+
- Partial coverage routes
|
|
147
|
+
- Suggested test code for uncovered elements
|
|
148
|
+
- Shared component indicators
|
|
149
|
+
|
|
150
|
+
--json Output results in JSON format (for CI integration)
|
|
151
|
+
|
|
152
|
+
--quiet, -q Minimal output (only errors and final result)
|
|
153
|
+
|
|
154
|
+
--help, -h Show this help message
|
|
155
|
+
|
|
156
|
+
Environment Variables:
|
|
157
|
+
PREFLIGHT_INTERACTION_SCAN_MODE Set mode (warn|block)
|
|
158
|
+
PREFLIGHT_INTERACTION_SCAN_ACTIONS Enable actions mode (1|true)
|
|
159
|
+
PREFLIGHT_INTERACTION_SCAN_MIN_ROUTE_COVERAGE Minimum route coverage % (default: 80 in actions mode)
|
|
160
|
+
PREFLIGHT_INTERACTION_SCAN_MIN_OVERALL_COVERAGE Minimum overall coverage % (default: 90 in actions mode)
|
|
161
|
+
|
|
162
|
+
Severity Levels (in actions mode):
|
|
163
|
+
${console_chars_1.emoji.stop} CRITICAL - Payment, checkout, refund, delete actions
|
|
164
|
+
${console_chars_1.emoji.warning} HIGH - Save, submit, approve, reject, form inputs
|
|
165
|
+
${console_chars_1.emoji.warning} MEDIUM - Toggles, selects, menus
|
|
166
|
+
${console_chars_1.emoji.info} LOW - Tabs, accordions, navigation
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
npx tsx e2e-interaction-coverage-scan.ts --mode=warn --verbose
|
|
170
|
+
npx tsx e2e-interaction-coverage-scan.ts --actions --json
|
|
171
|
+
PREFLIGHT_INTERACTION_SCAN_ACTIONS=1 npx tsx e2e-interaction-coverage-scan.ts
|
|
172
|
+
`);
|
|
173
|
+
}
|
|
174
|
+
function shouldShowHelp() {
|
|
175
|
+
return process.argv.includes("--help") || process.argv.includes("-h");
|
|
176
|
+
}
|
|
177
|
+
function getMinRouteCoverage(actionsMode) {
|
|
178
|
+
const raw = process.env.PREFLIGHT_INTERACTION_SCAN_MIN_ROUTE_COVERAGE;
|
|
179
|
+
if (raw) {
|
|
180
|
+
const parsed = Number(raw);
|
|
181
|
+
if (Number.isFinite(parsed))
|
|
182
|
+
return parsed;
|
|
183
|
+
}
|
|
184
|
+
// Threshold for per-route coverage
|
|
185
|
+
// Set to 0 to only warn about low coverage routes without blocking
|
|
186
|
+
// The overall coverage threshold is the primary gate
|
|
187
|
+
return actionsMode ? 0 : 0;
|
|
188
|
+
}
|
|
189
|
+
function getMinOverallCoverage(actionsMode) {
|
|
190
|
+
const raw = process.env.PREFLIGHT_INTERACTION_SCAN_MIN_OVERALL_COVERAGE;
|
|
191
|
+
if (raw) {
|
|
192
|
+
const parsed = Number(raw);
|
|
193
|
+
if (Number.isFinite(parsed))
|
|
194
|
+
return parsed;
|
|
195
|
+
}
|
|
196
|
+
// Overall coverage threshold - 80% is reasonable with enhanced detection
|
|
197
|
+
// This accounts for form inputs, selects, and other new element types
|
|
198
|
+
return actionsMode ? 80 : 0;
|
|
199
|
+
}
|
|
200
|
+
function extractImportSpecifiers(content) {
|
|
201
|
+
const specifiers = [];
|
|
202
|
+
const importFrom = /from\s+["']([^"']+)["']/g;
|
|
203
|
+
let match;
|
|
204
|
+
while ((match = importFrom.exec(content)) !== null) {
|
|
205
|
+
specifiers.push(match[1]);
|
|
206
|
+
}
|
|
207
|
+
const dynamicImport = /import\(\s*["']([^"']+)["']\s*\)/g;
|
|
208
|
+
while ((match = dynamicImport.exec(content)) !== null) {
|
|
209
|
+
specifiers.push(match[1]);
|
|
210
|
+
}
|
|
211
|
+
return specifiers;
|
|
212
|
+
}
|
|
213
|
+
function resolveAppImport(fromFile, specifier) {
|
|
214
|
+
const fromDir = path.dirname(fromFile);
|
|
215
|
+
const candidates = [];
|
|
216
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
217
|
+
const base = path.resolve(fromDir, specifier);
|
|
218
|
+
candidates.push(base);
|
|
219
|
+
}
|
|
220
|
+
else if (specifier.startsWith("@/app/")) {
|
|
221
|
+
const rel = specifier.replace(/^@\//, "");
|
|
222
|
+
candidates.push(path.resolve(process.cwd(), rel));
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
const resolvedCandidates = [];
|
|
228
|
+
for (const base of candidates) {
|
|
229
|
+
if (base.endsWith(".ts") || base.endsWith(".tsx")) {
|
|
230
|
+
resolvedCandidates.push(base);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
resolvedCandidates.push(`${base}.tsx`, `${base}.ts`, path.join(base, "index.tsx"), path.join(base, "index.ts"));
|
|
234
|
+
}
|
|
235
|
+
for (const filePath of resolvedCandidates) {
|
|
236
|
+
if (fs.existsSync(filePath) && filePath.replace(/\\/g, "/").includes("/app/")) {
|
|
237
|
+
return filePath;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
// CACHED FILE LISTS - Scan once, use everywhere
|
|
243
|
+
let _cachedE2ESpecFiles = null;
|
|
244
|
+
async function getE2ESpecFiles() {
|
|
245
|
+
if (!_cachedE2ESpecFiles) {
|
|
246
|
+
_cachedE2ESpecFiles = await file_cache_1.fileCache.getE2ESpecFiles();
|
|
247
|
+
}
|
|
248
|
+
return _cachedE2ESpecFiles;
|
|
249
|
+
}
|
|
250
|
+
async function computeReachableAppFiles(pageFiles) {
|
|
251
|
+
const reachable = new Set();
|
|
252
|
+
const queue = [];
|
|
253
|
+
for (const entry of pageFiles) {
|
|
254
|
+
reachable.add(entry);
|
|
255
|
+
queue.push(entry);
|
|
256
|
+
}
|
|
257
|
+
while (queue.length > 0) {
|
|
258
|
+
const current = queue.pop();
|
|
259
|
+
if (!current)
|
|
260
|
+
continue;
|
|
261
|
+
const content = fs.readFileSync(current, "utf-8");
|
|
262
|
+
const imports = extractImportSpecifiers(content);
|
|
263
|
+
for (const spec of imports) {
|
|
264
|
+
const resolved = resolveAppImport(current, spec);
|
|
265
|
+
if (!resolved)
|
|
266
|
+
continue;
|
|
267
|
+
if (reachable.has(resolved))
|
|
268
|
+
continue;
|
|
269
|
+
reachable.add(resolved);
|
|
270
|
+
queue.push(resolved);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return reachable;
|
|
274
|
+
}
|
|
275
|
+
// Routes that MUST have interaction test coverage
|
|
276
|
+
const REQUIRED_ROUTES = [
|
|
277
|
+
// Critical revenue paths
|
|
278
|
+
{
|
|
279
|
+
route: "/checkout",
|
|
280
|
+
reason: "Payment processing - Critical revenue path",
|
|
281
|
+
severity: "critical",
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
route: "/cart",
|
|
285
|
+
reason: "Cart management - Add, Remove, Update actions",
|
|
286
|
+
severity: "high",
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
route: "/product/",
|
|
290
|
+
reason: "Product page - Add to cart, Sell one like this, Seller links",
|
|
291
|
+
severity: "high",
|
|
292
|
+
},
|
|
293
|
+
// Account settings - User preferences (NEW)
|
|
294
|
+
{
|
|
295
|
+
route: "/account/notifications",
|
|
296
|
+
reason: "Notification preferences - Email/SMS/Push toggles, Save preferences",
|
|
297
|
+
severity: "high",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
route: "/account/profile",
|
|
301
|
+
reason: "Profile management - Update name, email, phone, visibility toggle, permalink",
|
|
302
|
+
severity: "high",
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
route: "/account/settings",
|
|
306
|
+
reason: "Account settings - Profile updates, password change",
|
|
307
|
+
severity: "medium",
|
|
308
|
+
},
|
|
309
|
+
// Store/Seller management
|
|
310
|
+
{
|
|
311
|
+
route: "/store/orders",
|
|
312
|
+
reason: "Order management - Ship, Cancel, Refund actions",
|
|
313
|
+
severity: "high",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
route: "/store/billing",
|
|
317
|
+
reason: "Subscription management - Cancel actions",
|
|
318
|
+
severity: "high",
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
route: "/store/listings/new",
|
|
322
|
+
reason: "Listing creation - Form submission, image upload",
|
|
323
|
+
severity: "high",
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
route: "/store/notifications",
|
|
327
|
+
reason: "Store notification preferences - Email/SMS/Push toggles",
|
|
328
|
+
severity: "medium",
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
route: "/store/profile",
|
|
332
|
+
reason: "Store profile - Update store info, logo upload",
|
|
333
|
+
severity: "medium",
|
|
334
|
+
},
|
|
335
|
+
// Admin management
|
|
336
|
+
{
|
|
337
|
+
route: "/admin/listings",
|
|
338
|
+
reason: "Listing approval - Approve, Reject, Delete, Publish actions",
|
|
339
|
+
severity: "high",
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
route: "/admin/templates",
|
|
343
|
+
reason: "Template management - Delete actions",
|
|
344
|
+
severity: "medium",
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
route: "/admin/users",
|
|
348
|
+
reason: "User management - Suspend, Verify, Block actions",
|
|
349
|
+
severity: "high",
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
route: "/admin/stores",
|
|
353
|
+
reason: "Store management - Verify, Suspend actions",
|
|
354
|
+
severity: "high",
|
|
355
|
+
},
|
|
356
|
+
];
|
|
357
|
+
// Patterns to detect interactive elements
|
|
358
|
+
const INTERACTION_PATTERNS = {
|
|
359
|
+
form: [/onSubmit\s*=\s*\{/g, /handleSubmit/g, /type\s*=\s*["']submit["']/g, /<form\s/gi],
|
|
360
|
+
button: [
|
|
361
|
+
/onClick\s*=\s*\{[^}]*(?:delete|remove|cancel|approve|reject|save|update|create|add|submit|confirm)/gi,
|
|
362
|
+
/handleDelete/g,
|
|
363
|
+
/handleRemove/g,
|
|
364
|
+
/handleApprove/g,
|
|
365
|
+
/handleReject/g,
|
|
366
|
+
/handleSave/g,
|
|
367
|
+
/handleCreate/g,
|
|
368
|
+
/handleUpdate/g,
|
|
369
|
+
/handleCancel/g,
|
|
370
|
+
],
|
|
371
|
+
modal: [/Dialog|Modal/g, /setOpen\s*\(/g, /setIsOpen\s*\(/g, /onClose\s*=\s*\{/g],
|
|
372
|
+
crud: [
|
|
373
|
+
/prisma\.\w+\.create/g,
|
|
374
|
+
/prisma\.\w+\.update/g,
|
|
375
|
+
/prisma\.\w+\.delete/g,
|
|
376
|
+
/\.mutate\s*\(/g,
|
|
377
|
+
/useMutation/g,
|
|
378
|
+
],
|
|
379
|
+
navigation: [/router\.push\s*\(/g, /router\.replace\s*\(/g, /redirect\s*\(/g],
|
|
380
|
+
toggle: [/onChange\s*=\s*\{[^}]*toggle/gi, /setEnabled/g, /setActive/g, /handleToggle/g],
|
|
381
|
+
link: [
|
|
382
|
+
/href\s*=\s*["']\/[^"']+["']/g, // Internal links
|
|
383
|
+
/<Link\s+[^>]*href/g,
|
|
384
|
+
/FooterLink\s+href/g,
|
|
385
|
+
],
|
|
386
|
+
};
|
|
387
|
+
// Enhancement #1: Extended actionable component types
|
|
388
|
+
const ACTION_TAGS = [
|
|
389
|
+
// Buttons - high priority
|
|
390
|
+
{ tag: "Button", type: "button", requires: ["onClick", "typeSubmit"], severity: "high" },
|
|
391
|
+
{ tag: "IconButton", type: "button", requires: ["onClick"], severity: "medium" },
|
|
392
|
+
{ tag: "LoadingButton", type: "button", requires: ["onClick", "typeSubmit"], severity: "high" },
|
|
393
|
+
{ tag: "AnimatedButton", type: "button", requires: ["onClick"], severity: "medium" },
|
|
394
|
+
// Toggles
|
|
395
|
+
{ tag: "Switch", type: "toggle", requires: ["onChange"], severity: "high" },
|
|
396
|
+
{ tag: "Checkbox", type: "toggle", requires: ["onChange"], severity: "medium" },
|
|
397
|
+
{ tag: "Radio", type: "toggle", requires: ["onChange"], severity: "medium" },
|
|
398
|
+
// Forms
|
|
399
|
+
{ tag: "form", type: "form", requires: ["onSubmit"], severity: "critical" },
|
|
400
|
+
// Enhancement #1: New component types
|
|
401
|
+
// Selects and Dropdowns
|
|
402
|
+
{ tag: "Select", type: "select", requires: ["onChange", "onSelect"], severity: "high" },
|
|
403
|
+
{ tag: "SmartDropdown", type: "select", requires: ["onChange", "onSelect"], severity: "medium" },
|
|
404
|
+
{ tag: "CategorySelector", type: "select", requires: ["onChange"], severity: "medium" },
|
|
405
|
+
{ tag: "ConditionSelector", type: "select", requires: ["onChange"], severity: "medium" },
|
|
406
|
+
{ tag: "GradingSelector", type: "select", requires: ["onChange"], severity: "medium" },
|
|
407
|
+
{ tag: "LeagueSelector", type: "select", requires: ["onChange"], severity: "medium" },
|
|
408
|
+
{ tag: "OptionCardSelector", type: "select", requires: ["onChange"], severity: "medium" },
|
|
409
|
+
// Menus
|
|
410
|
+
{ tag: "Menu", type: "menu", requires: ["onClick"], severity: "medium" },
|
|
411
|
+
{ tag: "DropdownMenu", type: "menu", requires: ["onClick"], severity: "medium" },
|
|
412
|
+
{ tag: "ActionCenter", type: "menu", requires: ["onClick"], severity: "medium" },
|
|
413
|
+
{ tag: "QuickActions", type: "menu", requires: ["onClick"], severity: "medium" },
|
|
414
|
+
// Tabs
|
|
415
|
+
{ tag: "Tabs", type: "tab", requires: ["onChange", "onSelect"], severity: "medium" },
|
|
416
|
+
{ tag: "Tab", type: "tab", requires: ["onClick"], severity: "low" },
|
|
417
|
+
// Accordions
|
|
418
|
+
{ tag: "Accordion", type: "accordion", requires: ["onChange"], severity: "low" },
|
|
419
|
+
{ tag: "AccordionItem", type: "accordion", requires: ["onClick"], severity: "low" },
|
|
420
|
+
// Dialogs and Modals
|
|
421
|
+
{ tag: "Dialog", type: "dialog", requires: ["onOpenChange"], severity: "high" },
|
|
422
|
+
{ tag: "Modal", type: "dialog", requires: ["onOpenChange"], severity: "high" },
|
|
423
|
+
{ tag: "UnifiedDialog", type: "dialog", requires: ["onOpenChange"], severity: "high" },
|
|
424
|
+
{ tag: "ConfirmDialog", type: "dialog", requires: ["onOpenChange"], severity: "critical" },
|
|
425
|
+
{ tag: "CompSearchDialog", type: "dialog", requires: ["onOpenChange"], severity: "medium" },
|
|
426
|
+
];
|
|
427
|
+
// Enhancement #2: Form input tags that need .fill() coverage
|
|
428
|
+
const INPUT_TAGS = [
|
|
429
|
+
{ tag: "Input", type: "input", severity: "high" },
|
|
430
|
+
{ tag: "TextField", type: "input", severity: "high" },
|
|
431
|
+
{ tag: "TextArea", type: "input", severity: "medium" },
|
|
432
|
+
{ tag: "Textarea", type: "input", severity: "medium" },
|
|
433
|
+
{ tag: "NumericInput", type: "input", severity: "high" },
|
|
434
|
+
{ tag: "PriceInput", type: "input", severity: "critical" },
|
|
435
|
+
{ tag: "QuantityInput", type: "input", severity: "high" },
|
|
436
|
+
{ tag: "WeightInput", type: "input", severity: "medium" },
|
|
437
|
+
{ tag: "SearchInput", type: "input", severity: "medium" },
|
|
438
|
+
{ tag: "UnifiedSearch", type: "input", severity: "medium" },
|
|
439
|
+
{ tag: "DatePicker", type: "input", severity: "medium" },
|
|
440
|
+
{ tag: "DateRangePicker", type: "input", severity: "medium" },
|
|
441
|
+
];
|
|
442
|
+
// Enhancement #5: Shared component patterns to cross-reference
|
|
443
|
+
const SHARED_COMPONENT_PATTERNS = [
|
|
444
|
+
"UnifiedProductCard",
|
|
445
|
+
"UnifiedDialog",
|
|
446
|
+
"UnifiedEmptyState",
|
|
447
|
+
"UnifiedPagination",
|
|
448
|
+
"UnifiedSearch",
|
|
449
|
+
"ConfirmDialog",
|
|
450
|
+
"EnhancedDataTable",
|
|
451
|
+
"BulkActionToolbar",
|
|
452
|
+
"ActionButtonGroup",
|
|
453
|
+
"ActionCard",
|
|
454
|
+
"ActionRow",
|
|
455
|
+
"QuickActions",
|
|
456
|
+
"FilterSystem",
|
|
457
|
+
"FormBuilder",
|
|
458
|
+
"ImageUploadZone",
|
|
459
|
+
"FileUpload",
|
|
460
|
+
"CardUploadWizard",
|
|
461
|
+
];
|
|
462
|
+
// Critical action patterns that MUST have test coverage
|
|
463
|
+
const CRITICAL_ACTION_PATTERNS = [
|
|
464
|
+
{
|
|
465
|
+
pattern: /handleDelete|onDelete|deleteItem|removeItem/gi,
|
|
466
|
+
name: "Delete action",
|
|
467
|
+
severity: "high",
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
pattern: /handleApprove|onApprove|approveItem|handleApproval/gi,
|
|
471
|
+
name: "Approve action",
|
|
472
|
+
severity: "high",
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
pattern: /handleReject|onReject|rejectItem|handleRejection/gi,
|
|
476
|
+
name: "Reject action",
|
|
477
|
+
severity: "high",
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
pattern: /handlePayment|processPayment|submitPayment/gi,
|
|
481
|
+
name: "Payment action",
|
|
482
|
+
severity: "critical",
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
pattern: /handleCheckout|submitOrder|placeOrder/gi,
|
|
486
|
+
name: "Checkout action",
|
|
487
|
+
severity: "critical",
|
|
488
|
+
},
|
|
489
|
+
{ pattern: /handleRefund|processRefund/gi, name: "Refund action", severity: "critical" },
|
|
490
|
+
{
|
|
491
|
+
pattern: /handleCancel|cancelOrder|cancelSubscription/gi,
|
|
492
|
+
name: "Cancel action",
|
|
493
|
+
severity: "high",
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
pattern: /handleShip|shipOrder|markShipped|markAsShipped/gi,
|
|
497
|
+
name: "Ship action",
|
|
498
|
+
severity: "high",
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
pattern: /handlePublish|publishListing|publishItem/gi,
|
|
502
|
+
name: "Publish action",
|
|
503
|
+
severity: "medium",
|
|
504
|
+
},
|
|
505
|
+
{ pattern: /handleSuspend|suspendUser|suspendStore/gi, name: "Suspend action", severity: "high" },
|
|
506
|
+
{ pattern: /handleVerify|verifyUser|verifyStore/gi, name: "Verify action", severity: "medium" },
|
|
507
|
+
{
|
|
508
|
+
pattern: /handleBulk|bulkAction|bulkDelete|bulkApprove/gi,
|
|
509
|
+
name: "Bulk action",
|
|
510
|
+
severity: "high",
|
|
511
|
+
},
|
|
512
|
+
{ pattern: /handleExport|exportData|downloadCsv/gi, name: "Export action", severity: "medium" },
|
|
513
|
+
{ pattern: /handleImport|importData|uploadCsv/gi, name: "Import action", severity: "medium" },
|
|
514
|
+
// Additional critical patterns
|
|
515
|
+
{
|
|
516
|
+
pattern: /handleArchive|archiveItem|archiveListing/gi,
|
|
517
|
+
name: "Archive action",
|
|
518
|
+
severity: "medium",
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
pattern: /handleRestore|restoreItem|restoreListing/gi,
|
|
522
|
+
name: "Restore action",
|
|
523
|
+
severity: "medium",
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
pattern: /handleDuplicate|duplicateItem|cloneListing/gi,
|
|
527
|
+
name: "Duplicate action",
|
|
528
|
+
severity: "low",
|
|
529
|
+
},
|
|
530
|
+
{ pattern: /handleTransfer|transferOwnership/gi, name: "Transfer action", severity: "high" },
|
|
531
|
+
{ pattern: /handleBlock|blockUser|banUser/gi, name: "Block/Ban action", severity: "high" },
|
|
532
|
+
{ pattern: /handleUnblock|unblockUser|unbanUser/gi, name: "Unblock action", severity: "medium" },
|
|
533
|
+
// Account/Profile settings patterns
|
|
534
|
+
{
|
|
535
|
+
pattern: /handleSave|handleSaveSlug|handleSaveProfileDetails/gi,
|
|
536
|
+
name: "Save settings action",
|
|
537
|
+
severity: "high",
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
pattern: /handleToggleVisibility|toggleNotification|toggleAllForChannel/gi,
|
|
541
|
+
name: "Toggle preference action",
|
|
542
|
+
severity: "high",
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
pattern: /updateProfileVisibility|updateProfileSlug|updateProfileDetails/gi,
|
|
546
|
+
name: "Profile update action",
|
|
547
|
+
severity: "high",
|
|
548
|
+
},
|
|
549
|
+
];
|
|
550
|
+
function extractRouteFromFile(filePath) {
|
|
551
|
+
// Convert file path to route
|
|
552
|
+
// app/store/orders/page.tsx -> /store/orders
|
|
553
|
+
// app/(marketing)/about/page.tsx -> /about
|
|
554
|
+
// app/account/notifications/AccountNotificationsClient.tsx -> /account/notifications
|
|
555
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
556
|
+
let route = normalized
|
|
557
|
+
.replace(/^app/, "")
|
|
558
|
+
.replace(/\/page\.tsx$/, "")
|
|
559
|
+
.replace(/\/[A-Z][a-zA-Z]*Client\.tsx$/, "") // Remove client component files like AccountNotificationsClient.tsx
|
|
560
|
+
.replace(/\/[A-Z][a-zA-Z0-9_]*\.tsx$/, "") // Remove other component files like Step4ProductSelection.tsx
|
|
561
|
+
.replace(/\/\([^)]+\)/g, "") // Remove route groups
|
|
562
|
+
.replace(/\/_components.*$/, "") // Remove component folders
|
|
563
|
+
.replace(/\/components.*$/, "");
|
|
564
|
+
if (!route || route === "")
|
|
565
|
+
route = "/";
|
|
566
|
+
if (!route.startsWith("/"))
|
|
567
|
+
route = "/" + route;
|
|
568
|
+
return route;
|
|
569
|
+
}
|
|
570
|
+
function getLineNumberAtIndex(content, index) {
|
|
571
|
+
return content.substring(0, index).split("\n").length;
|
|
572
|
+
}
|
|
573
|
+
function extractJsxTag(content, startIndex) {
|
|
574
|
+
// Extract a JSX/HTML tag starting at '<' until the matching '>'
|
|
575
|
+
// while respecting string quotes and JSX expression braces.
|
|
576
|
+
if (content[startIndex] !== "<")
|
|
577
|
+
return null;
|
|
578
|
+
let i = startIndex;
|
|
579
|
+
let inSingle = false;
|
|
580
|
+
let inDouble = false;
|
|
581
|
+
let braceDepth = 0;
|
|
582
|
+
while (i < content.length) {
|
|
583
|
+
const ch = content[i];
|
|
584
|
+
const prev = i > startIndex ? content[i - 1] : "";
|
|
585
|
+
if (!inDouble && ch === "'" && prev !== "\\") {
|
|
586
|
+
inSingle = !inSingle;
|
|
587
|
+
}
|
|
588
|
+
else if (!inSingle && ch === '"' && prev !== "\\") {
|
|
589
|
+
inDouble = !inDouble;
|
|
590
|
+
}
|
|
591
|
+
else if (!inSingle && !inDouble) {
|
|
592
|
+
if (ch === "{")
|
|
593
|
+
braceDepth++;
|
|
594
|
+
if (ch === "}" && braceDepth > 0)
|
|
595
|
+
braceDepth--;
|
|
596
|
+
if (ch === ">" && braceDepth === 0) {
|
|
597
|
+
const tagText = content.slice(startIndex, i + 1);
|
|
598
|
+
return { tagText, endIndex: i + 1 };
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
i++;
|
|
602
|
+
}
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
function extractFirstLiteralChildText(content, tagEndIndex, tagName) {
|
|
606
|
+
// Attempts to extract simple literal text like: <Button>Save</Button>
|
|
607
|
+
// Only handles immediate string content (no JSX expressions).
|
|
608
|
+
const after = content.slice(tagEndIndex);
|
|
609
|
+
const closeIdx = after.indexOf(`</${tagName}>`);
|
|
610
|
+
if (closeIdx === -1)
|
|
611
|
+
return null;
|
|
612
|
+
const between = after.slice(0, closeIdx);
|
|
613
|
+
const trimmed = between.replace(/\s+/g, " ").trim();
|
|
614
|
+
if (!trimmed)
|
|
615
|
+
return null;
|
|
616
|
+
if (trimmed.startsWith("{") || trimmed.includes("<"))
|
|
617
|
+
return null;
|
|
618
|
+
return trimmed;
|
|
619
|
+
}
|
|
620
|
+
function parseSelectorFromTag(tagText) {
|
|
621
|
+
const testId = tagText.match(/data-testid\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
622
|
+
if (testId)
|
|
623
|
+
return { selectorType: "testid", selectorValue: testId };
|
|
624
|
+
const aria = tagText.match(/aria-label\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
625
|
+
if (aria)
|
|
626
|
+
return { selectorType: "aria-label", selectorValue: aria };
|
|
627
|
+
const label = tagText.match(/\blabel\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
628
|
+
if (label)
|
|
629
|
+
return { selectorType: "label", selectorValue: label };
|
|
630
|
+
const title = tagText.match(/\btitle\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
631
|
+
if (title)
|
|
632
|
+
return { selectorType: "label", selectorValue: title };
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
function hasRequiredHandler(tagText, requires) {
|
|
636
|
+
const hasOnClick = /\bonClick\s*=\s*\{/i.test(tagText);
|
|
637
|
+
const hasOnChange = /\bonChange\s*=\s*\{/i.test(tagText);
|
|
638
|
+
const hasOnSubmit = /\bonSubmit\s*=\s*\{/i.test(tagText);
|
|
639
|
+
const hasTypeSubmit = /\btype\s*=\s*["']submit["']/i.test(tagText);
|
|
640
|
+
const hasOnSelect = /\bonSelect\s*=\s*\{/i.test(tagText);
|
|
641
|
+
const hasOnOpenChange = /\bonOpenChange\s*=\s*\{/i.test(tagText);
|
|
642
|
+
// For Button, treat submit buttons as actionable even without explicit onClick.
|
|
643
|
+
return requires.some((r) => {
|
|
644
|
+
if (r === "onClick")
|
|
645
|
+
return hasOnClick;
|
|
646
|
+
if (r === "onChange")
|
|
647
|
+
return hasOnChange;
|
|
648
|
+
if (r === "onSubmit")
|
|
649
|
+
return hasOnSubmit;
|
|
650
|
+
if (r === "onSelect")
|
|
651
|
+
return hasOnSelect;
|
|
652
|
+
if (r === "onOpenChange")
|
|
653
|
+
return hasOnOpenChange;
|
|
654
|
+
return hasTypeSubmit;
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
function findActionableControlsInFile(filePath) {
|
|
658
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
659
|
+
const route = extractRouteFromFile(filePath);
|
|
660
|
+
const interactions = [];
|
|
661
|
+
// Enhancement #1: Process ACTION_TAGS (buttons, toggles, selects, menus, tabs, dialogs)
|
|
662
|
+
for (const { tag, type, requires, severity } of ACTION_TAGS) {
|
|
663
|
+
const tagRegex = new RegExp(`<${tag}\\b`, "g");
|
|
664
|
+
let match;
|
|
665
|
+
while ((match = tagRegex.exec(content)) !== null) {
|
|
666
|
+
const startIndex = match.index;
|
|
667
|
+
const tagExtract = extractJsxTag(content, startIndex);
|
|
668
|
+
if (!tagExtract)
|
|
669
|
+
continue;
|
|
670
|
+
const tagText = tagExtract.tagText;
|
|
671
|
+
if (!hasRequiredHandler(tagText, requires))
|
|
672
|
+
continue;
|
|
673
|
+
const selector = parseSelectorFromTag(tagText);
|
|
674
|
+
const line = getLineNumberAtIndex(content, startIndex);
|
|
675
|
+
let name = `${tag}:${type}`;
|
|
676
|
+
let selectorType;
|
|
677
|
+
let selectorValue;
|
|
678
|
+
if (selector) {
|
|
679
|
+
selectorType = selector.selectorType;
|
|
680
|
+
selectorValue = selector.selectorValue;
|
|
681
|
+
name = selector.selectorValue;
|
|
682
|
+
}
|
|
683
|
+
else if (tag === "Button" ||
|
|
684
|
+
tag === "IconButton" ||
|
|
685
|
+
tag === "LoadingButton" ||
|
|
686
|
+
tag === "AnimatedButton") {
|
|
687
|
+
const childText = extractFirstLiteralChildText(content, tagExtract.endIndex, tag);
|
|
688
|
+
if (childText) {
|
|
689
|
+
selectorType = "text";
|
|
690
|
+
selectorValue = childText;
|
|
691
|
+
name = childText;
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
// No stable selector; skip in actions mode to avoid noise.
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
// For toggles/forms without selector, skip in actions mode to avoid noise.
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
// Enhancement #5: Check if this is a shared component
|
|
703
|
+
const isSharedComponent = SHARED_COMPONENT_PATTERNS.some((pattern) => tag === pattern || tagText.includes(pattern));
|
|
704
|
+
// Enhancement #4: Determine severity based on context
|
|
705
|
+
let effectiveSeverity = severity;
|
|
706
|
+
if (selectorValue) {
|
|
707
|
+
const lowerValue = selectorValue.toLowerCase();
|
|
708
|
+
if (/delete|remove|cancel|refund/.test(lowerValue)) {
|
|
709
|
+
effectiveSeverity = "critical";
|
|
710
|
+
}
|
|
711
|
+
else if (/save|submit|confirm|approve|reject/.test(lowerValue)) {
|
|
712
|
+
effectiveSeverity = "high";
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
// Enhancement #6: Generate suggested test code
|
|
716
|
+
const suggestedTest = generateSuggestedTest(route, type, selectorType, selectorValue, name);
|
|
717
|
+
interactions.push({
|
|
718
|
+
file: filePath,
|
|
719
|
+
route,
|
|
720
|
+
type,
|
|
721
|
+
name,
|
|
722
|
+
line,
|
|
723
|
+
hasTestCoverage: false,
|
|
724
|
+
coveringTests: [],
|
|
725
|
+
selectorType,
|
|
726
|
+
selectorValue,
|
|
727
|
+
severity: effectiveSeverity,
|
|
728
|
+
isSharedComponent,
|
|
729
|
+
suggestedTest,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
// Enhancement #2: Process INPUT_TAGS (form inputs that need .fill() coverage)
|
|
734
|
+
for (const { tag, type, severity } of INPUT_TAGS) {
|
|
735
|
+
const tagRegex = new RegExp(`<${tag}\\b`, "g");
|
|
736
|
+
let match;
|
|
737
|
+
while ((match = tagRegex.exec(content)) !== null) {
|
|
738
|
+
const startIndex = match.index;
|
|
739
|
+
const tagExtract = extractJsxTag(content, startIndex);
|
|
740
|
+
if (!tagExtract)
|
|
741
|
+
continue;
|
|
742
|
+
const tagText = tagExtract.tagText;
|
|
743
|
+
const selector = parseSelectorFromTag(tagText);
|
|
744
|
+
const line = getLineNumberAtIndex(content, startIndex);
|
|
745
|
+
// Also check for placeholder as selector
|
|
746
|
+
const placeholder = tagText.match(/placeholder\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
747
|
+
let name = `${tag}:${type}`;
|
|
748
|
+
let selectorType;
|
|
749
|
+
let selectorValue;
|
|
750
|
+
if (selector) {
|
|
751
|
+
selectorType = selector.selectorType;
|
|
752
|
+
selectorValue = selector.selectorValue;
|
|
753
|
+
name = selector.selectorValue;
|
|
754
|
+
}
|
|
755
|
+
else if (placeholder) {
|
|
756
|
+
selectorType = "placeholder";
|
|
757
|
+
selectorValue = placeholder;
|
|
758
|
+
name = placeholder;
|
|
759
|
+
}
|
|
760
|
+
else {
|
|
761
|
+
// No stable selector; skip
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
// Skip toggle/visibility buttons that are incorrectly detected as inputs
|
|
765
|
+
// These are typically IconButtons inside Input endAdornment
|
|
766
|
+
if (selectorValue && /toggle|visibility/i.test(selectorValue)) {
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
769
|
+
// Enhancement #4: Determine severity based on field type
|
|
770
|
+
let effectiveSeverity = severity;
|
|
771
|
+
if (selectorValue) {
|
|
772
|
+
const lowerValue = selectorValue.toLowerCase();
|
|
773
|
+
if (/email|password|card|cvv|ssn|phone/.test(lowerValue)) {
|
|
774
|
+
effectiveSeverity = "critical";
|
|
775
|
+
}
|
|
776
|
+
else if (/name|address|price|amount|quantity/.test(lowerValue)) {
|
|
777
|
+
effectiveSeverity = "high";
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// Enhancement #6: Generate suggested test code
|
|
781
|
+
const suggestedTest = generateSuggestedTestForInput(route, selectorType, selectorValue, name);
|
|
782
|
+
interactions.push({
|
|
783
|
+
file: filePath,
|
|
784
|
+
route,
|
|
785
|
+
type,
|
|
786
|
+
name,
|
|
787
|
+
line,
|
|
788
|
+
hasTestCoverage: false,
|
|
789
|
+
coveringTests: [],
|
|
790
|
+
selectorType,
|
|
791
|
+
selectorValue,
|
|
792
|
+
severity: effectiveSeverity,
|
|
793
|
+
suggestedTest,
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return interactions;
|
|
798
|
+
}
|
|
799
|
+
// Enhancement #6: Generate suggested test code for buttons/actions
|
|
800
|
+
function generateSuggestedTest(route, type, selectorType, selectorValue, name) {
|
|
801
|
+
if (!selectorType || !selectorValue)
|
|
802
|
+
return "";
|
|
803
|
+
const routeForTest = route === "/" ? "/" : route;
|
|
804
|
+
let selector = "";
|
|
805
|
+
let action = ".click()";
|
|
806
|
+
switch (selectorType) {
|
|
807
|
+
case "testid":
|
|
808
|
+
selector = `page.getByTestId("${selectorValue}")`;
|
|
809
|
+
break;
|
|
810
|
+
case "aria-label":
|
|
811
|
+
case "label":
|
|
812
|
+
if (type === "button") {
|
|
813
|
+
selector = `page.getByRole("button", { name: "${selectorValue}" })`;
|
|
814
|
+
}
|
|
815
|
+
else if (type === "toggle") {
|
|
816
|
+
selector = `page.getByLabel("${selectorValue}")`;
|
|
817
|
+
action = ".check()";
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
selector = `page.getByLabel("${selectorValue}")`;
|
|
821
|
+
}
|
|
822
|
+
break;
|
|
823
|
+
case "text":
|
|
824
|
+
selector = `page.getByRole("button", { name: "${selectorValue}" })`;
|
|
825
|
+
break;
|
|
826
|
+
default:
|
|
827
|
+
return "";
|
|
828
|
+
}
|
|
829
|
+
return `test("should ${type === "toggle" ? "toggle" : "click"} ${name}", async ({ page }) => {
|
|
830
|
+
await page.goto("${routeForTest}");
|
|
831
|
+
await ${selector}${action};
|
|
832
|
+
await expect(page.locator("main")).toBeVisible(); // Add specific outcome
|
|
833
|
+
});`;
|
|
834
|
+
}
|
|
835
|
+
// Enhancement #6: Generate suggested test code for form inputs
|
|
836
|
+
function generateSuggestedTestForInput(route, selectorType, selectorValue, name) {
|
|
837
|
+
if (!selectorType || !selectorValue)
|
|
838
|
+
return "";
|
|
839
|
+
const routeForTest = route === "/" ? "/" : route;
|
|
840
|
+
let selector = "";
|
|
841
|
+
switch (selectorType) {
|
|
842
|
+
case "testid":
|
|
843
|
+
selector = `page.getByTestId("${selectorValue}")`;
|
|
844
|
+
break;
|
|
845
|
+
case "aria-label":
|
|
846
|
+
case "label":
|
|
847
|
+
selector = `page.getByLabel("${selectorValue}")`;
|
|
848
|
+
break;
|
|
849
|
+
case "placeholder":
|
|
850
|
+
selector = `page.getByPlaceholder("${selectorValue}")`;
|
|
851
|
+
break;
|
|
852
|
+
default:
|
|
853
|
+
return "";
|
|
854
|
+
}
|
|
855
|
+
return `test("should fill ${name} field", async ({ page }) => {
|
|
856
|
+
await page.goto("${routeForTest}");
|
|
857
|
+
await ${selector}.fill("test value");
|
|
858
|
+
await expect(${selector}).toHaveValue("test value");
|
|
859
|
+
});`;
|
|
860
|
+
}
|
|
861
|
+
function findInteractionsInFile(filePath) {
|
|
862
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
863
|
+
const lines = content.split("\n");
|
|
864
|
+
const route = extractRouteFromFile(filePath);
|
|
865
|
+
const interactions = [];
|
|
866
|
+
for (const [type, patterns] of Object.entries(INTERACTION_PATTERNS)) {
|
|
867
|
+
for (const pattern of patterns) {
|
|
868
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
869
|
+
let match;
|
|
870
|
+
while ((match = regex.exec(content)) !== null) {
|
|
871
|
+
const lineNumber = content.substring(0, match.index).split("\n").length;
|
|
872
|
+
const lineContent = lines[lineNumber - 1] || "";
|
|
873
|
+
// Extract a meaningful name from context
|
|
874
|
+
let name = match[0].replace(/[=\s{(]/g, "").substring(0, 30);
|
|
875
|
+
// Try to get better context from surrounding lines
|
|
876
|
+
const contextStart = Math.max(0, lineNumber - 3);
|
|
877
|
+
const contextEnd = Math.min(lines.length, lineNumber + 2);
|
|
878
|
+
const context = lines.slice(contextStart, contextEnd).join(" ");
|
|
879
|
+
// Look for button/form labels
|
|
880
|
+
const labelMatch = context.match(/(?:label|name|title|aria-label)\s*[=:]\s*["']([^"']+)["']/i);
|
|
881
|
+
if (labelMatch) {
|
|
882
|
+
name = labelMatch[1];
|
|
883
|
+
}
|
|
884
|
+
interactions.push({
|
|
885
|
+
file: filePath,
|
|
886
|
+
route,
|
|
887
|
+
type: type,
|
|
888
|
+
name,
|
|
889
|
+
line: lineNumber,
|
|
890
|
+
hasTestCoverage: false,
|
|
891
|
+
coveringTests: [],
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return interactions;
|
|
897
|
+
}
|
|
898
|
+
function findCriticalActionsInFile(filePath) {
|
|
899
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
900
|
+
const actions = [];
|
|
901
|
+
for (const { pattern, name, severity } of CRITICAL_ACTION_PATTERNS) {
|
|
902
|
+
const regex = new RegExp(pattern.source, pattern.flags);
|
|
903
|
+
let match;
|
|
904
|
+
while ((match = regex.exec(content)) !== null) {
|
|
905
|
+
const lineNumber = content.substring(0, match.index).split("\n").length;
|
|
906
|
+
actions.push({ name, severity, line: lineNumber });
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return actions;
|
|
910
|
+
}
|
|
911
|
+
function getRouteMatchCandidates(route) {
|
|
912
|
+
// For dynamic routes, tests typically hit example URLs rather than the literal
|
|
913
|
+
// pattern string (e.g. "/product/[slug]" vs "/product/e2e-baseball-card-1").
|
|
914
|
+
// Treat the static prefix as a valid coverage signal.
|
|
915
|
+
const candidates = new Set();
|
|
916
|
+
candidates.add(route);
|
|
917
|
+
if (route.includes("[")) {
|
|
918
|
+
// Replace dynamic segments with empty string.
|
|
919
|
+
const prefix = route.replace(/\[[^\]]+\]/g, "").replace(/\/\/+/g, "/");
|
|
920
|
+
if (prefix && prefix !== "/") {
|
|
921
|
+
candidates.add(prefix);
|
|
922
|
+
// Also add a no-trailing-slash variant to catch tests using "/product".
|
|
923
|
+
if (prefix.endsWith("/")) {
|
|
924
|
+
candidates.add(prefix.slice(0, -1));
|
|
925
|
+
}
|
|
926
|
+
else {
|
|
927
|
+
candidates.add(prefix + "/");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return Array.from(candidates);
|
|
932
|
+
}
|
|
933
|
+
function escapeRegExp(value) {
|
|
934
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
935
|
+
}
|
|
936
|
+
function testHasOutcome(content) {
|
|
937
|
+
return /toHaveURL|toHaveText|toContainText|toBeVisible|waitForResponse|expect\.poll|toHaveValue|toBeEnabled|toBeDisabled|toBeChecked/i.test(content);
|
|
938
|
+
}
|
|
939
|
+
function testCoversInteractionBySelector(content, interaction) {
|
|
940
|
+
if (!interaction.selectorType || !interaction.selectorValue)
|
|
941
|
+
return false;
|
|
942
|
+
const value = interaction.selectorValue;
|
|
943
|
+
// Outcome is required for all actionable selector-based checks.
|
|
944
|
+
if (!testHasOutcome(content))
|
|
945
|
+
return false;
|
|
946
|
+
// Enhancement #2: For input types, check for .fill() coverage
|
|
947
|
+
if (interaction.type === "input") {
|
|
948
|
+
return testCoversInputBySelector(content, interaction);
|
|
949
|
+
}
|
|
950
|
+
// Enhancement #1: For select types, check for .selectOption() or .click()
|
|
951
|
+
if (interaction.type === "select") {
|
|
952
|
+
return testCoversSelectBySelector(content, interaction);
|
|
953
|
+
}
|
|
954
|
+
if (interaction.selectorType === "testid") {
|
|
955
|
+
const v = escapeRegExp(value);
|
|
956
|
+
// Direct chained pattern
|
|
957
|
+
const testIdClick = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.click\\s*\\(`, "i");
|
|
958
|
+
const locatorClick = new RegExp(`locator\\(\\s*['\"][^'\"]*data-testid[^'\"]*${v}[^'\"]*['\"]\\s*\\)[\\s\\S]{0,120}\\.click\\s*\\(`, "i");
|
|
959
|
+
const locatorDataTestIdClick = new RegExp(`locator\\(\\s*['\"]\\[data-testid=['\"]${v}['\"]\\]\\s*['\"]\\s*\\)[\\s\\S]{0,120}\\.click\\s*\\(`, "i");
|
|
960
|
+
// Variable-based pattern: const x = page.getByTestId("..."); ... x.click(
|
|
961
|
+
const testIdVarClick = new RegExp(`=\\s*(?:page\\.)?getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
962
|
+
const testIdCheck = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.(check|uncheck)\\s*\\(`, "i");
|
|
963
|
+
if (interaction.type === "toggle") {
|
|
964
|
+
return (testIdCheck.test(content) ||
|
|
965
|
+
testIdClick.test(content) ||
|
|
966
|
+
locatorClick.test(content) ||
|
|
967
|
+
locatorDataTestIdClick.test(content) ||
|
|
968
|
+
testIdVarClick.test(content));
|
|
969
|
+
}
|
|
970
|
+
return (testIdClick.test(content) ||
|
|
971
|
+
locatorClick.test(content) ||
|
|
972
|
+
locatorDataTestIdClick.test(content) ||
|
|
973
|
+
testIdVarClick.test(content));
|
|
974
|
+
}
|
|
975
|
+
if (interaction.selectorType === "aria-label" || interaction.selectorType === "label") {
|
|
976
|
+
const v = escapeRegExp(value);
|
|
977
|
+
// Direct chained pattern
|
|
978
|
+
const roleClick = new RegExp(`getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,200}name:\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.click\\s*\\(`, "i");
|
|
979
|
+
const labelClick = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.click\\s*\\(`, "i");
|
|
980
|
+
const labelCheck = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.(check|uncheck)\\s*\\(`, "i");
|
|
981
|
+
const ariaLocatorClick = new RegExp(`locator\\(\\s*['\"][^'\"]*aria-label[^'\"]*${v}[^'\"]*['\"]\\s*\\)[\\s\\S]{0,120}\\.click\\s*\\(`, "i");
|
|
982
|
+
// Variable-based pattern: const x = page.getByLabel("..."); ... x.click(
|
|
983
|
+
const labelVarClick = new RegExp(`=\\s*(?:page\\.)?getByLabel\\(\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
984
|
+
// Variable-based pattern for getByRole: const x = page.getByRole("button", { name: "..." }); ... x.click(
|
|
985
|
+
const roleVarClick = new RegExp(`=\\s*(?:page\\.)?getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,200}name:\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
986
|
+
if (interaction.type === "toggle") {
|
|
987
|
+
return (labelCheck.test(content) ||
|
|
988
|
+
roleClick.test(content) ||
|
|
989
|
+
labelClick.test(content) ||
|
|
990
|
+
ariaLocatorClick.test(content) ||
|
|
991
|
+
labelVarClick.test(content) ||
|
|
992
|
+
roleVarClick.test(content));
|
|
993
|
+
}
|
|
994
|
+
return (roleClick.test(content) ||
|
|
995
|
+
labelClick.test(content) ||
|
|
996
|
+
ariaLocatorClick.test(content) ||
|
|
997
|
+
labelVarClick.test(content) ||
|
|
998
|
+
roleVarClick.test(content));
|
|
999
|
+
}
|
|
1000
|
+
if (interaction.selectorType === "text") {
|
|
1001
|
+
const v = escapeRegExp(value);
|
|
1002
|
+
// Direct chained pattern
|
|
1003
|
+
const roleClick = new RegExp(`getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,200}name:\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.click\\s*\\(`, "i");
|
|
1004
|
+
const textClick = new RegExp(`getByText\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.click\\s*\\(`, "i");
|
|
1005
|
+
// Variable-based pattern: const x = page.getByRole("button", { name: "..." }); ... x.click(
|
|
1006
|
+
const roleVarClick = new RegExp(`=\\s*(?:page\\.)?getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,200}name:\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
1007
|
+
// Variable-based pattern: const x = page.getByText("..."); ... x.click(
|
|
1008
|
+
const textVarClick = new RegExp(`=\\s*(?:page\\.)?getByText\\(\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
1009
|
+
if (roleClick.test(content) ||
|
|
1010
|
+
textClick.test(content) ||
|
|
1011
|
+
roleVarClick.test(content) ||
|
|
1012
|
+
textVarClick.test(content))
|
|
1013
|
+
return true;
|
|
1014
|
+
// Allow partial regex matches for dynamic text labels like
|
|
1015
|
+
// "Mark All Read ({unreadCount})" where tests should sensibly use
|
|
1016
|
+
// name: /Mark All Read/i.
|
|
1017
|
+
const prefix = value.split(/[({]/)[0]?.trim();
|
|
1018
|
+
if (prefix && prefix.length >= 4) {
|
|
1019
|
+
const p = escapeRegExp(prefix);
|
|
1020
|
+
const roleClickPrefix = new RegExp(`getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,220}name:\\s*\\/[^\\/]*${p}[^\\/]*\\/[igmsuy]*[\\s\\S]{0,140}\\)\\.click\\s*\\(`, "i");
|
|
1021
|
+
const textClickPrefix = new RegExp(`getByText\\(\\s*\\/[^\\/]*${p}[^\\/]*\\/[igmsuy]*[\\s\\S]{0,140}\\)\\.click\\s*\\(`, "i");
|
|
1022
|
+
// Variable-based pattern with prefix
|
|
1023
|
+
const roleVarClickPrefix = new RegExp(`=\\s*(?:page\\.)?getByRole\\(\\s*['\"]button['\"][\\s\\S]{0,220}name:\\s*\\/[^\\/]*${p}[^\\/]*\\/[igmsuy]*[\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
1024
|
+
return (roleClickPrefix.test(content) ||
|
|
1025
|
+
textClickPrefix.test(content) ||
|
|
1026
|
+
roleVarClickPrefix.test(content));
|
|
1027
|
+
}
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
return false;
|
|
1031
|
+
}
|
|
1032
|
+
// Enhancement #2: Check if test covers input with .fill()
|
|
1033
|
+
// Supports both direct chained patterns and variable-based patterns
|
|
1034
|
+
function testCoversInputBySelector(content, interaction) {
|
|
1035
|
+
if (!interaction.selectorType || !interaction.selectorValue)
|
|
1036
|
+
return false;
|
|
1037
|
+
const value = interaction.selectorValue;
|
|
1038
|
+
const v = escapeRegExp(value);
|
|
1039
|
+
if (interaction.selectorType === "testid") {
|
|
1040
|
+
// Direct chained pattern
|
|
1041
|
+
const testIdFill = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.fill\\s*\\(`, "i");
|
|
1042
|
+
const testIdType = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.type\\s*\\(`, "i");
|
|
1043
|
+
// Variable-based pattern: const x = page.getByTestId("..."); ... x.fill(
|
|
1044
|
+
const testIdVarFill = new RegExp(`=\\s*(?:page\\.)?getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,500}\\.fill\\s*\\(`, "i");
|
|
1045
|
+
return testIdFill.test(content) || testIdType.test(content) || testIdVarFill.test(content);
|
|
1046
|
+
}
|
|
1047
|
+
if (interaction.selectorType === "label" || interaction.selectorType === "aria-label") {
|
|
1048
|
+
// Direct chained pattern
|
|
1049
|
+
const labelFill = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.fill\\s*\\(`, "i");
|
|
1050
|
+
const labelType = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.type\\s*\\(`, "i");
|
|
1051
|
+
const roleTextbox = new RegExp(`getByRole\\(\\s*['\"]textbox['\"][\\s\\S]{0,200}name:\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.fill\\s*\\(`, "i");
|
|
1052
|
+
// Variable-based pattern: const x = page.getByLabel("..."); ... x.fill(
|
|
1053
|
+
const labelVarFill = new RegExp(`=\\s*(?:page\\.)?getByLabel\\(\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.fill\\s*\\(`, "i");
|
|
1054
|
+
return (labelFill.test(content) ||
|
|
1055
|
+
labelType.test(content) ||
|
|
1056
|
+
roleTextbox.test(content) ||
|
|
1057
|
+
labelVarFill.test(content));
|
|
1058
|
+
}
|
|
1059
|
+
if (interaction.selectorType === "placeholder") {
|
|
1060
|
+
// Direct chained pattern
|
|
1061
|
+
const placeholderFill = new RegExp(`getByPlaceholder\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.fill\\s*\\(`, "i");
|
|
1062
|
+
const placeholderType = new RegExp(`getByPlaceholder\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.type\\s*\\(`, "i");
|
|
1063
|
+
// Variable-based pattern
|
|
1064
|
+
const placeholderVarFill = new RegExp(`=\\s*(?:page\\.)?getByPlaceholder\\(\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.fill\\s*\\(`, "i");
|
|
1065
|
+
return (placeholderFill.test(content) ||
|
|
1066
|
+
placeholderType.test(content) ||
|
|
1067
|
+
placeholderVarFill.test(content));
|
|
1068
|
+
}
|
|
1069
|
+
return false;
|
|
1070
|
+
}
|
|
1071
|
+
// Enhancement #1: Check if test covers select with .selectOption() or .click()
|
|
1072
|
+
// Supports both direct chained patterns and variable-based patterns
|
|
1073
|
+
function testCoversSelectBySelector(content, interaction) {
|
|
1074
|
+
if (!interaction.selectorType || !interaction.selectorValue)
|
|
1075
|
+
return false;
|
|
1076
|
+
const value = interaction.selectorValue;
|
|
1077
|
+
const v = escapeRegExp(value);
|
|
1078
|
+
if (interaction.selectorType === "testid") {
|
|
1079
|
+
// Direct chained pattern
|
|
1080
|
+
const testIdSelect = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.selectOption\\s*\\(`, "i");
|
|
1081
|
+
const testIdClick = new RegExp(`getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,120}\\.click\\s*\\(`, "i");
|
|
1082
|
+
// Variable-based pattern
|
|
1083
|
+
const testIdVarClick = new RegExp(`=\\s*(?:page\\.)?getByTestId\\(\\s*['\"]${v}['\"]\\s*\\)[\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
1084
|
+
return testIdSelect.test(content) || testIdClick.test(content) || testIdVarClick.test(content);
|
|
1085
|
+
}
|
|
1086
|
+
if (interaction.selectorType === "label" || interaction.selectorType === "aria-label") {
|
|
1087
|
+
// Direct chained pattern
|
|
1088
|
+
const labelSelect = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.selectOption\\s*\\(`, "i");
|
|
1089
|
+
const labelClick = new RegExp(`getByLabel\\(\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.click\\s*\\(`, "i");
|
|
1090
|
+
const roleCombobox = new RegExp(`getByRole\\(\\s*['\"]combobox['\"][\\s\\S]{0,200}name:\\s*(?:['\"]${v}['\"]|\\/${v}\\/[igmsuy]*)[\\s\\S]{0,120}\\)\\.(?:selectOption|click)\\s*\\(`, "i");
|
|
1091
|
+
// Variable-based pattern
|
|
1092
|
+
const labelVarClick = new RegExp(`=\\s*(?:page\\.)?getByLabel\\(\\s*['\"]${v}['\"][\\s\\S]{0,500}\\.click\\s*\\(`, "i");
|
|
1093
|
+
return (labelSelect.test(content) ||
|
|
1094
|
+
labelClick.test(content) ||
|
|
1095
|
+
roleCombobox.test(content) ||
|
|
1096
|
+
labelVarClick.test(content));
|
|
1097
|
+
}
|
|
1098
|
+
return false;
|
|
1099
|
+
}
|
|
1100
|
+
function checkTestCoverage(interactions, testFiles) {
|
|
1101
|
+
// Build index of test content
|
|
1102
|
+
const testContentIndex = new Map();
|
|
1103
|
+
for (const testFile of testFiles) {
|
|
1104
|
+
if (fs.existsSync(testFile)) {
|
|
1105
|
+
testContentIndex.set(testFile, fs.readFileSync(testFile, "utf-8"));
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
for (const interaction of interactions) {
|
|
1109
|
+
const route = interaction.route;
|
|
1110
|
+
const routeCandidates = getRouteMatchCandidates(route);
|
|
1111
|
+
const coveringTests = [];
|
|
1112
|
+
for (const [testFile, content] of testContentIndex) {
|
|
1113
|
+
// Check if test covers this route
|
|
1114
|
+
const coversRoute = routeCandidates.some((candidate) => content.includes(candidate) || content.includes(candidate.replace(/\//g, "\\/")));
|
|
1115
|
+
if (!coversRoute)
|
|
1116
|
+
continue;
|
|
1117
|
+
// If the interaction has a stable selector (actions mode), require the test
|
|
1118
|
+
// to actually click/check that selector (not just any click on the route).
|
|
1119
|
+
if (interaction.selectorType && interaction.selectorValue) {
|
|
1120
|
+
if (testCoversInteractionBySelector(content, interaction)) {
|
|
1121
|
+
coveringTests.push(testFile);
|
|
1122
|
+
}
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
// Check if test has relevant interactions
|
|
1126
|
+
let hasRelevantInteraction = false;
|
|
1127
|
+
switch (interaction.type) {
|
|
1128
|
+
case "form":
|
|
1129
|
+
hasRelevantInteraction = /\.fill\s*\(|\.type\s*\(|submit/i.test(content);
|
|
1130
|
+
break;
|
|
1131
|
+
case "button":
|
|
1132
|
+
hasRelevantInteraction = /\.click\s*\(/i.test(content);
|
|
1133
|
+
break;
|
|
1134
|
+
case "modal":
|
|
1135
|
+
hasRelevantInteraction = /dialog|modal|\.click\s*\(/i.test(content);
|
|
1136
|
+
break;
|
|
1137
|
+
case "crud":
|
|
1138
|
+
hasRelevantInteraction = /waitForResponse|waitForRequest|\.click\s*\(/i.test(content);
|
|
1139
|
+
break;
|
|
1140
|
+
case "navigation":
|
|
1141
|
+
hasRelevantInteraction = /toHaveURL|\.click\s*\(|\.goto\s*\(/i.test(content);
|
|
1142
|
+
break;
|
|
1143
|
+
case "toggle":
|
|
1144
|
+
hasRelevantInteraction = /\.click\s*\(|\.check\s*\(/i.test(content);
|
|
1145
|
+
break;
|
|
1146
|
+
case "link":
|
|
1147
|
+
// Links are covered if test navigates to the page and verifies content
|
|
1148
|
+
hasRelevantInteraction = /\.goto\s*\(|\.locator\s*\(|getByText|getByRole/i.test(content);
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
// Check for outcome verification
|
|
1152
|
+
const hasOutcome = testHasOutcome(content);
|
|
1153
|
+
if (hasRelevantInteraction && hasOutcome) {
|
|
1154
|
+
coveringTests.push(testFile);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
interaction.hasTestCoverage = coveringTests.length > 0;
|
|
1158
|
+
interaction.coveringTests = coveringTests;
|
|
1159
|
+
}
|
|
1160
|
+
return interactions;
|
|
1161
|
+
}
|
|
1162
|
+
function groupByRoute(interactions) {
|
|
1163
|
+
const routeMap = new Map();
|
|
1164
|
+
for (const interaction of interactions) {
|
|
1165
|
+
if (!routeMap.has(interaction.route)) {
|
|
1166
|
+
routeMap.set(interaction.route, {
|
|
1167
|
+
route: interaction.route,
|
|
1168
|
+
file: interaction.file,
|
|
1169
|
+
interactions: [],
|
|
1170
|
+
testCoverage: 0,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
routeMap.get(interaction.route).interactions.push(interaction);
|
|
1174
|
+
}
|
|
1175
|
+
// Calculate coverage percentage
|
|
1176
|
+
for (const routeData of routeMap.values()) {
|
|
1177
|
+
const covered = routeData.interactions.filter((i) => i.hasTestCoverage).length;
|
|
1178
|
+
routeData.testCoverage =
|
|
1179
|
+
routeData.interactions.length > 0
|
|
1180
|
+
? Math.round((covered / routeData.interactions.length) * 100)
|
|
1181
|
+
: 100;
|
|
1182
|
+
}
|
|
1183
|
+
return Array.from(routeMap.values()).sort((a, b) => a.testCoverage - b.testCoverage);
|
|
1184
|
+
}
|
|
1185
|
+
async function main() {
|
|
1186
|
+
// Check for help flag first
|
|
1187
|
+
if (shouldShowHelp()) {
|
|
1188
|
+
showHelp();
|
|
1189
|
+
process.exit(0);
|
|
1190
|
+
}
|
|
1191
|
+
const mode = getModeFromArgsOrEnv();
|
|
1192
|
+
const verbose = isVerbose();
|
|
1193
|
+
const jsonOutput = isJsonOutput();
|
|
1194
|
+
const quiet = isQuietMode();
|
|
1195
|
+
const actionsMode = isActionsMode();
|
|
1196
|
+
const minRouteCoverage = getMinRouteCoverage(actionsMode);
|
|
1197
|
+
const minOverallCoverage = getMinOverallCoverage(actionsMode);
|
|
1198
|
+
console.log(`\n${console_chars_1.emoji.search} E2E INTERACTION COVERAGE SCANNER`);
|
|
1199
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1200
|
+
console.log(`Mode: ${mode} | Verbose: ${verbose}`);
|
|
1201
|
+
if (actionsMode) {
|
|
1202
|
+
console.log(`${console_chars_1.emoji.info} Actions mode enabled: requiring selector-specific clicks/checks for actionable controls (set PREFLIGHT_INTERACTION_SCAN_ACTIONS=0 to disable).`);
|
|
1203
|
+
}
|
|
1204
|
+
console.log("Scanning app for interactive elements...\n");
|
|
1205
|
+
// Find all app files
|
|
1206
|
+
let appFiles = await (0, glob_1.glob)("app/**/*.tsx", {
|
|
1207
|
+
windowsPathsNoEscape: true,
|
|
1208
|
+
ignore: [
|
|
1209
|
+
"app/**/layout.tsx",
|
|
1210
|
+
"app/**/loading.tsx",
|
|
1211
|
+
"app/**/error.tsx",
|
|
1212
|
+
"app/**/not-found.tsx",
|
|
1213
|
+
// Dev-only tools should not be held to action-coverage contracts
|
|
1214
|
+
// (they're intentionally disabled outside development).
|
|
1215
|
+
...(actionsMode ? ["app/dev/**/*"] : []),
|
|
1216
|
+
"app/api/**/*",
|
|
1217
|
+
],
|
|
1218
|
+
});
|
|
1219
|
+
// In actions mode, only scan files reachable from pages to avoid false
|
|
1220
|
+
// positives from orphan components.
|
|
1221
|
+
if (actionsMode) {
|
|
1222
|
+
const pageFiles = await (0, glob_1.glob)("app/**/page.tsx", {
|
|
1223
|
+
windowsPathsNoEscape: true,
|
|
1224
|
+
ignore: ["app/api/**/*", "app/dev/**/*"],
|
|
1225
|
+
});
|
|
1226
|
+
const reachable = await computeReachableAppFiles(pageFiles);
|
|
1227
|
+
appFiles = appFiles.filter((f) => reachable.has(f));
|
|
1228
|
+
}
|
|
1229
|
+
// Find all test files
|
|
1230
|
+
const testFiles = await getE2ESpecFiles();
|
|
1231
|
+
console.log(`📂 Scanning ${appFiles.length} app files...`);
|
|
1232
|
+
console.log(`📂 Found ${testFiles.length} E2E test files...\n`);
|
|
1233
|
+
// Find all interactions
|
|
1234
|
+
let allInteractions = [];
|
|
1235
|
+
const criticalActions = [];
|
|
1236
|
+
for (const file of appFiles) {
|
|
1237
|
+
const interactions = findInteractionsInFile(file);
|
|
1238
|
+
allInteractions.push(...interactions);
|
|
1239
|
+
if (actionsMode) {
|
|
1240
|
+
allInteractions.push(...findActionableControlsInFile(file));
|
|
1241
|
+
}
|
|
1242
|
+
// Find critical actions
|
|
1243
|
+
const route = extractRouteFromFile(file);
|
|
1244
|
+
const actions = findCriticalActionsInFile(file);
|
|
1245
|
+
for (const action of actions) {
|
|
1246
|
+
criticalActions.push({
|
|
1247
|
+
file,
|
|
1248
|
+
route,
|
|
1249
|
+
...action,
|
|
1250
|
+
hasCoverage: false,
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
// Deduplicate interactions (same type on same line)
|
|
1255
|
+
const seen = new Set();
|
|
1256
|
+
allInteractions = allInteractions.filter((i) => {
|
|
1257
|
+
const key = `${i.file}:${i.line}:${i.type}:${i.selectorType ?? ""}:${i.selectorValue ?? ""}`;
|
|
1258
|
+
if (seen.has(key))
|
|
1259
|
+
return false;
|
|
1260
|
+
seen.add(key);
|
|
1261
|
+
return true;
|
|
1262
|
+
});
|
|
1263
|
+
console.log(`${console_chars_1.emoji.target} Found ${allInteractions.length} interactive elements`);
|
|
1264
|
+
console.log(`${console_chars_1.emoji.warning} Found ${criticalActions.length} critical actions\n`);
|
|
1265
|
+
// Check test coverage
|
|
1266
|
+
allInteractions = checkTestCoverage(allInteractions, testFiles);
|
|
1267
|
+
// Check critical action coverage
|
|
1268
|
+
for (const action of criticalActions) {
|
|
1269
|
+
const routeCandidates = getRouteMatchCandidates(action.route);
|
|
1270
|
+
const hasTest = testFiles.some((testFile) => {
|
|
1271
|
+
if (!fs.existsSync(testFile))
|
|
1272
|
+
return false;
|
|
1273
|
+
const content = fs.readFileSync(testFile, "utf-8");
|
|
1274
|
+
const coversRoute = routeCandidates.some((candidate) => content.includes(candidate) || content.includes(candidate.replace(/\//g, "\\/")));
|
|
1275
|
+
return (coversRoute &&
|
|
1276
|
+
/\.click\s*\(/.test(content) &&
|
|
1277
|
+
/toHaveURL|toHaveText|toBeVisible|waitForResponse/.test(content));
|
|
1278
|
+
});
|
|
1279
|
+
action.hasCoverage = hasTest;
|
|
1280
|
+
}
|
|
1281
|
+
// Group by route
|
|
1282
|
+
const routeData = groupByRoute(allInteractions);
|
|
1283
|
+
// Report: Routes with no coverage
|
|
1284
|
+
const noCoverage = routeData.filter((r) => r.testCoverage === 0 && r.interactions.length > 0);
|
|
1285
|
+
const lowCoverage = routeData.filter((r) => r.testCoverage > 0 && r.testCoverage < 50);
|
|
1286
|
+
const goodCoverage = routeData.filter((r) => r.testCoverage >= 50);
|
|
1287
|
+
if (noCoverage.length > 0) {
|
|
1288
|
+
console.log(`${console_chars_1.emoji.error} ROUTES WITH NO INTERACTION TEST COVERAGE`);
|
|
1289
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1290
|
+
for (const route of noCoverage.slice(0, 20)) {
|
|
1291
|
+
console.log(`\n 📍 ${route.route} (${route.interactions.length} interactions)`);
|
|
1292
|
+
if (verbose) {
|
|
1293
|
+
const types = new Map();
|
|
1294
|
+
for (const i of route.interactions) {
|
|
1295
|
+
types.set(i.type, (types.get(i.type) || 0) + 1);
|
|
1296
|
+
}
|
|
1297
|
+
console.log(` Types: ${Array.from(types.entries())
|
|
1298
|
+
.map(([t, c]) => `${t}(${c})`)
|
|
1299
|
+
.join(", ")}`);
|
|
1300
|
+
const top = getTopUncoveredInteractions(route, 8);
|
|
1301
|
+
if (top.length > 0) {
|
|
1302
|
+
console.log(" Missing interactions (sample):");
|
|
1303
|
+
top.forEach((i) => console.log(` - ${formatInteractionForReport(i)}`));
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
if (noCoverage.length > 20) {
|
|
1308
|
+
console.log(`\n ... and ${noCoverage.length - 20} more routes`);
|
|
1309
|
+
}
|
|
1310
|
+
console.log();
|
|
1311
|
+
}
|
|
1312
|
+
if (lowCoverage.length > 0 && verbose) {
|
|
1313
|
+
console.log(`${console_chars_1.emoji.warning} ROUTES WITH LOW COVERAGE (<50%)`);
|
|
1314
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1315
|
+
for (const route of lowCoverage.slice(0, 10)) {
|
|
1316
|
+
console.log(` ${console_chars_1.emoji.lightning} ${route.route} (${route.testCoverage}% coverage)`);
|
|
1317
|
+
const top = getTopUncoveredInteractions(route, 6);
|
|
1318
|
+
if (top.length > 0) {
|
|
1319
|
+
console.log(" Missing interactions (sample):");
|
|
1320
|
+
top.forEach((i) => console.log(` - ${formatInteractionForReport(i)}`));
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
console.log();
|
|
1324
|
+
}
|
|
1325
|
+
if (verbose) {
|
|
1326
|
+
const partial = routeData
|
|
1327
|
+
.filter((r) => r.interactions.length > 0 && r.testCoverage < 100)
|
|
1328
|
+
.sort((a, b) => a.testCoverage - b.testCoverage);
|
|
1329
|
+
if (partial.length > 0) {
|
|
1330
|
+
console.log(`${console_chars_1.emoji.info} ROUTES WITH PARTIAL COVERAGE (<100%)`);
|
|
1331
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1332
|
+
for (const route of partial.slice(0, 12)) {
|
|
1333
|
+
console.log(` ${console_chars_1.emoji.lightning} ${route.route} (${route.testCoverage}% coverage)`);
|
|
1334
|
+
const top = getTopUncoveredInteractions(route, 6);
|
|
1335
|
+
if (top.length > 0) {
|
|
1336
|
+
console.log(" Missing interactions (sample):");
|
|
1337
|
+
top.forEach((i) => console.log(` - ${formatInteractionForReport(i)}`));
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
if (partial.length > 12) {
|
|
1341
|
+
console.log(` ${console_chars_1.chars.ellipsis} and ${partial.length - 12} more`);
|
|
1342
|
+
}
|
|
1343
|
+
console.log();
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
// Report: Critical actions without coverage
|
|
1347
|
+
const uncoveredCritical = criticalActions.filter((a) => !a.hasCoverage);
|
|
1348
|
+
const criticalBySeverity = {
|
|
1349
|
+
critical: uncoveredCritical.filter((a) => a.severity === "critical"),
|
|
1350
|
+
high: uncoveredCritical.filter((a) => a.severity === "high"),
|
|
1351
|
+
medium: uncoveredCritical.filter((a) => a.severity === "medium"),
|
|
1352
|
+
};
|
|
1353
|
+
if (uncoveredCritical.length > 0) {
|
|
1354
|
+
console.log(`${console_chars_1.emoji.bell} CRITICAL ACTIONS WITHOUT TEST COVERAGE`);
|
|
1355
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1356
|
+
if (criticalBySeverity.critical.length > 0) {
|
|
1357
|
+
console.log(`\n ${console_chars_1.emoji.stop} CRITICAL (payment, checkout, refund):`);
|
|
1358
|
+
for (const action of criticalBySeverity.critical.slice(0, 10)) {
|
|
1359
|
+
console.log(` - ${action.name} at ${action.route}`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (criticalBySeverity.high.length > 0) {
|
|
1363
|
+
console.log(`\n ${console_chars_1.emoji.warning} HIGH (delete, approve, reject, cancel, ship):`);
|
|
1364
|
+
for (const action of criticalBySeverity.high.slice(0, 15)) {
|
|
1365
|
+
console.log(` - ${action.name} at ${action.route}`);
|
|
1366
|
+
}
|
|
1367
|
+
if (criticalBySeverity.high.length > 15) {
|
|
1368
|
+
console.log(` ... and ${criticalBySeverity.high.length - 15} more`);
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
if (criticalBySeverity.medium.length > 0 && verbose) {
|
|
1372
|
+
console.log(`\n ${console_chars_1.emoji.warning} MEDIUM (publish, verify):`);
|
|
1373
|
+
for (const action of criticalBySeverity.medium.slice(0, 10)) {
|
|
1374
|
+
console.log(` - ${action.name} at ${action.route}`);
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
console.log();
|
|
1378
|
+
}
|
|
1379
|
+
// Check required routes coverage
|
|
1380
|
+
console.log(`${console_chars_1.emoji.clipboard} REQUIRED ROUTES COVERAGE`);
|
|
1381
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1382
|
+
const requiredRouteCoverage = [];
|
|
1383
|
+
// Build test content index for required routes check
|
|
1384
|
+
const testContents = [];
|
|
1385
|
+
for (const testFile of testFiles) {
|
|
1386
|
+
if (fs.existsSync(testFile)) {
|
|
1387
|
+
testContents.push(fs.readFileSync(testFile, "utf-8"));
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
for (const req of REQUIRED_ROUTES) {
|
|
1391
|
+
const matchingRoute = routeData.find((r) => r.route.includes(req.route) || req.route.includes(r.route));
|
|
1392
|
+
// Check if any test file references this route AND has interactions + outcomes
|
|
1393
|
+
const hasDirectTestCoverage = testContents.some((content) => {
|
|
1394
|
+
const hasRoute = content.includes(req.route) ||
|
|
1395
|
+
content.includes(`"${req.route}"`) ||
|
|
1396
|
+
content.includes(`'${req.route}'`);
|
|
1397
|
+
const hasInteraction = /\.click\s*\(|\.fill\s*\(/i.test(content);
|
|
1398
|
+
const hasOutcome = /toHaveURL|toBeVisible|waitForResponse|getByText/i.test(content);
|
|
1399
|
+
return hasRoute && hasInteraction && hasOutcome;
|
|
1400
|
+
});
|
|
1401
|
+
const covered = hasDirectTestCoverage || (matchingRoute ? matchingRoute.testCoverage > 0 : false);
|
|
1402
|
+
const interactionCount = matchingRoute ? matchingRoute.interactions.length : 0;
|
|
1403
|
+
requiredRouteCoverage.push({
|
|
1404
|
+
route: req.route,
|
|
1405
|
+
reason: req.reason,
|
|
1406
|
+
severity: req.severity,
|
|
1407
|
+
covered,
|
|
1408
|
+
interactionCount,
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
const coveredRequired = requiredRouteCoverage.filter((r) => r.covered);
|
|
1412
|
+
const uncoveredRequired = requiredRouteCoverage.filter((r) => !r.covered);
|
|
1413
|
+
console.log(`\n${console_chars_1.emoji.success} Covered: ${coveredRequired.length}/${requiredRouteCoverage.length}`);
|
|
1414
|
+
for (const r of coveredRequired) {
|
|
1415
|
+
console.log(` ${console_chars_1.emoji.success} ${r.route}`);
|
|
1416
|
+
}
|
|
1417
|
+
if (uncoveredRequired.length > 0) {
|
|
1418
|
+
console.log(`\n${console_chars_1.emoji.error} Uncovered: ${uncoveredRequired.length}`);
|
|
1419
|
+
for (const r of uncoveredRequired) {
|
|
1420
|
+
const icon = r.severity === "critical"
|
|
1421
|
+
? "${emoji.stop}"
|
|
1422
|
+
: r.severity === "high"
|
|
1423
|
+
? "${emoji.warning}"
|
|
1424
|
+
: "${emoji.warning}";
|
|
1425
|
+
console.log(` ${icon} ${r.route} (${r.severity})`);
|
|
1426
|
+
console.log(` Reason: ${r.reason}`);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
console.log();
|
|
1430
|
+
// Enhancement #7: Detect and report static/orphan routes
|
|
1431
|
+
const allPageRoutes = await findAllPageRoutes();
|
|
1432
|
+
const routesWithInteractions = new Set(routeData.map((r) => r.route));
|
|
1433
|
+
const staticRoutes = allPageRoutes.filter((r) => !routesWithInteractions.has(r));
|
|
1434
|
+
const uncoveredStaticRoutes = [];
|
|
1435
|
+
if (staticRoutes.length > 0) {
|
|
1436
|
+
for (const route of staticRoutes) {
|
|
1437
|
+
if (!checkStaticRouteCoverage(route, testFiles)) {
|
|
1438
|
+
uncoveredStaticRoutes.push(route);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
if (uncoveredStaticRoutes.length > 0) {
|
|
1442
|
+
console.log(`${console_chars_1.emoji.error} STATIC/ORPHAN ROUTES WITHOUT TEST COVERAGE`);
|
|
1443
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1444
|
+
console.log(`${console_chars_1.emoji.info} These routes have no detectable interactions but must still be visited by E2E tests.`);
|
|
1445
|
+
for (const route of uncoveredStaticRoutes.slice(0, 20)) {
|
|
1446
|
+
console.log(` 📍 ${route} (0 interactions)`);
|
|
1447
|
+
}
|
|
1448
|
+
if (uncoveredStaticRoutes.length > 20) {
|
|
1449
|
+
console.log(`\n ... and ${uncoveredStaticRoutes.length - 20} more routes`);
|
|
1450
|
+
}
|
|
1451
|
+
console.log();
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
// Summary
|
|
1455
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1456
|
+
console.log(`${console_chars_1.emoji.chart} SUMMARY`);
|
|
1457
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
1458
|
+
console.log(`Total interactive elements: ${allInteractions.length}`);
|
|
1459
|
+
console.log(`Routes with interactions: ${routeData.length}`);
|
|
1460
|
+
console.log(`Routes with no coverage: ${noCoverage.length}`);
|
|
1461
|
+
console.log(`Routes with low coverage: ${lowCoverage.length}`);
|
|
1462
|
+
console.log(`Routes with good coverage: ${goodCoverage.length}`);
|
|
1463
|
+
console.log(`Critical actions uncovered: ${uncoveredCritical.length} (${criticalBySeverity.critical.length} critical, ${criticalBySeverity.high.length} high)`);
|
|
1464
|
+
console.log(`Required routes covered: ${coveredRequired.length}/${requiredRouteCoverage.length}`);
|
|
1465
|
+
// Calculate overall score
|
|
1466
|
+
const coveredInteractions = allInteractions.filter((i) => i.hasTestCoverage).length;
|
|
1467
|
+
const overallCoverage = allInteractions.length > 0
|
|
1468
|
+
? Math.round((coveredInteractions / allInteractions.length) * 100)
|
|
1469
|
+
: 100;
|
|
1470
|
+
console.log(`\n${console_chars_1.emoji.graph} Overall interaction coverage: ${overallCoverage}%`);
|
|
1471
|
+
// Write report
|
|
1472
|
+
writeReport(routeData, criticalActions, overallCoverage, requiredRouteCoverage);
|
|
1473
|
+
// Determine exit status
|
|
1474
|
+
const errors = [];
|
|
1475
|
+
const warnings = [];
|
|
1476
|
+
if (criticalBySeverity.critical.length > 0) {
|
|
1477
|
+
errors.push(`${criticalBySeverity.critical.length} CRITICAL actions (payment/checkout/refund) have no test coverage`);
|
|
1478
|
+
}
|
|
1479
|
+
// Check for uncovered required routes with high/critical severity
|
|
1480
|
+
const uncoveredHighRequired = uncoveredRequired.filter((r) => r.severity === "critical" || r.severity === "high");
|
|
1481
|
+
if (uncoveredHighRequired.length > 0) {
|
|
1482
|
+
errors.push(`${uncoveredHighRequired.length} required HIGH/CRITICAL routes have no test coverage`);
|
|
1483
|
+
for (const r of uncoveredHighRequired) {
|
|
1484
|
+
errors.push(` ${console_chars_1.chars.arrow} ${r.route}: ${r.reason}`);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
if (criticalBySeverity.high.length > 5) {
|
|
1488
|
+
warnings.push(`${criticalBySeverity.high.length} HIGH severity actions lack test coverage`);
|
|
1489
|
+
}
|
|
1490
|
+
if (noCoverage.length > 10) {
|
|
1491
|
+
warnings.push(`${noCoverage.length} routes have zero interaction test coverage`);
|
|
1492
|
+
}
|
|
1493
|
+
if (overallCoverage < 30) {
|
|
1494
|
+
warnings.push(`Overall interaction coverage is only ${overallCoverage}%`);
|
|
1495
|
+
}
|
|
1496
|
+
// Medium severity required routes
|
|
1497
|
+
const uncoveredMediumRequired = uncoveredRequired.filter((r) => r.severity === "medium");
|
|
1498
|
+
if (uncoveredMediumRequired.length > 0) {
|
|
1499
|
+
warnings.push(`${uncoveredMediumRequired.length} required MEDIUM routes lack test coverage`);
|
|
1500
|
+
}
|
|
1501
|
+
if (warnings.length > 0) {
|
|
1502
|
+
console.log(`\n${console_chars_1.emoji.warning} WARNINGS:`);
|
|
1503
|
+
warnings.forEach((w) => console.log(` - ${w}`));
|
|
1504
|
+
}
|
|
1505
|
+
if (actionsMode && minRouteCoverage > 0) {
|
|
1506
|
+
const belowMin = routeData.filter((r) => r.interactions.length > 0 && r.testCoverage < minRouteCoverage);
|
|
1507
|
+
if (belowMin.length > 0) {
|
|
1508
|
+
errors.push(`${belowMin.length} routes are below minimum interaction coverage of ${minRouteCoverage}% (actions mode)`);
|
|
1509
|
+
for (const r of belowMin.slice(0, 10)) {
|
|
1510
|
+
errors.push(` ${console_chars_1.chars.arrow} ${r.route}: ${r.testCoverage}% (${r.interactions.length} interactions)`);
|
|
1511
|
+
}
|
|
1512
|
+
if (belowMin.length > 10) {
|
|
1513
|
+
errors.push(` ${console_chars_1.chars.ellipsis} and ${belowMin.length - 10} more`);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
if (actionsMode && minOverallCoverage > 0 && overallCoverage < minOverallCoverage) {
|
|
1518
|
+
errors.push(`Overall interaction coverage is ${overallCoverage}%, below minimum ${minOverallCoverage}% (actions mode)`);
|
|
1519
|
+
}
|
|
1520
|
+
if (errors.length > 0) {
|
|
1521
|
+
console.log(`\n${console_chars_1.emoji.error} ERRORS:`);
|
|
1522
|
+
errors.forEach((e) => console.log(` - ${e}`));
|
|
1523
|
+
if (mode === "block") {
|
|
1524
|
+
console.log(`\n${console_chars_1.emoji.error} Interaction coverage scan FAILED`);
|
|
1525
|
+
process.exit(1);
|
|
1526
|
+
}
|
|
1527
|
+
console.log("\nMode=warn: not blocking build.");
|
|
1528
|
+
}
|
|
1529
|
+
else {
|
|
1530
|
+
console.log(`\n${console_chars_1.emoji.success} Interaction coverage scan PASSED`);
|
|
1531
|
+
}
|
|
1532
|
+
process.exit(0);
|
|
1533
|
+
}
|
|
1534
|
+
function writeReport(routeData, criticalActions, overallCoverage, requiredRouteCoverage) {
|
|
1535
|
+
const reportDir = path.join(process.cwd(), "test-results");
|
|
1536
|
+
if (!fs.existsSync(reportDir)) {
|
|
1537
|
+
fs.mkdirSync(reportDir, { recursive: true });
|
|
1538
|
+
}
|
|
1539
|
+
// Enhancement #4 & #6: Include severity breakdown and suggested tests
|
|
1540
|
+
const allInteractions = routeData.flatMap((r) => r.interactions);
|
|
1541
|
+
const uncoveredBySeverity = {
|
|
1542
|
+
critical: allInteractions.filter((i) => !i.hasTestCoverage && i.severity === "critical"),
|
|
1543
|
+
high: allInteractions.filter((i) => !i.hasTestCoverage && i.severity === "high"),
|
|
1544
|
+
medium: allInteractions.filter((i) => !i.hasTestCoverage && i.severity === "medium"),
|
|
1545
|
+
low: allInteractions.filter((i) => !i.hasTestCoverage && i.severity === "low"),
|
|
1546
|
+
};
|
|
1547
|
+
// Enhancement #5: Count shared component usage
|
|
1548
|
+
const sharedComponentCount = allInteractions.filter((i) => i.isSharedComponent).length;
|
|
1549
|
+
const uncoveredSharedComponents = allInteractions.filter((i) => !i.hasTestCoverage && i.isSharedComponent);
|
|
1550
|
+
const report = {
|
|
1551
|
+
timestamp: new Date().toISOString(),
|
|
1552
|
+
overallCoverage,
|
|
1553
|
+
summary: {
|
|
1554
|
+
totalRoutes: routeData.length,
|
|
1555
|
+
routesWithNoCoverage: routeData.filter((r) => r.testCoverage === 0).length,
|
|
1556
|
+
routesWithLowCoverage: routeData.filter((r) => r.testCoverage > 0 && r.testCoverage < 50)
|
|
1557
|
+
.length,
|
|
1558
|
+
routesWithGoodCoverage: routeData.filter((r) => r.testCoverage >= 50).length,
|
|
1559
|
+
criticalActionsUncovered: criticalActions.filter((a) => !a.hasCoverage).length,
|
|
1560
|
+
requiredRoutesCovered: requiredRouteCoverage.filter((r) => r.covered).length,
|
|
1561
|
+
requiredRoutesTotal: requiredRouteCoverage.length,
|
|
1562
|
+
// Enhancement #4: Severity breakdown
|
|
1563
|
+
uncoveredBySeverity: {
|
|
1564
|
+
critical: uncoveredBySeverity.critical.length,
|
|
1565
|
+
high: uncoveredBySeverity.high.length,
|
|
1566
|
+
medium: uncoveredBySeverity.medium.length,
|
|
1567
|
+
low: uncoveredBySeverity.low.length,
|
|
1568
|
+
},
|
|
1569
|
+
// Enhancement #5: Shared component stats
|
|
1570
|
+
sharedComponentsTotal: sharedComponentCount,
|
|
1571
|
+
sharedComponentsUncovered: uncoveredSharedComponents.length,
|
|
1572
|
+
},
|
|
1573
|
+
requiredRoutes: requiredRouteCoverage,
|
|
1574
|
+
// Enhancement #4: Critical uncovered interactions with suggested tests
|
|
1575
|
+
criticalUncovered: uncoveredBySeverity.critical.slice(0, 20).map((i) => ({
|
|
1576
|
+
route: i.route,
|
|
1577
|
+
type: i.type,
|
|
1578
|
+
name: i.name,
|
|
1579
|
+
selectorType: i.selectorType ?? null,
|
|
1580
|
+
selectorValue: i.selectorValue ?? null,
|
|
1581
|
+
file: i.file.replace(process.cwd() + path.sep, ""),
|
|
1582
|
+
line: i.line,
|
|
1583
|
+
suggestedTest: i.suggestedTest ?? null,
|
|
1584
|
+
})),
|
|
1585
|
+
highUncovered: uncoveredBySeverity.high.slice(0, 30).map((i) => ({
|
|
1586
|
+
route: i.route,
|
|
1587
|
+
type: i.type,
|
|
1588
|
+
name: i.name,
|
|
1589
|
+
selectorType: i.selectorType ?? null,
|
|
1590
|
+
selectorValue: i.selectorValue ?? null,
|
|
1591
|
+
file: i.file.replace(process.cwd() + path.sep, ""),
|
|
1592
|
+
line: i.line,
|
|
1593
|
+
suggestedTest: i.suggestedTest ?? null,
|
|
1594
|
+
})),
|
|
1595
|
+
lowCoverageRoutes: routeData
|
|
1596
|
+
.filter((r) => r.testCoverage > 0 && r.testCoverage < 50)
|
|
1597
|
+
.slice(0, 25)
|
|
1598
|
+
.map((r) => ({
|
|
1599
|
+
route: r.route,
|
|
1600
|
+
testCoverage: r.testCoverage,
|
|
1601
|
+
interactionCount: r.interactions.length,
|
|
1602
|
+
missingSample: getTopUncoveredInteractions(r, 12).map((i) => ({
|
|
1603
|
+
type: i.type,
|
|
1604
|
+
name: i.name,
|
|
1605
|
+
severity: i.severity ?? null,
|
|
1606
|
+
selectorType: i.selectorType ?? null,
|
|
1607
|
+
selectorValue: i.selectorValue ?? null,
|
|
1608
|
+
file: i.file,
|
|
1609
|
+
line: i.line,
|
|
1610
|
+
suggestedTest: i.suggestedTest ?? null,
|
|
1611
|
+
})),
|
|
1612
|
+
})),
|
|
1613
|
+
uncoveredRoutes: routeData
|
|
1614
|
+
.filter((r) => r.testCoverage === 0)
|
|
1615
|
+
.map((r) => ({
|
|
1616
|
+
route: r.route,
|
|
1617
|
+
interactionCount: r.interactions.length,
|
|
1618
|
+
types: [...new Set(r.interactions.map((i) => i.type))],
|
|
1619
|
+
missingSample: getTopUncoveredInteractions(r, 12).map((i) => ({
|
|
1620
|
+
type: i.type,
|
|
1621
|
+
name: i.name,
|
|
1622
|
+
severity: i.severity ?? null,
|
|
1623
|
+
selectorType: i.selectorType ?? null,
|
|
1624
|
+
selectorValue: i.selectorValue ?? null,
|
|
1625
|
+
file: i.file,
|
|
1626
|
+
line: i.line,
|
|
1627
|
+
suggestedTest: i.suggestedTest ?? null,
|
|
1628
|
+
})),
|
|
1629
|
+
})),
|
|
1630
|
+
uncoveredCriticalActions: criticalActions
|
|
1631
|
+
.filter((a) => !a.hasCoverage)
|
|
1632
|
+
.map((a) => ({
|
|
1633
|
+
route: a.route,
|
|
1634
|
+
action: a.name,
|
|
1635
|
+
severity: a.severity,
|
|
1636
|
+
})),
|
|
1637
|
+
// Enhancement #5: Uncovered shared components
|
|
1638
|
+
uncoveredSharedComponents: uncoveredSharedComponents.slice(0, 20).map((i) => ({
|
|
1639
|
+
route: i.route,
|
|
1640
|
+
type: i.type,
|
|
1641
|
+
name: i.name,
|
|
1642
|
+
file: i.file.replace(process.cwd() + path.sep, ""),
|
|
1643
|
+
line: i.line,
|
|
1644
|
+
suggestedTest: i.suggestedTest ?? null,
|
|
1645
|
+
})),
|
|
1646
|
+
};
|
|
1647
|
+
fs.writeFileSync(path.join(reportDir, "e2e-interaction-scan-report.json"), JSON.stringify(report, null, 2));
|
|
1648
|
+
}
|
|
1649
|
+
// Enhancement #7: Find all page routes to detect static pages with no interactions
|
|
1650
|
+
async function findAllPageRoutes() {
|
|
1651
|
+
const pageFiles = await (0, glob_1.glob)("app/**/page.tsx", {
|
|
1652
|
+
windowsPathsNoEscape: true,
|
|
1653
|
+
ignore: [
|
|
1654
|
+
"app/**/layout.tsx",
|
|
1655
|
+
"app/**/loading.tsx",
|
|
1656
|
+
"app/**/error.tsx",
|
|
1657
|
+
"app/**/not-found.tsx",
|
|
1658
|
+
"app/api/**/*",
|
|
1659
|
+
"app/dev/**/*", // Ignore debug routes
|
|
1660
|
+
],
|
|
1661
|
+
});
|
|
1662
|
+
return pageFiles.map((file) => extractRouteFromFile(file)).sort();
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Enhancement #7: Check coverage for static routes
|
|
1666
|
+
* A static route is covered if a test navigates to it or checks its URL.
|
|
1667
|
+
*/
|
|
1668
|
+
function checkStaticRouteCoverage(route, testFiles) {
|
|
1669
|
+
// Build test content index (lazy loaded ideally, but for now we read all)
|
|
1670
|
+
const routeCandidates = getRouteMatchCandidates(route);
|
|
1671
|
+
for (const testFile of testFiles) {
|
|
1672
|
+
if (!fs.existsSync(testFile))
|
|
1673
|
+
continue;
|
|
1674
|
+
const content = fs.readFileSync(testFile, "utf-8");
|
|
1675
|
+
// Check if test interacts with this route
|
|
1676
|
+
const hasRoute = routeCandidates.some((candidate) => content.includes(candidate) || content.includes(candidate.replace(/\//g, "\\/")));
|
|
1677
|
+
if (hasRoute) {
|
|
1678
|
+
// For static pages, essentially just visiting or asserting URL is enough
|
|
1679
|
+
return /\.goto\s*\(/.test(content) || /toHaveURL/.test(content);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
return false;
|
|
1683
|
+
}
|
|
1684
|
+
main().catch((err) => {
|
|
1685
|
+
console.error(`${console_chars_1.emoji.error} Preflight failed:`, err);
|
|
1686
|
+
process.exit(1);
|
|
1687
|
+
});
|
|
1688
|
+
//# sourceMappingURL=e2e-interaction-coverage-scan.js.map
|