create-appraisejs 0.1.10-alpha.8 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -52
- package/dist/cli.e2e.test.d.ts +2 -0
- package/dist/cli.e2e.test.d.ts.map +1 -0
- package/dist/cli.e2e.test.js +73 -0
- package/dist/cli.e2e.test.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +65 -0
- package/dist/config.test.js.map +1 -0
- package/dist/copy-template.test.d.ts +2 -0
- package/dist/copy-template.test.d.ts.map +1 -0
- package/dist/copy-template.test.js +71 -0
- package/dist/copy-template.test.js.map +1 -0
- package/dist/download-repo.test.d.ts +2 -0
- package/dist/download-repo.test.d.ts.map +1 -0
- package/dist/download-repo.test.js +14 -0
- package/dist/download-repo.test.js.map +1 -0
- package/dist/install.test.d.ts +2 -0
- package/dist/install.test.d.ts.map +1 -0
- package/dist/install.test.js +119 -0
- package/dist/install.test.js.map +1 -0
- package/dist/prepare-template-utils.d.ts.map +1 -1
- package/dist/prepare-template-utils.js +5 -0
- package/dist/prepare-template-utils.js.map +1 -1
- package/dist/prompts.test.d.ts +2 -0
- package/dist/prompts.test.d.ts.map +1 -0
- package/dist/prompts.test.js +58 -0
- package/dist/prompts.test.js.map +1 -0
- package/dist/scaffold-gitignore.d.ts +1 -0
- package/dist/scaffold-gitignore.d.ts.map +1 -1
- package/dist/scaffold-gitignore.js +3 -0
- package/dist/scaffold-gitignore.js.map +1 -1
- package/package.json +3 -2
- package/templates/default/.appraise-template-meta.json +2 -2
- package/templates/default/.env.example +2 -2
- package/templates/default/.vscode/settings.json +2 -1
- package/templates/default/README.md +53 -53
- package/templates/default/automation/mapping/locator-map.json +1 -14
- package/templates/default/automation/steps/actions/click.step.ts +58 -58
- package/templates/default/automation/steps/actions/hover.step.ts +27 -27
- package/templates/default/automation/steps/actions/input.step.ts +84 -84
- package/templates/default/automation/steps/actions/navigation.step.ts +70 -70
- package/templates/default/automation/steps/actions/random_data.step.ts +142 -142
- package/templates/default/automation/steps/actions/store.step.ts +86 -86
- package/templates/default/automation/steps/actions/wait.step.ts +90 -90
- package/templates/default/automation/steps/validations/active_state_assertion.step.ts +30 -30
- package/templates/default/automation/steps/validations/navigation_assertion.step.ts +22 -22
- package/templates/default/automation/steps/validations/text_assertion.step.ts +107 -107
- package/templates/default/automation/steps/validations/visibility_assertion.step.ts +26 -26
- package/templates/default/components.json +24 -24
- package/templates/default/cucumber.mjs +16 -16
- package/templates/default/eslint.config.mjs +16 -16
- package/templates/default/gitignore +3 -0
- package/templates/default/next-env.d.ts +6 -6
- package/templates/default/next.config.ts +11 -11
- package/templates/default/package-lock.json +146 -75
- package/templates/default/package.json +2 -1
- package/templates/default/packages/cucumber-runtime/package.json +13 -13
- package/templates/default/packages/cucumber-runtime/src/cache.util.ts +93 -93
- package/templates/default/packages/cucumber-runtime/src/cli.ts +68 -68
- package/templates/default/packages/cucumber-runtime/src/environment.util.ts +21 -21
- package/templates/default/packages/cucumber-runtime/src/executor.ts +32 -32
- package/templates/default/packages/cucumber-runtime/src/hooks.ts +25 -3
- package/templates/default/packages/cucumber-runtime/src/index.ts +17 -17
- package/templates/default/packages/cucumber-runtime/src/locator.util.ts +234 -234
- package/templates/default/packages/cucumber-runtime/src/parameter-types.ts +7 -7
- package/templates/default/packages/cucumber-runtime/src/paths.ts +66 -1
- package/templates/default/packages/cucumber-runtime/src/random-data.util.ts +35 -35
- package/templates/default/packages/cucumber-runtime/src/types.ts +13 -13
- package/templates/default/packages/cucumber-runtime/src/world.ts +44 -44
- package/templates/default/packages/cucumber-runtime/tsconfig.json +11 -11
- package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +1 -0
- package/templates/default/packages/locator-picker-companion/dist/cli.js +302 -0
- package/templates/default/packages/locator-picker-companion/dist/index.d.ts +3 -0
- package/templates/default/packages/locator-picker-companion/dist/index.js +3 -0
- package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +1 -0
- package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +615 -0
- package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +11 -0
- package/templates/default/packages/locator-picker-companion/dist/launcher.js +59 -0
- package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +3 -0
- package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +257 -0
- package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +22 -0
- package/templates/default/packages/locator-picker-companion/dist/session-file.js +150 -0
- package/templates/default/packages/locator-picker-companion/dist/types.d.ts +31 -0
- package/templates/default/packages/locator-picker-companion/dist/types.js +1 -0
- package/templates/default/packages/locator-picker-companion/package.json +17 -0
- package/templates/default/packages/locator-picker-companion/src/cli.ts +428 -0
- package/templates/default/packages/locator-picker-companion/src/index.ts +3 -0
- package/templates/default/packages/locator-picker-companion/src/injected-picker-script.ts +771 -0
- package/templates/default/packages/locator-picker-companion/src/launcher.ts +77 -0
- package/templates/default/packages/locator-picker-companion/src/selector-generator.ts +339 -0
- package/templates/default/packages/locator-picker-companion/src/session-file.ts +226 -0
- package/templates/default/packages/locator-picker-companion/src/types.ts +42 -0
- package/templates/default/packages/locator-picker-companion/tsconfig.json +14 -0
- package/templates/default/postcss.config.mjs +8 -8
- package/templates/default/prisma/dev.db +0 -0
- package/templates/default/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
- package/templates/default/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
- package/templates/default/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
- package/templates/default/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
- package/templates/default/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
- package/templates/default/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
- package/templates/default/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
- package/templates/default/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
- package/templates/default/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
- package/templates/default/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
- package/templates/default/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
- package/templates/default/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
- package/templates/default/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
- package/templates/default/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -0
- package/templates/default/prisma/migrations/20260318120000_add_test_suite_context_to_test_run_test_case/migration.sql +20 -0
- package/templates/default/prisma/migrations/20260318173512_add_support_of_test_suite_level_runs/migration.sql +2 -0
- package/templates/default/prisma/schema.prisma +4 -0
- package/templates/default/scripts/install-playwright.ts +20 -0
- package/templates/default/scripts/protect-seeded-files.ts +38 -38
- package/templates/default/scripts/regenerate-features.ts +94 -94
- package/templates/default/scripts/setup-env.ts +19 -19
- package/templates/default/scripts/sync-all.ts +22 -66
- package/templates/default/scripts/sync-appraise-base-template.ts +57 -19
- package/templates/default/scripts/sync-environments.ts +40 -21
- package/templates/default/scripts/sync-locator-groups.ts +410 -410
- package/templates/default/scripts/sync-locators.ts +398 -398
- package/templates/default/scripts/sync-modules.ts +341 -341
- package/templates/default/scripts/sync-tags.ts +2 -3
- package/templates/default/scripts/sync-template-step-groups.ts +0 -3
- package/templates/default/scripts/sync-template-steps.ts +37 -11
- package/templates/default/scripts/sync-test-cases.ts +68 -16
- package/templates/default/scripts/sync-test-suites.ts +7 -5
- package/templates/default/src/actions/conflict/conflict.action.ts +33 -33
- package/templates/default/src/actions/dashboard/dashboard-actions.ts +240 -240
- package/templates/default/src/actions/environments/environment-actions.ts +188 -188
- package/templates/default/src/actions/locator/locator-actions.ts +490 -490
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +6 -3
- package/templates/default/src/actions/locator-picker/locator-picker-actions.ts +243 -0
- package/templates/default/src/actions/modules/module-actions.ts +135 -135
- package/templates/default/src/actions/reports/report-actions.ts +51 -49
- package/templates/default/src/actions/review/review-actions.ts +147 -147
- package/templates/default/src/actions/settings/sync-actions.ts +46 -0
- package/templates/default/src/actions/tags/tag-actions.ts +107 -107
- package/templates/default/src/actions/template-step/template-step-actions.ts +38 -4
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +10 -3
- package/templates/default/src/actions/template-test-case/template-test-case-actions.ts +238 -238
- package/templates/default/src/actions/test-case/test-case-actions.ts +356 -356
- package/templates/default/src/actions/test-run/test-run-actions.ts +222 -129
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +95 -17
- package/templates/default/src/actions/user/user-actions.ts +13 -13
- package/templates/default/src/app/(base)/environments/create/page.tsx +28 -28
- package/templates/default/src/app/(base)/environments/environment-form.tsx +219 -219
- package/templates/default/src/app/(base)/environments/environment-table-columns.tsx +96 -96
- package/templates/default/src/app/(base)/environments/environment-table.tsx +24 -24
- package/templates/default/src/app/(base)/environments/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/environments/page.tsx +59 -59
- package/templates/default/src/app/(base)/layout.tsx +10 -10
- package/templates/default/src/app/(base)/locator-groups/create/page.tsx +44 -44
- package/templates/default/src/app/(base)/locator-groups/locator-group-form.tsx +215 -215
- package/templates/default/src/app/(base)/locator-groups/locator-group-table-columns.tsx +77 -77
- package/templates/default/src/app/(base)/locator-groups/locator-group-table.tsx +28 -28
- package/templates/default/src/app/(base)/locator-groups/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/locator-groups/page.tsx +20 -8
- package/templates/default/src/app/(base)/locators/create/create-locator-workspace.tsx +542 -0
- package/templates/default/src/app/(base)/locators/create/page.tsx +32 -19
- package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
- package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -73
- package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
- package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +56 -27
- package/templates/default/src/app/(base)/locators/page.tsx +13 -13
- package/templates/default/src/app/(base)/locators/picker/page.tsx +7 -0
- package/templates/default/src/app/(base)/locators/sync-locators-button.tsx +66 -66
- package/templates/default/src/app/(base)/modules/create/page.tsx +34 -34
- package/templates/default/src/app/(base)/modules/modify/[id]/page.tsx +46 -46
- package/templates/default/src/app/(base)/modules/module-form.tsx +126 -126
- package/templates/default/src/app/(base)/modules/module-table-columns.tsx +85 -85
- package/templates/default/src/app/(base)/modules/module-table.tsx +24 -24
- package/templates/default/src/app/(base)/modules/page.tsx +59 -59
- package/templates/default/src/app/(base)/reports/[id]/page.tsx +40 -33
- package/templates/default/src/app/(base)/reports/duration-chart.tsx +33 -33
- package/templates/default/src/app/(base)/reports/feature-chart.tsx +78 -78
- package/templates/default/src/app/(base)/reports/overview-chart.tsx +49 -46
- package/templates/default/src/app/(base)/reports/page.tsx +98 -98
- package/templates/default/src/app/(base)/reports/report-metric-card.tsx +78 -16
- package/templates/default/src/app/(base)/reports/report-table-columns.tsx +189 -189
- package/templates/default/src/app/(base)/reports/report-table.tsx +72 -72
- package/templates/default/src/app/(base)/reports/report-view-table-columns.tsx +12 -1
- package/templates/default/src/app/(base)/reports/report-view-table.tsx +1 -0
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +40 -42
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table-columns.tsx +115 -115
- package/templates/default/src/app/(base)/reports/test-cases/test-cases-metric-table.tsx +27 -27
- package/templates/default/src/app/(base)/reports/test-suites/page.tsx +42 -42
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table-columns.tsx +79 -79
- package/templates/default/src/app/(base)/reports/test-suites/test-suites-metric-table.tsx +27 -27
- package/templates/default/src/app/(base)/reports/view-logs-button.tsx +58 -60
- package/templates/default/src/app/(base)/reviews/create/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/created-reviews-table.tsx +15 -15
- package/templates/default/src/app/(base)/reviews/modify/[id]/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/review/[id]/page.tsx +26 -26
- package/templates/default/src/app/(base)/reviews/review-form.tsx +11 -11
- package/templates/default/src/app/(base)/reviews/review-table-by-creator-columns.tsx +9 -9
- package/templates/default/src/app/(base)/reviews/review-table-by-reviewer-columns.tsx +9 -9
- package/templates/default/src/app/(base)/reviews/reviewer-reviews-table.tsx +15 -15
- package/templates/default/src/app/(base)/settings/page.tsx +30 -0
- package/templates/default/src/app/(base)/settings/settings-sync-panel.tsx +261 -0
- package/templates/default/src/app/(base)/tags/create/page.tsx +39 -39
- package/templates/default/src/app/(base)/tags/modify/[id]/page.tsx +50 -50
- package/templates/default/src/app/(base)/tags/page.tsx +58 -58
- package/templates/default/src/app/(base)/tags/tag-form.tsx +147 -147
- package/templates/default/src/app/(base)/tags/tag-table-columns.tsx +63 -63
- package/templates/default/src/app/(base)/tags/tag-table.tsx +29 -29
- package/templates/default/src/app/(base)/template-step-groups/create/page.tsx +28 -28
- package/templates/default/src/app/(base)/template-step-groups/modify/[id]/page.tsx +45 -45
- package/templates/default/src/app/(base)/template-step-groups/page.tsx +60 -60
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-form.tsx +167 -167
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table-columns.tsx +89 -89
- package/templates/default/src/app/(base)/template-step-groups/template-step-group-table.tsx +32 -32
- package/templates/default/src/app/(base)/template-steps/create/page.tsx +37 -37
- package/templates/default/src/app/(base)/template-steps/modify/[id]/page.tsx +49 -49
- package/templates/default/src/app/(base)/template-steps/page.tsx +58 -58
- package/templates/default/src/app/(base)/template-steps/paramChip.tsx +213 -213
- package/templates/default/src/app/(base)/template-steps/template-step-form.tsx +384 -384
- package/templates/default/src/app/(base)/template-steps/template-step-table-columns.tsx +158 -158
- package/templates/default/src/app/(base)/template-steps/template-step-table.tsx +24 -24
- package/templates/default/src/app/(base)/template-test-cases/create/page.tsx +56 -56
- package/templates/default/src/app/(base)/template-test-cases/modify/[id]/page.tsx +89 -89
- package/templates/default/src/app/(base)/template-test-cases/page.tsx +58 -58
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-flow.tsx +84 -84
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-form.tsx +262 -262
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table-columns.tsx +76 -76
- package/templates/default/src/app/(base)/template-test-cases/template-test-case-table.tsx +32 -32
- package/templates/default/src/app/(base)/test-cases/create/page.tsx +76 -76
- package/templates/default/src/app/(base)/test-cases/create-from-template/generate/[id]/page.tsx +96 -96
- package/templates/default/src/app/(base)/test-cases/create-from-template/page.tsx +38 -38
- package/templates/default/src/app/(base)/test-cases/create-from-template/template-selection-form.tsx +73 -73
- package/templates/default/src/app/(base)/test-cases/modify/[id]/page.tsx +106 -106
- package/templates/default/src/app/(base)/test-cases/page.tsx +2 -2
- package/templates/default/src/app/(base)/test-cases/test-case-flow.tsx +82 -82
- package/templates/default/src/app/(base)/test-cases/test-case-form.tsx +395 -395
- package/templates/default/src/app/(base)/test-cases/test-case-table-columns.tsx +6 -71
- package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +2 -2
- package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +4 -1
- package/templates/default/src/app/(base)/test-runs/create/page.tsx +11 -9
- package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
- package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +37 -44
- package/templates/default/src/app/(base)/test-runs/test-run-table-columns.tsx +229 -229
- package/templates/default/src/app/(base)/test-runs/test-run-table.tsx +127 -127
- package/templates/default/src/app/(base)/test-suites/create/page.tsx +3 -2
- package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +2 -1
- package/templates/default/src/app/(base)/test-suites/page.tsx +57 -21
- package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +16 -17
- package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +2 -1
- package/templates/default/src/app/(base)/test-suites/test-suite-table.tsx +29 -29
- package/templates/default/src/app/(dashboard-components)/app-drawer.tsx +187 -187
- package/templates/default/src/app/(dashboard-components)/data-card-grid.tsx +12 -12
- package/templates/default/src/app/(dashboard-components)/data-card.tsx +26 -26
- package/templates/default/src/app/(dashboard-components)/execution-health-panel.tsx +56 -56
- package/templates/default/src/app/(dashboard-components)/ongoing-test-runs-card.tsx +87 -87
- package/templates/default/src/app/(dashboard-components)/quick-actions-drawer.tsx +44 -44
- package/templates/default/src/app/api/reports/steps/[stepId]/screenshot/route.ts +52 -0
- package/templates/default/src/app/api/test-runs/[runId]/download/route.ts +97 -34
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +4 -1
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -147
- package/templates/default/src/app/globals.css +147 -147
- package/templates/default/src/app/layout.tsx +4 -0
- package/templates/default/src/app/page.tsx +2 -0
- package/templates/default/src/assets/icons/empty-tube.tsx +23 -23
- package/templates/default/src/assets/icons/tube-plus.tsx +29 -29
- package/templates/default/src/components/base-node.tsx +21 -21
- package/templates/default/src/components/chart/pie-chart.tsx +73 -73
- package/templates/default/src/components/data-extraction/locator-inspector.tsx +460 -460
- package/templates/default/src/components/data-state/empty-state.tsx +40 -40
- package/templates/default/src/components/data-visualization/info-card.tsx +70 -70
- package/templates/default/src/components/data-visualization/info-grid.tsx +22 -22
- package/templates/default/src/components/diagram/button-edge.tsx +54 -54
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +474 -474
- package/templates/default/src/components/diagram/edit-header-option.tsx +36 -36
- package/templates/default/src/components/diagram/flow-diagram.tsx +470 -470
- package/templates/default/src/components/diagram/node-form.tsx +262 -262
- package/templates/default/src/components/diagram/options-header-node.tsx +57 -57
- package/templates/default/src/components/diagram/template-step-combobox.tsx +155 -155
- package/templates/default/src/components/form/error-message.tsx +7 -7
- package/templates/default/src/components/kokonutui/smooth-tab.tsx +453 -453
- package/templates/default/src/components/loading-skeleton/data-table/data-table-skeleton.tsx +30 -30
- package/templates/default/src/components/loading-skeleton/form/button-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/form/icon-button-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/form/text-input-skeleton.tsx +8 -8
- package/templates/default/src/components/loading-skeleton/visualization/table-skeleton.tsx +14 -14
- package/templates/default/src/components/logo.tsx +15 -15
- package/templates/default/src/components/navigation/command-badge.tsx +34 -34
- package/templates/default/src/components/navigation/command-chain-input.tsx +51 -51
- package/templates/default/src/components/navigation/entity-search-command.tsx +116 -116
- package/templates/default/src/components/navigation/nav-card.tsx +31 -31
- package/templates/default/src/components/navigation/nav-command.tsx +13 -0
- package/templates/default/src/components/navigation/nav-link.tsx +60 -60
- package/templates/default/src/components/navigation/nav-menu-card-deck.tsx +112 -112
- package/templates/default/src/components/node-header.tsx +159 -159
- package/templates/default/src/components/reports/test-case-logs-modal.tsx +310 -253
- package/templates/default/src/components/table/table-actions.tsx +172 -172
- package/templates/default/src/components/test-case/test-case-columns.tsx +76 -0
- package/templates/default/src/components/test-case/test-case-picker.tsx +244 -0
- package/templates/default/src/components/test-run/download-logs-button.tsx +92 -99
- package/templates/default/src/components/test-run/log-viewer.tsx +1 -14
- package/templates/default/src/components/test-run/test-run-details.tsx +15 -2
- package/templates/default/src/components/test-run/test-run-header.tsx +149 -149
- package/templates/default/src/components/test-run/view-report-button.tsx +102 -102
- package/templates/default/src/components/test-suite/test-suite-picker.tsx +444 -0
- package/templates/default/src/components/theme/mode-toggle.tsx +54 -54
- package/templates/default/src/components/theme/theme-provider.tsx +8 -8
- package/templates/default/src/components/typography/page-header-subtitle.tsx +7 -7
- package/templates/default/src/components/typography/page-header.tsx +7 -7
- package/templates/default/src/components/ui/alert-dialog.tsx +106 -106
- package/templates/default/src/components/ui/alert.tsx +43 -43
- package/templates/default/src/components/ui/avatar.tsx +40 -40
- package/templates/default/src/components/ui/badge.tsx +29 -29
- package/templates/default/src/components/ui/button.tsx +47 -47
- package/templates/default/src/components/ui/calendar.tsx +158 -158
- package/templates/default/src/components/ui/card.tsx +43 -43
- package/templates/default/src/components/ui/checkbox.tsx +28 -28
- package/templates/default/src/components/ui/command.tsx +135 -135
- package/templates/default/src/components/ui/data-table-column-header.tsx +61 -61
- package/templates/default/src/components/ui/data-table-pagination.tsx +87 -87
- package/templates/default/src/components/ui/data-table-view-options.tsx +50 -50
- package/templates/default/src/components/ui/data-table.tsx +261 -261
- package/templates/default/src/components/ui/dialog.tsx +97 -97
- package/templates/default/src/components/ui/dropdown-menu.tsx +182 -182
- package/templates/default/src/components/ui/input.tsx +22 -22
- package/templates/default/src/components/ui/kbd.tsx +28 -28
- package/templates/default/src/components/ui/label.tsx +19 -19
- package/templates/default/src/components/ui/loading.tsx +12 -12
- package/templates/default/src/components/ui/multi-select-with-preview.tsx +116 -116
- package/templates/default/src/components/ui/multi-select.tsx +142 -142
- package/templates/default/src/components/ui/navigation-menu.tsx +120 -120
- package/templates/default/src/components/ui/popover.tsx +33 -33
- package/templates/default/src/components/ui/progress.tsx +25 -25
- package/templates/default/src/components/ui/radio-group.tsx +44 -44
- package/templates/default/src/components/ui/scroll-area.tsx +40 -40
- package/templates/default/src/components/ui/select.tsx +151 -151
- package/templates/default/src/components/ui/separator.tsx +22 -22
- package/templates/default/src/components/ui/skeleton.tsx +7 -7
- package/templates/default/src/components/ui/table.tsx +76 -76
- package/templates/default/src/components/ui/tabs.tsx +55 -55
- package/templates/default/src/components/ui/textarea.tsx +21 -21
- package/templates/default/src/components/ui/toast.tsx +113 -113
- package/templates/default/src/components/ui/toaster.tsx +26 -26
- package/templates/default/src/components/user-prompt/delete-prompt.tsx +87 -87
- package/templates/default/src/config/db-config.ts +10 -10
- package/templates/default/src/constants/form-opts/diagram/node-form.ts +30 -30
- package/templates/default/src/constants/form-opts/environment-form-opts.ts +24 -24
- package/templates/default/src/constants/form-opts/locator-form-opts.ts +20 -20
- package/templates/default/src/constants/form-opts/locator-group-form-opts.ts +28 -28
- package/templates/default/src/constants/form-opts/module-form-opts.ts +21 -21
- package/templates/default/src/constants/form-opts/review-form-opts.ts +23 -23
- package/templates/default/src/constants/form-opts/tag-form-opts.ts +42 -42
- package/templates/default/src/constants/form-opts/template-selection-form-opts.ts +16 -16
- package/templates/default/src/constants/form-opts/template-step-group-form-opts.ts +24 -24
- package/templates/default/src/constants/form-opts/template-test-case-form-opts.ts +39 -39
- package/templates/default/src/constants/form-opts/template-test-step-form-opts.ts +36 -36
- package/templates/default/src/constants/form-opts/test-case-form-opts.ts +43 -43
- package/templates/default/src/constants/form-opts/test-run-form-opts.ts +5 -3
- package/templates/default/src/constants/form-opts/test-suite-form-opts.ts +24 -24
- package/templates/default/src/hooks/use-toast.ts +187 -187
- package/templates/default/src/lib/automation/paths.ts +42 -12
- package/templates/default/src/lib/automation/projection-service.ts +2 -1
- package/templates/default/src/lib/bidirectional-sync.ts +432 -432
- package/templates/default/src/lib/database-sync.ts +2 -7
- package/templates/default/src/lib/environment-file-utils.ts +184 -184
- package/templates/default/src/lib/executor/local-executor-adapter.ts +24 -25
- package/templates/default/src/lib/executor/types.ts +2 -2
- package/templates/default/src/lib/feature-file-generator.ts +5 -66
- package/templates/default/src/lib/gherkin-parser.ts +259 -259
- package/templates/default/src/lib/locator-group-file-utils.ts +307 -307
- package/templates/default/src/lib/locator-picker/session-manager.ts +452 -0
- package/templates/default/src/lib/locator-picker/suggestions.ts +124 -0
- package/templates/default/src/lib/metrics/metric-calculator.ts +5 -0
- package/templates/default/src/lib/module-hierarchy-builder.ts +205 -205
- package/templates/default/src/lib/path-helpers/module-path.ts +71 -71
- package/templates/default/src/lib/process/task-spawner.ts +39 -2
- package/templates/default/src/lib/sync/projected-feature-utils.ts +113 -0
- package/templates/default/src/lib/sync/sync-executor.ts +130 -0
- package/templates/default/src/lib/sync/sync-pending-counts.test.ts +239 -0
- package/templates/default/src/lib/sync/sync-pending-counts.ts +1358 -0
- package/templates/default/src/lib/sync/sync-registry.ts +149 -0
- package/templates/default/src/lib/tag-utils.ts +28 -0
- package/templates/default/src/lib/template-sync-utils.d.ts +6 -6
- package/templates/default/src/lib/template-sync-utils.js +46 -46
- package/templates/default/src/lib/template-sync-utils.ts +63 -63
- package/templates/default/src/lib/test-case-utils.ts +6 -6
- package/templates/default/src/lib/test-run/log-formatter.ts +83 -83
- package/templates/default/src/lib/test-run/matching.ts +117 -0
- package/templates/default/src/lib/test-run/process-manager.ts +2 -0
- package/templates/default/src/lib/test-run/report-parser.ts +352 -316
- package/templates/default/src/lib/test-run/test-run-executor.ts +13 -15
- package/templates/default/src/lib/test-run/winston-logger.ts +64 -66
- package/templates/default/src/lib/test-suite-identifier-service.ts +76 -0
- package/templates/default/src/lib/test-suite-utils.ts +6 -0
- package/templates/default/src/lib/transformers/gherkin-converter.ts +42 -42
- package/templates/default/src/lib/transformers/key-to-icon-transformer.tsx +95 -95
- package/templates/default/src/lib/transformers/template-test-case-converter.ts +160 -160
- package/templates/default/src/lib/utils/node-param-validation.ts +81 -81
- package/templates/default/src/lib/utils/template-step-file-generator.ts +104 -104
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +0 -8
- package/templates/default/src/lib/utils/template-step-file-manager.ts +166 -166
- package/templates/default/src/lib/utils.ts +31 -31
- package/templates/default/src/types/diagram/diagram.ts +34 -34
- package/templates/default/src/types/diagram/template-step.ts +11 -11
- package/templates/default/src/types/executor/browser.type.ts +1 -1
- package/templates/default/src/types/form/actionHandler.ts +6 -6
- package/templates/default/src/types/locator/locator.type.ts +11 -11
- package/templates/default/src/types/locator-picker.ts +65 -0
- package/templates/default/src/types/step/step.type.ts +1 -1
- package/templates/default/src/types/table/data-table.ts +6 -6
- package/templates/default/src/types/test-case-picker.ts +6 -0
- package/templates/default/src/types/test-suite-picker.ts +18 -0
- package/templates/default/tailwind.config.ts +62 -62
- package/templates/default/tsconfig.json +4 -1
- package/templates/default/appraisejs.config.json +0 -1
|
@@ -1,99 +1,92 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useState } from 'react'
|
|
4
|
-
import { Button } from '@/components/ui/button'
|
|
5
|
-
import { Download, LoaderCircle } from 'lucide-react'
|
|
6
|
-
import { AnimatePresence, motion } from 'motion/react'
|
|
7
|
-
import { toast } from '@/hooks/use-toast'
|
|
8
|
-
|
|
9
|
-
interface DownloadLogsButtonProps {
|
|
10
|
-
testRunId: string
|
|
11
|
-
className?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function DownloadLogsButton({ testRunId, className }: DownloadLogsButtonProps) {
|
|
15
|
-
const [isDownloading, setIsDownloading] = useState(false)
|
|
16
|
-
|
|
17
|
-
const handleDownload = async () => {
|
|
18
|
-
setIsDownloading(true)
|
|
19
|
-
try {
|
|
20
|
-
const response = await fetch(`/api/test-runs/${testRunId}/download`)
|
|
21
|
-
|
|
22
|
-
if (!response.ok) {
|
|
23
|
-
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }))
|
|
24
|
-
throw new Error(errorData.error || `Failed to download: ${response.statusText}`)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Get the filename from Content-Disposition header or use a default
|
|
28
|
-
const contentDisposition = response.headers.get('Content-Disposition')
|
|
29
|
-
let filename = `test-run-${testRunId}.zip`
|
|
30
|
-
if (contentDisposition) {
|
|
31
|
-
const filenameMatch = contentDisposition.match(/filename="?(.+?)"?$/)
|
|
32
|
-
if (filenameMatch) {
|
|
33
|
-
filename = filenameMatch[1]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Create a blob from the response
|
|
38
|
-
const blob = await response.blob()
|
|
39
|
-
|
|
40
|
-
// Create a download link and trigger it
|
|
41
|
-
const url = window.URL.createObjectURL(blob)
|
|
42
|
-
const a = document.createElement('a')
|
|
43
|
-
a.href = url
|
|
44
|
-
a.download = filename
|
|
45
|
-
document.body.appendChild(a)
|
|
46
|
-
a.click()
|
|
47
|
-
document.body.removeChild(a)
|
|
48
|
-
window.URL.revokeObjectURL(url)
|
|
49
|
-
|
|
50
|
-
toast({
|
|
51
|
-
title: 'Download started',
|
|
52
|
-
description: '
|
|
53
|
-
})
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error('[DownloadLogsButton] Error downloading logs:', error)
|
|
56
|
-
toast({
|
|
57
|
-
title: 'Download failed',
|
|
58
|
-
description: error instanceof Error ? error.message : 'Failed to download
|
|
59
|
-
variant: 'destructive',
|
|
60
|
-
})
|
|
61
|
-
} finally {
|
|
62
|
-
setIsDownloading(false)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return (
|
|
67
|
-
<Button
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
)}
|
|
94
|
-
</motion.div>
|
|
95
|
-
</AnimatePresence>
|
|
96
|
-
</Button>
|
|
97
|
-
)
|
|
98
|
-
}
|
|
99
|
-
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { Download, LoaderCircle } from 'lucide-react'
|
|
6
|
+
import { AnimatePresence, motion } from 'motion/react'
|
|
7
|
+
import { toast } from '@/hooks/use-toast'
|
|
8
|
+
|
|
9
|
+
interface DownloadLogsButtonProps {
|
|
10
|
+
testRunId: string
|
|
11
|
+
className?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function DownloadLogsButton({ testRunId, className }: DownloadLogsButtonProps) {
|
|
15
|
+
const [isDownloading, setIsDownloading] = useState(false)
|
|
16
|
+
|
|
17
|
+
const handleDownload = async () => {
|
|
18
|
+
setIsDownloading(true)
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`/api/test-runs/${testRunId}/download`)
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
const errorData = await response.json().catch(() => ({ error: 'Unknown error' }))
|
|
24
|
+
throw new Error(errorData.error || `Failed to download: ${response.statusText}`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Get the filename from Content-Disposition header or use a default
|
|
28
|
+
const contentDisposition = response.headers.get('Content-Disposition')
|
|
29
|
+
let filename = `test-run-${testRunId}.zip`
|
|
30
|
+
if (contentDisposition) {
|
|
31
|
+
const filenameMatch = contentDisposition.match(/filename="?(.+?)"?$/)
|
|
32
|
+
if (filenameMatch) {
|
|
33
|
+
filename = filenameMatch[1]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Create a blob from the response
|
|
38
|
+
const blob = await response.blob()
|
|
39
|
+
|
|
40
|
+
// Create a download link and trigger it
|
|
41
|
+
const url = window.URL.createObjectURL(blob)
|
|
42
|
+
const a = document.createElement('a')
|
|
43
|
+
a.href = url
|
|
44
|
+
a.download = filename
|
|
45
|
+
document.body.appendChild(a)
|
|
46
|
+
a.click()
|
|
47
|
+
document.body.removeChild(a)
|
|
48
|
+
window.URL.revokeObjectURL(url)
|
|
49
|
+
|
|
50
|
+
toast({
|
|
51
|
+
title: 'Download started',
|
|
52
|
+
description: 'Run artifacts are being downloaded',
|
|
53
|
+
})
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('[DownloadLogsButton] Error downloading logs:', error)
|
|
56
|
+
toast({
|
|
57
|
+
title: 'Download failed',
|
|
58
|
+
description: error instanceof Error ? error.message : 'Failed to download run artifacts',
|
|
59
|
+
variant: 'destructive',
|
|
60
|
+
})
|
|
61
|
+
} finally {
|
|
62
|
+
setIsDownloading(false)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Button onClick={handleDownload} disabled={isDownloading} variant="outline" size="sm" className={className}>
|
|
68
|
+
<AnimatePresence mode="wait" initial={false}>
|
|
69
|
+
<motion.div
|
|
70
|
+
key={isDownloading ? 'downloading' : 'idle'}
|
|
71
|
+
initial={{ opacity: 0, y: 4 }}
|
|
72
|
+
animate={{ opacity: 1, y: 0 }}
|
|
73
|
+
exit={{ opacity: 0, y: -4 }}
|
|
74
|
+
transition={{ duration: 0.15 }}
|
|
75
|
+
className="flex items-center gap-2"
|
|
76
|
+
>
|
|
77
|
+
{isDownloading ? (
|
|
78
|
+
<>
|
|
79
|
+
<LoaderCircle className="h-4 w-4 animate-spin" />
|
|
80
|
+
Downloading...
|
|
81
|
+
</>
|
|
82
|
+
) : (
|
|
83
|
+
<>
|
|
84
|
+
<Download className="h-4 w-4" />
|
|
85
|
+
Download Run Artifacts
|
|
86
|
+
</>
|
|
87
|
+
)}
|
|
88
|
+
</motion.div>
|
|
89
|
+
</AnimatePresence>
|
|
90
|
+
</Button>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
@@ -6,7 +6,7 @@ import { Badge } from '@/components/ui/badge'
|
|
|
6
6
|
import { Alert, AlertDescription } from '@/components/ui/alert'
|
|
7
7
|
import { LoaderCircle, Wifi, WifiOff, CheckCircle, XCircle, Logs } from 'lucide-react'
|
|
8
8
|
import { cn } from '@/lib/utils'
|
|
9
|
-
import { getTestRunLogsAction
|
|
9
|
+
import { getTestRunLogsAction } from '@/actions/test-run/test-run-actions'
|
|
10
10
|
import { TestRunStatus } from '@prisma/client'
|
|
11
11
|
import { DownloadLogsButton } from './download-logs-button'
|
|
12
12
|
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card'
|
|
@@ -278,19 +278,6 @@ export function LogViewer({ testRunId, status, className }: LogViewerProps) {
|
|
|
278
278
|
`[LogViewer] Scenario ended: ${scenarioName} with status: ${status}${tracePath ? `, tracePath: ${tracePath}` : ''}`,
|
|
279
279
|
)
|
|
280
280
|
|
|
281
|
-
// Update test case status in database
|
|
282
|
-
// This will gracefully handle test runs filtered by tags (no test cases)
|
|
283
|
-
const response = await updateTestRunTestCaseStatusAction(testRunId, scenarioName, status, tracePath)
|
|
284
|
-
if (response.error && response.status !== 200) {
|
|
285
|
-
// Only log as error if it's not a 200 status (which means it was skipped gracefully)
|
|
286
|
-
console.error('[LogViewer] Error updating test case status:', response.error)
|
|
287
|
-
} else if (response.status === 200) {
|
|
288
|
-
// Log success or graceful skip (200 status means it was handled correctly)
|
|
289
|
-
console.log(
|
|
290
|
-
`[LogViewer] ${response.message || `Successfully updated test case status for scenario: ${scenarioName}`}`,
|
|
291
|
-
)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
281
|
// Also add to logs for visibility
|
|
295
282
|
setLogs(prev => [
|
|
296
283
|
...prev,
|
|
@@ -46,7 +46,10 @@ import { toast } from '@/hooks/use-toast'
|
|
|
46
46
|
|
|
47
47
|
interface TestRunDetailsProps {
|
|
48
48
|
testRun: TestRun & {
|
|
49
|
-
testCases: (TestRunTestCase & {
|
|
49
|
+
testCases: (TestRunTestCase & {
|
|
50
|
+
testCase: { title: string; description: string }
|
|
51
|
+
testSuite: { id: string; name: string } | null
|
|
52
|
+
})[]
|
|
50
53
|
tags: Tag[]
|
|
51
54
|
environment: Environment
|
|
52
55
|
reports: Report[]
|
|
@@ -81,7 +84,10 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
|
|
|
81
84
|
}
|
|
82
85
|
// TypeScript now knows updatedTestRun is defined - cast to proper type
|
|
83
86
|
const typedTestRun = updatedTestRun as TestRun & {
|
|
84
|
-
testCases: (TestRunTestCase & {
|
|
87
|
+
testCases: (TestRunTestCase & {
|
|
88
|
+
testCase: { title: string; description: string }
|
|
89
|
+
testSuite: { id: string; name: string } | null
|
|
90
|
+
})[]
|
|
85
91
|
tags: Tag[]
|
|
86
92
|
environment: Environment
|
|
87
93
|
reports: Report[]
|
|
@@ -544,6 +550,13 @@ export function TestRunDetails({ testRun: initialTestRun }: TestRunDetailsProps)
|
|
|
544
550
|
<div className="flex flex-col gap-1">
|
|
545
551
|
<span className="text-sm font-semibold">{testCase.testCase.title}</span>
|
|
546
552
|
<span className="text-xs text-muted-foreground">{testCase.testCase.description}</span>
|
|
553
|
+
{testCase.testSuite && (
|
|
554
|
+
<div className="pt-1">
|
|
555
|
+
<Badge variant="outline" className="w-fit text-[11px]">
|
|
556
|
+
Suite: {testCase.testSuite.name}
|
|
557
|
+
</Badge>
|
|
558
|
+
</div>
|
|
559
|
+
)}
|
|
547
560
|
</div>
|
|
548
561
|
</div>
|
|
549
562
|
<div className="flex items-center gap-2">
|
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react'
|
|
4
|
-
import { getTestRunByIdAction } from '@/actions/test-run/test-run-actions'
|
|
5
|
-
import PageHeader from '@/components/typography/page-header'
|
|
6
|
-
import HeaderSubtitle from '@/components/typography/page-header-subtitle'
|
|
7
|
-
import { ViewReportButton } from '@/components/test-run/view-report-button'
|
|
8
|
-
import { TestRun, TestRunTestCase, Tag, Environment, TestRunStatus, Report } from '@prisma/client'
|
|
9
|
-
|
|
10
|
-
interface TestRunHeaderProps {
|
|
11
|
-
initialTestRun: TestRun & {
|
|
12
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
13
|
-
tags: Tag[]
|
|
14
|
-
environment: Environment
|
|
15
|
-
reports: Report[]
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function TestRunHeader({ initialTestRun }: TestRunHeaderProps) {
|
|
20
|
-
const [testRun, setTestRun] = useState(initialTestRun)
|
|
21
|
-
|
|
22
|
-
// Poll for status updates while test run is running or queued
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
// Only poll if test run is not completed/cancelled
|
|
25
|
-
if (testRun.status === TestRunStatus.COMPLETED || testRun.status === TestRunStatus.CANCELLED) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const pollInterval = setInterval(async () => {
|
|
30
|
-
try {
|
|
31
|
-
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
32
|
-
if (error || !updatedTestRun) {
|
|
33
|
-
console.error('Error polling test run status:', error)
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const typedTestRun = updatedTestRun as TestRun & {
|
|
38
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
39
|
-
tags: Tag[]
|
|
40
|
-
environment: Environment
|
|
41
|
-
reports: Report[]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Update state with latest test run data
|
|
45
|
-
setTestRun(typedTestRun)
|
|
46
|
-
|
|
47
|
-
// Stop polling if test run is completed or cancelled
|
|
48
|
-
if (typedTestRun.status === TestRunStatus.COMPLETED || typedTestRun.status === TestRunStatus.CANCELLED) {
|
|
49
|
-
clearInterval(pollInterval)
|
|
50
|
-
}
|
|
51
|
-
} catch (error) {
|
|
52
|
-
console.error('Error polling test run status:', error)
|
|
53
|
-
}
|
|
54
|
-
}, 2000) // Poll every 2 seconds
|
|
55
|
-
|
|
56
|
-
return () => clearInterval(pollInterval)
|
|
57
|
-
}, [testRun.id, testRun.status])
|
|
58
|
-
|
|
59
|
-
// Listen for SSE exit events from LogViewer as a backup signal
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const handleTestRunExit = (event: CustomEvent<{ testRunId: string }>) => {
|
|
62
|
-
// Only handle events for this test run
|
|
63
|
-
if (event.detail.testRunId === testRun.runId) {
|
|
64
|
-
// Trigger a status refresh
|
|
65
|
-
getTestRunByIdAction(testRun.id)
|
|
66
|
-
.then(response => {
|
|
67
|
-
if (response.data && !response.error) {
|
|
68
|
-
const typedTestRun = response.data as TestRun & {
|
|
69
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
70
|
-
tags: Tag[]
|
|
71
|
-
environment: Environment
|
|
72
|
-
reports: Report[]
|
|
73
|
-
}
|
|
74
|
-
setTestRun(typedTestRun)
|
|
75
|
-
}
|
|
76
|
-
})
|
|
77
|
-
.catch(error => {
|
|
78
|
-
console.error('Error refreshing test run status after exit event:', error)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Listen for custom event dispatched by LogViewer
|
|
84
|
-
window.addEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
85
|
-
|
|
86
|
-
return () => {
|
|
87
|
-
window.removeEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
88
|
-
}
|
|
89
|
-
}, [testRun.id, testRun.runId])
|
|
90
|
-
|
|
91
|
-
// Poll for report updates after test run completes
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
// Only poll if test run is completed (not cancelled) but no report exists yet
|
|
94
|
-
// Cancelled runs won't generate reports, so we don't poll for them
|
|
95
|
-
const shouldPoll = testRun.status === TestRunStatus.COMPLETED && testRun.reports.length === 0
|
|
96
|
-
|
|
97
|
-
if (!shouldPoll) {
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Poll for reports (they might be created asynchronously after test run completes)
|
|
102
|
-
const pollInterval = setInterval(async () => {
|
|
103
|
-
try {
|
|
104
|
-
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
105
|
-
if (error || !updatedTestRun) {
|
|
106
|
-
console.error('Error polling for report:', error)
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const typedTestRun = updatedTestRun as TestRun & {
|
|
111
|
-
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
112
|
-
tags: Tag[]
|
|
113
|
-
environment: Environment
|
|
114
|
-
reports: Report[]
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Update if reports are now available
|
|
118
|
-
if (typedTestRun.reports.length > 0) {
|
|
119
|
-
setTestRun(typedTestRun)
|
|
120
|
-
clearInterval(pollInterval)
|
|
121
|
-
}
|
|
122
|
-
} catch (error) {
|
|
123
|
-
console.error('Error polling for report:', error)
|
|
124
|
-
}
|
|
125
|
-
}, 2000) // Poll every 2 seconds
|
|
126
|
-
|
|
127
|
-
// Stop polling after 30 seconds to avoid infinite polling
|
|
128
|
-
const timeout = setTimeout(() => {
|
|
129
|
-
clearInterval(pollInterval)
|
|
130
|
-
}, 30000)
|
|
131
|
-
|
|
132
|
-
return () => {
|
|
133
|
-
clearInterval(pollInterval)
|
|
134
|
-
clearTimeout(timeout)
|
|
135
|
-
}
|
|
136
|
-
}, [testRun.id, testRun.status, testRun.reports.length])
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div className="mb-8">
|
|
140
|
-
<div className="flex items-start justify-between gap-4">
|
|
141
|
-
<div className="flex-1">
|
|
142
|
-
<PageHeader>Test Run Details</PageHeader>
|
|
143
|
-
<HeaderSubtitle>View test run execution details and live logs</HeaderSubtitle>
|
|
144
|
-
</div>
|
|
145
|
-
<ViewReportButton testRunStatus={testRun.status} reports={testRun.reports} className="mt-2" />
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from 'react'
|
|
4
|
+
import { getTestRunByIdAction } from '@/actions/test-run/test-run-actions'
|
|
5
|
+
import PageHeader from '@/components/typography/page-header'
|
|
6
|
+
import HeaderSubtitle from '@/components/typography/page-header-subtitle'
|
|
7
|
+
import { ViewReportButton } from '@/components/test-run/view-report-button'
|
|
8
|
+
import { TestRun, TestRunTestCase, Tag, Environment, TestRunStatus, Report } from '@prisma/client'
|
|
9
|
+
|
|
10
|
+
interface TestRunHeaderProps {
|
|
11
|
+
initialTestRun: TestRun & {
|
|
12
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
13
|
+
tags: Tag[]
|
|
14
|
+
environment: Environment
|
|
15
|
+
reports: Report[]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function TestRunHeader({ initialTestRun }: TestRunHeaderProps) {
|
|
20
|
+
const [testRun, setTestRun] = useState(initialTestRun)
|
|
21
|
+
|
|
22
|
+
// Poll for status updates while test run is running or queued
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
// Only poll if test run is not completed/cancelled
|
|
25
|
+
if (testRun.status === TestRunStatus.COMPLETED || testRun.status === TestRunStatus.CANCELLED) {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const pollInterval = setInterval(async () => {
|
|
30
|
+
try {
|
|
31
|
+
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
32
|
+
if (error || !updatedTestRun) {
|
|
33
|
+
console.error('Error polling test run status:', error)
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const typedTestRun = updatedTestRun as TestRun & {
|
|
38
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
39
|
+
tags: Tag[]
|
|
40
|
+
environment: Environment
|
|
41
|
+
reports: Report[]
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Update state with latest test run data
|
|
45
|
+
setTestRun(typedTestRun)
|
|
46
|
+
|
|
47
|
+
// Stop polling if test run is completed or cancelled
|
|
48
|
+
if (typedTestRun.status === TestRunStatus.COMPLETED || typedTestRun.status === TestRunStatus.CANCELLED) {
|
|
49
|
+
clearInterval(pollInterval)
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error('Error polling test run status:', error)
|
|
53
|
+
}
|
|
54
|
+
}, 2000) // Poll every 2 seconds
|
|
55
|
+
|
|
56
|
+
return () => clearInterval(pollInterval)
|
|
57
|
+
}, [testRun.id, testRun.status])
|
|
58
|
+
|
|
59
|
+
// Listen for SSE exit events from LogViewer as a backup signal
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
const handleTestRunExit = (event: CustomEvent<{ testRunId: string }>) => {
|
|
62
|
+
// Only handle events for this test run
|
|
63
|
+
if (event.detail.testRunId === testRun.runId) {
|
|
64
|
+
// Trigger a status refresh
|
|
65
|
+
getTestRunByIdAction(testRun.id)
|
|
66
|
+
.then(response => {
|
|
67
|
+
if (response.data && !response.error) {
|
|
68
|
+
const typedTestRun = response.data as TestRun & {
|
|
69
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
70
|
+
tags: Tag[]
|
|
71
|
+
environment: Environment
|
|
72
|
+
reports: Report[]
|
|
73
|
+
}
|
|
74
|
+
setTestRun(typedTestRun)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
.catch(error => {
|
|
78
|
+
console.error('Error refreshing test run status after exit event:', error)
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Listen for custom event dispatched by LogViewer
|
|
84
|
+
window.addEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
85
|
+
|
|
86
|
+
return () => {
|
|
87
|
+
window.removeEventListener('testrun:exit', handleTestRunExit as EventListener)
|
|
88
|
+
}
|
|
89
|
+
}, [testRun.id, testRun.runId])
|
|
90
|
+
|
|
91
|
+
// Poll for report updates after test run completes
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
// Only poll if test run is completed (not cancelled) but no report exists yet
|
|
94
|
+
// Cancelled runs won't generate reports, so we don't poll for them
|
|
95
|
+
const shouldPoll = testRun.status === TestRunStatus.COMPLETED && testRun.reports.length === 0
|
|
96
|
+
|
|
97
|
+
if (!shouldPoll) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Poll for reports (they might be created asynchronously after test run completes)
|
|
102
|
+
const pollInterval = setInterval(async () => {
|
|
103
|
+
try {
|
|
104
|
+
const { data: updatedTestRun, error } = await getTestRunByIdAction(testRun.id)
|
|
105
|
+
if (error || !updatedTestRun) {
|
|
106
|
+
console.error('Error polling for report:', error)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const typedTestRun = updatedTestRun as TestRun & {
|
|
111
|
+
testCases: (TestRunTestCase & { testCase: { title: string; description: string } })[]
|
|
112
|
+
tags: Tag[]
|
|
113
|
+
environment: Environment
|
|
114
|
+
reports: Report[]
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Update if reports are now available
|
|
118
|
+
if (typedTestRun.reports.length > 0) {
|
|
119
|
+
setTestRun(typedTestRun)
|
|
120
|
+
clearInterval(pollInterval)
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('Error polling for report:', error)
|
|
124
|
+
}
|
|
125
|
+
}, 2000) // Poll every 2 seconds
|
|
126
|
+
|
|
127
|
+
// Stop polling after 30 seconds to avoid infinite polling
|
|
128
|
+
const timeout = setTimeout(() => {
|
|
129
|
+
clearInterval(pollInterval)
|
|
130
|
+
}, 30000)
|
|
131
|
+
|
|
132
|
+
return () => {
|
|
133
|
+
clearInterval(pollInterval)
|
|
134
|
+
clearTimeout(timeout)
|
|
135
|
+
}
|
|
136
|
+
}, [testRun.id, testRun.status, testRun.reports.length])
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div className="mb-8">
|
|
140
|
+
<div className="flex items-start justify-between gap-4">
|
|
141
|
+
<div className="flex-1">
|
|
142
|
+
<PageHeader>Test Run Details</PageHeader>
|
|
143
|
+
<HeaderSubtitle>View test run execution details and live logs</HeaderSubtitle>
|
|
144
|
+
</div>
|
|
145
|
+
<ViewReportButton testRunStatus={testRun.status} reports={testRun.reports} className="mt-2" />
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|