@camaradesuk/git-worktree-tools 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/lib/config.d.ts +2 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +11 -0
- package/dist/lib/config.js.map +1 -1
- package/package.json +12 -3
- package/schemas/worktreerc.schema.json +1 -1
- package/dist/api/list.test.d.ts +0 -5
- package/dist/api/list.test.d.ts.map +0 -1
- package/dist/api/list.test.js +0 -390
- package/dist/api/list.test.js.map +0 -1
- package/dist/cli/cleanpr.test.d.ts +0 -2
- package/dist/cli/cleanpr.test.d.ts.map +0 -1
- package/dist/cli/cleanpr.test.js +0 -954
- package/dist/cli/cleanpr.test.js.map +0 -1
- package/dist/cli/lswt.test.d.ts +0 -2
- package/dist/cli/lswt.test.d.ts.map +0 -1
- package/dist/cli/lswt.test.js +0 -376
- package/dist/cli/lswt.test.js.map +0 -1
- package/dist/cli/newpr.test.d.ts +0 -2
- package/dist/cli/newpr.test.d.ts.map +0 -1
- package/dist/cli/newpr.test.js +0 -1182
- package/dist/cli/newpr.test.js.map +0 -1
- package/dist/cli/prs.test.d.ts +0 -8
- package/dist/cli/prs.test.d.ts.map +0 -1
- package/dist/cli/prs.test.js +0 -463
- package/dist/cli/prs.test.js.map +0 -1
- package/dist/cli/wt/clean.test.d.ts +0 -8
- package/dist/cli/wt/clean.test.d.ts.map +0 -1
- package/dist/cli/wt/clean.test.js +0 -624
- package/dist/cli/wt/clean.test.js.map +0 -1
- package/dist/cli/wt/completion.test.d.ts +0 -5
- package/dist/cli/wt/completion.test.d.ts.map +0 -1
- package/dist/cli/wt/completion.test.js +0 -275
- package/dist/cli/wt/completion.test.js.map +0 -1
- package/dist/cli/wt/config.test.d.ts +0 -7
- package/dist/cli/wt/config.test.d.ts.map +0 -1
- package/dist/cli/wt/config.test.js +0 -440
- package/dist/cli/wt/config.test.js.map +0 -1
- package/dist/cli/wt/entry.test.d.ts +0 -8
- package/dist/cli/wt/entry.test.d.ts.map +0 -1
- package/dist/cli/wt/entry.test.js +0 -201
- package/dist/cli/wt/entry.test.js.map +0 -1
- package/dist/cli/wt/init.test.d.ts +0 -5
- package/dist/cli/wt/init.test.d.ts.map +0 -1
- package/dist/cli/wt/init.test.js +0 -165
- package/dist/cli/wt/init.test.js.map +0 -1
- package/dist/cli/wt/init.unit.test.d.ts +0 -5
- package/dist/cli/wt/init.unit.test.d.ts.map +0 -1
- package/dist/cli/wt/init.unit.test.js +0 -432
- package/dist/cli/wt/init.unit.test.js.map +0 -1
- package/dist/cli/wt/interactive-menu.test.d.ts +0 -12
- package/dist/cli/wt/interactive-menu.test.d.ts.map +0 -1
- package/dist/cli/wt/interactive-menu.test.js +0 -796
- package/dist/cli/wt/interactive-menu.test.js.map +0 -1
- package/dist/cli/wt/list.test.d.ts +0 -10
- package/dist/cli/wt/list.test.d.ts.map +0 -1
- package/dist/cli/wt/list.test.js +0 -157
- package/dist/cli/wt/list.test.js.map +0 -1
- package/dist/cli/wt/prs.test.d.ts +0 -5
- package/dist/cli/wt/prs.test.d.ts.map +0 -1
- package/dist/cli/wt/prs.test.js +0 -410
- package/dist/cli/wt/prs.test.js.map +0 -1
- package/dist/cli/wt/run-command.test.d.ts +0 -5
- package/dist/cli/wt/run-command.test.d.ts.map +0 -1
- package/dist/cli/wt/run-command.test.js +0 -88
- package/dist/cli/wt/run-command.test.js.map +0 -1
- package/dist/cli/wt/state.test.d.ts +0 -9
- package/dist/cli/wt/state.test.d.ts.map +0 -1
- package/dist/cli/wt/state.test.js +0 -127
- package/dist/cli/wt/state.test.js.map +0 -1
- package/dist/cli/wt/wt.test.d.ts +0 -8
- package/dist/cli/wt/wt.test.d.ts.map +0 -1
- package/dist/cli/wt/wt.test.js +0 -739
- package/dist/cli/wt/wt.test.js.map +0 -1
- package/dist/cli/wt.unit.test.d.ts +0 -7
- package/dist/cli/wt.unit.test.d.ts.map +0 -1
- package/dist/cli/wt.unit.test.js +0 -160
- package/dist/cli/wt.unit.test.js.map +0 -1
- package/dist/cli/wtconfig.test.d.ts +0 -5
- package/dist/cli/wtconfig.test.d.ts.map +0 -1
- package/dist/cli/wtconfig.test.js +0 -1289
- package/dist/cli/wtconfig.test.js.map +0 -1
- package/dist/cli/wtlink.test.d.ts +0 -2
- package/dist/cli/wtlink.test.d.ts.map +0 -1
- package/dist/cli/wtlink.test.js +0 -249
- package/dist/cli/wtlink.test.js.map +0 -1
- package/dist/cli/wtstate.test.d.ts +0 -5
- package/dist/cli/wtstate.test.d.ts.map +0 -1
- package/dist/cli/wtstate.test.js +0 -193
- package/dist/cli/wtstate.test.js.map +0 -1
- package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts +0 -2
- package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts.map +0 -1
- package/dist/e2e/cleanpr/cleanpr.e2e.test.js +0 -326
- package/dist/e2e/cleanpr/cleanpr.e2e.test.js.map +0 -1
- package/dist/e2e/cli.e2e.test.d.ts +0 -2
- package/dist/e2e/cli.e2e.test.d.ts.map +0 -1
- package/dist/e2e/cli.e2e.test.js +0 -417
- package/dist/e2e/cli.e2e.test.js.map +0 -1
- package/dist/e2e/lswt/lswt.e2e.test.d.ts +0 -2
- package/dist/e2e/lswt/lswt.e2e.test.d.ts.map +0 -1
- package/dist/e2e/lswt/lswt.e2e.test.js +0 -361
- package/dist/e2e/lswt/lswt.e2e.test.js.map +0 -1
- package/dist/e2e/newpr/newpr.e2e.test.d.ts +0 -2
- package/dist/e2e/newpr/newpr.e2e.test.d.ts.map +0 -1
- package/dist/e2e/newpr/newpr.e2e.test.js +0 -286
- package/dist/e2e/newpr/newpr.e2e.test.js.map +0 -1
- package/dist/e2e/newpr/scenarios.e2e.test.d.ts +0 -2
- package/dist/e2e/newpr/scenarios.e2e.test.d.ts.map +0 -1
- package/dist/e2e/newpr/scenarios.e2e.test.js +0 -426
- package/dist/e2e/newpr/scenarios.e2e.test.js.map +0 -1
- package/dist/e2e/newpr-full-flow.e2e.test.d.ts +0 -2
- package/dist/e2e/newpr-full-flow.e2e.test.d.ts.map +0 -1
- package/dist/e2e/newpr-full-flow.e2e.test.js +0 -280
- package/dist/e2e/newpr-full-flow.e2e.test.js.map +0 -1
- package/dist/e2e/prs/prs.e2e.test.d.ts +0 -7
- package/dist/e2e/prs/prs.e2e.test.d.ts.map +0 -1
- package/dist/e2e/prs/prs.e2e.test.js +0 -606
- package/dist/e2e/prs/prs.e2e.test.js.map +0 -1
- package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts +0 -2
- package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts.map +0 -1
- package/dist/e2e/workflows/pr-lifecycle.e2e.test.js +0 -298
- package/dist/e2e/workflows/pr-lifecycle.e2e.test.js.map +0 -1
- package/dist/e2e/wt/interactive-menu.e2e.test.d.ts +0 -8
- package/dist/e2e/wt/interactive-menu.e2e.test.d.ts.map +0 -1
- package/dist/e2e/wt/interactive-menu.e2e.test.js +0 -583
- package/dist/e2e/wt/interactive-menu.e2e.test.js.map +0 -1
- package/dist/e2e/wt/wt.e2e.test.d.ts +0 -9
- package/dist/e2e/wt/wt.e2e.test.d.ts.map +0 -1
- package/dist/e2e/wt/wt.e2e.test.js +0 -597
- package/dist/e2e/wt/wt.e2e.test.js.map +0 -1
- package/dist/e2e/wtlink/wtlink.e2e.test.d.ts +0 -2
- package/dist/e2e/wtlink/wtlink.e2e.test.d.ts.map +0 -1
- package/dist/e2e/wtlink/wtlink.e2e.test.js +0 -416
- package/dist/e2e/wtlink/wtlink.e2e.test.js.map +0 -1
- package/dist/integration/git.integration.test.d.ts +0 -2
- package/dist/integration/git.integration.test.d.ts.map +0 -1
- package/dist/integration/git.integration.test.js +0 -336
- package/dist/integration/git.integration.test.js.map +0 -1
- package/dist/integration/lswt-remote-pr.integration.test.d.ts +0 -2
- package/dist/integration/lswt-remote-pr.integration.test.d.ts.map +0 -1
- package/dist/integration/lswt-remote-pr.integration.test.js +0 -222
- package/dist/integration/lswt-remote-pr.integration.test.js.map +0 -1
- package/dist/integration/newpr-branchfrom-head.integration.test.d.ts +0 -2
- package/dist/integration/newpr-branchfrom-head.integration.test.d.ts.map +0 -1
- package/dist/integration/newpr-branchfrom-head.integration.test.js +0 -498
- package/dist/integration/newpr-branchfrom-head.integration.test.js.map +0 -1
- package/dist/integration/newpr.integration.test.d.ts +0 -2
- package/dist/integration/newpr.integration.test.d.ts.map +0 -1
- package/dist/integration/newpr.integration.test.js +0 -460
- package/dist/integration/newpr.integration.test.js.map +0 -1
- package/dist/integration/prs.integration.test.d.ts +0 -8
- package/dist/integration/prs.integration.test.d.ts.map +0 -1
- package/dist/integration/prs.integration.test.js +0 -478
- package/dist/integration/prs.integration.test.js.map +0 -1
- package/dist/lib/ai/base-provider.test.d.ts +0 -7
- package/dist/lib/ai/base-provider.test.d.ts.map +0 -1
- package/dist/lib/ai/base-provider.test.js +0 -319
- package/dist/lib/ai/base-provider.test.js.map +0 -1
- package/dist/lib/ai/cli-provider.test.d.ts +0 -5
- package/dist/lib/ai/cli-provider.test.d.ts.map +0 -1
- package/dist/lib/ai/cli-provider.test.js +0 -460
- package/dist/lib/ai/cli-provider.test.js.map +0 -1
- package/dist/lib/ai/fallback-provider.test.d.ts +0 -7
- package/dist/lib/ai/fallback-provider.test.d.ts.map +0 -1
- package/dist/lib/ai/fallback-provider.test.js +0 -165
- package/dist/lib/ai/fallback-provider.test.js.map +0 -1
- package/dist/lib/ai/generation-service.test.d.ts +0 -7
- package/dist/lib/ai/generation-service.test.d.ts.map +0 -1
- package/dist/lib/ai/generation-service.test.js +0 -213
- package/dist/lib/ai/generation-service.test.js.map +0 -1
- package/dist/lib/ai/provider-manager.test.d.ts +0 -5
- package/dist/lib/ai/provider-manager.test.d.ts.map +0 -1
- package/dist/lib/ai/provider-manager.test.js +0 -312
- package/dist/lib/ai/provider-manager.test.js.map +0 -1
- package/dist/lib/ai/repo-docs.test.d.ts +0 -5
- package/dist/lib/ai/repo-docs.test.d.ts.map +0 -1
- package/dist/lib/ai/repo-docs.test.js +0 -357
- package/dist/lib/ai/repo-docs.test.js.map +0 -1
- package/dist/lib/cleanpr/args.test.d.ts +0 -2
- package/dist/lib/cleanpr/args.test.d.ts.map +0 -1
- package/dist/lib/cleanpr/args.test.js +0 -269
- package/dist/lib/cleanpr/args.test.js.map +0 -1
- package/dist/lib/cleanpr/cleanup.test.d.ts +0 -2
- package/dist/lib/cleanpr/cleanup.test.d.ts.map +0 -1
- package/dist/lib/cleanpr/cleanup.test.js +0 -296
- package/dist/lib/cleanpr/cleanup.test.js.map +0 -1
- package/dist/lib/cleanpr/worktree-info.test.d.ts +0 -2
- package/dist/lib/cleanpr/worktree-info.test.d.ts.map +0 -1
- package/dist/lib/cleanpr/worktree-info.test.js +0 -228
- package/dist/lib/cleanpr/worktree-info.test.js.map +0 -1
- package/dist/lib/colors.test.d.ts +0 -2
- package/dist/lib/colors.test.d.ts.map +0 -1
- package/dist/lib/colors.test.js +0 -142
- package/dist/lib/colors.test.js.map +0 -1
- package/dist/lib/config-editor.test.d.ts +0 -11
- package/dist/lib/config-editor.test.d.ts.map +0 -1
- package/dist/lib/config-editor.test.js +0 -526
- package/dist/lib/config-editor.test.js.map +0 -1
- package/dist/lib/config-migration/detector.test.d.ts +0 -5
- package/dist/lib/config-migration/detector.test.d.ts.map +0 -1
- package/dist/lib/config-migration/detector.test.js +0 -201
- package/dist/lib/config-migration/detector.test.js.map +0 -1
- package/dist/lib/config-migration/reporter.test.d.ts +0 -5
- package/dist/lib/config-migration/reporter.test.d.ts.map +0 -1
- package/dist/lib/config-migration/reporter.test.js +0 -305
- package/dist/lib/config-migration/reporter.test.js.map +0 -1
- package/dist/lib/config-migration/runner.test.d.ts +0 -5
- package/dist/lib/config-migration/runner.test.d.ts.map +0 -1
- package/dist/lib/config-migration/runner.test.js +0 -235
- package/dist/lib/config-migration/runner.test.js.map +0 -1
- package/dist/lib/config-validation.test.d.ts +0 -5
- package/dist/lib/config-validation.test.d.ts.map +0 -1
- package/dist/lib/config-validation.test.js +0 -423
- package/dist/lib/config-validation.test.js.map +0 -1
- package/dist/lib/config.test.d.ts +0 -2
- package/dist/lib/config.test.d.ts.map +0 -1
- package/dist/lib/config.test.js +0 -554
- package/dist/lib/config.test.js.map +0 -1
- package/dist/lib/constants.test.d.ts +0 -5
- package/dist/lib/constants.test.d.ts.map +0 -1
- package/dist/lib/constants.test.js +0 -180
- package/dist/lib/constants.test.js.map +0 -1
- package/dist/lib/deprecation.test.d.ts +0 -2
- package/dist/lib/deprecation.test.d.ts.map +0 -1
- package/dist/lib/deprecation.test.js +0 -71
- package/dist/lib/deprecation.test.js.map +0 -1
- package/dist/lib/errors.test.d.ts +0 -2
- package/dist/lib/errors.test.d.ts.map +0 -1
- package/dist/lib/errors.test.js +0 -117
- package/dist/lib/errors.test.js.map +0 -1
- package/dist/lib/git.test.d.ts +0 -2
- package/dist/lib/git.test.d.ts.map +0 -1
- package/dist/lib/git.test.js +0 -608
- package/dist/lib/git.test.js.map +0 -1
- package/dist/lib/github.test.d.ts +0 -2
- package/dist/lib/github.test.d.ts.map +0 -1
- package/dist/lib/github.test.js +0 -441
- package/dist/lib/github.test.js.map +0 -1
- package/dist/lib/global-check.test.d.ts +0 -5
- package/dist/lib/global-check.test.d.ts.map +0 -1
- package/dist/lib/global-check.test.js +0 -150
- package/dist/lib/global-check.test.js.map +0 -1
- package/dist/lib/global-config.test.d.ts +0 -5
- package/dist/lib/global-config.test.d.ts.map +0 -1
- package/dist/lib/global-config.test.js +0 -282
- package/dist/lib/global-config.test.js.map +0 -1
- package/dist/lib/hooks/confirmation.test.d.ts +0 -7
- package/dist/lib/hooks/confirmation.test.d.ts.map +0 -1
- package/dist/lib/hooks/confirmation.test.js +0 -300
- package/dist/lib/hooks/confirmation.test.js.map +0 -1
- package/dist/lib/hooks/executor.test.d.ts +0 -5
- package/dist/lib/hooks/executor.test.d.ts.map +0 -1
- package/dist/lib/hooks/executor.test.js +0 -648
- package/dist/lib/hooks/executor.test.js.map +0 -1
- package/dist/lib/hooks/templates.test.d.ts +0 -5
- package/dist/lib/hooks/templates.test.d.ts.map +0 -1
- package/dist/lib/hooks/templates.test.js +0 -163
- package/dist/lib/hooks/templates.test.js.map +0 -1
- package/dist/lib/hooks/types.test.d.ts +0 -5
- package/dist/lib/hooks/types.test.d.ts.map +0 -1
- package/dist/lib/hooks/types.test.js +0 -132
- package/dist/lib/hooks/types.test.js.map +0 -1
- package/dist/lib/json-output.test.d.ts +0 -5
- package/dist/lib/json-output.test.d.ts.map +0 -1
- package/dist/lib/json-output.test.js +0 -261
- package/dist/lib/json-output.test.js.map +0 -1
- package/dist/lib/logger.test.d.ts +0 -14
- package/dist/lib/logger.test.d.ts.map +0 -1
- package/dist/lib/logger.test.js +0 -692
- package/dist/lib/logger.test.js.map +0 -1
- package/dist/lib/lswt/action-executors.test.d.ts +0 -2
- package/dist/lib/lswt/action-executors.test.d.ts.map +0 -1
- package/dist/lib/lswt/action-executors.test.js +0 -1127
- package/dist/lib/lswt/action-executors.test.js.map +0 -1
- package/dist/lib/lswt/actions.test.d.ts +0 -2
- package/dist/lib/lswt/actions.test.d.ts.map +0 -1
- package/dist/lib/lswt/actions.test.js +0 -497
- package/dist/lib/lswt/actions.test.js.map +0 -1
- package/dist/lib/lswt/args.test.d.ts +0 -2
- package/dist/lib/lswt/args.test.d.ts.map +0 -1
- package/dist/lib/lswt/args.test.js +0 -195
- package/dist/lib/lswt/args.test.js.map +0 -1
- package/dist/lib/lswt/environment.test.d.ts +0 -2
- package/dist/lib/lswt/environment.test.d.ts.map +0 -1
- package/dist/lib/lswt/environment.test.js +0 -544
- package/dist/lib/lswt/environment.test.js.map +0 -1
- package/dist/lib/lswt/formatters.test.d.ts +0 -2
- package/dist/lib/lswt/formatters.test.d.ts.map +0 -1
- package/dist/lib/lswt/formatters.test.js +0 -323
- package/dist/lib/lswt/formatters.test.js.map +0 -1
- package/dist/lib/lswt/fuzzy-search.test.d.ts +0 -5
- package/dist/lib/lswt/fuzzy-search.test.d.ts.map +0 -1
- package/dist/lib/lswt/fuzzy-search.test.js +0 -207
- package/dist/lib/lswt/fuzzy-search.test.js.map +0 -1
- package/dist/lib/lswt/interactive.test.d.ts +0 -2
- package/dist/lib/lswt/interactive.test.d.ts.map +0 -1
- package/dist/lib/lswt/interactive.test.js +0 -771
- package/dist/lib/lswt/interactive.test.js.map +0 -1
- package/dist/lib/lswt/table.test.d.ts +0 -5
- package/dist/lib/lswt/table.test.d.ts.map +0 -1
- package/dist/lib/lswt/table.test.js +0 -262
- package/dist/lib/lswt/table.test.js.map +0 -1
- package/dist/lib/lswt/worktree-info.test.d.ts +0 -2
- package/dist/lib/lswt/worktree-info.test.d.ts.map +0 -1
- package/dist/lib/lswt/worktree-info.test.js +0 -484
- package/dist/lib/lswt/worktree-info.test.js.map +0 -1
- package/dist/lib/newpr/action-deps.test.d.ts +0 -5
- package/dist/lib/newpr/action-deps.test.d.ts.map +0 -1
- package/dist/lib/newpr/action-deps.test.js +0 -111
- package/dist/lib/newpr/action-deps.test.js.map +0 -1
- package/dist/lib/newpr/actions.test.d.ts +0 -2
- package/dist/lib/newpr/actions.test.d.ts.map +0 -1
- package/dist/lib/newpr/actions.test.js +0 -254
- package/dist/lib/newpr/actions.test.js.map +0 -1
- package/dist/lib/newpr/args.test.d.ts +0 -2
- package/dist/lib/newpr/args.test.d.ts.map +0 -1
- package/dist/lib/newpr/args.test.js +0 -479
- package/dist/lib/newpr/args.test.js.map +0 -1
- package/dist/lib/newpr/hook-runner.test.d.ts +0 -7
- package/dist/lib/newpr/hook-runner.test.d.ts.map +0 -1
- package/dist/lib/newpr/hook-runner.test.js +0 -422
- package/dist/lib/newpr/hook-runner.test.js.map +0 -1
- package/dist/lib/newpr/plan-generator.test.d.ts +0 -7
- package/dist/lib/newpr/plan-generator.test.d.ts.map +0 -1
- package/dist/lib/newpr/plan-generator.test.js +0 -387
- package/dist/lib/newpr/plan-generator.test.js.map +0 -1
- package/dist/lib/newpr/scenario-handler.test.d.ts +0 -2
- package/dist/lib/newpr/scenario-handler.test.d.ts.map +0 -1
- package/dist/lib/newpr/scenario-handler.test.js +0 -256
- package/dist/lib/newpr/scenario-handler.test.js.map +0 -1
- package/dist/lib/prompts.test.d.ts +0 -2
- package/dist/lib/prompts.test.d.ts.map +0 -1
- package/dist/lib/prompts.test.js +0 -807
- package/dist/lib/prompts.test.js.map +0 -1
- package/dist/lib/prs/actions.test.d.ts +0 -5
- package/dist/lib/prs/actions.test.d.ts.map +0 -1
- package/dist/lib/prs/actions.test.js +0 -356
- package/dist/lib/prs/actions.test.js.map +0 -1
- package/dist/lib/prs/command.test.d.ts +0 -11
- package/dist/lib/prs/command.test.d.ts.map +0 -1
- package/dist/lib/prs/command.test.js +0 -409
- package/dist/lib/prs/command.test.js.map +0 -1
- package/dist/lib/prs/data.test.d.ts +0 -5
- package/dist/lib/prs/data.test.d.ts.map +0 -1
- package/dist/lib/prs/data.test.js +0 -417
- package/dist/lib/prs/data.test.js.map +0 -1
- package/dist/lib/prs/details.test.d.ts +0 -5
- package/dist/lib/prs/details.test.d.ts.map +0 -1
- package/dist/lib/prs/details.test.js +0 -325
- package/dist/lib/prs/details.test.js.map +0 -1
- package/dist/lib/prs/filters.test.d.ts +0 -5
- package/dist/lib/prs/filters.test.d.ts.map +0 -1
- package/dist/lib/prs/filters.test.js +0 -312
- package/dist/lib/prs/filters.test.js.map +0 -1
- package/dist/lib/prs/formatters.test.d.ts +0 -2
- package/dist/lib/prs/formatters.test.d.ts.map +0 -1
- package/dist/lib/prs/formatters.test.js +0 -387
- package/dist/lib/prs/formatters.test.js.map +0 -1
- package/dist/lib/prs/interactive.test.d.ts +0 -5
- package/dist/lib/prs/interactive.test.d.ts.map +0 -1
- package/dist/lib/prs/interactive.test.js +0 -517
- package/dist/lib/prs/interactive.test.js.map +0 -1
- package/dist/lib/schema.test.d.ts +0 -10
- package/dist/lib/schema.test.d.ts.map +0 -1
- package/dist/lib/schema.test.js +0 -309
- package/dist/lib/schema.test.js.map +0 -1
- package/dist/lib/state-detection.test.d.ts +0 -2
- package/dist/lib/state-detection.test.d.ts.map +0 -1
- package/dist/lib/state-detection.test.js +0 -451
- package/dist/lib/state-detection.test.js.map +0 -1
- package/dist/lib/ui/error.test.d.ts +0 -2
- package/dist/lib/ui/error.test.d.ts.map +0 -1
- package/dist/lib/ui/error.test.js +0 -143
- package/dist/lib/ui/error.test.js.map +0 -1
- package/dist/lib/ui/output.test.d.ts +0 -2
- package/dist/lib/ui/output.test.d.ts.map +0 -1
- package/dist/lib/ui/output.test.js +0 -59
- package/dist/lib/ui/output.test.js.map +0 -1
- package/dist/lib/ui/status.test.d.ts +0 -2
- package/dist/lib/ui/status.test.d.ts.map +0 -1
- package/dist/lib/ui/status.test.js +0 -158
- package/dist/lib/ui/status.test.js.map +0 -1
- package/dist/lib/ui/table.test.d.ts +0 -2
- package/dist/lib/ui/table.test.d.ts.map +0 -1
- package/dist/lib/ui/table.test.js +0 -115
- package/dist/lib/ui/table.test.js.map +0 -1
- package/dist/lib/ui/theme.test.d.ts +0 -2
- package/dist/lib/ui/theme.test.d.ts.map +0 -1
- package/dist/lib/ui/theme.test.js +0 -76
- package/dist/lib/ui/theme.test.js.map +0 -1
- package/dist/lib/wtconfig/config-manager.test.d.ts +0 -5
- package/dist/lib/wtconfig/config-manager.test.d.ts.map +0 -1
- package/dist/lib/wtconfig/config-manager.test.js +0 -501
- package/dist/lib/wtconfig/config-manager.test.js.map +0 -1
- package/dist/lib/wtconfig/environment.test.d.ts +0 -5
- package/dist/lib/wtconfig/environment.test.d.ts.map +0 -1
- package/dist/lib/wtconfig/environment.test.js +0 -285
- package/dist/lib/wtconfig/environment.test.js.map +0 -1
- package/dist/lib/wtlink/config-manifest.test.d.ts +0 -2
- package/dist/lib/wtlink/config-manifest.test.d.ts.map +0 -1
- package/dist/lib/wtlink/config-manifest.test.js +0 -486
- package/dist/lib/wtlink/config-manifest.test.js.map +0 -1
- package/dist/lib/wtlink/link-configs.test.d.ts +0 -2
- package/dist/lib/wtlink/link-configs.test.d.ts.map +0 -1
- package/dist/lib/wtlink/link-configs.test.js +0 -612
- package/dist/lib/wtlink/link-configs.test.js.map +0 -1
- package/dist/lib/wtlink/main-menu.test.d.ts +0 -5
- package/dist/lib/wtlink/main-menu.test.d.ts.map +0 -1
- package/dist/lib/wtlink/main-menu.test.js +0 -126
- package/dist/lib/wtlink/main-menu.test.js.map +0 -1
- package/dist/lib/wtlink/manage-manifest.test.d.ts +0 -2
- package/dist/lib/wtlink/manage-manifest.test.d.ts.map +0 -1
- package/dist/lib/wtlink/manage-manifest.test.js +0 -714
- package/dist/lib/wtlink/manage-manifest.test.js.map +0 -1
- package/dist/lib/wtlink/validate-manifest.test.d.ts +0 -2
- package/dist/lib/wtlink/validate-manifest.test.d.ts.map +0 -1
- package/dist/lib/wtlink/validate-manifest.test.js +0 -220
- package/dist/lib/wtlink/validate-manifest.test.js.map +0 -1
- package/dist/lib/wtstate/analyze.test.d.ts +0 -5
- package/dist/lib/wtstate/analyze.test.d.ts.map +0 -1
- package/dist/lib/wtstate/analyze.test.js +0 -282
- package/dist/lib/wtstate/analyze.test.js.map +0 -1
- package/dist/lib/wtstate/args.test.d.ts +0 -5
- package/dist/lib/wtstate/args.test.d.ts.map +0 -1
- package/dist/lib/wtstate/args.test.js +0 -120
- package/dist/lib/wtstate/args.test.js.map +0 -1
- package/dist/mcp/server.test.d.ts +0 -9
- package/dist/mcp/server.test.d.ts.map +0 -1
- package/dist/mcp/server.test.js +0 -550
- package/dist/mcp/server.test.js.map +0 -1
|
@@ -1,796 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for interactive menu flows
|
|
3
|
-
*
|
|
4
|
-
* These tests verify that each menu flow:
|
|
5
|
-
* 1. Gathers the correct user inputs
|
|
6
|
-
* 2. Calls the correct library functions with proper arguments
|
|
7
|
-
* 3. Returns to menu after operation execution (not exit)
|
|
8
|
-
* 4. Handles cancellation and back navigation correctly
|
|
9
|
-
* 5. Uses direct library calls (no subprocess spawning)
|
|
10
|
-
*/
|
|
11
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
12
|
-
// Mock modules before importing the module under test
|
|
13
|
-
vi.mock('../../lib/prompts.js', () => {
|
|
14
|
-
// Define UserNavigatedBack inside the factory to avoid hoisting issues
|
|
15
|
-
class MockUserNavigatedBack extends Error {
|
|
16
|
-
constructor() {
|
|
17
|
-
super('User navigated back');
|
|
18
|
-
this.name = 'UserNavigatedBack';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
promptChoice: vi.fn(),
|
|
23
|
-
promptInput: vi.fn(),
|
|
24
|
-
promptConfirm: vi.fn(),
|
|
25
|
-
UserNavigatedBack: MockUserNavigatedBack,
|
|
26
|
-
};
|
|
27
|
-
});
|
|
28
|
-
vi.mock('../../lib/config.js', () => ({
|
|
29
|
-
loadConfig: vi.fn(() => ({
|
|
30
|
-
configVersion: 1,
|
|
31
|
-
sharedRepos: [],
|
|
32
|
-
baseBranch: 'main',
|
|
33
|
-
draftPr: true,
|
|
34
|
-
worktreePattern: '{repo}.pr{number}',
|
|
35
|
-
worktreeParent: '..',
|
|
36
|
-
syncPatterns: [],
|
|
37
|
-
branchPrefix: 'feat',
|
|
38
|
-
previewLabel: 'preview',
|
|
39
|
-
preferredEditor: 'vscode',
|
|
40
|
-
ai: {
|
|
41
|
-
provider: 'auto',
|
|
42
|
-
fallback: 'none',
|
|
43
|
-
branchName: false,
|
|
44
|
-
prTitle: false,
|
|
45
|
-
prDescription: false,
|
|
46
|
-
commitMessage: false,
|
|
47
|
-
planDocument: false,
|
|
48
|
-
},
|
|
49
|
-
hooks: {},
|
|
50
|
-
hookDefaults: { timeout: 30000, maxTimeout: 60000 },
|
|
51
|
-
plugins: [],
|
|
52
|
-
generators: {},
|
|
53
|
-
integrations: {},
|
|
54
|
-
logging: { level: 'info', timestamps: true },
|
|
55
|
-
global: { warnNotGlobal: true },
|
|
56
|
-
wtlink: { enabled: [], disabled: [] },
|
|
57
|
-
})),
|
|
58
|
-
}));
|
|
59
|
-
vi.mock('../../lib/git.js', () => ({
|
|
60
|
-
getRepoRoot: vi.fn(() => '/mock/repo'),
|
|
61
|
-
listLocalBranches: vi.fn(() => ['feat/existing-branch', 'fix/bug-fix', 'main', 'develop']),
|
|
62
|
-
removeWorktree: vi.fn(),
|
|
63
|
-
pruneWorktrees: vi.fn(),
|
|
64
|
-
}));
|
|
65
|
-
vi.mock('../../lib/wtlink/config-manifest.js', () => ({
|
|
66
|
-
loadManifestData: vi.fn(() => ({
|
|
67
|
-
enabled: ['.env', '.env.local'],
|
|
68
|
-
disabled: ['config.json'],
|
|
69
|
-
source: 'config',
|
|
70
|
-
})),
|
|
71
|
-
saveManifestData: vi.fn(),
|
|
72
|
-
}));
|
|
73
|
-
// Mock direct library imports
|
|
74
|
-
vi.mock('../../lib/lswt/index.js', () => ({
|
|
75
|
-
gatherWorktreeInfo: vi.fn(async () => []),
|
|
76
|
-
createDefaultDeps: vi.fn(() => ({})),
|
|
77
|
-
runInteractiveMode: vi.fn(async () => { }),
|
|
78
|
-
}));
|
|
79
|
-
vi.mock('../../lib/prs/command.js', () => ({
|
|
80
|
-
runPrsCommand: vi.fn(async () => { }),
|
|
81
|
-
}));
|
|
82
|
-
vi.mock('../newpr.js', () => ({
|
|
83
|
-
runNewprHandler: vi.fn(async () => { }),
|
|
84
|
-
}));
|
|
85
|
-
vi.mock('../../lib/cleanpr/index.js', () => ({
|
|
86
|
-
gatherPrWorktreeInfo: vi.fn(async () => []),
|
|
87
|
-
createDefaultDeps: vi.fn(() => ({})),
|
|
88
|
-
getCleanableWorktrees: vi.fn(() => []),
|
|
89
|
-
cleanWorktree: vi.fn(() => ({ success: true, message: 'Cleaned', prNumber: 42 })),
|
|
90
|
-
findWorktreeByPrNumber: vi.fn(() => null),
|
|
91
|
-
summarizeResults: vi.fn(() => ({ cleaned: 0, total: 0 })),
|
|
92
|
-
}));
|
|
93
|
-
vi.mock('../../lib/wtstate/index.js', () => ({
|
|
94
|
-
analyzeState: vi.fn(() => ({
|
|
95
|
-
scenario: 'main_clean_same',
|
|
96
|
-
scenarioDescription: 'On main, clean, same as origin',
|
|
97
|
-
currentBranch: 'main',
|
|
98
|
-
baseBranch: 'main',
|
|
99
|
-
worktreeType: 'main_worktree',
|
|
100
|
-
hasChanges: false,
|
|
101
|
-
hasStagedChanges: false,
|
|
102
|
-
hasUnstagedChanges: false,
|
|
103
|
-
localCommits: 0,
|
|
104
|
-
stagedFiles: [],
|
|
105
|
-
unstagedFiles: [],
|
|
106
|
-
availableActions: [],
|
|
107
|
-
recommendedAction: null,
|
|
108
|
-
})),
|
|
109
|
-
formatText: vi.fn(() => 'State: main_clean_same'),
|
|
110
|
-
}));
|
|
111
|
-
vi.mock('../../lib/wtlink/link-configs.js', () => ({
|
|
112
|
-
run: vi.fn(async () => { }),
|
|
113
|
-
}));
|
|
114
|
-
vi.mock('../../lib/wtlink/validate-manifest.js', () => ({
|
|
115
|
-
run: vi.fn(() => { }),
|
|
116
|
-
}));
|
|
117
|
-
vi.mock('../../lib/wtconfig/index.js', () => ({
|
|
118
|
-
formatConfigDisplay: vi.fn(() => '{ baseBranch: "main" }'),
|
|
119
|
-
setConfigValue: vi.fn((config, _key, _value) => config),
|
|
120
|
-
loadRepoConfig: vi.fn(() => ({})),
|
|
121
|
-
saveRepoConfig: vi.fn(),
|
|
122
|
-
validateConfig: vi.fn(() => ({ valid: true, errors: [], warnings: [] })),
|
|
123
|
-
}));
|
|
124
|
-
vi.mock('../../lib/constants.js', () => ({
|
|
125
|
-
DEFAULT_MANIFEST_FILE: '.wtlinkrc',
|
|
126
|
-
}));
|
|
127
|
-
vi.mock('../../lib/ui/index.js', () => ({
|
|
128
|
-
printStatus: vi.fn(),
|
|
129
|
-
}));
|
|
130
|
-
vi.mock('child_process', () => ({
|
|
131
|
-
execSync: vi.fn(),
|
|
132
|
-
}));
|
|
133
|
-
// Import mocked modules
|
|
134
|
-
import { promptChoice, promptInput, promptConfirm } from '../../lib/prompts.js';
|
|
135
|
-
import { loadConfig } from '../../lib/config.js';
|
|
136
|
-
import * as git from '../../lib/git.js';
|
|
137
|
-
import { loadManifestData, saveManifestData } from '../../lib/wtlink/config-manifest.js';
|
|
138
|
-
import { gatherWorktreeInfo, runInteractiveMode } from '../../lib/lswt/index.js';
|
|
139
|
-
import { runPrsCommand } from '../../lib/prs/command.js';
|
|
140
|
-
import { runNewprHandler } from '../newpr.js';
|
|
141
|
-
import { gatherPrWorktreeInfo, getCleanableWorktrees, } from '../../lib/cleanpr/index.js';
|
|
142
|
-
import { analyzeState, formatText } from '../../lib/wtstate/index.js';
|
|
143
|
-
import { run as runWtlinkLink } from '../../lib/wtlink/link-configs.js';
|
|
144
|
-
import { run as runWtlinkValidate } from '../../lib/wtlink/validate-manifest.js';
|
|
145
|
-
import { formatConfigDisplay, setConfigValue, loadRepoConfig, saveRepoConfig, } from '../../lib/wtconfig/index.js';
|
|
146
|
-
// Import flows after mocks are set up
|
|
147
|
-
import { flows, showMainMenu } from './interactive-menu.js';
|
|
148
|
-
// Mock console.log to keep test output clean
|
|
149
|
-
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
150
|
-
describe('Interactive Menu Flows', () => {
|
|
151
|
-
beforeEach(() => {
|
|
152
|
-
vi.clearAllMocks();
|
|
153
|
-
});
|
|
154
|
-
afterEach(() => {
|
|
155
|
-
consoleSpy.mockClear();
|
|
156
|
-
});
|
|
157
|
-
describe('handleListWorktrees', () => {
|
|
158
|
-
it('calls gatherWorktreeInfo and runInteractiveMode and returns to menu', async () => {
|
|
159
|
-
const result = await flows.handleListWorktrees();
|
|
160
|
-
expect(gatherWorktreeInfo).toHaveBeenCalledWith('/mock/repo', { verbose: false, json: false, showStatus: false }, expect.anything());
|
|
161
|
-
expect(runInteractiveMode).toHaveBeenCalled();
|
|
162
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
163
|
-
});
|
|
164
|
-
it('returns to menu with error message when library call fails', async () => {
|
|
165
|
-
vi.mocked(gatherWorktreeInfo).mockRejectedValueOnce(new Error('git error'));
|
|
166
|
-
const result = await flows.handleListWorktrees();
|
|
167
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
168
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('git error'));
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
describe('handleBrowsePRs', () => {
|
|
172
|
-
it('calls runPrsCommand and returns to menu', async () => {
|
|
173
|
-
const result = await flows.handleBrowsePRs();
|
|
174
|
-
expect(runPrsCommand).toHaveBeenCalledWith({
|
|
175
|
-
state: 'open',
|
|
176
|
-
limit: 50,
|
|
177
|
-
json: false,
|
|
178
|
-
noInteractive: false,
|
|
179
|
-
});
|
|
180
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
describe('handleShowState', () => {
|
|
184
|
-
it('calls analyzeState and formatText and returns to menu', async () => {
|
|
185
|
-
const result = await flows.handleShowState();
|
|
186
|
-
expect(analyzeState).toHaveBeenCalledWith({
|
|
187
|
-
verbose: false,
|
|
188
|
-
json: false,
|
|
189
|
-
baseBranch: 'main',
|
|
190
|
-
});
|
|
191
|
-
expect(formatText).toHaveBeenCalled();
|
|
192
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
describe('handleNewPR', () => {
|
|
196
|
-
it('returns CANCELLED when user selects back', async () => {
|
|
197
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('back');
|
|
198
|
-
const result = await flows.handleNewPR();
|
|
199
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
200
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
201
|
-
});
|
|
202
|
-
it('handles user cancellation (Ctrl+C)', async () => {
|
|
203
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
|
|
204
|
-
const result = await flows.handleNewPR();
|
|
205
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
206
|
-
});
|
|
207
|
-
describe('from-description flow', () => {
|
|
208
|
-
it('gathers all inputs and calls runNewprHandler with correct Options', async () => {
|
|
209
|
-
vi.mocked(promptChoice)
|
|
210
|
-
.mockResolvedValueOnce('from-description') // New PR sub-menu
|
|
211
|
-
.mockResolvedValueOnce(true); // Draft PR selection
|
|
212
|
-
vi.mocked(promptInput)
|
|
213
|
-
.mockResolvedValueOnce('Add dark mode support') // Description
|
|
214
|
-
.mockResolvedValueOnce('main'); // Base branch
|
|
215
|
-
vi.mocked(promptConfirm)
|
|
216
|
-
.mockResolvedValueOnce(false) // Install deps
|
|
217
|
-
.mockResolvedValueOnce(false); // Open VS Code
|
|
218
|
-
const result = await flows.handleNewPR();
|
|
219
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
220
|
-
mode: 'new',
|
|
221
|
-
description: 'Add dark mode support',
|
|
222
|
-
baseBranch: 'main',
|
|
223
|
-
draft: true,
|
|
224
|
-
installDeps: false,
|
|
225
|
-
openEditor: false,
|
|
226
|
-
}));
|
|
227
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
228
|
-
});
|
|
229
|
-
it('passes ready flag when not draft', async () => {
|
|
230
|
-
vi.mocked(promptChoice)
|
|
231
|
-
.mockResolvedValueOnce('from-description')
|
|
232
|
-
.mockResolvedValueOnce(false); // Ready for review (not draft)
|
|
233
|
-
vi.mocked(promptInput)
|
|
234
|
-
.mockResolvedValueOnce('Fix critical bug')
|
|
235
|
-
.mockResolvedValueOnce('main');
|
|
236
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
237
|
-
const result = await flows.handleNewPR();
|
|
238
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
239
|
-
mode: 'new',
|
|
240
|
-
description: 'Fix critical bug',
|
|
241
|
-
draft: false,
|
|
242
|
-
}));
|
|
243
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
244
|
-
});
|
|
245
|
-
it('passes non-main base branch', async () => {
|
|
246
|
-
vi.mocked(promptChoice)
|
|
247
|
-
.mockResolvedValueOnce('from-description')
|
|
248
|
-
.mockResolvedValueOnce(true);
|
|
249
|
-
vi.mocked(promptInput)
|
|
250
|
-
.mockResolvedValueOnce('Feature work')
|
|
251
|
-
.mockResolvedValueOnce('develop'); // Non-main base branch
|
|
252
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
253
|
-
const result = await flows.handleNewPR();
|
|
254
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
255
|
-
baseBranch: 'develop',
|
|
256
|
-
}));
|
|
257
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
258
|
-
});
|
|
259
|
-
it('passes install flag when requested', async () => {
|
|
260
|
-
vi.mocked(promptChoice)
|
|
261
|
-
.mockResolvedValueOnce('from-description')
|
|
262
|
-
.mockResolvedValueOnce(true);
|
|
263
|
-
vi.mocked(promptInput).mockResolvedValueOnce('Add feature').mockResolvedValueOnce('main');
|
|
264
|
-
vi.mocked(promptConfirm)
|
|
265
|
-
.mockResolvedValueOnce(true) // Install deps
|
|
266
|
-
.mockResolvedValueOnce(false);
|
|
267
|
-
const result = await flows.handleNewPR();
|
|
268
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
269
|
-
installDeps: true,
|
|
270
|
-
}));
|
|
271
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
272
|
-
});
|
|
273
|
-
it('passes code flag when requested', async () => {
|
|
274
|
-
vi.mocked(promptChoice)
|
|
275
|
-
.mockResolvedValueOnce('from-description')
|
|
276
|
-
.mockResolvedValueOnce(true);
|
|
277
|
-
vi.mocked(promptInput).mockResolvedValueOnce('Add feature').mockResolvedValueOnce('main');
|
|
278
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(true); // Open VS Code
|
|
279
|
-
const result = await flows.handleNewPR();
|
|
280
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
281
|
-
openEditor: true,
|
|
282
|
-
}));
|
|
283
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
284
|
-
});
|
|
285
|
-
it('passes all optional flags together', async () => {
|
|
286
|
-
vi.mocked(promptChoice)
|
|
287
|
-
.mockResolvedValueOnce('from-description')
|
|
288
|
-
.mockResolvedValueOnce(false); // Ready
|
|
289
|
-
vi.mocked(promptInput)
|
|
290
|
-
.mockResolvedValueOnce('Full feature')
|
|
291
|
-
.mockResolvedValueOnce('develop');
|
|
292
|
-
vi.mocked(promptConfirm)
|
|
293
|
-
.mockResolvedValueOnce(true) // Install
|
|
294
|
-
.mockResolvedValueOnce(true); // VS Code
|
|
295
|
-
const result = await flows.handleNewPR();
|
|
296
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
297
|
-
mode: 'new',
|
|
298
|
-
description: 'Full feature',
|
|
299
|
-
baseBranch: 'develop',
|
|
300
|
-
draft: false,
|
|
301
|
-
installDeps: true,
|
|
302
|
-
openEditor: true,
|
|
303
|
-
}));
|
|
304
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
305
|
-
});
|
|
306
|
-
it('returns CANCELLED when description is empty', async () => {
|
|
307
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-description');
|
|
308
|
-
vi.mocked(promptInput).mockResolvedValueOnce(''); // Empty description
|
|
309
|
-
const result = await flows.handleNewPR();
|
|
310
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
311
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
312
|
-
});
|
|
313
|
-
it('handles user cancellation during input', async () => {
|
|
314
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-description');
|
|
315
|
-
vi.mocked(promptInput).mockRejectedValueOnce(new Error('User cancelled'));
|
|
316
|
-
const result = await flows.handleNewPR();
|
|
317
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
318
|
-
});
|
|
319
|
-
});
|
|
320
|
-
describe('from-pr flow', () => {
|
|
321
|
-
it('gathers PR number and calls runNewprHandler with mode pr', async () => {
|
|
322
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
323
|
-
vi.mocked(promptInput).mockResolvedValueOnce('42');
|
|
324
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
325
|
-
const result = await flows.handleNewPR();
|
|
326
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
327
|
-
mode: 'pr',
|
|
328
|
-
prNumber: 42,
|
|
329
|
-
}));
|
|
330
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
331
|
-
});
|
|
332
|
-
it('passes install and code flags', async () => {
|
|
333
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
334
|
-
vi.mocked(promptInput).mockResolvedValueOnce('123');
|
|
335
|
-
vi.mocked(promptConfirm)
|
|
336
|
-
.mockResolvedValueOnce(true) // Install
|
|
337
|
-
.mockResolvedValueOnce(true); // VS Code
|
|
338
|
-
const result = await flows.handleNewPR();
|
|
339
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
340
|
-
mode: 'pr',
|
|
341
|
-
prNumber: 123,
|
|
342
|
-
installDeps: true,
|
|
343
|
-
openEditor: true,
|
|
344
|
-
}));
|
|
345
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
346
|
-
});
|
|
347
|
-
it('returns CANCELLED when PR number is empty', async () => {
|
|
348
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
349
|
-
vi.mocked(promptInput).mockResolvedValueOnce('');
|
|
350
|
-
const result = await flows.handleNewPR();
|
|
351
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
352
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
353
|
-
});
|
|
354
|
-
it('returns CANCELLED when PR number is invalid', async () => {
|
|
355
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
356
|
-
vi.mocked(promptInput).mockResolvedValueOnce('not-a-number');
|
|
357
|
-
const result = await flows.handleNewPR();
|
|
358
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
359
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
360
|
-
});
|
|
361
|
-
it('returns CANCELLED when PR number is zero', async () => {
|
|
362
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
363
|
-
vi.mocked(promptInput).mockResolvedValueOnce('0');
|
|
364
|
-
const result = await flows.handleNewPR();
|
|
365
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
366
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
367
|
-
});
|
|
368
|
-
it('returns CANCELLED when PR number is negative', async () => {
|
|
369
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
|
|
370
|
-
vi.mocked(promptInput).mockResolvedValueOnce('-5');
|
|
371
|
-
const result = await flows.handleNewPR();
|
|
372
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
373
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
|
-
describe('from-branch flow', () => {
|
|
377
|
-
it('allows selecting from existing branches', async () => {
|
|
378
|
-
vi.mocked(promptChoice)
|
|
379
|
-
.mockResolvedValueOnce('from-branch') // New PR sub-menu
|
|
380
|
-
.mockResolvedValueOnce('feat/existing-branch') // Select branch
|
|
381
|
-
.mockResolvedValueOnce(true); // Draft PR
|
|
382
|
-
vi.mocked(promptInput).mockResolvedValueOnce('main');
|
|
383
|
-
const result = await flows.handleNewPR();
|
|
384
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
385
|
-
mode: 'branch',
|
|
386
|
-
branchName: 'feat/existing-branch',
|
|
387
|
-
}));
|
|
388
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
389
|
-
});
|
|
390
|
-
it('allows typing custom branch name', async () => {
|
|
391
|
-
vi.mocked(promptChoice)
|
|
392
|
-
.mockResolvedValueOnce('from-branch')
|
|
393
|
-
.mockResolvedValueOnce('__custom__') // Select custom option
|
|
394
|
-
.mockResolvedValueOnce(true);
|
|
395
|
-
vi.mocked(promptInput)
|
|
396
|
-
.mockResolvedValueOnce('feat/my-new-branch') // Custom branch name
|
|
397
|
-
.mockResolvedValueOnce('main');
|
|
398
|
-
const result = await flows.handleNewPR();
|
|
399
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
400
|
-
mode: 'branch',
|
|
401
|
-
branchName: 'feat/my-new-branch',
|
|
402
|
-
}));
|
|
403
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
404
|
-
});
|
|
405
|
-
it('passes non-main base branch and ready flag', async () => {
|
|
406
|
-
vi.mocked(promptChoice)
|
|
407
|
-
.mockResolvedValueOnce('from-branch')
|
|
408
|
-
.mockResolvedValueOnce('fix/bug-fix')
|
|
409
|
-
.mockResolvedValueOnce(false); // Ready for review
|
|
410
|
-
vi.mocked(promptInput).mockResolvedValueOnce('develop');
|
|
411
|
-
const result = await flows.handleNewPR();
|
|
412
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
413
|
-
mode: 'branch',
|
|
414
|
-
branchName: 'fix/bug-fix',
|
|
415
|
-
baseBranch: 'develop',
|
|
416
|
-
draft: false,
|
|
417
|
-
}));
|
|
418
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
419
|
-
});
|
|
420
|
-
it('returns CANCELLED when branch name is empty', async () => {
|
|
421
|
-
vi.mocked(promptChoice)
|
|
422
|
-
.mockResolvedValueOnce('from-branch')
|
|
423
|
-
.mockResolvedValueOnce('__custom__');
|
|
424
|
-
vi.mocked(promptInput).mockResolvedValueOnce(''); // Empty branch name
|
|
425
|
-
const result = await flows.handleNewPR();
|
|
426
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
427
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
428
|
-
});
|
|
429
|
-
it('handles empty branch list gracefully', async () => {
|
|
430
|
-
// Mock empty branch list
|
|
431
|
-
vi.mocked(git.listLocalBranches).mockReturnValueOnce([]);
|
|
432
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-branch');
|
|
433
|
-
vi.mocked(promptInput)
|
|
434
|
-
.mockResolvedValueOnce('feat/new-branch') // Manual branch input
|
|
435
|
-
.mockResolvedValueOnce('main');
|
|
436
|
-
vi.mocked(promptChoice).mockResolvedValueOnce(true); // Draft
|
|
437
|
-
const result = await flows.handleNewPR();
|
|
438
|
-
// Should have prompted for branch name directly
|
|
439
|
-
expect(promptInput).toHaveBeenCalledWith('Branch name');
|
|
440
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
441
|
-
});
|
|
442
|
-
});
|
|
443
|
-
});
|
|
444
|
-
describe('handleCleanPRs', () => {
|
|
445
|
-
it('returns CANCELLED when user selects back', async () => {
|
|
446
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('back');
|
|
447
|
-
const result = await flows.handleCleanPRs();
|
|
448
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
449
|
-
expect(gatherPrWorktreeInfo).not.toHaveBeenCalled();
|
|
450
|
-
});
|
|
451
|
-
describe('clean-all', () => {
|
|
452
|
-
it('calls cleanpr library after confirmation and returns to menu', async () => {
|
|
453
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('clean-all');
|
|
454
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(true);
|
|
455
|
-
const result = await flows.handleCleanPRs();
|
|
456
|
-
expect(gatherPrWorktreeInfo).toHaveBeenCalled();
|
|
457
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
458
|
-
});
|
|
459
|
-
it('returns CANCELLED when not confirmed', async () => {
|
|
460
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('clean-all');
|
|
461
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false);
|
|
462
|
-
const result = await flows.handleCleanPRs();
|
|
463
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
464
|
-
expect(gatherPrWorktreeInfo).not.toHaveBeenCalled();
|
|
465
|
-
});
|
|
466
|
-
});
|
|
467
|
-
describe('clean-specific', () => {
|
|
468
|
-
it('calls cleanpr with PR number and returns to menu', async () => {
|
|
469
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
|
|
470
|
-
vi.mocked(promptInput).mockResolvedValueOnce('42');
|
|
471
|
-
const result = await flows.handleCleanPRs();
|
|
472
|
-
expect(gatherPrWorktreeInfo).toHaveBeenCalled();
|
|
473
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
474
|
-
});
|
|
475
|
-
it('returns CANCELLED when PR number is empty', async () => {
|
|
476
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
|
|
477
|
-
vi.mocked(promptInput).mockResolvedValueOnce('');
|
|
478
|
-
const result = await flows.handleCleanPRs();
|
|
479
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
480
|
-
});
|
|
481
|
-
it('returns CANCELLED when PR number is invalid', async () => {
|
|
482
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
|
|
483
|
-
vi.mocked(promptInput).mockResolvedValueOnce('invalid');
|
|
484
|
-
const result = await flows.handleCleanPRs();
|
|
485
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
describe('dry-run', () => {
|
|
489
|
-
it('calls cleanpr with dry-run and returns to menu', async () => {
|
|
490
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('dry-run');
|
|
491
|
-
const result = await flows.handleCleanPRs();
|
|
492
|
-
expect(gatherPrWorktreeInfo).toHaveBeenCalled();
|
|
493
|
-
expect(getCleanableWorktrees).toHaveBeenCalled();
|
|
494
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
495
|
-
});
|
|
496
|
-
});
|
|
497
|
-
it('handles user cancellation', async () => {
|
|
498
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
|
|
499
|
-
const result = await flows.handleCleanPRs();
|
|
500
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
501
|
-
});
|
|
502
|
-
});
|
|
503
|
-
describe('handleLinkConfig', () => {
|
|
504
|
-
it('returns CANCELLED when user selects back', async () => {
|
|
505
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('back');
|
|
506
|
-
const result = await flows.handleLinkConfig();
|
|
507
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
508
|
-
});
|
|
509
|
-
describe('view via library', () => {
|
|
510
|
-
it('displays manifest contents from loadManifestData', async () => {
|
|
511
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('view');
|
|
512
|
-
const result = await flows.handleLinkConfig();
|
|
513
|
-
expect(loadManifestData).toHaveBeenCalledWith('/mock/repo');
|
|
514
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
515
|
-
});
|
|
516
|
-
it('shows empty message when manifest has no files', async () => {
|
|
517
|
-
vi.mocked(loadManifestData).mockReturnValueOnce({
|
|
518
|
-
enabled: [],
|
|
519
|
-
disabled: [],
|
|
520
|
-
source: 'empty',
|
|
521
|
-
});
|
|
522
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('view');
|
|
523
|
-
const result = await flows.handleLinkConfig();
|
|
524
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
525
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('No files'));
|
|
526
|
-
});
|
|
527
|
-
it('displays enabled and disabled files', async () => {
|
|
528
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('view');
|
|
529
|
-
const result = await flows.handleLinkConfig();
|
|
530
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
531
|
-
// Check enabled files are shown
|
|
532
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Enabled'));
|
|
533
|
-
expect(consoleSpy).toHaveBeenCalledWith(' .env');
|
|
534
|
-
expect(consoleSpy).toHaveBeenCalledWith(' .env.local');
|
|
535
|
-
// Check disabled files are shown
|
|
536
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Disabled'));
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
describe('sync via wtlink link', () => {
|
|
540
|
-
it('calls wtlink link library function', async () => {
|
|
541
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('sync');
|
|
542
|
-
const result = await flows.handleLinkConfig();
|
|
543
|
-
expect(runWtlinkLink).toHaveBeenCalledWith(expect.objectContaining({
|
|
544
|
-
manifestFile: '.wtlinkrc',
|
|
545
|
-
dryRun: false,
|
|
546
|
-
type: 'hard',
|
|
547
|
-
}));
|
|
548
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
549
|
-
});
|
|
550
|
-
it('shows error when sync fails', async () => {
|
|
551
|
-
vi.mocked(runWtlinkLink).mockRejectedValueOnce(new Error('Link failed'));
|
|
552
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('sync');
|
|
553
|
-
const result = await flows.handleLinkConfig();
|
|
554
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
555
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Link failed'));
|
|
556
|
-
});
|
|
557
|
-
});
|
|
558
|
-
describe('add via library', () => {
|
|
559
|
-
it('adds file to manifest via saveManifestData', async () => {
|
|
560
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('add');
|
|
561
|
-
vi.mocked(promptInput).mockResolvedValueOnce('.npmrc');
|
|
562
|
-
const result = await flows.handleLinkConfig();
|
|
563
|
-
expect(saveManifestData).toHaveBeenCalledWith('/mock/repo', ['.env', '.env.local', '.npmrc'], ['config.json']);
|
|
564
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
565
|
-
});
|
|
566
|
-
it('skips duplicate files', async () => {
|
|
567
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('add');
|
|
568
|
-
vi.mocked(promptInput).mockResolvedValueOnce('.env');
|
|
569
|
-
const result = await flows.handleLinkConfig();
|
|
570
|
-
expect(saveManifestData).not.toHaveBeenCalled();
|
|
571
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
572
|
-
});
|
|
573
|
-
it('returns CANCELLED when file path is empty', async () => {
|
|
574
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('add');
|
|
575
|
-
vi.mocked(promptInput).mockResolvedValueOnce('');
|
|
576
|
-
const result = await flows.handleLinkConfig();
|
|
577
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
578
|
-
expect(saveManifestData).not.toHaveBeenCalled();
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
describe('remove via library', () => {
|
|
582
|
-
it('removes file from manifest via saveManifestData', async () => {
|
|
583
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('remove');
|
|
584
|
-
vi.mocked(promptInput).mockResolvedValueOnce('.env');
|
|
585
|
-
const result = await flows.handleLinkConfig();
|
|
586
|
-
expect(saveManifestData).toHaveBeenCalledWith('/mock/repo', ['.env.local'], ['config.json']);
|
|
587
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
588
|
-
});
|
|
589
|
-
it('handles file not in manifest', async () => {
|
|
590
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('remove');
|
|
591
|
-
vi.mocked(promptInput).mockResolvedValueOnce('nonexistent.txt');
|
|
592
|
-
const result = await flows.handleLinkConfig();
|
|
593
|
-
expect(saveManifestData).not.toHaveBeenCalled();
|
|
594
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
595
|
-
});
|
|
596
|
-
it('returns CANCELLED when file path is empty', async () => {
|
|
597
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('remove');
|
|
598
|
-
vi.mocked(promptInput).mockResolvedValueOnce('');
|
|
599
|
-
const result = await flows.handleLinkConfig();
|
|
600
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
601
|
-
});
|
|
602
|
-
});
|
|
603
|
-
describe('validate', () => {
|
|
604
|
-
it('calls wtlink validate and returns to menu', async () => {
|
|
605
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('validate');
|
|
606
|
-
const result = await flows.handleLinkConfig();
|
|
607
|
-
expect(runWtlinkValidate).toHaveBeenCalledWith(expect.objectContaining({
|
|
608
|
-
manifestFile: '.wtlinkrc',
|
|
609
|
-
}));
|
|
610
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
611
|
-
});
|
|
612
|
-
});
|
|
613
|
-
it('handles user cancellation', async () => {
|
|
614
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
|
|
615
|
-
const result = await flows.handleLinkConfig();
|
|
616
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
describe('handleConfigure', () => {
|
|
620
|
-
it('returns CANCELLED when user selects back', async () => {
|
|
621
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('back');
|
|
622
|
-
const result = await flows.handleConfigure();
|
|
623
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
624
|
-
});
|
|
625
|
-
it('view calls formatConfigDisplay and returns to menu', async () => {
|
|
626
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('view');
|
|
627
|
-
const result = await flows.handleConfigure();
|
|
628
|
-
expect(loadRepoConfig).toHaveBeenCalledWith('/mock/repo');
|
|
629
|
-
expect(formatConfigDisplay).toHaveBeenCalled();
|
|
630
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
631
|
-
});
|
|
632
|
-
it('init shows redirect message after confirmation and returns to menu', async () => {
|
|
633
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('init');
|
|
634
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(true);
|
|
635
|
-
const result = await flows.handleConfigure();
|
|
636
|
-
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('wt init'));
|
|
637
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
638
|
-
});
|
|
639
|
-
it('init returns CANCELLED when not confirmed', async () => {
|
|
640
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('init');
|
|
641
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false);
|
|
642
|
-
const result = await flows.handleConfigure();
|
|
643
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
644
|
-
});
|
|
645
|
-
it('edit calls setConfigValue and saveRepoConfig with setting and value', async () => {
|
|
646
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('edit').mockResolvedValueOnce('baseBranch');
|
|
647
|
-
vi.mocked(promptInput).mockResolvedValueOnce('develop');
|
|
648
|
-
const result = await flows.handleConfigure();
|
|
649
|
-
expect(setConfigValue).toHaveBeenCalledWith({}, 'baseBranch', 'develop');
|
|
650
|
-
expect(saveRepoConfig).toHaveBeenCalled();
|
|
651
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
652
|
-
});
|
|
653
|
-
it('edit returns CANCELLED when value is empty', async () => {
|
|
654
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('edit').mockResolvedValueOnce('branchPrefix');
|
|
655
|
-
vi.mocked(promptInput).mockResolvedValueOnce('');
|
|
656
|
-
const result = await flows.handleConfigure();
|
|
657
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
658
|
-
expect(saveRepoConfig).not.toHaveBeenCalled();
|
|
659
|
-
});
|
|
660
|
-
it('handles user cancellation', async () => {
|
|
661
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
|
|
662
|
-
const result = await flows.handleConfigure();
|
|
663
|
-
expect(result).toEqual({ completed: false, returnToMenu: true });
|
|
664
|
-
});
|
|
665
|
-
});
|
|
666
|
-
describe('showMainMenu', () => {
|
|
667
|
-
it('exits on exit selection', async () => {
|
|
668
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('exit');
|
|
669
|
-
await showMainMenu();
|
|
670
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
671
|
-
});
|
|
672
|
-
it('exits on user cancellation', async () => {
|
|
673
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
|
|
674
|
-
await showMainMenu();
|
|
675
|
-
expect(runNewprHandler).not.toHaveBeenCalled();
|
|
676
|
-
});
|
|
677
|
-
it('re-throws non-cancellation errors', async () => {
|
|
678
|
-
vi.mocked(promptChoice).mockRejectedValueOnce(new Error('Some other error'));
|
|
679
|
-
await expect(showMainMenu()).rejects.toThrow('Some other error');
|
|
680
|
-
});
|
|
681
|
-
it('returns to menu when flow returns returnToMenu=true', async () => {
|
|
682
|
-
vi.mocked(promptChoice)
|
|
683
|
-
.mockResolvedValueOnce('new-pr') // First: select new-pr
|
|
684
|
-
.mockResolvedValueOnce('back') // Then: go back from new-pr sub-menu
|
|
685
|
-
.mockResolvedValueOnce('exit'); // Finally: exit
|
|
686
|
-
await showMainMenu();
|
|
687
|
-
// Should have called promptChoice 3 times (menu -> sub-menu -> back to menu -> exit)
|
|
688
|
-
expect(promptChoice).toHaveBeenCalledTimes(3);
|
|
689
|
-
});
|
|
690
|
-
it('handles list worktrees and returns to menu', async () => {
|
|
691
|
-
vi.mocked(promptChoice)
|
|
692
|
-
.mockResolvedValueOnce('list') // Select list
|
|
693
|
-
.mockResolvedValueOnce('exit'); // Then exit
|
|
694
|
-
await showMainMenu();
|
|
695
|
-
expect(gatherWorktreeInfo).toHaveBeenCalled();
|
|
696
|
-
expect(promptChoice).toHaveBeenCalledTimes(2);
|
|
697
|
-
});
|
|
698
|
-
it('handles browse PRs and returns to menu', async () => {
|
|
699
|
-
vi.mocked(promptChoice)
|
|
700
|
-
.mockResolvedValueOnce('browse-prs') // Select browse-prs
|
|
701
|
-
.mockResolvedValueOnce('exit'); // Then exit
|
|
702
|
-
await showMainMenu();
|
|
703
|
-
expect(runPrsCommand).toHaveBeenCalled();
|
|
704
|
-
expect(promptChoice).toHaveBeenCalledTimes(2);
|
|
705
|
-
});
|
|
706
|
-
it('handles show state and returns to menu', async () => {
|
|
707
|
-
vi.mocked(promptChoice)
|
|
708
|
-
.mockResolvedValueOnce('state') // Select state
|
|
709
|
-
.mockResolvedValueOnce('exit'); // Then exit
|
|
710
|
-
await showMainMenu();
|
|
711
|
-
expect(analyzeState).toHaveBeenCalled();
|
|
712
|
-
expect(promptChoice).toHaveBeenCalledTimes(2);
|
|
713
|
-
});
|
|
714
|
-
});
|
|
715
|
-
describe('FlowResult types', () => {
|
|
716
|
-
it('CANCELLED has correct structure', async () => {
|
|
717
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('back');
|
|
718
|
-
const result = await flows.handleNewPR();
|
|
719
|
-
expect(result.completed).toBe(false);
|
|
720
|
-
expect(result.returnToMenu).toBe(true);
|
|
721
|
-
});
|
|
722
|
-
it('flows that run operations return completed with returnToMenu=true', async () => {
|
|
723
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('dry-run');
|
|
724
|
-
const result = await flows.handleCleanPRs();
|
|
725
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
726
|
-
});
|
|
727
|
-
});
|
|
728
|
-
});
|
|
729
|
-
describe('Config loading in flows', () => {
|
|
730
|
-
beforeEach(() => {
|
|
731
|
-
vi.clearAllMocks();
|
|
732
|
-
});
|
|
733
|
-
it('uses config default for base branch', async () => {
|
|
734
|
-
// Set up config mock to return custom baseBranch
|
|
735
|
-
vi.mocked(loadConfig).mockReturnValueOnce({
|
|
736
|
-
configVersion: 1,
|
|
737
|
-
sharedRepos: [],
|
|
738
|
-
baseBranch: 'develop',
|
|
739
|
-
draftPr: true,
|
|
740
|
-
worktreePattern: '{repo}.pr{number}',
|
|
741
|
-
worktreeParent: '..',
|
|
742
|
-
syncPatterns: [],
|
|
743
|
-
branchPrefix: 'feat',
|
|
744
|
-
previewLabel: 'preview',
|
|
745
|
-
preferredEditor: 'vscode',
|
|
746
|
-
ai: {
|
|
747
|
-
provider: 'auto',
|
|
748
|
-
fallback: 'none',
|
|
749
|
-
branchName: false,
|
|
750
|
-
prTitle: false,
|
|
751
|
-
prDescription: false,
|
|
752
|
-
commitMessage: false,
|
|
753
|
-
planDocument: false,
|
|
754
|
-
},
|
|
755
|
-
hooks: {},
|
|
756
|
-
hookDefaults: { timeout: 30000, maxTimeout: 60000 },
|
|
757
|
-
plugins: [],
|
|
758
|
-
generators: {},
|
|
759
|
-
integrations: {},
|
|
760
|
-
logging: { level: 'info', timestamps: true },
|
|
761
|
-
global: { warnNotGlobal: true },
|
|
762
|
-
wtlink: { enabled: [], disabled: [] },
|
|
763
|
-
linkConfigFiles: undefined,
|
|
764
|
-
});
|
|
765
|
-
vi.mocked(promptChoice).mockResolvedValueOnce('from-description').mockResolvedValueOnce(true);
|
|
766
|
-
vi.mocked(promptInput).mockResolvedValueOnce('Test feature').mockResolvedValueOnce('develop'); // User accepts default
|
|
767
|
-
vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
|
|
768
|
-
const result = await flows.handleNewPR();
|
|
769
|
-
// Verify loadConfig was called
|
|
770
|
-
expect(loadConfig).toHaveBeenCalled();
|
|
771
|
-
// Verify runNewprHandler was called with develop base branch
|
|
772
|
-
expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
|
|
773
|
-
baseBranch: 'develop',
|
|
774
|
-
}));
|
|
775
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
776
|
-
});
|
|
777
|
-
});
|
|
778
|
-
describe('Git branch listing in flows', () => {
|
|
779
|
-
beforeEach(() => {
|
|
780
|
-
vi.clearAllMocks();
|
|
781
|
-
});
|
|
782
|
-
it('filters out main/master/develop from branch selection', async () => {
|
|
783
|
-
// The mock already returns ['feat/existing-branch', 'fix/bug-fix', 'main', 'develop']
|
|
784
|
-
// The flow should filter out main and develop
|
|
785
|
-
vi.mocked(promptChoice)
|
|
786
|
-
.mockResolvedValueOnce('from-branch')
|
|
787
|
-
.mockResolvedValueOnce('feat/existing-branch')
|
|
788
|
-
.mockResolvedValueOnce(true);
|
|
789
|
-
vi.mocked(promptInput).mockResolvedValueOnce('main');
|
|
790
|
-
const result = await flows.handleNewPR();
|
|
791
|
-
// Check that listLocalBranches was called
|
|
792
|
-
expect(git.listLocalBranches).toHaveBeenCalled();
|
|
793
|
-
expect(result).toEqual({ completed: true, returnToMenu: true });
|
|
794
|
-
});
|
|
795
|
-
});
|
|
796
|
-
//# sourceMappingURL=interactive-menu.test.js.map
|