@nathapp/nax 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -2
- package/dist/nax.js +72691 -0
- package/package.json +12 -4
- package/src/cli/config.ts +3 -1
- package/src/config/defaults.ts +1 -0
- package/src/config/schemas.ts +1 -0
- package/src/config/types.ts +1 -0
- package/src/context/builder.ts +10 -1
- package/src/prompts/sections/role-task.ts +4 -2
- package/src/review/runner.ts +6 -1
- package/src/version.ts +2 -1
- package/.claude/rules/01-project-conventions.md +0 -34
- package/.claude/rules/02-test-architecture.md +0 -39
- package/.claude/rules/03-test-writing.md +0 -58
- package/.claude/rules/04-forbidden-patterns.md +0 -29
- package/.claude/settings.json +0 -15
- package/.githooks/pre-commit +0 -16
- package/.gitlab-ci.yml +0 -103
- package/.mcp.json +0 -8
- package/BRIEF.md +0 -140
- package/CLAUDE.md +0 -143
- package/US-007-IMPLEMENTATION.md +0 -139
- package/biome.json +0 -14
- package/bun.lock +0 -163
- package/bunfig.toml +0 -12
- package/docker-compose.test.yml +0 -15
- package/docs/20260216-fix-plan-context-review.md +0 -56
- package/docs/20260216-relentless-vs-ngent-comparison.md +0 -208
- package/docs/20260216-v02-plan.md +0 -136
- package/docs/20260216-v02-review.md +0 -685
- package/docs/20260217-dogfood-findings.md +0 -56
- package/docs/20260217-p2-plus-plan.md +0 -117
- package/docs/20260217-partial-fixes-plan.md +0 -62
- package/docs/20260217-plan-analyze-spec.md +0 -117
- package/docs/20260217-post-impl-review.md +0 -1137
- package/docs/20260217-quick-wins-plan.md +0 -66
- package/docs/20260217-split-runner-plan.md +0 -75
- package/docs/20260217-v03-impl-plan.md +0 -80
- package/docs/20260217-v03-post-impl-review.md +0 -589
- package/docs/20260217-v04-impl-plan.md +0 -86
- package/docs/20260217-v05-post-impl-review.md +0 -850
- package/docs/20260217-v06-post-impl-review.md +0 -817
- package/docs/20260218-adr003-port-plan.md +0 -151
- package/docs/20260218-review-adr003-verification.md +0 -175
- package/docs/20260219-fix-plan-bug16-19.md +0 -79
- package/docs/20260219-fix-plan-bug20-22.md +0 -114
- package/docs/20260219-plan-llm-routing.md +0 -116
- package/docs/20260219-review-bug20-22-fixes.md +0 -135
- package/docs/20260219-routing-baseline-keyword.md +0 -63
- package/docs/20260220-plan-structured-logging-p1.md +0 -80
- package/docs/20260220-plan-structured-logging-p2.md +0 -37
- package/docs/20260220-review-llm-routing.md +0 -180
- package/docs/20260220-review-post-fix-llm-routing.md +0 -70
- package/docs/20260221-fix-plan-relevantfiles-split.md +0 -101
- package/docs/20260221-fix-plan-routing-mode.md +0 -125
- package/docs/20260221-review-v0.9-implementation.md +0 -379
- package/docs/20260222-fix-plan-v091-routing-isolation.md +0 -197
- package/docs/20260223-fix-plan-prompt-audit.md +0 -62
- package/docs/20260224-nax-roadmap-phases.md +0 -189
- package/docs/20260225-phase2-llm-service-layer.md +0 -401
- package/docs/20260225-review-v0.10.1.md +0 -187
- package/docs/20260303-v010-implementation-plan.md +0 -165
- package/docs/20260304-review-nax.md +0 -492
- package/docs/CLAUDE.md.bak +0 -191
- package/docs/ROADMAP.md +0 -390
- package/docs/SPEC-rectification.md +0 -0
- package/docs/SPEC.md +0 -324
- package/docs/US-001-plugin-loading-verification.md +0 -152
- package/docs/adr/ADR-005-implementation-plan.md +0 -655
- package/docs/adr/ADR-005-pipeline-re-architecture.md +0 -464
- package/docs/architecture-analysis.md +0 -1076
- package/docs/bugs/BUG-21-escalation-null-attempts.md +0 -48
- package/docs/bugs-from-dogfood-run-c.md +0 -243
- package/docs/code-review-20260228.md +0 -612
- package/docs/code-review-v0.15.0.md +0 -629
- package/docs/hook-lifecycle-test-plan.md +0 -149
- package/docs/releases/v0.11.0-and-earlier.md +0 -20
- package/docs/releases/v0.12.0.md +0 -15
- package/docs/releases/v0.13.0.md +0 -14
- package/docs/releases/v0.14.0.md +0 -20
- package/docs/releases/v0.14.1.md +0 -36
- package/docs/releases/v0.14.2.md +0 -51
- package/docs/releases/v0.14.3.md +0 -174
- package/docs/releases/v0.14.4.md +0 -94
- package/docs/releases/v0.15.0.md +0 -502
- package/docs/releases/v0.15.1.md +0 -170
- package/docs/releases/v0.15.3.md +0 -193
- package/docs/specs/bug-039-orphan-processes.md +0 -131
- package/docs/specs/bug-040-review-rectification.md +0 -82
- package/docs/specs/bug-041-cross-story-test-isolation.md +0 -88
- package/docs/specs/bug-042-verifier-failure-capture.md +0 -117
- package/docs/specs/bun-pty-migration.md +0 -171
- package/docs/specs/central-run-registry.md +0 -116
- package/docs/specs/feat-010-smart-runner-git-history.md +0 -96
- package/docs/specs/feat-011-file-context-strategy.md +0 -73
- package/docs/specs/feat-012-tdd-writer-tier.md +0 -79
- package/docs/specs/feat-013-test-after-review.md +0 -89
- package/docs/specs/feat-014-heartbeat-observability.md +0 -127
- package/docs/specs/status-file-consolidation.md +0 -93
- package/docs/specs/status-file-v0.10.1.md +0 -812
- package/docs/specs/trigger-completion.md +0 -145
- package/docs/specs/verification-architecture-v2.md +0 -343
- package/docs/tdd/strategies.md +0 -97
- package/docs/v0.10-global-config.md +0 -206
- package/docs/v0.10-plugin-system.md +0 -415
- package/docs/v0.10-prompt-optimizer.md +0 -234
- package/docs/v0.3-spec.md +0 -244
- package/docs/v0.4-spec.md +0 -140
- package/docs/v0.5-spec.md +0 -237
- package/docs/v0.6-spec.md +0 -371
- package/docs/v0.7-spec.md +0 -177
- package/docs/v0.8-llm-routing.md +0 -206
- package/docs/v0.8-structured-logging.md +0 -132
- package/docs/v0.9.3-prompt-audit.md +0 -112
- package/examples/plugins/console-reporter/index.test.ts +0 -207
- package/examples/plugins/console-reporter/index.ts +0 -110
- package/memory/topic/feat-010-baseref.md +0 -28
- package/memory/topic/feat-013-test-after-deprecation.md +0 -22
- package/nax/config.json +0 -154
- package/nax/features/bug-039-medium/prd.json +0 -45
- package/nax/features/bugfix-v0171/prd.json +0 -52
- package/nax/features/central-run-registry/prd.json +0 -105
- package/nax/features/config-management/prd.json +0 -108
- package/nax/features/config-management/progress.txt +0 -5
- package/nax/features/diagnose/acceptance.test.ts +0 -414
- package/nax/features/diagnose/prd.json +0 -41
- package/nax/features/nax-compliance/prd.json +0 -52
- package/nax/features/nax-compliance/progress.txt +0 -1
- package/nax/features/orchestration-fixes/prd.json +0 -89
- package/nax/features/orchestration-fixes/progress.txt +0 -1
- package/nax/features/plugin-integration/US-007-VERIFICATION.md +0 -259
- package/nax/features/plugin-integration/prd.json +0 -208
- package/nax/features/plugin-integration/progress.txt +0 -5
- package/nax/features/post-rearch-bugfix/prd.json +0 -137
- package/nax/features/precheck/prd.json +0 -205
- package/nax/features/precheck/progress.txt +0 -15
- package/nax/features/prompt-builder/prd.json +0 -152
- package/nax/features/prompt-builder/progress.txt +0 -3
- package/nax/features/review-quality/prd.json +0 -55
- package/nax/features/routing-persistence/prd.json +0 -104
- package/nax/features/routing-persistence/progress.txt +0 -1
- package/nax/features/smart-test-runner/plan.md +0 -7
- package/nax/features/smart-test-runner/prd.json +0 -203
- package/nax/features/smart-test-runner/progress.txt +0 -13
- package/nax/features/smart-test-runner/spec.md +0 -7
- package/nax/features/smart-test-runner/tasks.md +0 -8
- package/nax/features/status-file-consolidation/prd.json +0 -106
- package/nax/features/structured-logging/prd.json +0 -199
- package/nax/features/trigger-completion/prd.json +0 -150
- package/nax/features/trigger-completion/progress.txt +0 -7
- package/nax/features/unlock/prd.json +0 -36
- package/nax/features/v0.18.3-execution-reliability/prd.json +0 -80
- package/nax/features/v0.18.3-execution-reliability/progress.txt +0 -3
- package/nax/features/v0.19.0-hardening/plan.md +0 -7
- package/nax/features/v0.19.0-hardening/prd.json +0 -84
- package/nax/features/v0.19.0-hardening/progress.txt +0 -7
- package/nax/features/v0.19.0-hardening/spec.md +0 -18
- package/nax/features/v0.19.0-hardening/tasks.md +0 -8
- package/nax/features/verify-v2/prd.json +0 -79
- package/nax/features/verify-v2/progress.txt +0 -3
- package/nax/status.json +0 -36
- package/test/COVERAGE-GAPS.md +0 -333
- package/test/e2e/cm-003-default-view.test.ts +0 -195
- package/test/e2e/plan-analyze-run.test.ts +0 -902
- package/test/helpers/helpers.test.ts +0 -295
- package/test/helpers/timeout.ts +0 -42
- package/test/integration/US-002-TEST-SUMMARY.md +0 -107
- package/test/integration/US-003-TEST-SUMMARY.md +0 -149
- package/test/integration/US-004-TEST-SUMMARY.md +0 -106
- package/test/integration/US-005-TEST-SUMMARY.md +0 -138
- package/test/integration/US-007-TEST-SUMMARY.md +0 -100
- package/test/integration/cli/agent-validation.test.ts +0 -439
- package/test/integration/cli/cli-config-default-edge-cases.test.ts +0 -223
- package/test/integration/cli/cli-config-default-view.test.ts +0 -230
- package/test/integration/cli/cli-config-diff.test.ts +0 -461
- package/test/integration/cli/cli-config-prompts-explain.test.ts +0 -74
- package/test/integration/cli/cli-config.test.ts +0 -737
- package/test/integration/cli/cli-diagnose.test.ts +0 -595
- package/test/integration/cli/cli-logs.test.ts +0 -346
- package/test/integration/cli/cli-plugins.test.ts +0 -679
- package/test/integration/cli/cli-precheck.test.ts +0 -372
- package/test/integration/cli/cli-run-headless.test.ts +0 -174
- package/test/integration/cli/cli.test.ts +0 -76
- package/test/integration/cli/precheck-integration.test.ts +0 -476
- package/test/integration/cli/precheck-orchestrator.test.ts +0 -247
- package/test/integration/cli/precheck.test.ts +0 -806
- package/test/integration/config/config-loader.test.ts +0 -266
- package/test/integration/config/config.test.ts +0 -444
- package/test/integration/config/merger.test.ts +0 -466
- package/test/integration/config/paths.test.ts +0 -52
- package/test/integration/config/security-loader.test.ts +0 -83
- package/test/integration/context/context-integration.test.ts +0 -703
- package/test/integration/context/context-path-security.test.ts +0 -173
- package/test/integration/context/context-provider-injection.test.ts +0 -507
- package/test/integration/context/context-verification-integration.test.ts +0 -296
- package/test/integration/context/s5-greenfield-fallback.test.ts +0 -298
- package/test/integration/execution/execution-isolation.test.ts +0 -143
- package/test/integration/execution/execution.test.ts +0 -634
- package/test/integration/execution/feature-status-write.test.ts +0 -302
- package/test/integration/execution/parallel.test.ts +0 -251
- package/test/integration/execution/prd-pause.test.ts +0 -205
- package/test/integration/execution/prd-resolvers.test.ts +0 -186
- package/test/integration/execution/progress.test.ts +0 -34
- package/test/integration/execution/runner-batching.test.ts +0 -682
- package/test/integration/execution/runner-config-plugins.test.ts +0 -462
- package/test/integration/execution/runner-escalation.test.ts +0 -561
- package/test/integration/execution/runner-fixes.test.ts +0 -400
- package/test/integration/execution/runner-plugin-integration.test.ts +0 -544
- package/test/integration/execution/runner-queue-and-attempts.test.ts +0 -476
- package/test/integration/execution/status-file-integration.test.ts +0 -289
- package/test/integration/execution/status-file.test.ts +0 -380
- package/test/integration/execution/status-writer.test.ts +0 -447
- package/test/integration/execution/story-id-in-events.test.ts +0 -274
- package/test/integration/interaction/interaction-chain-pipeline.test.ts +0 -476
- package/test/integration/pipeline/hooks.test.ts +0 -363
- package/test/integration/pipeline/pipeline-acceptance.test.ts +0 -303
- package/test/integration/pipeline/pipeline-events.test.ts +0 -476
- package/test/integration/pipeline/pipeline.test.ts +0 -660
- package/test/integration/pipeline/reporter-lifecycle.test.ts +0 -862
- package/test/integration/pipeline/verify-stage.test.ts +0 -286
- package/test/integration/plan/analyze-integration.test.ts +0 -262
- package/test/integration/plan/analyze-scanner.test.ts +0 -132
- package/test/integration/plan/logger.test.ts +0 -461
- package/test/integration/plan/plan.test.ts +0 -157
- package/test/integration/plugins/config-integration.test.ts +0 -173
- package/test/integration/plugins/config-resolution.test.ts +0 -523
- package/test/integration/plugins/loader.test.ts +0 -644
- package/test/integration/plugins/plugins-registry.test.ts +0 -747
- package/test/integration/plugins/validator.test.ts +0 -564
- package/test/integration/prompts/pb-004-migration.test.ts +0 -523
- package/test/integration/review/review-config-commands.test.ts +0 -320
- package/test/integration/review/review-config-schema.test.ts +0 -117
- package/test/integration/review/review-plugin-integration.test.ts +0 -729
- package/test/integration/review/review.test.ts +0 -150
- package/test/integration/routing/plugin-routing-advanced.test.ts +0 -461
- package/test/integration/routing/plugin-routing-core.test.ts +0 -527
- package/test/integration/routing/routing-stage-bug-021.test.ts +0 -275
- package/test/integration/routing/routing-stage-greenfield.test.ts +0 -287
- package/test/integration/tdd/tdd-cleanup.test.ts +0 -246
- package/test/integration/tdd/tdd-orchestrator-core.test.ts +0 -565
- package/test/integration/tdd/tdd-orchestrator-failureCategory.test.ts +0 -355
- package/test/integration/tdd/tdd-orchestrator-fallback.test.ts +0 -311
- package/test/integration/tdd/tdd-orchestrator-lite.test.ts +0 -289
- package/test/integration/tdd/tdd-orchestrator-prompts.test.ts +0 -260
- package/test/integration/tdd/tdd-orchestrator-verdict.test.ts +0 -536
- package/test/integration/tmp/headless-test/test.jsonl +0 -30
- package/test/integration/verification/test-scanner.test.ts +0 -403
- package/test/integration/verification/verification-asset-check.test.ts +0 -143
- package/test/integration/worktree/manager.test.ts +0 -218
- package/test/integration/worktree/worktree-merge.test.ts +0 -341
- package/test/manual/logging-formatter-demo.ts +0 -158
- package/test/ui/tui-agent-panel.test.tsx +0 -99
- package/test/ui/tui-pty-integration.test.tsx +0 -146
- package/test/unit/acceptance.test.ts +0 -187
- package/test/unit/agent-stderr-capture.test.ts +0 -147
- package/test/unit/agents/claude.test.ts +0 -107
- package/test/unit/analyze-classifier.test.ts +0 -216
- package/test/unit/analyze.test.ts +0 -224
- package/test/unit/auto-detect.test.ts +0 -250
- package/test/unit/cli-status-project-level.test.ts +0 -283
- package/test/unit/cli-status.test.ts +0 -418
- package/test/unit/commands/common.test.ts +0 -321
- package/test/unit/commands/logs.test.ts +0 -458
- package/test/unit/commands/runs.test.ts +0 -303
- package/test/unit/commands/unlock.test.ts +0 -320
- package/test/unit/config/defaults.test.ts +0 -70
- package/test/unit/config/quality-commands-schema.test.ts +0 -72
- package/test/unit/config/regression-gate-schema.test.ts +0 -160
- package/test/unit/config/smart-runner-flag.test.ts +0 -250
- package/test/unit/constitution-generators.test.ts +0 -161
- package/test/unit/constitution.test.ts +0 -210
- package/test/unit/context/context-autodetect.test.ts +0 -297
- package/test/unit/context/context-build.test.ts +0 -575
- package/test/unit/context/context-coverage.test.ts +0 -236
- package/test/unit/context/context-error.test.ts +0 -93
- package/test/unit/context/context-estimate-tokens.test.ts +0 -201
- package/test/unit/context/context-format.test.ts +0 -302
- package/test/unit/context/context-isolation.test.ts +0 -267
- package/test/unit/context/context-sort.test.ts +0 -93
- package/test/unit/context/context-story.test.ts +0 -108
- package/test/unit/context/prior-failures.test.ts +0 -463
- package/test/unit/context.test.ts +0 -1726
- package/test/unit/cost.test.ts +0 -231
- package/test/unit/crash-recovery.test.ts +0 -309
- package/test/unit/escalation.test.ts +0 -127
- package/test/unit/execution/lifecycle/run-completion.test.ts +0 -240
- package/test/unit/execution/lifecycle/run-regression.test.ts +0 -420
- package/test/unit/execution/pid-registry.test.ts +0 -241
- package/test/unit/execution/sequential-executor.test.ts +0 -235
- package/test/unit/execution/sfc-004-dead-code-cleanup.test.ts +0 -89
- package/test/unit/execution/structured-failure.test.ts +0 -415
- package/test/unit/execution-logging-stderr.test.ts +0 -157
- package/test/unit/execution-stage.test.ts +0 -123
- package/test/unit/fix-generator.test.ts +0 -276
- package/test/unit/formatters.test.ts +0 -468
- package/test/unit/greenfield.test.ts +0 -180
- package/test/unit/hooks/shell-security.test.ts +0 -40
- package/test/unit/interaction/auto-plugin.test.ts +0 -162
- package/test/unit/interaction/human-review-trigger.test.ts +0 -165
- package/test/unit/interaction-network-failures.test.ts +0 -390
- package/test/unit/interaction-plugins.test.ts +0 -472
- package/test/unit/logging/formatter.test.ts +0 -456
- package/test/unit/merge.test.ts +0 -269
- package/test/unit/metrics/aggregator.test.ts +0 -164
- package/test/unit/metrics/tracker.test.ts +0 -186
- package/test/unit/metrics.test.ts +0 -276
- package/test/unit/optimizer/noop.optimizer.test.ts +0 -125
- package/test/unit/optimizer/rule-based.optimizer.test.ts +0 -358
- package/test/unit/pipeline/event-bus.test.ts +0 -105
- package/test/unit/pipeline/routing-partial-override.test.ts +0 -121
- package/test/unit/pipeline/runner-retry.test.ts +0 -89
- package/test/unit/pipeline/stages/autofix.test.ts +0 -97
- package/test/unit/pipeline/stages/completion-review-gate.test.ts +0 -218
- package/test/unit/pipeline/stages/execution-ambiguity.test.ts +0 -311
- package/test/unit/pipeline/stages/execution-merge-conflict.test.ts +0 -218
- package/test/unit/pipeline/stages/rectify.test.ts +0 -101
- package/test/unit/pipeline/stages/regression-stage.test.ts +0 -69
- package/test/unit/pipeline/stages/review.test.ts +0 -201
- package/test/unit/pipeline/stages/routing-idempotence.test.ts +0 -139
- package/test/unit/pipeline/stages/routing-initial-complexity.test.ts +0 -321
- package/test/unit/pipeline/stages/routing-persistence.test.ts +0 -380
- package/test/unit/pipeline/stages/verify.test.ts +0 -267
- package/test/unit/pipeline/subscribers/events-writer.test.ts +0 -227
- package/test/unit/pipeline/subscribers/hooks.test.ts +0 -84
- package/test/unit/pipeline/subscribers/interaction.test.ts +0 -313
- package/test/unit/pipeline/subscribers/registry.test.ts +0 -149
- package/test/unit/pipeline/subscribers/reporters.test.ts +0 -90
- package/test/unit/pipeline/verify-smart-runner.test.ts +0 -345
- package/test/unit/prd-auto-default.test.ts +0 -291
- package/test/unit/prd-failure-category.test.ts +0 -177
- package/test/unit/prd-get-next-story.test.ts +0 -215
- package/test/unit/precheck/checks-warnings.test.ts +0 -114
- package/test/unit/precheck-checks.test.ts +0 -841
- package/test/unit/precheck-story-size-gate.test.ts +0 -288
- package/test/unit/precheck-types.test.ts +0 -143
- package/test/unit/prompts/builder.test.ts +0 -258
- package/test/unit/prompts/loader.test.ts +0 -355
- package/test/unit/prompts/sections/conventions.test.ts +0 -30
- package/test/unit/prompts/sections/isolation.test.ts +0 -35
- package/test/unit/prompts/sections/role-task.test.ts +0 -40
- package/test/unit/prompts/sections/sections.test.ts +0 -238
- package/test/unit/prompts/sections/story.test.ts +0 -45
- package/test/unit/prompts/sections/verdict.test.ts +0 -58
- package/test/unit/prompts.test.ts +0 -476
- package/test/unit/queue.test.ts +0 -237
- package/test/unit/rectification.test.ts +0 -285
- package/test/unit/registry.test.ts +0 -288
- package/test/unit/review/runner.test.ts +0 -117
- package/test/unit/routing/content-hash.test.ts +0 -99
- package/test/unit/routing/routing-stability.test.ts +0 -208
- package/test/unit/routing/strategies/llm.test.ts +0 -306
- package/test/unit/routing-advanced.test.ts +0 -313
- package/test/unit/routing-core.test.ts +0 -341
- package/test/unit/routing-strategies.test.ts +0 -440
- package/test/unit/storyid-events.test.ts +0 -213
- package/test/unit/tdd-verdict.test.ts +0 -492
- package/test/unit/test-output-parser.test.ts +0 -377
- package/test/unit/ui/tui-controls.test.ts +0 -335
- package/test/unit/ui/tui-cost-and-pty.test.ts +0 -190
- package/test/unit/ui/tui-layout.test.ts +0 -379
- package/test/unit/ui/tui-stories.test.ts +0 -333
- package/test/unit/unit-isolation.test.ts +0 -135
- package/test/unit/utils/git.test.ts +0 -50
- package/test/unit/utils/path-security.test.ts +0 -47
- package/test/unit/utils-helpers.test.ts +0 -318
- package/test/unit/verdict.test.ts +0 -325
- package/test/unit/verification/orchestrator-types.test.ts +0 -54
- package/test/unit/verification/orchestrator.test.ts +0 -66
- package/test/unit/verification/smart-runner-config.test.ts +0 -163
- package/test/unit/verification/smart-runner-discovery.test.ts +0 -354
- package/test/unit/verification/smart-runner.test.ts +0 -262
- package/test/unit/verification/strategies/acceptance.test.ts +0 -33
- package/test/unit/verification/strategies/regression.test.ts +0 -87
- package/test/unit/verification/strategies/scoped.test.ts +0 -100
- package/test/unit/worktree-manager.test.ts +0 -159
- package/tsconfig.json +0 -27
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { type TestFailure, formatFailureSummary, parseBunTestOutput } from "../../src/execution/test-output-parser";
|
|
3
|
-
|
|
4
|
-
describe("parseBunTestOutput", () => {
|
|
5
|
-
test("parses passing output (0 failures)", () => {
|
|
6
|
-
const output = `
|
|
7
|
-
bun test v1.0.0
|
|
8
|
-
|
|
9
|
-
test/example.test.ts:
|
|
10
|
-
✓ test 1 [0.5ms]
|
|
11
|
-
✓ test 2 [0.3ms]
|
|
12
|
-
✓ test 3 [0.7ms]
|
|
13
|
-
|
|
14
|
-
3 tests passed [1.5ms]
|
|
15
|
-
`.trim();
|
|
16
|
-
|
|
17
|
-
const result = parseBunTestOutput(output);
|
|
18
|
-
|
|
19
|
-
expect(result.passed).toBe(3);
|
|
20
|
-
expect(result.failed).toBe(0);
|
|
21
|
-
expect(result.failures).toHaveLength(0);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test("parses mixed pass/fail output", () => {
|
|
25
|
-
const output = `
|
|
26
|
-
bun test v1.0.0
|
|
27
|
-
|
|
28
|
-
test/example.test.ts:
|
|
29
|
-
✓ passing test [0.5ms]
|
|
30
|
-
✗ failing test [1.2ms]
|
|
31
|
-
|
|
32
|
-
(fail) failing test [1.2ms]
|
|
33
|
-
Error: Expected 1 to equal 2
|
|
34
|
-
at /path/to/file.ts:10:15
|
|
35
|
-
at Object.test (/path/to/file.ts:8:3)
|
|
36
|
-
|
|
37
|
-
1 passed, 1 failed [1.7ms]
|
|
38
|
-
`.trim();
|
|
39
|
-
|
|
40
|
-
const result = parseBunTestOutput(output);
|
|
41
|
-
|
|
42
|
-
expect(result.passed).toBe(1);
|
|
43
|
-
expect(result.failed).toBe(1);
|
|
44
|
-
expect(result.failures).toHaveLength(1);
|
|
45
|
-
expect(result.failures[0].file).toBe("test/example.test.ts");
|
|
46
|
-
expect(result.failures[0].testName).toBe("failing test");
|
|
47
|
-
expect(result.failures[0].error).toBe("Error: Expected 1 to equal 2");
|
|
48
|
-
expect(result.failures[0].stackTrace).toHaveLength(2);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("extracts test names from nested describe blocks", () => {
|
|
52
|
-
const output = `
|
|
53
|
-
bun test v1.0.0
|
|
54
|
-
|
|
55
|
-
test/nested.test.ts:
|
|
56
|
-
✓ outer test [0.2ms]
|
|
57
|
-
✗ inner test [0.8ms]
|
|
58
|
-
|
|
59
|
-
(fail) describe block > nested block > inner test [0.8ms]
|
|
60
|
-
Error: Assertion failed
|
|
61
|
-
at /path/to/nested.ts:20:10
|
|
62
|
-
|
|
63
|
-
1 passed, 1 failed [1.0ms]
|
|
64
|
-
`.trim();
|
|
65
|
-
|
|
66
|
-
const result = parseBunTestOutput(output);
|
|
67
|
-
|
|
68
|
-
expect(result.failures).toHaveLength(1);
|
|
69
|
-
expect(result.failures[0].testName).toBe("describe block > nested block > inner test");
|
|
70
|
-
expect(result.failures[0].file).toBe("test/nested.test.ts");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("truncates stack trace to 5 lines", () => {
|
|
74
|
-
const output = `
|
|
75
|
-
bun test v1.0.0
|
|
76
|
-
|
|
77
|
-
test/stack.test.ts:
|
|
78
|
-
✗ test with long stack [2.0ms]
|
|
79
|
-
|
|
80
|
-
(fail) test with long stack [2.0ms]
|
|
81
|
-
Error: Stack overflow
|
|
82
|
-
at line1 (/path/to/file.ts:1:1)
|
|
83
|
-
at line2 (/path/to/file.ts:2:2)
|
|
84
|
-
at line3 (/path/to/file.ts:3:3)
|
|
85
|
-
at line4 (/path/to/file.ts:4:4)
|
|
86
|
-
at line5 (/path/to/file.ts:5:5)
|
|
87
|
-
at line6 (/path/to/file.ts:6:6)
|
|
88
|
-
at line7 (/path/to/file.ts:7:7)
|
|
89
|
-
at line8 (/path/to/file.ts:8:8)
|
|
90
|
-
|
|
91
|
-
0 passed, 1 failed [2.0ms]
|
|
92
|
-
`.trim();
|
|
93
|
-
|
|
94
|
-
const result = parseBunTestOutput(output);
|
|
95
|
-
|
|
96
|
-
expect(result.failures).toHaveLength(1);
|
|
97
|
-
expect(result.failures[0].stackTrace).toHaveLength(5);
|
|
98
|
-
expect(result.failures[0].stackTrace[0]).toBe("at line1 (/path/to/file.ts:1:1)");
|
|
99
|
-
expect(result.failures[0].stackTrace[4]).toBe("at line5 (/path/to/file.ts:5:5)");
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test("handles empty/malformed input", () => {
|
|
103
|
-
const emptyResult = parseBunTestOutput("");
|
|
104
|
-
expect(emptyResult.passed).toBe(0);
|
|
105
|
-
expect(emptyResult.failed).toBe(0);
|
|
106
|
-
expect(emptyResult.failures).toHaveLength(0);
|
|
107
|
-
|
|
108
|
-
const malformedResult = parseBunTestOutput("random text\nno test output");
|
|
109
|
-
expect(malformedResult.passed).toBe(0);
|
|
110
|
-
expect(malformedResult.failed).toBe(0);
|
|
111
|
-
expect(malformedResult.failures).toHaveLength(0);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test("handles multiple test files", () => {
|
|
115
|
-
const output = `
|
|
116
|
-
bun test v1.0.0
|
|
117
|
-
|
|
118
|
-
test/file1.test.ts:
|
|
119
|
-
✓ test 1 [0.5ms]
|
|
120
|
-
✗ test 2 [1.2ms]
|
|
121
|
-
|
|
122
|
-
(fail) test 2 [1.2ms]
|
|
123
|
-
Error: File 1 error
|
|
124
|
-
at /path/to/file1.ts:10:15
|
|
125
|
-
|
|
126
|
-
test/file2.test.ts:
|
|
127
|
-
✓ test 3 [0.3ms]
|
|
128
|
-
✗ test 4 [0.8ms]
|
|
129
|
-
|
|
130
|
-
(fail) test 4 [0.8ms]
|
|
131
|
-
Error: File 2 error
|
|
132
|
-
at /path/to/file2.ts:20:25
|
|
133
|
-
|
|
134
|
-
2 passed, 2 failed [2.8ms]
|
|
135
|
-
`.trim();
|
|
136
|
-
|
|
137
|
-
const result = parseBunTestOutput(output);
|
|
138
|
-
|
|
139
|
-
expect(result.passed).toBe(2);
|
|
140
|
-
expect(result.failed).toBe(2);
|
|
141
|
-
expect(result.failures).toHaveLength(2);
|
|
142
|
-
expect(result.failures[0].file).toBe("test/file1.test.ts");
|
|
143
|
-
expect(result.failures[0].error).toBe("Error: File 1 error");
|
|
144
|
-
expect(result.failures[1].file).toBe("test/file2.test.ts");
|
|
145
|
-
expect(result.failures[1].error).toBe("Error: File 2 error");
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test("handles test files with .js extension", () => {
|
|
149
|
-
const output = `
|
|
150
|
-
bun test v1.0.0
|
|
151
|
-
|
|
152
|
-
test/example.test.js:
|
|
153
|
-
✗ failing test [1.0ms]
|
|
154
|
-
|
|
155
|
-
(fail) failing test [1.0ms]
|
|
156
|
-
Error: JS test error
|
|
157
|
-
at /path/to/file.js:5:10
|
|
158
|
-
|
|
159
|
-
0 passed, 1 failed [1.0ms]
|
|
160
|
-
`.trim();
|
|
161
|
-
|
|
162
|
-
const result = parseBunTestOutput(output);
|
|
163
|
-
|
|
164
|
-
expect(result.failures).toHaveLength(1);
|
|
165
|
-
expect(result.failures[0].file).toBe("test/example.test.js");
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
test("handles failures without file context", () => {
|
|
169
|
-
const output = `
|
|
170
|
-
bun test v1.0.0
|
|
171
|
-
|
|
172
|
-
✗ orphan test [1.0ms]
|
|
173
|
-
|
|
174
|
-
(fail) orphan test [1.0ms]
|
|
175
|
-
Error: No file context
|
|
176
|
-
at /path/to/unknown.ts:1:1
|
|
177
|
-
|
|
178
|
-
0 passed, 1 failed [1.0ms]
|
|
179
|
-
`.trim();
|
|
180
|
-
|
|
181
|
-
const result = parseBunTestOutput(output);
|
|
182
|
-
|
|
183
|
-
expect(result.failures).toHaveLength(1);
|
|
184
|
-
expect(result.failures[0].file).toBe("unknown");
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
test("handles failures with no error message", () => {
|
|
188
|
-
const output = `
|
|
189
|
-
bun test v1.0.0
|
|
190
|
-
|
|
191
|
-
test/minimal.test.ts:
|
|
192
|
-
✗ minimal fail [0.5ms]
|
|
193
|
-
|
|
194
|
-
(fail) minimal fail [0.5ms]
|
|
195
|
-
|
|
196
|
-
0 passed, 1 failed [0.5ms]
|
|
197
|
-
`.trim();
|
|
198
|
-
|
|
199
|
-
const result = parseBunTestOutput(output);
|
|
200
|
-
|
|
201
|
-
expect(result.failures).toHaveLength(1);
|
|
202
|
-
expect(result.failures[0].error).toBe("Unknown error");
|
|
203
|
-
expect(result.failures[0].stackTrace).toHaveLength(0);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
test("handles alternative check marks (✔ and ✘)", () => {
|
|
207
|
-
const output = `
|
|
208
|
-
bun test v1.0.0
|
|
209
|
-
|
|
210
|
-
test/marks.test.ts:
|
|
211
|
-
✔ pass with heavy check [0.2ms]
|
|
212
|
-
✘ fail with heavy X [0.5ms]
|
|
213
|
-
|
|
214
|
-
(fail) fail with heavy X [0.5ms]
|
|
215
|
-
Error: Alternative marks error
|
|
216
|
-
|
|
217
|
-
1 passed, 1 failed [0.7ms]
|
|
218
|
-
`.trim();
|
|
219
|
-
|
|
220
|
-
const result = parseBunTestOutput(output);
|
|
221
|
-
|
|
222
|
-
expect(result.passed).toBe(1);
|
|
223
|
-
expect(result.failed).toBe(1);
|
|
224
|
-
expect(result.failures).toHaveLength(1);
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
describe("formatFailureSummary", () => {
|
|
229
|
-
test("returns 'No test failures' for empty array", () => {
|
|
230
|
-
const result = formatFailureSummary([]);
|
|
231
|
-
expect(result).toBe("No test failures");
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
test("formats single failure", () => {
|
|
235
|
-
const failures: TestFailure[] = [
|
|
236
|
-
{
|
|
237
|
-
file: "test/example.test.ts",
|
|
238
|
-
testName: "failing test",
|
|
239
|
-
error: "Expected 1 to equal 2",
|
|
240
|
-
stackTrace: ["at /path/to/file.ts:10:15"],
|
|
241
|
-
},
|
|
242
|
-
];
|
|
243
|
-
|
|
244
|
-
const result = formatFailureSummary(failures);
|
|
245
|
-
|
|
246
|
-
expect(result).toContain("1. test/example.test.ts > failing test");
|
|
247
|
-
expect(result).toContain("Error: Expected 1 to equal 2");
|
|
248
|
-
expect(result).toContain("at /path/to/file.ts:10:15");
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test("formats multiple failures", () => {
|
|
252
|
-
const failures: TestFailure[] = [
|
|
253
|
-
{
|
|
254
|
-
file: "test/file1.test.ts",
|
|
255
|
-
testName: "test 1",
|
|
256
|
-
error: "Error 1",
|
|
257
|
-
stackTrace: ["at /path/file1.ts:5:10"],
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
file: "test/file2.test.ts",
|
|
261
|
-
testName: "test 2",
|
|
262
|
-
error: "Error 2",
|
|
263
|
-
stackTrace: ["at /path/file2.ts:15:20"],
|
|
264
|
-
},
|
|
265
|
-
];
|
|
266
|
-
|
|
267
|
-
const result = formatFailureSummary(failures);
|
|
268
|
-
|
|
269
|
-
expect(result).toContain("1. test/file1.test.ts > test 1");
|
|
270
|
-
expect(result).toContain("Error: Error 1");
|
|
271
|
-
expect(result).toContain("2. test/file2.test.ts > test 2");
|
|
272
|
-
expect(result).toContain("Error: Error 2");
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
test("respects maxChars limit", () => {
|
|
276
|
-
const failures: TestFailure[] = Array.from({ length: 10 }, (_, i) => ({
|
|
277
|
-
file: `test/file${i}.test.ts`,
|
|
278
|
-
testName: `test ${i}`,
|
|
279
|
-
error: `Error message ${i}`,
|
|
280
|
-
stackTrace: [`at /path/file${i}.ts:${i}:${i}`],
|
|
281
|
-
}));
|
|
282
|
-
|
|
283
|
-
const result = formatFailureSummary(failures, 300);
|
|
284
|
-
|
|
285
|
-
expect(result.length).toBeLessThanOrEqual(350); // Some buffer for truncation message
|
|
286
|
-
expect(result).toContain("... and");
|
|
287
|
-
expect(result).toContain("more failure(s) (truncated)");
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test("handles failure without stack trace", () => {
|
|
291
|
-
const failures: TestFailure[] = [
|
|
292
|
-
{
|
|
293
|
-
file: "test/nostack.test.ts",
|
|
294
|
-
testName: "no stack",
|
|
295
|
-
error: "Error without stack",
|
|
296
|
-
stackTrace: [],
|
|
297
|
-
},
|
|
298
|
-
];
|
|
299
|
-
|
|
300
|
-
const result = formatFailureSummary(failures);
|
|
301
|
-
|
|
302
|
-
expect(result).toContain("1. test/nostack.test.ts > no stack");
|
|
303
|
-
expect(result).toContain("Error: Error without stack");
|
|
304
|
-
expect(result).not.toContain("at ");
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
test("handles nested test names", () => {
|
|
308
|
-
const failures: TestFailure[] = [
|
|
309
|
-
{
|
|
310
|
-
file: "test/nested.test.ts",
|
|
311
|
-
testName: "outer > middle > inner",
|
|
312
|
-
error: "Nested test error",
|
|
313
|
-
stackTrace: ["at /path/nested.ts:30:5"],
|
|
314
|
-
},
|
|
315
|
-
];
|
|
316
|
-
|
|
317
|
-
const result = formatFailureSummary(failures);
|
|
318
|
-
|
|
319
|
-
expect(result).toContain("1. test/nested.test.ts > outer > middle > inner");
|
|
320
|
-
expect(result).toContain("Error: Nested test error");
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
test("includes only first stack trace line", () => {
|
|
324
|
-
const failures: TestFailure[] = [
|
|
325
|
-
{
|
|
326
|
-
file: "test/multi.test.ts",
|
|
327
|
-
testName: "multi stack",
|
|
328
|
-
error: "Error with multiple stack lines",
|
|
329
|
-
stackTrace: ["at /path/file.ts:10:5", "at /path/file.ts:20:10", "at /path/file.ts:30:15"],
|
|
330
|
-
},
|
|
331
|
-
];
|
|
332
|
-
|
|
333
|
-
const result = formatFailureSummary(failures);
|
|
334
|
-
|
|
335
|
-
expect(result).toContain("at /path/file.ts:10:5");
|
|
336
|
-
expect(result).not.toContain("at /path/file.ts:20:10");
|
|
337
|
-
expect(result).not.toContain("at /path/file.ts:30:15");
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
test("separates failures with blank lines", () => {
|
|
341
|
-
const failures: TestFailure[] = [
|
|
342
|
-
{
|
|
343
|
-
file: "test/a.test.ts",
|
|
344
|
-
testName: "test a",
|
|
345
|
-
error: "Error A",
|
|
346
|
-
stackTrace: ["at a.ts:1:1"],
|
|
347
|
-
},
|
|
348
|
-
{
|
|
349
|
-
file: "test/b.test.ts",
|
|
350
|
-
testName: "test b",
|
|
351
|
-
error: "Error B",
|
|
352
|
-
stackTrace: ["at b.ts:2:2"],
|
|
353
|
-
},
|
|
354
|
-
];
|
|
355
|
-
|
|
356
|
-
const result = formatFailureSummary(failures);
|
|
357
|
-
|
|
358
|
-
// Check that there's proper separation between failures
|
|
359
|
-
const lines = result.split("\n");
|
|
360
|
-
const blankLines = lines.filter((line) => line.trim() === "");
|
|
361
|
-
expect(blankLines.length).toBeGreaterThan(0);
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
test("uses default maxChars of 2000", () => {
|
|
365
|
-
const failures: TestFailure[] = Array.from({ length: 50 }, (_, i) => ({
|
|
366
|
-
file: `test/file${i}.test.ts`,
|
|
367
|
-
testName: `test ${i}`,
|
|
368
|
-
error: `Error message ${i}`,
|
|
369
|
-
stackTrace: [`at /path/file${i}.ts:${i}:${i}`],
|
|
370
|
-
}));
|
|
371
|
-
|
|
372
|
-
const result = formatFailureSummary(failures); // No maxChars argument
|
|
373
|
-
|
|
374
|
-
expect(result.length).toBeLessThanOrEqual(2100); // Some buffer
|
|
375
|
-
expect(result).toContain("(truncated)");
|
|
376
|
-
});
|
|
377
|
-
});
|
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
// RE-ARCH: keep
|
|
2
|
-
/**
|
|
3
|
-
* TUI Controls Tests
|
|
4
|
-
*
|
|
5
|
-
* Tests keyboard shortcuts, overlays, focus mode switching,
|
|
6
|
-
* and queue command writing.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
10
|
-
import { unlink } from "node:fs/promises";
|
|
11
|
-
import { render } from "ink-testing-library";
|
|
12
|
-
import { createElement } from "react";
|
|
13
|
-
import type { UserStory } from "../../../src/prd/types";
|
|
14
|
-
import { CostOverlay } from "../../../src/tui/components/CostOverlay";
|
|
15
|
-
import { HelpOverlay } from "../../../src/tui/components/HelpOverlay";
|
|
16
|
-
import type { KeyboardAction } from "../../../src/tui/hooks/useKeyboard";
|
|
17
|
-
import { PanelFocus } from "../../../src/tui/types";
|
|
18
|
-
import type { StoryDisplayState } from "../../../src/tui/types";
|
|
19
|
-
import { writeQueueCommand } from "../../../src/utils/queue-writer";
|
|
20
|
-
|
|
21
|
-
// Helper to create mock stories
|
|
22
|
-
function createMockStory(id: string, status: StoryDisplayState["status"], cost = 0.01): StoryDisplayState {
|
|
23
|
-
const story: UserStory = {
|
|
24
|
-
id,
|
|
25
|
-
title: `Test story ${id}`,
|
|
26
|
-
description: "Test description",
|
|
27
|
-
acceptanceCriteria: [],
|
|
28
|
-
dependencies: [],
|
|
29
|
-
tags: [],
|
|
30
|
-
passes: status === "passed",
|
|
31
|
-
status: status === "passed" ? "passed" : "pending",
|
|
32
|
-
escalations: [],
|
|
33
|
-
attempts: 0,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
story,
|
|
38
|
-
status,
|
|
39
|
-
routing: {
|
|
40
|
-
complexity: "simple",
|
|
41
|
-
modelTier: "fast",
|
|
42
|
-
testStrategy: "test-after",
|
|
43
|
-
reasoning: "Test routing",
|
|
44
|
-
},
|
|
45
|
-
cost,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
describe("HelpOverlay", () => {
|
|
50
|
-
test("does not render when visible=false", () => {
|
|
51
|
-
const { lastFrame } = render(createElement(HelpOverlay, { visible: false }));
|
|
52
|
-
expect(lastFrame()).toBe("");
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("renders keybindings when visible=true", () => {
|
|
56
|
-
const { lastFrame } = render(createElement(HelpOverlay, { visible: true }));
|
|
57
|
-
const output = lastFrame();
|
|
58
|
-
|
|
59
|
-
expect(output).toContain("Keyboard Shortcuts");
|
|
60
|
-
expect(output).toContain("p"); // Pause
|
|
61
|
-
expect(output).toContain("a"); // Abort
|
|
62
|
-
expect(output).toContain("s"); // Skip
|
|
63
|
-
expect(output).toContain("Tab"); // Toggle focus
|
|
64
|
-
expect(output).toContain("q"); // Quit
|
|
65
|
-
expect(output).toContain("?"); // Show help
|
|
66
|
-
expect(output).toContain("c"); // Show cost
|
|
67
|
-
expect(output).toContain("r"); // Retry
|
|
68
|
-
expect(output).toContain("Esc"); // Close overlay
|
|
69
|
-
expect(output).toContain("Ctrl+]"); // Escape agent panel
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("displays Stories panel keybindings", () => {
|
|
73
|
-
const { lastFrame } = render(createElement(HelpOverlay, { visible: true }));
|
|
74
|
-
const output = lastFrame();
|
|
75
|
-
|
|
76
|
-
expect(output).toContain("Stories Panel");
|
|
77
|
-
expect(output).toContain("Pause after current story");
|
|
78
|
-
expect(output).toContain("Abort run");
|
|
79
|
-
expect(output).toContain("Skip current story");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("displays Agent panel keybindings", () => {
|
|
83
|
-
const { lastFrame } = render(createElement(HelpOverlay, { visible: true }));
|
|
84
|
-
const output = lastFrame();
|
|
85
|
-
|
|
86
|
-
expect(output).toContain("Agent Panel");
|
|
87
|
-
expect(output).toContain("Escape back to Stories panel");
|
|
88
|
-
expect(output).toContain("Forwarded to agent PTY");
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe("CostOverlay", () => {
|
|
93
|
-
test("does not render when visible=false", () => {
|
|
94
|
-
const { lastFrame } = render(createElement(CostOverlay, { visible: false }));
|
|
95
|
-
expect(lastFrame()).toBe("");
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test("renders cost breakdown when visible=true", () => {
|
|
99
|
-
const stories = [
|
|
100
|
-
createMockStory("US-001", "passed", 0.023),
|
|
101
|
-
createMockStory("US-002", "running", 0.015),
|
|
102
|
-
createMockStory("US-003", "pending", 0),
|
|
103
|
-
];
|
|
104
|
-
|
|
105
|
-
const { lastFrame } = render(
|
|
106
|
-
createElement(CostOverlay, {
|
|
107
|
-
visible: true,
|
|
108
|
-
stories,
|
|
109
|
-
totalCost: 0.038,
|
|
110
|
-
}),
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
const output = lastFrame();
|
|
114
|
-
expect(output).toContain("Cost Breakdown");
|
|
115
|
-
expect(output).toContain("Story ID");
|
|
116
|
-
expect(output).toContain("Status");
|
|
117
|
-
expect(output).toContain("Cost");
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("displays executed stories with costs", () => {
|
|
121
|
-
const stories = [createMockStory("US-001", "passed", 0.023), createMockStory("US-002", "failed", 0.015)];
|
|
122
|
-
|
|
123
|
-
const { lastFrame } = render(
|
|
124
|
-
createElement(CostOverlay, {
|
|
125
|
-
visible: true,
|
|
126
|
-
stories,
|
|
127
|
-
totalCost: 0.038,
|
|
128
|
-
}),
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const output = lastFrame();
|
|
132
|
-
expect(output).toContain("US-001");
|
|
133
|
-
expect(output).toContain("passed");
|
|
134
|
-
expect(output).toContain("$0.0230");
|
|
135
|
-
expect(output).toContain("US-002");
|
|
136
|
-
expect(output).toContain("failed");
|
|
137
|
-
expect(output).toContain("$0.0150");
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test("displays total cost", () => {
|
|
141
|
-
const stories = [createMockStory("US-001", "passed", 0.023)];
|
|
142
|
-
|
|
143
|
-
const { lastFrame } = render(
|
|
144
|
-
createElement(CostOverlay, {
|
|
145
|
-
visible: true,
|
|
146
|
-
stories,
|
|
147
|
-
totalCost: 0.123456,
|
|
148
|
-
}),
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
const output = lastFrame();
|
|
152
|
-
expect(output).toContain("Total Cost:");
|
|
153
|
-
expect(output).toContain("$0.1235");
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("shows message when no stories executed", () => {
|
|
157
|
-
const stories = [createMockStory("US-001", "pending", 0)];
|
|
158
|
-
|
|
159
|
-
const { lastFrame } = render(
|
|
160
|
-
createElement(CostOverlay, {
|
|
161
|
-
visible: true,
|
|
162
|
-
stories,
|
|
163
|
-
totalCost: 0,
|
|
164
|
-
}),
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
const output = lastFrame();
|
|
168
|
-
expect(output).toContain("No stories executed yet");
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe("Keyboard action types", () => {
|
|
173
|
-
test("PAUSE action has correct type", () => {
|
|
174
|
-
const action: KeyboardAction = { type: "PAUSE" };
|
|
175
|
-
expect(action.type).toBe("PAUSE");
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test("ABORT action has correct type", () => {
|
|
179
|
-
const action: KeyboardAction = { type: "ABORT" };
|
|
180
|
-
expect(action.type).toBe("ABORT");
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
test("SKIP action has story ID", () => {
|
|
184
|
-
const action: KeyboardAction = { type: "SKIP", storyId: "US-042" };
|
|
185
|
-
expect(action.type).toBe("SKIP");
|
|
186
|
-
expect(action.storyId).toBe("US-042");
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test("TOGGLE_FOCUS action has correct type", () => {
|
|
190
|
-
const action: KeyboardAction = { type: "TOGGLE_FOCUS" };
|
|
191
|
-
expect(action.type).toBe("TOGGLE_FOCUS");
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
test("ESCAPE_AGENT action has correct type", () => {
|
|
195
|
-
const action: KeyboardAction = { type: "ESCAPE_AGENT" };
|
|
196
|
-
expect(action.type).toBe("ESCAPE_AGENT");
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("QUIT action has correct type", () => {
|
|
200
|
-
const action: KeyboardAction = { type: "QUIT" };
|
|
201
|
-
expect(action.type).toBe("QUIT");
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test("SHOW_HELP action has correct type", () => {
|
|
205
|
-
const action: KeyboardAction = { type: "SHOW_HELP" };
|
|
206
|
-
expect(action.type).toBe("SHOW_HELP");
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
test("SHOW_COST action has correct type", () => {
|
|
210
|
-
const action: KeyboardAction = { type: "SHOW_COST" };
|
|
211
|
-
expect(action.type).toBe("SHOW_COST");
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("RETRY action has correct type", () => {
|
|
215
|
-
const action: KeyboardAction = { type: "RETRY" };
|
|
216
|
-
expect(action.type).toBe("RETRY");
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
test("CLOSE_OVERLAY action has correct type", () => {
|
|
220
|
-
const action: KeyboardAction = { type: "CLOSE_OVERLAY" };
|
|
221
|
-
expect(action.type).toBe("CLOSE_OVERLAY");
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe("Focus mode", () => {
|
|
226
|
-
test("PanelFocus enum has Stories value", () => {
|
|
227
|
-
expect(PanelFocus.Stories).toBe("stories");
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
test("PanelFocus enum has Agent value", () => {
|
|
231
|
-
expect(PanelFocus.Agent).toBe("agent");
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
test("focus mode toggles between Stories and Agent", () => {
|
|
235
|
-
let focus: PanelFocus = PanelFocus.Stories;
|
|
236
|
-
focus = focus === PanelFocus.Stories ? PanelFocus.Agent : PanelFocus.Stories;
|
|
237
|
-
expect(focus).toBe(PanelFocus.Agent);
|
|
238
|
-
|
|
239
|
-
focus = focus === PanelFocus.Stories ? PanelFocus.Agent : PanelFocus.Stories;
|
|
240
|
-
expect(focus).toBe(PanelFocus.Stories);
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
describe("Queue command writer", () => {
|
|
245
|
-
const tempQueueFile = "/tmp/nax-test-queue.txt";
|
|
246
|
-
|
|
247
|
-
beforeEach(async () => {
|
|
248
|
-
// Clean up any existing test file
|
|
249
|
-
try {
|
|
250
|
-
await unlink(tempQueueFile);
|
|
251
|
-
} catch {
|
|
252
|
-
// Ignore if doesn't exist
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
afterEach(async () => {
|
|
257
|
-
// Clean up after tests
|
|
258
|
-
try {
|
|
259
|
-
await unlink(tempQueueFile);
|
|
260
|
-
} catch {
|
|
261
|
-
// Ignore if doesn't exist
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
test("writes PAUSE command to queue file", async () => {
|
|
266
|
-
await writeQueueCommand(tempQueueFile, { type: "PAUSE" });
|
|
267
|
-
|
|
268
|
-
const content = await Bun.file(tempQueueFile).text();
|
|
269
|
-
expect(content.trim()).toBe("PAUSE");
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
test("writes ABORT command to queue file", async () => {
|
|
273
|
-
await writeQueueCommand(tempQueueFile, { type: "ABORT" });
|
|
274
|
-
|
|
275
|
-
const content = await Bun.file(tempQueueFile).text();
|
|
276
|
-
expect(content.trim()).toBe("ABORT");
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
test("writes SKIP command with story ID to queue file", async () => {
|
|
280
|
-
await writeQueueCommand(tempQueueFile, { type: "SKIP", storyId: "US-042" });
|
|
281
|
-
|
|
282
|
-
const content = await Bun.file(tempQueueFile).text();
|
|
283
|
-
expect(content.trim()).toBe("SKIP US-042");
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test("appends multiple commands to queue file", async () => {
|
|
287
|
-
await writeQueueCommand(tempQueueFile, { type: "SKIP", storyId: "US-001" });
|
|
288
|
-
await writeQueueCommand(tempQueueFile, { type: "PAUSE" });
|
|
289
|
-
await writeQueueCommand(tempQueueFile, { type: "ABORT" });
|
|
290
|
-
|
|
291
|
-
const content = await Bun.file(tempQueueFile).text();
|
|
292
|
-
const lines = content.trim().split("\n");
|
|
293
|
-
|
|
294
|
-
expect(lines).toEqual(["SKIP US-001", "PAUSE", "ABORT"]);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
test("creates queue file if it doesn't exist", async () => {
|
|
298
|
-
// Ensure file doesn't exist
|
|
299
|
-
try {
|
|
300
|
-
await unlink(tempQueueFile);
|
|
301
|
-
} catch {
|
|
302
|
-
// Ignore
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
await writeQueueCommand(tempQueueFile, { type: "PAUSE" });
|
|
306
|
-
|
|
307
|
-
const file = Bun.file(tempQueueFile);
|
|
308
|
-
expect(await file.exists()).toBe(true);
|
|
309
|
-
|
|
310
|
-
const content = await file.text();
|
|
311
|
-
expect(content.trim()).toBe("PAUSE");
|
|
312
|
-
});
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
describe("Ctrl+] escape sequence", () => {
|
|
316
|
-
test("Ctrl+] should escape from agent panel", () => {
|
|
317
|
-
// This would be tested in integration with the useKeyboard hook
|
|
318
|
-
// For now, we verify the concept:
|
|
319
|
-
const input = "]";
|
|
320
|
-
const keyCtrl = true;
|
|
321
|
-
|
|
322
|
-
if (keyCtrl && input === "]") {
|
|
323
|
-
const action: KeyboardAction = { type: "ESCAPE_AGENT" };
|
|
324
|
-
expect(action.type).toBe("ESCAPE_AGENT");
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
test("regular ] without Ctrl should not escape", () => {
|
|
329
|
-
const input = "]";
|
|
330
|
-
const keyCtrl = false;
|
|
331
|
-
|
|
332
|
-
// Should not trigger escape
|
|
333
|
-
expect(keyCtrl && input === "]").toBe(false);
|
|
334
|
-
});
|
|
335
|
-
});
|