create-appraisejs 0.1.6 → 0.1.8-alpha
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 +45 -45
- package/dist/cli.js +4 -4
- package/dist/cli.js.map +1 -1
- package/dist/copy-template.d.ts +2 -1
- package/dist/copy-template.d.ts.map +1 -1
- package/dist/copy-template.js +10 -7
- package/dist/copy-template.js.map +1 -1
- package/dist/copy-template.test.js +19 -0
- package/dist/copy-template.test.js.map +1 -1
- package/package.json +69 -67
- package/templates/default/.vscode/settings.json +5 -0
- package/templates/default/appraisejs.config.json +1 -1
- package/templates/default/components.json +24 -24
- package/templates/default/cucumber.mjs +16 -0
- package/templates/default/eslint.config.mjs +15 -15
- package/templates/default/next.config.ts +13 -7
- package/templates/default/package-lock.json +13732 -14321
- package/templates/default/package.json +11 -9
- package/templates/default/postcss.config.mjs +8 -8
- 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/schema.prisma +554 -554
- 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 +341 -341
- package/templates/default/scripts/sync-appraise-base-template.ts +52 -2
- package/templates/default/scripts/sync-environments.ts +323 -323
- package/templates/default/scripts/sync-locator-groups.ts +413 -413
- package/templates/default/scripts/sync-locators.ts +402 -402
- package/templates/default/scripts/sync-modules.ts +349 -349
- package/templates/default/scripts/sync-tags.ts +292 -292
- package/templates/default/scripts/sync-template-step-groups.ts +399 -399
- package/templates/default/scripts/sync-template-steps.ts +806 -806
- package/templates/default/scripts/sync-test-cases.ts +905 -905
- package/templates/default/scripts/sync-test-suites.ts +411 -411
- 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 +205 -205
- package/templates/default/src/actions/locator/locator-actions.ts +547 -547
- package/templates/default/src/actions/locator-groups/locator-group-actions.ts +344 -344
- package/templates/default/src/actions/modules/module-actions.ts +133 -133
- package/templates/default/src/actions/reports/report-actions.ts +613 -613
- package/templates/default/src/actions/review/review-actions.ts +147 -147
- package/templates/default/src/actions/tags/tag-actions.ts +104 -104
- package/templates/default/src/actions/template-step/template-step-actions.ts +332 -332
- package/templates/default/src/actions/template-step-group/template-step-group-actions.ts +278 -278
- 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 +419 -419
- package/templates/default/src/actions/test-run/test-run-actions.ts +1185 -1185
- package/templates/default/src/actions/test-suite/test-suite-actions.ts +253 -253
- 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 +61 -61
- package/templates/default/src/app/(base)/locators/create/page.tsx +38 -38
- package/templates/default/src/app/(base)/locators/locator-form.tsx +163 -163
- package/templates/default/src/app/(base)/locators/locator-table-columns.tsx +73 -90
- package/templates/default/src/app/(base)/locators/locator-table.tsx +28 -28
- package/templates/default/src/app/(base)/locators/modify/[id]/page.tsx +45 -45
- package/templates/default/src/app/(base)/locators/page.tsx +65 -65
- 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 +517 -517
- 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 +46 -46
- package/templates/default/src/app/(base)/reports/page.tsx +98 -98
- package/templates/default/src/app/(base)/reports/report-metric-card.tsx +16 -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 +131 -131
- package/templates/default/src/app/(base)/reports/report-view-table.tsx +82 -82
- package/templates/default/src/app/(base)/reports/test-cases/page.tsx +42 -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 +60 -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)/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 +59 -59
- 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 +60 -60
- 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 +90 -90
- package/templates/default/src/app/(base)/test-cases/test-case-table.tsx +35 -35
- package/templates/default/src/app/(base)/test-runs/[id]/page.tsx +56 -56
- package/templates/default/src/app/(base)/test-runs/create/page.tsx +47 -47
- package/templates/default/src/app/(base)/test-runs/page.tsx +60 -60
- package/templates/default/src/app/(base)/test-runs/test-run-form.tsx +508 -512
- 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 +45 -45
- package/templates/default/src/app/(base)/test-suites/modify/[id]/page.tsx +55 -55
- package/templates/default/src/app/(base)/test-suites/page.tsx +82 -82
- package/templates/default/src/app/(base)/test-suites/test-suite-form.tsx +269 -269
- package/templates/default/src/app/(base)/test-suites/test-suite-table-columns.tsx +97 -97
- 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/test-runs/[runId]/download/route.ts +133 -133
- package/templates/default/src/app/api/test-runs/[runId]/logs/route.ts +420 -420
- package/templates/default/src/app/api/test-runs/[runId]/trace/[testCaseId]/route.ts +146 -146
- package/templates/default/src/app/globals.css +147 -147
- package/templates/default/src/app/layout.tsx +171 -171
- package/templates/default/src/app/page.tsx +64 -64
- 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/devtools/providers.tsx +19 -13
- package/templates/default/src/components/diagram/button-edge.tsx +54 -54
- package/templates/default/src/components/diagram/dynamic-parameters.tsx +438 -438
- 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 +508 -508
- 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 +253 -253
- package/templates/default/src/components/table/table-actions.tsx +172 -172
- package/templates/default/src/components/test-run/download-logs-button.tsx +99 -99
- package/templates/default/src/components/test-run/log-viewer.tsx +445 -445
- package/templates/default/src/components/test-run/test-run-details.tsx +611 -611
- 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/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 +267 -267
- 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 -144
- 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 +31 -31
- 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/bidirectional-sync.ts +432 -432
- package/templates/default/src/lib/database-sync.ts +531 -531
- package/templates/default/src/lib/environment-file-utils.ts +221 -221
- package/templates/default/src/lib/feature-file-generator.ts +411 -411
- package/templates/default/src/lib/gherkin-parser.ts +259 -259
- package/templates/default/src/lib/locator-group-file-utils.ts +370 -370
- package/templates/default/src/lib/metrics/metric-calculator.ts +613 -613
- 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/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/process-manager.ts +191 -191
- package/templates/default/src/lib/test-run/report-parser.ts +316 -316
- package/templates/default/src/lib/test-run/test-run-executor.ts +144 -144
- package/templates/default/src/lib/test-run/winston-logger.ts +95 -95
- 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 +167 -167
- package/templates/default/src/lib/utils/template-step-file-manager-intelligent.ts +723 -723
- 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/tests/config/executor/world.ts +41 -41
- package/templates/default/src/tests/executor.ts +80 -80
- package/templates/default/src/tests/hooks/hooks.ts +99 -99
- package/templates/default/src/tests/mapping/locator-map.json +1 -1
- package/templates/default/src/tests/steps/actions/click.step.ts +62 -62
- package/templates/default/src/tests/steps/actions/navigation.step.ts +73 -72
- package/templates/default/src/tests/steps/validations/active_state_assertion.step.ts +34 -34
- package/templates/default/src/tests/steps/validations/navigation_assertion.step.ts +24 -23
- package/templates/default/src/tests/steps/validations/text_assertion.step.ts +111 -111
- package/templates/default/src/tests/steps/validations/visibility_assertion.step.ts +30 -30
- package/templates/default/src/tests/support/parameter-types.ts +12 -12
- package/templates/default/src/tests/utils/cache.util.ts +260 -260
- package/templates/default/src/tests/utils/cli.util.ts +177 -177
- package/templates/default/src/tests/utils/environment.util.ts +65 -65
- package/templates/default/src/tests/utils/locator.util.ts +248 -248
- package/templates/default/src/tests/utils/random-data.util.ts +44 -44
- package/templates/default/src/tests/utils/spawner.util.ts +617 -617
- 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/step/step.type.ts +1 -1
- package/templates/default/src/types/table/data-table.ts +6 -6
- package/templates/default/tailwind.config.ts +62 -62
- package/templates/default/.env +0 -2
- package/templates/default/next-env.d.ts +0 -6
- package/templates/default/prisma/prisma/dev.db +0 -0
- package/templates/default/src/tests/config/environments/environments.json +0 -14
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Log formatting utilities for storing and retrieving test run logs
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface LogEntry {
|
|
6
|
-
type: 'stdout' | 'stderr' | 'status'
|
|
7
|
-
message: string
|
|
8
|
-
timestamp: Date
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Formats log entries into a single text string for storage in the database
|
|
13
|
-
* Format: [timestamp] [TYPE] message
|
|
14
|
-
*
|
|
15
|
-
* @param logs - Array of log entries to format
|
|
16
|
-
* @returns Formatted log string
|
|
17
|
-
*/
|
|
18
|
-
export function formatLogsForStorage(logs: LogEntry[]): string {
|
|
19
|
-
return logs
|
|
20
|
-
.map(log => {
|
|
21
|
-
const timestamp = log.timestamp.toISOString()
|
|
22
|
-
const type = log.type.toUpperCase()
|
|
23
|
-
// Escape newlines in message to preserve them in the formatted string
|
|
24
|
-
const escapedMessage = log.message.replace(/\n/g, '\\n')
|
|
25
|
-
return `[${timestamp}] [${type}] ${escapedMessage}`
|
|
26
|
-
})
|
|
27
|
-
.join('\n')
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Parses formatted log text back into an array of LogEntry objects
|
|
32
|
-
*
|
|
33
|
-
* @param formattedLogs - Formatted log string from database
|
|
34
|
-
* @returns Array of log entries
|
|
35
|
-
*/
|
|
36
|
-
export function parseLogsFromStorage(formattedLogs: string): LogEntry[] {
|
|
37
|
-
if (!formattedLogs || formattedLogs.trim() === '') {
|
|
38
|
-
return []
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const lines = formattedLogs.split('\n')
|
|
42
|
-
const parsedLogs: LogEntry[] = []
|
|
43
|
-
|
|
44
|
-
for (const line of lines) {
|
|
45
|
-
if (!line.trim()) continue
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
// Match format: [timestamp] [TYPE] message
|
|
49
|
-
const match = line.match(/^\[([^\]]+)\] \[([^\]]+)\] (.+)$/)
|
|
50
|
-
|
|
51
|
-
if (match) {
|
|
52
|
-
const [, timestampStr, typeStr, message] = match
|
|
53
|
-
const timestamp = new Date(timestampStr)
|
|
54
|
-
const type = typeStr.toLowerCase() as 'stdout' | 'stderr' | 'status'
|
|
55
|
-
|
|
56
|
-
// Unescape newlines in message
|
|
57
|
-
const unescapedMessage = message.replace(/\\n/g, '\n')
|
|
58
|
-
|
|
59
|
-
// Validate type
|
|
60
|
-
if (type === 'stdout' || type === 'stderr' || type === 'status') {
|
|
61
|
-
parsedLogs.push({
|
|
62
|
-
type,
|
|
63
|
-
message: unescapedMessage,
|
|
64
|
-
timestamp: isNaN(timestamp.getTime()) ? new Date() : timestamp,
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
// Fallback: treat as stdout if format doesn't match
|
|
69
|
-
parsedLogs.push({
|
|
70
|
-
type: 'stdout',
|
|
71
|
-
message: line,
|
|
72
|
-
timestamp: new Date(),
|
|
73
|
-
})
|
|
74
|
-
}
|
|
75
|
-
} catch (error) {
|
|
76
|
-
// Skip malformed lines
|
|
77
|
-
console.error('[LogFormatter] Error parsing log line:', line, error)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return parsedLogs
|
|
82
|
-
}
|
|
83
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Log formatting utilities for storing and retrieving test run logs
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface LogEntry {
|
|
6
|
+
type: 'stdout' | 'stderr' | 'status'
|
|
7
|
+
message: string
|
|
8
|
+
timestamp: Date
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Formats log entries into a single text string for storage in the database
|
|
13
|
+
* Format: [timestamp] [TYPE] message
|
|
14
|
+
*
|
|
15
|
+
* @param logs - Array of log entries to format
|
|
16
|
+
* @returns Formatted log string
|
|
17
|
+
*/
|
|
18
|
+
export function formatLogsForStorage(logs: LogEntry[]): string {
|
|
19
|
+
return logs
|
|
20
|
+
.map(log => {
|
|
21
|
+
const timestamp = log.timestamp.toISOString()
|
|
22
|
+
const type = log.type.toUpperCase()
|
|
23
|
+
// Escape newlines in message to preserve them in the formatted string
|
|
24
|
+
const escapedMessage = log.message.replace(/\n/g, '\\n')
|
|
25
|
+
return `[${timestamp}] [${type}] ${escapedMessage}`
|
|
26
|
+
})
|
|
27
|
+
.join('\n')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parses formatted log text back into an array of LogEntry objects
|
|
32
|
+
*
|
|
33
|
+
* @param formattedLogs - Formatted log string from database
|
|
34
|
+
* @returns Array of log entries
|
|
35
|
+
*/
|
|
36
|
+
export function parseLogsFromStorage(formattedLogs: string): LogEntry[] {
|
|
37
|
+
if (!formattedLogs || formattedLogs.trim() === '') {
|
|
38
|
+
return []
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const lines = formattedLogs.split('\n')
|
|
42
|
+
const parsedLogs: LogEntry[] = []
|
|
43
|
+
|
|
44
|
+
for (const line of lines) {
|
|
45
|
+
if (!line.trim()) continue
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// Match format: [timestamp] [TYPE] message
|
|
49
|
+
const match = line.match(/^\[([^\]]+)\] \[([^\]]+)\] (.+)$/)
|
|
50
|
+
|
|
51
|
+
if (match) {
|
|
52
|
+
const [, timestampStr, typeStr, message] = match
|
|
53
|
+
const timestamp = new Date(timestampStr)
|
|
54
|
+
const type = typeStr.toLowerCase() as 'stdout' | 'stderr' | 'status'
|
|
55
|
+
|
|
56
|
+
// Unescape newlines in message
|
|
57
|
+
const unescapedMessage = message.replace(/\\n/g, '\n')
|
|
58
|
+
|
|
59
|
+
// Validate type
|
|
60
|
+
if (type === 'stdout' || type === 'stderr' || type === 'status') {
|
|
61
|
+
parsedLogs.push({
|
|
62
|
+
type,
|
|
63
|
+
message: unescapedMessage,
|
|
64
|
+
timestamp: isNaN(timestamp.getTime()) ? new Date() : timestamp,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
// Fallback: treat as stdout if format doesn't match
|
|
69
|
+
parsedLogs.push({
|
|
70
|
+
type: 'stdout',
|
|
71
|
+
message: line,
|
|
72
|
+
timestamp: new Date(),
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
// Skip malformed lines
|
|
77
|
+
console.error('[LogFormatter] Error parsing log line:', line, error)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return parsedLogs
|
|
82
|
+
}
|
|
83
|
+
|
|
@@ -1,191 +1,191 @@
|
|
|
1
|
-
import type { SpawnedProcess } from '@/tests/utils/spawner.util'
|
|
2
|
-
import { EventEmitter } from 'events'
|
|
3
|
-
import { taskSpawner } from '@/tests/utils/spawner.util'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Process Manager - Singleton to track running test processes by test run ID
|
|
7
|
-
*
|
|
8
|
-
* This manager maintains a registry of active test processes, allowing
|
|
9
|
-
* the SSE route handler to look up processes and stream their logs.
|
|
10
|
-
*
|
|
11
|
-
* Uses global variable pattern (like Prisma) to persist across Next.js runtime contexts
|
|
12
|
-
*
|
|
13
|
-
* Security: Currently stores processes by testRunId only.
|
|
14
|
-
* TODO: When user authentication is implemented, consider adding user isolation:
|
|
15
|
-
* - Option 1: Use composite keys like `${userId}:${testRunId}`
|
|
16
|
-
* - Option 2: Store userId in process metadata and filter by userId in get() method
|
|
17
|
-
* - Option 3: Create separate ProcessManager instances per user (more complex)
|
|
18
|
-
*/
|
|
19
|
-
class ProcessManager extends EventEmitter {
|
|
20
|
-
private processes: Map<string, SpawnedProcess> = new Map()
|
|
21
|
-
// Track event listeners for cleanup
|
|
22
|
-
private eventListeners: Map<string, Map<string, () => void>> = new Map()
|
|
23
|
-
|
|
24
|
-
private constructor() {
|
|
25
|
-
super()
|
|
26
|
-
// Private constructor for singleton pattern
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Get the singleton instance of ProcessManager
|
|
31
|
-
* Uses global variable to persist across Next.js runtime contexts
|
|
32
|
-
*/
|
|
33
|
-
static getInstance(): ProcessManager {
|
|
34
|
-
const globalForProcessManager = global as unknown as {
|
|
35
|
-
processManager: ProcessManager | undefined
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
if (!globalForProcessManager.processManager) {
|
|
39
|
-
globalForProcessManager.processManager = new ProcessManager()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return globalForProcessManager.processManager
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Register a process for a test run
|
|
47
|
-
* Sets up event listeners to parse custom events from stdout/stderr
|
|
48
|
-
* @param testRunId - The test run ID
|
|
49
|
-
* @param process - The spawned process instance
|
|
50
|
-
*/
|
|
51
|
-
register(testRunId: string, process: SpawnedProcess): void {
|
|
52
|
-
this.processes.set(testRunId, process)
|
|
53
|
-
|
|
54
|
-
// Set up listeners to parse custom events from stdout/stderr
|
|
55
|
-
const listeners = new Map<string, () => void>()
|
|
56
|
-
|
|
57
|
-
// Handler for stdout events - parse for custom events
|
|
58
|
-
const onStdout = ({ processName, data }: { processName: string; data: string }) => {
|
|
59
|
-
if (processName === process.name) {
|
|
60
|
-
this.parseAndEmitCustomEvents(testRunId, data)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Handler for stderr events - parse for custom events
|
|
65
|
-
const onStderr = ({ processName, data }: { processName: string; data: string }) => {
|
|
66
|
-
if (processName === process.name) {
|
|
67
|
-
this.parseAndEmitCustomEvents(testRunId, data)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Store cleanup functions
|
|
72
|
-
listeners.set('stdout', () => taskSpawner.removeListener('stdout', onStdout))
|
|
73
|
-
listeners.set('stderr', () => taskSpawner.removeListener('stderr', onStderr))
|
|
74
|
-
|
|
75
|
-
// Register listeners
|
|
76
|
-
taskSpawner.on('stdout', onStdout)
|
|
77
|
-
taskSpawner.on('stderr', onStderr)
|
|
78
|
-
|
|
79
|
-
this.eventListeners.set(testRunId, listeners)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Parse stdout/stderr output for custom event markers and emit them
|
|
84
|
-
* Expects events in JSON format: {"event":"scenario::end","data":{...}}
|
|
85
|
-
*/
|
|
86
|
-
private parseAndEmitCustomEvents(testRunId: string, output: string): void {
|
|
87
|
-
// Split by newlines to handle multi-line output
|
|
88
|
-
const lines = output.split('\n')
|
|
89
|
-
|
|
90
|
-
for (const line of lines) {
|
|
91
|
-
if (!line.trim()) continue
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
// Look for JSON objects in the line that contain an "event" field
|
|
95
|
-
// Matches: {"event":"scenario::end","data":{...}}
|
|
96
|
-
const jsonMatch = line.match(/\{[\s\S]*"event"[\s\S]*\}/)
|
|
97
|
-
if (jsonMatch) {
|
|
98
|
-
const eventData = JSON.parse(jsonMatch[0])
|
|
99
|
-
if (eventData.event === 'scenario::end') {
|
|
100
|
-
console.log(`[ProcessManager] Parsed scenario::end event for testRunId: ${testRunId}`, eventData)
|
|
101
|
-
this.emit('scenario::end', {
|
|
102
|
-
testRunId,
|
|
103
|
-
scenarioName: eventData.data?.scenarioName,
|
|
104
|
-
status: eventData.data?.status,
|
|
105
|
-
tracePath: eventData.data?.tracePath,
|
|
106
|
-
...eventData.data,
|
|
107
|
-
})
|
|
108
|
-
console.log(`[ProcessManager] Emitted scenario::end event for testRunId: ${testRunId}`)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} catch (error) {
|
|
112
|
-
// Not a custom event, continue parsing other lines
|
|
113
|
-
// This is expected for regular log output
|
|
114
|
-
// Only log if it looks like it might be a JSON parse error
|
|
115
|
-
if (line.trim().startsWith('{')) {
|
|
116
|
-
console.warn(`[ProcessManager] Failed to parse potential event JSON: ${line.substring(0, 100)}`, error)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Get a process by test run ID
|
|
124
|
-
* @param testRunId - The test run ID
|
|
125
|
-
* @returns The spawned process or undefined if not found
|
|
126
|
-
*/
|
|
127
|
-
get(testRunId: string): SpawnedProcess | undefined {
|
|
128
|
-
return this.processes.get(testRunId)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Unregister a process for a test run
|
|
133
|
-
* Cleans up event listeners
|
|
134
|
-
* @param testRunId - The test run ID
|
|
135
|
-
* @returns True if the process was found and removed, false otherwise
|
|
136
|
-
*/
|
|
137
|
-
unregister(testRunId: string): boolean {
|
|
138
|
-
// Clean up event listeners
|
|
139
|
-
const listeners = this.eventListeners.get(testRunId)
|
|
140
|
-
if (listeners) {
|
|
141
|
-
listeners.forEach(cleanup => cleanup())
|
|
142
|
-
this.eventListeners.delete(testRunId)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const deleted = this.processes.delete(testRunId)
|
|
146
|
-
console.log(
|
|
147
|
-
`[ProcessManager] Unregistering process for testRunId: ${testRunId}, deleted: ${deleted}, remaining processes: ${this.processes.size}`,
|
|
148
|
-
)
|
|
149
|
-
return deleted
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Check if a process exists for a test run
|
|
154
|
-
* @param testRunId - The test run ID
|
|
155
|
-
* @returns True if a process exists, false otherwise
|
|
156
|
-
*/
|
|
157
|
-
has(testRunId: string): boolean {
|
|
158
|
-
return this.processes.has(testRunId)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Get all registered test run IDs (for debugging)
|
|
163
|
-
* @returns Array of test run IDs
|
|
164
|
-
*/
|
|
165
|
-
getAllTestRunIds(): string[] {
|
|
166
|
-
return Array.from(this.processes.keys())
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Clear all registered processes (useful for cleanup)
|
|
171
|
-
*/
|
|
172
|
-
clear(): void {
|
|
173
|
-
// Clean up all event listeners
|
|
174
|
-
this.eventListeners.forEach(listeners => {
|
|
175
|
-
listeners.forEach(cleanup => cleanup())
|
|
176
|
-
})
|
|
177
|
-
this.eventListeners.clear()
|
|
178
|
-
this.processes.clear()
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Get the number of active processes
|
|
183
|
-
* @returns The number of registered processes
|
|
184
|
-
*/
|
|
185
|
-
size(): number {
|
|
186
|
-
return this.processes.size
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Export singleton instance
|
|
191
|
-
export const processManager = ProcessManager.getInstance()
|
|
1
|
+
import type { SpawnedProcess } from '@/tests/utils/spawner.util'
|
|
2
|
+
import { EventEmitter } from 'events'
|
|
3
|
+
import { taskSpawner } from '@/tests/utils/spawner.util'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Process Manager - Singleton to track running test processes by test run ID
|
|
7
|
+
*
|
|
8
|
+
* This manager maintains a registry of active test processes, allowing
|
|
9
|
+
* the SSE route handler to look up processes and stream their logs.
|
|
10
|
+
*
|
|
11
|
+
* Uses global variable pattern (like Prisma) to persist across Next.js runtime contexts
|
|
12
|
+
*
|
|
13
|
+
* Security: Currently stores processes by testRunId only.
|
|
14
|
+
* TODO: When user authentication is implemented, consider adding user isolation:
|
|
15
|
+
* - Option 1: Use composite keys like `${userId}:${testRunId}`
|
|
16
|
+
* - Option 2: Store userId in process metadata and filter by userId in get() method
|
|
17
|
+
* - Option 3: Create separate ProcessManager instances per user (more complex)
|
|
18
|
+
*/
|
|
19
|
+
class ProcessManager extends EventEmitter {
|
|
20
|
+
private processes: Map<string, SpawnedProcess> = new Map()
|
|
21
|
+
// Track event listeners for cleanup
|
|
22
|
+
private eventListeners: Map<string, Map<string, () => void>> = new Map()
|
|
23
|
+
|
|
24
|
+
private constructor() {
|
|
25
|
+
super()
|
|
26
|
+
// Private constructor for singleton pattern
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the singleton instance of ProcessManager
|
|
31
|
+
* Uses global variable to persist across Next.js runtime contexts
|
|
32
|
+
*/
|
|
33
|
+
static getInstance(): ProcessManager {
|
|
34
|
+
const globalForProcessManager = global as unknown as {
|
|
35
|
+
processManager: ProcessManager | undefined
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!globalForProcessManager.processManager) {
|
|
39
|
+
globalForProcessManager.processManager = new ProcessManager()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return globalForProcessManager.processManager
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Register a process for a test run
|
|
47
|
+
* Sets up event listeners to parse custom events from stdout/stderr
|
|
48
|
+
* @param testRunId - The test run ID
|
|
49
|
+
* @param process - The spawned process instance
|
|
50
|
+
*/
|
|
51
|
+
register(testRunId: string, process: SpawnedProcess): void {
|
|
52
|
+
this.processes.set(testRunId, process)
|
|
53
|
+
|
|
54
|
+
// Set up listeners to parse custom events from stdout/stderr
|
|
55
|
+
const listeners = new Map<string, () => void>()
|
|
56
|
+
|
|
57
|
+
// Handler for stdout events - parse for custom events
|
|
58
|
+
const onStdout = ({ processName, data }: { processName: string; data: string }) => {
|
|
59
|
+
if (processName === process.name) {
|
|
60
|
+
this.parseAndEmitCustomEvents(testRunId, data)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Handler for stderr events - parse for custom events
|
|
65
|
+
const onStderr = ({ processName, data }: { processName: string; data: string }) => {
|
|
66
|
+
if (processName === process.name) {
|
|
67
|
+
this.parseAndEmitCustomEvents(testRunId, data)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Store cleanup functions
|
|
72
|
+
listeners.set('stdout', () => taskSpawner.removeListener('stdout', onStdout))
|
|
73
|
+
listeners.set('stderr', () => taskSpawner.removeListener('stderr', onStderr))
|
|
74
|
+
|
|
75
|
+
// Register listeners
|
|
76
|
+
taskSpawner.on('stdout', onStdout)
|
|
77
|
+
taskSpawner.on('stderr', onStderr)
|
|
78
|
+
|
|
79
|
+
this.eventListeners.set(testRunId, listeners)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Parse stdout/stderr output for custom event markers and emit them
|
|
84
|
+
* Expects events in JSON format: {"event":"scenario::end","data":{...}}
|
|
85
|
+
*/
|
|
86
|
+
private parseAndEmitCustomEvents(testRunId: string, output: string): void {
|
|
87
|
+
// Split by newlines to handle multi-line output
|
|
88
|
+
const lines = output.split('\n')
|
|
89
|
+
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (!line.trim()) continue
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Look for JSON objects in the line that contain an "event" field
|
|
95
|
+
// Matches: {"event":"scenario::end","data":{...}}
|
|
96
|
+
const jsonMatch = line.match(/\{[\s\S]*"event"[\s\S]*\}/)
|
|
97
|
+
if (jsonMatch) {
|
|
98
|
+
const eventData = JSON.parse(jsonMatch[0])
|
|
99
|
+
if (eventData.event === 'scenario::end') {
|
|
100
|
+
console.log(`[ProcessManager] Parsed scenario::end event for testRunId: ${testRunId}`, eventData)
|
|
101
|
+
this.emit('scenario::end', {
|
|
102
|
+
testRunId,
|
|
103
|
+
scenarioName: eventData.data?.scenarioName,
|
|
104
|
+
status: eventData.data?.status,
|
|
105
|
+
tracePath: eventData.data?.tracePath,
|
|
106
|
+
...eventData.data,
|
|
107
|
+
})
|
|
108
|
+
console.log(`[ProcessManager] Emitted scenario::end event for testRunId: ${testRunId}`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
// Not a custom event, continue parsing other lines
|
|
113
|
+
// This is expected for regular log output
|
|
114
|
+
// Only log if it looks like it might be a JSON parse error
|
|
115
|
+
if (line.trim().startsWith('{')) {
|
|
116
|
+
console.warn(`[ProcessManager] Failed to parse potential event JSON: ${line.substring(0, 100)}`, error)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get a process by test run ID
|
|
124
|
+
* @param testRunId - The test run ID
|
|
125
|
+
* @returns The spawned process or undefined if not found
|
|
126
|
+
*/
|
|
127
|
+
get(testRunId: string): SpawnedProcess | undefined {
|
|
128
|
+
return this.processes.get(testRunId)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Unregister a process for a test run
|
|
133
|
+
* Cleans up event listeners
|
|
134
|
+
* @param testRunId - The test run ID
|
|
135
|
+
* @returns True if the process was found and removed, false otherwise
|
|
136
|
+
*/
|
|
137
|
+
unregister(testRunId: string): boolean {
|
|
138
|
+
// Clean up event listeners
|
|
139
|
+
const listeners = this.eventListeners.get(testRunId)
|
|
140
|
+
if (listeners) {
|
|
141
|
+
listeners.forEach(cleanup => cleanup())
|
|
142
|
+
this.eventListeners.delete(testRunId)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const deleted = this.processes.delete(testRunId)
|
|
146
|
+
console.log(
|
|
147
|
+
`[ProcessManager] Unregistering process for testRunId: ${testRunId}, deleted: ${deleted}, remaining processes: ${this.processes.size}`,
|
|
148
|
+
)
|
|
149
|
+
return deleted
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check if a process exists for a test run
|
|
154
|
+
* @param testRunId - The test run ID
|
|
155
|
+
* @returns True if a process exists, false otherwise
|
|
156
|
+
*/
|
|
157
|
+
has(testRunId: string): boolean {
|
|
158
|
+
return this.processes.has(testRunId)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get all registered test run IDs (for debugging)
|
|
163
|
+
* @returns Array of test run IDs
|
|
164
|
+
*/
|
|
165
|
+
getAllTestRunIds(): string[] {
|
|
166
|
+
return Array.from(this.processes.keys())
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Clear all registered processes (useful for cleanup)
|
|
171
|
+
*/
|
|
172
|
+
clear(): void {
|
|
173
|
+
// Clean up all event listeners
|
|
174
|
+
this.eventListeners.forEach(listeners => {
|
|
175
|
+
listeners.forEach(cleanup => cleanup())
|
|
176
|
+
})
|
|
177
|
+
this.eventListeners.clear()
|
|
178
|
+
this.processes.clear()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the number of active processes
|
|
183
|
+
* @returns The number of registered processes
|
|
184
|
+
*/
|
|
185
|
+
size(): number {
|
|
186
|
+
return this.processes.size
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Export singleton instance
|
|
191
|
+
export const processManager = ProcessManager.getInstance()
|