create-appraise 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/package.json +63 -0
- package/templates/default/.env.example +2 -0
- package/templates/default/README.md +51 -0
- package/templates/default/appraise.config.json +4 -0
- package/templates/default/components.json +24 -0
- package/templates/default/eslint.config.mjs +15 -0
- package/templates/default/next-env.d.ts +6 -0
- package/templates/default/next.config.ts +7 -0
- package/templates/default/package-lock.json +14321 -0
- package/templates/default/package.json +124 -0
- package/templates/default/postcss.config.mjs +8 -0
- package/templates/default/prisma/migrations/20251026202316_migrate_back_to_sqlite/migration.sql +257 -0
- package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -0
- package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -0
- package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -0
- package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -0
- package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -0
- package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -0
- package/templates/default/prisma/migrations/20251130190737_add_trace_path_to_test_run_test_case/migration.sql +2 -0
- package/templates/default/prisma/migrations/20251213074835_add_log_path_to_test_run/migration.sql +2 -0
- package/templates/default/prisma/migrations/20251213183952_add_name_property_for_the_test_run_entities/migration.sql +30 -0
- package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -0
- package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -0
- package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -0
- package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -0
- package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -0
- package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -0
- package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -0
- package/templates/default/prisma/migrations/migration_lock.toml +3 -0
- package/templates/default/prisma/schema.prisma +554 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/file.svg +1 -0
- package/templates/default/public/globe.svg +1 -0
- package/templates/default/public/next.svg +1 -0
- package/templates/default/public/vercel.svg +1 -0
- package/templates/default/public/window.svg +1 -0
- package/templates/default/scripts/regenerate-features.ts +94 -0
- package/templates/default/scripts/setup-env.ts +19 -0
- package/templates/default/scripts/sync-all.ts +341 -0
- package/templates/default/scripts/sync-environments.ts +323 -0
- package/templates/default/scripts/sync-locator-groups.ts +413 -0
- package/templates/default/scripts/sync-locators.ts +402 -0
- package/templates/default/scripts/sync-modules.ts +349 -0
- package/templates/default/scripts/sync-tags.ts +292 -0
- package/templates/default/scripts/sync-template-step-groups.ts +399 -0
- package/templates/default/scripts/sync-template-steps.ts +806 -0
- package/templates/default/scripts/sync-test-cases.ts +905 -0
- package/templates/default/scripts/sync-test-suites.ts +411 -0
- package/templates/default/src/actions/conflict/conflict.action.ts +33 -0
- package/templates/default/src/actions/dashboard/dashboard-actions.ts +241 -0
- package/templates/default/src/actions/environments/environment-actions.ts +205 -0
- package/templates/default/src/actions/locator/locator-actions.ts +547 -0
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -0
- package/templates/default/src/actions/modules/module-actions.ts +133 -0
- package/templates/default/src/actions/reports/report-actions.ts +614 -0
- package/templates/default/src/actions/review/review-actions.ts +147 -0
- package/templates/default/src/actions/tags/tag-actions.ts +104 -0
- package/templates/default/src/actions/template-step/template-step-actions.ts +332 -0
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -0
- package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -0
- package/templates/default/src/actions/test-case/test-case-actions.ts +419 -0
- package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -0
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -0
- package/templates/default/src/actions/user/user-actions.ts +13 -0
- package/templates/default/src/app/(base)/environments/create/page.tsx +28 -0
- package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -0
- package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -0
- package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -0
- package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/environments/page.tsx +59 -0
- package/templates/default/src/app/(base)/layout.tsx +10 -0
- package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -0
- package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -0
- package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/locator-groups/page.tsx +61 -0
- package/templates/default/src/app/(base)/locators/create/page.tsx +38 -0
- package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -0
- package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +90 -0
- package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -0
- package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -0
- package/templates/default/src/app/(base)/locators/page.tsx +65 -0
- package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -0
- package/templates/default/src/app/(base)/modules/create/page.tsx +34 -0
- package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -0
- package/templates/default/src/app/(base)/modules/module-form.tsx +126 -0
- package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -0
- package/templates/default/src/app/(base)/modules/module-table.tsx +24 -0
- package/templates/default/src/app/(base)/modules/page.tsx +59 -0
- package/templates/default/src/app/(base)/reports/[id]/page.tsx +517 -0
- package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -0
- package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -0
- package/templates/default/src/app/(base)/reports/overview-chart.tsx +46 -0
- package/templates/default/src/app/(base)/reports/page.tsx +98 -0
- package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -0
- package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -0
- package/templates/default/src/app/(base)/reports/report-table.tsx +72 -0
- package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +131 -0
- package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -0
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -0
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -0
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -0
- package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -0
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -0
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -0
- package/templates/default/src/app/(base)/reports/view-logs-button.tsx +60 -0
- package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -0
- package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -0
- package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -0
- package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -0
- package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -0
- package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -0
- package/templates/default/src/app/(base)/tags/create/page.tsx +39 -0
- package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -0
- package/templates/default/src/app/(base)/tags/page.tsx +58 -0
- package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -0
- package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -0
- package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -0
- package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -0
- package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -0
- package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -0
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -0
- package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -0
- package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -0
- package/templates/default/src/app/(base)/template-steps/page.tsx +59 -0
- package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -0
- package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -0
- package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -0
- package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -0
- package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -0
- package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -0
- package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -0
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -0
- package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -0
- package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -0
- package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -0
- package/templates/default/src/app/(base)/test-cases/page.tsx +60 -0
- package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -0
- package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -0
- package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +90 -0
- package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -0
- package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -0
- package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -0
- package/templates/default/src/app/(base)/test-runs/page.tsx +60 -0
- package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +512 -0
- package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -0
- package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -0
- package/templates/default/src/app/(base)/test-suites/create/page.tsx +45 -0
- package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -0
- package/templates/default/src/app/(base)/test-suites/page.tsx +82 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -0
- package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -0
- package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -0
- package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +13 -0
- package/templates/default/src/app/(dashboard-components)/data-card.tsx +27 -0
- package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +57 -0
- package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -0
- package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +45 -0
- package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +133 -0
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -0
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -0
- package/templates/default/src/app/favicon.ico +0 -0
- package/templates/default/src/app/globals.css +147 -0
- package/templates/default/src/app/layout.tsx +171 -0
- package/templates/default/src/app/page.tsx +64 -0
- package/templates/default/src/assets/icons/empty-tube.tsx +23 -0
- package/templates/default/src/assets/icons/tube-plus.tsx +29 -0
- package/templates/default/src/components/base-node.tsx +21 -0
- package/templates/default/src/components/chart/pie-chart.tsx +73 -0
- package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -0
- package/templates/default/src/components/data-state/empty-state.tsx +40 -0
- package/templates/default/src/components/data-visualization/info-card.tsx +70 -0
- package/templates/default/src/components/data-visualization/info-grid.tsx +22 -0
- package/templates/default/src/components/devtools/providers.tsx +13 -0
- package/templates/default/src/components/diagram/button-edge.tsx +54 -0
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -0
- package/templates/default/src/components/diagram/edit-header-option.tsx +36 -0
- package/templates/default/src/components/diagram/flow-diagram.tsx +470 -0
- package/templates/default/src/components/diagram/node-form.tsx +262 -0
- package/templates/default/src/components/diagram/options-header-node.tsx +57 -0
- package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -0
- package/templates/default/src/components/form/error-message.tsx +7 -0
- package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -0
- package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -0
- package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -0
- package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -0
- package/templates/default/src/components/logo.tsx +15 -0
- package/templates/default/src/components/navigation/command-badge.tsx +34 -0
- package/templates/default/src/components/navigation/command-chain-input.tsx +51 -0
- package/templates/default/src/components/navigation/entity-search-command.tsx +116 -0
- package/templates/default/src/components/navigation/nav-card.tsx +31 -0
- package/templates/default/src/components/navigation/nav-command.tsx +508 -0
- package/templates/default/src/components/navigation/nav-link.tsx +60 -0
- package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -0
- package/templates/default/src/components/node-header.tsx +159 -0
- package/templates/default/src/components/reports/test-case-logs-modal.tsx +253 -0
- package/templates/default/src/components/table/table-actions.tsx +172 -0
- package/templates/default/src/components/test-run/download-logs-button.tsx +99 -0
- package/templates/default/src/components/test-run/log-viewer.tsx +445 -0
- package/templates/default/src/components/test-run/test-run-details.tsx +611 -0
- package/templates/default/src/components/test-run/test-run-header.tsx +149 -0
- package/templates/default/src/components/test-run/view-report-button.tsx +102 -0
- package/templates/default/src/components/theme/mode-toggle.tsx +54 -0
- package/templates/default/src/components/theme/theme-provider.tsx +8 -0
- package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -0
- package/templates/default/src/components/typography/page-header.tsx +7 -0
- package/templates/default/src/components/ui/alert-dialog.tsx +106 -0
- package/templates/default/src/components/ui/alert.tsx +43 -0
- package/templates/default/src/components/ui/avatar.tsx +40 -0
- package/templates/default/src/components/ui/badge.tsx +29 -0
- package/templates/default/src/components/ui/button.tsx +47 -0
- package/templates/default/src/components/ui/calendar.tsx +158 -0
- package/templates/default/src/components/ui/card.tsx +43 -0
- package/templates/default/src/components/ui/chart.tsx +369 -0
- package/templates/default/src/components/ui/checkbox.tsx +28 -0
- package/templates/default/src/components/ui/command.tsx +135 -0
- package/templates/default/src/components/ui/data-table-column-header.tsx +61 -0
- package/templates/default/src/components/ui/data-table-pagination.tsx +87 -0
- package/templates/default/src/components/ui/data-table-view-options.tsx +50 -0
- package/templates/default/src/components/ui/data-table.tsx +267 -0
- package/templates/default/src/components/ui/dialog.tsx +97 -0
- package/templates/default/src/components/ui/dropdown-menu.tsx +182 -0
- package/templates/default/src/components/ui/empty.tsx +104 -0
- package/templates/default/src/components/ui/input.tsx +22 -0
- package/templates/default/src/components/ui/kbd.tsx +28 -0
- package/templates/default/src/components/ui/label.tsx +19 -0
- package/templates/default/src/components/ui/loading.tsx +12 -0
- package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -0
- package/templates/default/src/components/ui/multi-select.tsx +142 -0
- package/templates/default/src/components/ui/navigation-menu.tsx +120 -0
- package/templates/default/src/components/ui/popover.tsx +33 -0
- package/templates/default/src/components/ui/progress.tsx +25 -0
- package/templates/default/src/components/ui/radio-group.tsx +44 -0
- package/templates/default/src/components/ui/scroll-area.tsx +40 -0
- package/templates/default/src/components/ui/select.tsx +144 -0
- package/templates/default/src/components/ui/separator.tsx +22 -0
- package/templates/default/src/components/ui/skeleton.tsx +7 -0
- package/templates/default/src/components/ui/table.tsx +76 -0
- package/templates/default/src/components/ui/tabs.tsx +55 -0
- package/templates/default/src/components/ui/textarea.tsx +21 -0
- package/templates/default/src/components/ui/toast.tsx +113 -0
- package/templates/default/src/components/ui/toaster.tsx +26 -0
- package/templates/default/src/components/ui/tooltip.tsx +32 -0
- package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -0
- package/templates/default/src/config/db-config.ts +10 -0
- package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -0
- package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -0
- package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -0
- package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -0
- package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -0
- package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -0
- package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -0
- package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -0
- package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -0
- package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -0
- package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -0
- package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -0
- package/templates/default/src/constants/form-opts/test-run-form-opts.ts +31 -0
- package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -0
- package/templates/default/src/hooks/use-toast.ts +187 -0
- package/templates/default/src/lib/bidirectional-sync.ts +432 -0
- package/templates/default/src/lib/database-sync.ts +531 -0
- package/templates/default/src/lib/environment-file-utils.ts +221 -0
- package/templates/default/src/lib/feature-file-generator.ts +411 -0
- package/templates/default/src/lib/gherkin-parser.ts +259 -0
- package/templates/default/src/lib/locator-group-file-utils.ts +370 -0
- package/templates/default/src/lib/metrics/metric-calculator.ts +613 -0
- package/templates/default/src/lib/module-hierarchy-builder.ts +205 -0
- package/templates/default/src/lib/path-helpers/module-path.ts +71 -0
- package/templates/default/src/lib/test-case-utils.ts +6 -0
- package/templates/default/src/lib/test-run/log-formatter.ts +83 -0
- package/templates/default/src/lib/test-run/process-manager.ts +191 -0
- package/templates/default/src/lib/test-run/report-parser.ts +316 -0
- package/templates/default/src/lib/test-run/test-run-executor.ts +144 -0
- package/templates/default/src/lib/test-run/winston-logger.ts +95 -0
- package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -0
- package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -0
- package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -0
- package/templates/default/src/lib/utils/node-param-validation.ts +81 -0
- package/templates/default/src/lib/utils/template-step-file-generator.ts +167 -0
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -0
- package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -0
- package/templates/default/src/lib/utils.ts +31 -0
- package/templates/default/src/tests/config/environments/environments.json +14 -0
- package/templates/default/src/tests/config/executor/world.ts +41 -0
- package/templates/default/src/tests/executor.ts +80 -0
- package/templates/default/src/tests/hooks/hooks.ts +99 -0
- package/templates/default/src/tests/mapping/locator-map.json +1 -0
- package/templates/default/src/tests/steps/actions/click.step.ts +62 -0
- package/templates/default/src/tests/steps/actions/hover.step.ts +31 -0
- package/templates/default/src/tests/steps/actions/input.step.ts +149 -0
- package/templates/default/src/tests/steps/actions/navigation.step.ts +72 -0
- package/templates/default/src/tests/steps/actions/random_data.step.ts +146 -0
- package/templates/default/src/tests/steps/actions/store.step.ts +90 -0
- package/templates/default/src/tests/steps/actions/wait.step.ts +107 -0
- package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -0
- package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +23 -0
- package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -0
- package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -0
- package/templates/default/src/tests/support/parameter-types.ts +12 -0
- package/templates/default/src/tests/utils/cache.util.ts +260 -0
- package/templates/default/src/tests/utils/cli.util.ts +177 -0
- package/templates/default/src/tests/utils/environment.util.ts +65 -0
- package/templates/default/src/tests/utils/locator.util.ts +248 -0
- package/templates/default/src/tests/utils/random-data.util.ts +45 -0
- package/templates/default/src/tests/utils/spawner.util.ts +617 -0
- package/templates/default/src/types/diagram/diagram.ts +34 -0
- package/templates/default/src/types/diagram/template-step.ts +11 -0
- package/templates/default/src/types/executor/browser.type.ts +1 -0
- package/templates/default/src/types/form/actionHandler.ts +6 -0
- package/templates/default/src/types/locator/locator.type.ts +11 -0
- package/templates/default/src/types/step/step.type.ts +1 -0
- package/templates/default/src/types/table/data-table.ts +6 -0
- package/templates/default/tailwind.config.ts +62 -0
- package/templates/default/tsconfig.json +28 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
import prisma from '@/config/db-config'
|
|
2
|
+
import { TestRunTestCaseResult, TestRunTestCaseStatus } from '@prisma/client'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Time period for "recent" runs in days
|
|
6
|
+
*/
|
|
7
|
+
const RECENT_PERIOD_DAYS = 7
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Threshold for consecutive failures to be considered "repeatedly failing"
|
|
11
|
+
*/
|
|
12
|
+
const REPEATEDLY_FAILING_THRESHOLD = 3
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Threshold for failure rate to be considered "flaky" (5%)
|
|
16
|
+
*/
|
|
17
|
+
const FLAKY_THRESHOLD = 0.05
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Calculate the date threshold for recent runs
|
|
21
|
+
*/
|
|
22
|
+
function getRecentPeriodDate(): Date {
|
|
23
|
+
const now = new Date()
|
|
24
|
+
now.setDate(now.getDate() - RECENT_PERIOD_DAYS)
|
|
25
|
+
return now
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Updates metrics for a single test case
|
|
30
|
+
* @param testCaseId - The test case ID
|
|
31
|
+
* @param result - The test case result (PASSED, FAILED, UNTESTED)
|
|
32
|
+
* @param executedAt - When the test case was executed
|
|
33
|
+
*/
|
|
34
|
+
export async function updateTestCaseMetrics(
|
|
35
|
+
testCaseId: string,
|
|
36
|
+
result: TestRunTestCaseResult,
|
|
37
|
+
executedAt: Date,
|
|
38
|
+
): Promise<void> {
|
|
39
|
+
try {
|
|
40
|
+
// Get existing metrics or create new one
|
|
41
|
+
const _existingMetrics = await prisma.testCaseMetrics.findUnique({
|
|
42
|
+
where: { testCaseId },
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// Query recent runs for this test case (last 7 days)
|
|
46
|
+
const recentPeriodDate = getRecentPeriodDate()
|
|
47
|
+
|
|
48
|
+
const recentTestRunTestCases = await prisma.testRunTestCase.findMany({
|
|
49
|
+
where: {
|
|
50
|
+
testCaseId,
|
|
51
|
+
status: TestRunTestCaseStatus.COMPLETED,
|
|
52
|
+
testRun: {
|
|
53
|
+
completedAt: {
|
|
54
|
+
gte: recentPeriodDate,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
include: {
|
|
59
|
+
testRun: {
|
|
60
|
+
select: {
|
|
61
|
+
completedAt: true,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
orderBy: {
|
|
66
|
+
testRun: {
|
|
67
|
+
completedAt: 'desc',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const totalRecentRuns = recentTestRunTestCases.length
|
|
73
|
+
const failedRecentRuns = recentTestRunTestCases.filter(
|
|
74
|
+
trtc => trtc.result === TestRunTestCaseResult.FAILED,
|
|
75
|
+
).length
|
|
76
|
+
|
|
77
|
+
// Calculate failure rate
|
|
78
|
+
const failureRate = totalRecentRuns > 0 ? failedRecentRuns / totalRecentRuns : 0
|
|
79
|
+
|
|
80
|
+
// Determine if flaky (failure rate > 5% but < 100%)
|
|
81
|
+
const isFlaky = failureRate > FLAKY_THRESHOLD && failureRate < 1.0
|
|
82
|
+
|
|
83
|
+
// Calculate consecutive failures by examining the actual sequence of results
|
|
84
|
+
// Start from the most recent and count backwards
|
|
85
|
+
// This ensures accuracy even if test runs are processed out of order
|
|
86
|
+
let consecutiveFailures = 0
|
|
87
|
+
for (const trtc of recentTestRunTestCases) {
|
|
88
|
+
if (trtc.result === TestRunTestCaseResult.FAILED) {
|
|
89
|
+
consecutiveFailures++
|
|
90
|
+
} else if (trtc.result === TestRunTestCaseResult.PASSED) {
|
|
91
|
+
// Once we hit a pass, stop counting consecutive failures
|
|
92
|
+
break
|
|
93
|
+
}
|
|
94
|
+
// UNTESTED results don't break the consecutive failure count
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Determine if repeatedly failing (3+ consecutive failures)
|
|
98
|
+
const isRepeatedlyFailing = consecutiveFailures >= REPEATEDLY_FAILING_THRESHOLD
|
|
99
|
+
|
|
100
|
+
// Determine which date fields to update
|
|
101
|
+
const updateData: {
|
|
102
|
+
lastExecutedAt: Date
|
|
103
|
+
lastFailedAt?: Date
|
|
104
|
+
lastPassedAt?: Date
|
|
105
|
+
isRepeatedlyFailing: boolean
|
|
106
|
+
isFlaky: boolean
|
|
107
|
+
consecutiveFailures: number
|
|
108
|
+
failureRate: number
|
|
109
|
+
totalRecentRuns: number
|
|
110
|
+
failedRecentRuns: number
|
|
111
|
+
} = {
|
|
112
|
+
lastExecutedAt: executedAt,
|
|
113
|
+
isRepeatedlyFailing,
|
|
114
|
+
isFlaky,
|
|
115
|
+
consecutiveFailures,
|
|
116
|
+
failureRate,
|
|
117
|
+
totalRecentRuns,
|
|
118
|
+
failedRecentRuns,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (result === TestRunTestCaseResult.FAILED) {
|
|
122
|
+
updateData.lastFailedAt = executedAt
|
|
123
|
+
} else if (result === TestRunTestCaseResult.PASSED) {
|
|
124
|
+
updateData.lastPassedAt = executedAt
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Upsert the metrics
|
|
128
|
+
await prisma.testCaseMetrics.upsert({
|
|
129
|
+
where: { testCaseId },
|
|
130
|
+
create: {
|
|
131
|
+
testCaseId,
|
|
132
|
+
...updateData,
|
|
133
|
+
},
|
|
134
|
+
update: updateData,
|
|
135
|
+
})
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(`[MetricCalculator] Error updating test case metrics for ${testCaseId}:`, error)
|
|
138
|
+
// Don't throw - metrics are non-critical
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Updates lastExecutedAt for a test suite
|
|
144
|
+
* @param testSuiteId - The test suite ID
|
|
145
|
+
* @param executedAt - When the test suite was executed
|
|
146
|
+
*/
|
|
147
|
+
export async function updateTestSuiteMetrics(
|
|
148
|
+
testSuiteId: string,
|
|
149
|
+
executedAt: Date,
|
|
150
|
+
): Promise<void> {
|
|
151
|
+
try {
|
|
152
|
+
await prisma.testSuiteMetrics.upsert({
|
|
153
|
+
where: { testSuiteId },
|
|
154
|
+
create: {
|
|
155
|
+
testSuiteId,
|
|
156
|
+
lastExecutedAt: executedAt,
|
|
157
|
+
},
|
|
158
|
+
update: {
|
|
159
|
+
lastExecutedAt: executedAt,
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error(`[MetricCalculator] Error updating test suite metrics for ${testSuiteId}:`, error)
|
|
164
|
+
// Don't throw - metrics are non-critical
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Finds all test suites that had test cases in a test run and updates their metrics
|
|
170
|
+
* @param testRunId - The test run ID
|
|
171
|
+
* @param executedAt - When the test run was executed
|
|
172
|
+
*/
|
|
173
|
+
export async function updateTestSuitesForTestRun(
|
|
174
|
+
testRunId: string,
|
|
175
|
+
executedAt: Date,
|
|
176
|
+
): Promise<void> {
|
|
177
|
+
try {
|
|
178
|
+
// Get all test cases in the test run
|
|
179
|
+
const testRunTestCases = await prisma.testRunTestCase.findMany({
|
|
180
|
+
where: { testRunId },
|
|
181
|
+
include: {
|
|
182
|
+
testCase: {
|
|
183
|
+
include: {
|
|
184
|
+
TestSuite: true,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Extract unique test suite IDs
|
|
191
|
+
const testSuiteIds = new Set<string>()
|
|
192
|
+
testRunTestCases.forEach(trtc => {
|
|
193
|
+
if (trtc.testCase && trtc.testCase.TestSuite) {
|
|
194
|
+
trtc.testCase.TestSuite.forEach(suite => {
|
|
195
|
+
testSuiteIds.add(suite.id)
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// Log for debugging
|
|
201
|
+
if (testSuiteIds.size === 0) {
|
|
202
|
+
console.warn(
|
|
203
|
+
`[MetricCalculator] No test suites found for test run ${testRunId}. Test cases: ${testRunTestCases.length}`,
|
|
204
|
+
)
|
|
205
|
+
} else {
|
|
206
|
+
console.log(
|
|
207
|
+
`[MetricCalculator] Updating metrics for ${testSuiteIds.size} test suite(s) for test run ${testRunId}`,
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Update lastExecutedAt for each suite
|
|
212
|
+
for (const suiteId of testSuiteIds) {
|
|
213
|
+
await updateTestSuiteMetrics(suiteId, executedAt)
|
|
214
|
+
}
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(`[MetricCalculator] Error updating test suite metrics for test run ${testRunId}:`, error)
|
|
217
|
+
// Don't throw - metrics are non-critical
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Updates dashboard metrics with aggregated counts
|
|
223
|
+
*/
|
|
224
|
+
export async function updateDashboardMetrics(): Promise<void> {
|
|
225
|
+
try {
|
|
226
|
+
const recentPeriodDate = getRecentPeriodDate()
|
|
227
|
+
|
|
228
|
+
// Count failed recent runs
|
|
229
|
+
const failedRecentRunsCount = await prisma.testRun.count({
|
|
230
|
+
where: {
|
|
231
|
+
result: 'FAILED',
|
|
232
|
+
completedAt: {
|
|
233
|
+
gte: recentPeriodDate,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
// Count repeatedly failing tests
|
|
239
|
+
const repeatedlyFailingTestsCount = await prisma.testCaseMetrics.count({
|
|
240
|
+
where: {
|
|
241
|
+
isRepeatedlyFailing: true,
|
|
242
|
+
},
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
// Count flaky tests
|
|
246
|
+
const flakyTestsCount = await prisma.testCaseMetrics.count({
|
|
247
|
+
where: {
|
|
248
|
+
isFlaky: true,
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// Count suites not executed recently
|
|
253
|
+
const suitesNotExecutedRecentlyCount = await prisma.testSuiteMetrics.count({
|
|
254
|
+
where: {
|
|
255
|
+
OR: [
|
|
256
|
+
{
|
|
257
|
+
lastExecutedAt: {
|
|
258
|
+
lt: recentPeriodDate,
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
lastExecutedAt: null,
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
},
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
// Update or create dashboard metrics (singleton pattern)
|
|
269
|
+
const existingMetrics = await prisma.dashboardMetrics.findFirst()
|
|
270
|
+
|
|
271
|
+
if (existingMetrics) {
|
|
272
|
+
await prisma.dashboardMetrics.update({
|
|
273
|
+
where: { id: existingMetrics.id },
|
|
274
|
+
data: {
|
|
275
|
+
failedRecentRunsCount,
|
|
276
|
+
repeatedlyFailingTestsCount,
|
|
277
|
+
flakyTestsCount,
|
|
278
|
+
suitesNotExecutedRecentlyCount,
|
|
279
|
+
lastUpdatedAt: new Date(),
|
|
280
|
+
},
|
|
281
|
+
})
|
|
282
|
+
} else {
|
|
283
|
+
await prisma.dashboardMetrics.create({
|
|
284
|
+
data: {
|
|
285
|
+
failedRecentRunsCount,
|
|
286
|
+
repeatedlyFailingTestsCount,
|
|
287
|
+
flakyTestsCount,
|
|
288
|
+
suitesNotExecutedRecentlyCount,
|
|
289
|
+
lastUpdatedAt: new Date(),
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error('[MetricCalculator] Error updating dashboard metrics:', error)
|
|
295
|
+
// Don't throw - metrics are non-critical
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Recalculates metrics for a single test case from scratch based on current database state
|
|
301
|
+
* This is used when test runs are deleted and we need to recalculate metrics without
|
|
302
|
+
* the deleted test run data.
|
|
303
|
+
* @param testCaseId - The test case ID
|
|
304
|
+
*/
|
|
305
|
+
export async function recalculateTestCaseMetrics(testCaseId: string): Promise<void> {
|
|
306
|
+
try {
|
|
307
|
+
const recentPeriodDate = getRecentPeriodDate()
|
|
308
|
+
|
|
309
|
+
// Query all recent test run test cases for this test case (last 7 days)
|
|
310
|
+
const recentTestRunTestCases = await prisma.testRunTestCase.findMany({
|
|
311
|
+
where: {
|
|
312
|
+
testCaseId,
|
|
313
|
+
status: TestRunTestCaseStatus.COMPLETED,
|
|
314
|
+
testRun: {
|
|
315
|
+
completedAt: {
|
|
316
|
+
gte: recentPeriodDate,
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
include: {
|
|
321
|
+
testRun: {
|
|
322
|
+
select: {
|
|
323
|
+
completedAt: true,
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
orderBy: {
|
|
328
|
+
testRun: {
|
|
329
|
+
completedAt: 'desc',
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
const totalRecentRuns = recentTestRunTestCases.length
|
|
335
|
+
const failedRecentRuns = recentTestRunTestCases.filter(
|
|
336
|
+
trtc => trtc.result === TestRunTestCaseResult.FAILED,
|
|
337
|
+
).length
|
|
338
|
+
|
|
339
|
+
// Calculate failure rate
|
|
340
|
+
const failureRate = totalRecentRuns > 0 ? failedRecentRuns / totalRecentRuns : 0
|
|
341
|
+
|
|
342
|
+
// Determine if flaky (failure rate > 5% but < 100%)
|
|
343
|
+
const isFlaky = failureRate > FLAKY_THRESHOLD && failureRate < 1.0
|
|
344
|
+
|
|
345
|
+
// Calculate consecutive failures by examining the actual sequence of results
|
|
346
|
+
// Start from the most recent and count backwards
|
|
347
|
+
let consecutiveFailures = 0
|
|
348
|
+
for (const trtc of recentTestRunTestCases) {
|
|
349
|
+
if (trtc.result === TestRunTestCaseResult.FAILED) {
|
|
350
|
+
consecutiveFailures++
|
|
351
|
+
} else if (trtc.result === TestRunTestCaseResult.PASSED) {
|
|
352
|
+
// Once we hit a pass, stop counting consecutive failures
|
|
353
|
+
break
|
|
354
|
+
}
|
|
355
|
+
// UNTESTED results don't break the consecutive failure count
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Determine if repeatedly failing (3+ consecutive failures)
|
|
359
|
+
const isRepeatedlyFailing = consecutiveFailures >= REPEATEDLY_FAILING_THRESHOLD
|
|
360
|
+
|
|
361
|
+
// Determine last executed, last failed, and last passed dates
|
|
362
|
+
let lastExecutedAt: Date | null = null
|
|
363
|
+
let lastFailedAt: Date | null = null
|
|
364
|
+
let lastPassedAt: Date | null = null
|
|
365
|
+
|
|
366
|
+
if (recentTestRunTestCases.length > 0) {
|
|
367
|
+
// Most recent execution
|
|
368
|
+
lastExecutedAt = recentTestRunTestCases[0].testRun.completedAt || new Date()
|
|
369
|
+
|
|
370
|
+
// Find most recent failure
|
|
371
|
+
const mostRecentFailure = recentTestRunTestCases.find(
|
|
372
|
+
trtc => trtc.result === TestRunTestCaseResult.FAILED,
|
|
373
|
+
)
|
|
374
|
+
if (mostRecentFailure) {
|
|
375
|
+
lastFailedAt = mostRecentFailure.testRun.completedAt || new Date()
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Find most recent pass
|
|
379
|
+
const mostRecentPass = recentTestRunTestCases.find(
|
|
380
|
+
trtc => trtc.result === TestRunTestCaseResult.PASSED,
|
|
381
|
+
)
|
|
382
|
+
if (mostRecentPass) {
|
|
383
|
+
lastPassedAt = mostRecentPass.testRun.completedAt || new Date()
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// If no recent runs, check if there are any older runs to get last executed/failed/passed dates
|
|
388
|
+
if (!lastExecutedAt || !lastFailedAt || !lastPassedAt) {
|
|
389
|
+
const olderTestRunTestCases = await prisma.testRunTestCase.findMany({
|
|
390
|
+
where: {
|
|
391
|
+
testCaseId,
|
|
392
|
+
status: TestRunTestCaseStatus.COMPLETED,
|
|
393
|
+
testRun: {
|
|
394
|
+
completedAt: {
|
|
395
|
+
lt: recentPeriodDate,
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
include: {
|
|
400
|
+
testRun: {
|
|
401
|
+
select: {
|
|
402
|
+
completedAt: true,
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
orderBy: {
|
|
407
|
+
testRun: {
|
|
408
|
+
completedAt: 'desc',
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
take: 1, // Only need the most recent one
|
|
412
|
+
})
|
|
413
|
+
|
|
414
|
+
if (olderTestRunTestCases.length > 0) {
|
|
415
|
+
const mostRecentOlder = olderTestRunTestCases[0]
|
|
416
|
+
const olderCompletedAt = mostRecentOlder.testRun.completedAt || new Date()
|
|
417
|
+
|
|
418
|
+
if (!lastExecutedAt) {
|
|
419
|
+
lastExecutedAt = olderCompletedAt
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Find most recent failure from older runs if not found in recent runs
|
|
423
|
+
if (!lastFailedAt) {
|
|
424
|
+
const olderFailure = olderTestRunTestCases.find(
|
|
425
|
+
trtc => trtc.result === TestRunTestCaseResult.FAILED,
|
|
426
|
+
)
|
|
427
|
+
if (!olderFailure) {
|
|
428
|
+
// Check all older runs for failures
|
|
429
|
+
const allOlderFailures = await prisma.testRunTestCase.findFirst({
|
|
430
|
+
where: {
|
|
431
|
+
testCaseId,
|
|
432
|
+
status: TestRunTestCaseStatus.COMPLETED,
|
|
433
|
+
result: TestRunTestCaseResult.FAILED,
|
|
434
|
+
testRun: {
|
|
435
|
+
completedAt: {
|
|
436
|
+
lt: recentPeriodDate,
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
},
|
|
440
|
+
include: {
|
|
441
|
+
testRun: {
|
|
442
|
+
select: {
|
|
443
|
+
completedAt: true,
|
|
444
|
+
},
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
orderBy: {
|
|
448
|
+
testRun: {
|
|
449
|
+
completedAt: 'desc',
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
})
|
|
453
|
+
if (allOlderFailures) {
|
|
454
|
+
lastFailedAt = allOlderFailures.testRun.completedAt || new Date()
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
lastFailedAt = olderFailure.testRun.completedAt || new Date()
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Find most recent pass from older runs if not found in recent runs
|
|
462
|
+
if (!lastPassedAt) {
|
|
463
|
+
const olderPass = olderTestRunTestCases.find(
|
|
464
|
+
trtc => trtc.result === TestRunTestCaseResult.PASSED,
|
|
465
|
+
)
|
|
466
|
+
if (!olderPass) {
|
|
467
|
+
// Check all older runs for passes
|
|
468
|
+
const allOlderPasses = await prisma.testRunTestCase.findFirst({
|
|
469
|
+
where: {
|
|
470
|
+
testCaseId,
|
|
471
|
+
status: TestRunTestCaseStatus.COMPLETED,
|
|
472
|
+
result: TestRunTestCaseResult.PASSED,
|
|
473
|
+
testRun: {
|
|
474
|
+
completedAt: {
|
|
475
|
+
lt: recentPeriodDate,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
include: {
|
|
480
|
+
testRun: {
|
|
481
|
+
select: {
|
|
482
|
+
completedAt: true,
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
orderBy: {
|
|
487
|
+
testRun: {
|
|
488
|
+
completedAt: 'desc',
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
})
|
|
492
|
+
if (allOlderPasses) {
|
|
493
|
+
lastPassedAt = allOlderPasses.testRun.completedAt || new Date()
|
|
494
|
+
}
|
|
495
|
+
} else {
|
|
496
|
+
lastPassedAt = olderPass.testRun.completedAt || new Date()
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// Prepare update data
|
|
503
|
+
const updateData: {
|
|
504
|
+
lastExecutedAt?: Date
|
|
505
|
+
lastFailedAt?: Date | null
|
|
506
|
+
lastPassedAt?: Date | null
|
|
507
|
+
isRepeatedlyFailing: boolean
|
|
508
|
+
isFlaky: boolean
|
|
509
|
+
consecutiveFailures: number
|
|
510
|
+
failureRate: number
|
|
511
|
+
totalRecentRuns: number
|
|
512
|
+
failedRecentRuns: number
|
|
513
|
+
} = {
|
|
514
|
+
isRepeatedlyFailing,
|
|
515
|
+
isFlaky,
|
|
516
|
+
consecutiveFailures,
|
|
517
|
+
failureRate,
|
|
518
|
+
totalRecentRuns,
|
|
519
|
+
failedRecentRuns,
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (lastExecutedAt) {
|
|
523
|
+
updateData.lastExecutedAt = lastExecutedAt
|
|
524
|
+
}
|
|
525
|
+
if (lastFailedAt !== null) {
|
|
526
|
+
updateData.lastFailedAt = lastFailedAt
|
|
527
|
+
}
|
|
528
|
+
if (lastPassedAt !== null) {
|
|
529
|
+
updateData.lastPassedAt = lastPassedAt
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Upsert the metrics
|
|
533
|
+
await prisma.testCaseMetrics.upsert({
|
|
534
|
+
where: { testCaseId },
|
|
535
|
+
create: {
|
|
536
|
+
testCaseId,
|
|
537
|
+
lastExecutedAt: lastExecutedAt || undefined,
|
|
538
|
+
lastFailedAt: lastFailedAt || undefined,
|
|
539
|
+
lastPassedAt: lastPassedAt || undefined,
|
|
540
|
+
...updateData,
|
|
541
|
+
},
|
|
542
|
+
update: updateData,
|
|
543
|
+
})
|
|
544
|
+
} catch (error) {
|
|
545
|
+
console.error(`[MetricCalculator] Error recalculating test case metrics for ${testCaseId}:`, error)
|
|
546
|
+
// Don't throw - metrics are non-critical
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Recalculates metrics for multiple test cases
|
|
552
|
+
* @param testCaseIds - Array of test case IDs to recalculate
|
|
553
|
+
*/
|
|
554
|
+
export async function recalculateMetricsForTestCases(testCaseIds: string[]): Promise<void> {
|
|
555
|
+
try {
|
|
556
|
+
// Remove duplicates
|
|
557
|
+
const uniqueTestCaseIds = [...new Set(testCaseIds)]
|
|
558
|
+
|
|
559
|
+
for (const testCaseId of uniqueTestCaseIds) {
|
|
560
|
+
await recalculateTestCaseMetrics(testCaseId)
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
console.error(`[MetricCalculator] Error recalculating metrics for test cases:`, error)
|
|
564
|
+
// Don't throw - metrics are non-critical
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Updates all metrics for a test run when it completes
|
|
570
|
+
* @param testRunId - The test run ID
|
|
571
|
+
*/
|
|
572
|
+
export async function updateMetricsForTestRun(testRunId: string): Promise<void> {
|
|
573
|
+
try {
|
|
574
|
+
// Get the test run with test cases
|
|
575
|
+
const testRun = await prisma.testRun.findUnique({
|
|
576
|
+
where: { id: testRunId },
|
|
577
|
+
include: {
|
|
578
|
+
testCases: {
|
|
579
|
+
include: {
|
|
580
|
+
testCase: true,
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
if (!testRun) {
|
|
587
|
+
console.warn(`[MetricCalculator] Test run ${testRunId} not found`)
|
|
588
|
+
return
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const executedAt = testRun.completedAt || testRun.startedAt
|
|
592
|
+
|
|
593
|
+
// Update metrics for all test cases in the run
|
|
594
|
+
for (const testRunTestCase of testRun.testCases) {
|
|
595
|
+
if (testRunTestCase.status === TestRunTestCaseStatus.COMPLETED) {
|
|
596
|
+
await updateTestCaseMetrics(
|
|
597
|
+
testRunTestCase.testCaseId,
|
|
598
|
+
testRunTestCase.result,
|
|
599
|
+
executedAt,
|
|
600
|
+
)
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// Update test suite metrics
|
|
605
|
+
await updateTestSuitesForTestRun(testRunId, executedAt)
|
|
606
|
+
|
|
607
|
+
// Update dashboard metrics
|
|
608
|
+
await updateDashboardMetrics()
|
|
609
|
+
} catch (error) {
|
|
610
|
+
console.error(`[MetricCalculator] Error updating metrics for test run ${testRunId}:`, error)
|
|
611
|
+
// Don't throw - metrics are non-critical
|
|
612
|
+
}
|
|
613
|
+
}
|