Repository navigation
Expand file tree
/
Copy pathhow-to-proceed-dispatch.test.ts
More file actions
71 lines (63 loc) · 2.59 KB
/
Copy pathhow-to-proceed-dispatch.test.ts
File metadata and controls
71 lines (63 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { beforeEach, expect, it, vi } from 'vitest'
import type { HandoffChoice, InitState } from '../../../init/types.js'
// `buildOptions` / `defaultChoice` / `resolveTarget` are pure and covered in
// `impl/__tests__/how-to-proceed.test.ts`. What is NOT covered there is the
// dispatch arm: a pre-resolved `state.handoff` must skip the picker and run
// the matching step. Misrouting or dropping an arm would otherwise pass CI.
const runs = vi.hoisted(() => ({
'claude-code': vi.fn(async (s: InitState) => s),
codex: vi.fn(async (s: InitState) => s),
'agents-md': vi.fn(async (s: InitState) => s),
lovable: vi.fn(async (s: InitState) => s),
wizard: vi.fn(async (s: InitState) => s),
}))
vi.mock('../handoff-claude.js', () => ({
handoffClaudeStep: { run: runs['claude-code'] },
}))
vi.mock('../handoff-codex.js', () => ({
handoffCodexStep: { run: runs.codex },
}))
vi.mock('../handoff-agents-md.js', () => ({
handoffAgentsMdStep: { run: runs['agents-md'] },
}))
vi.mock('../handoff-lovable.js', () => ({
handoffLovableStep: { run: runs.lovable },
}))
vi.mock('../handoff-wizard.js', () => ({
handoffWizardStep: { run: runs.wizard },
}))
const select = vi.hoisted(() => vi.fn())
vi.mock('@clack/prompts', () => ({
select,
isCancel: vi.fn(() => false),
note: vi.fn(),
log: { success: vi.fn(), info: vi.fn(), warn: vi.fn() },
}))
import { HANDOFF_CHOICES, howToProceedStep } from '../how-to-proceed.js'
beforeEach(() => {
vi.clearAllMocks()
})
// Table-driven off HANDOFF_CHOICES so a new target that reaches the picker
// without a dispatch arm fails here rather than at runtime.
for (const choice of HANDOFF_CHOICES) {
it(`routes a pre-resolved \`${choice}\` state to its own step, without a prompt`, async () => {
await howToProceedStep.run({ handoff: choice } as InitState)
expect(runs[choice]).toHaveBeenCalledTimes(1)
// The dispatched step must see the resolved choice on the state.
expect(runs[choice].mock.calls[0][0].handoff).toBe(choice)
// Every other arm stays untouched.
for (const other of HANDOFF_CHOICES) {
if (other !== choice) expect(runs[other]).not.toHaveBeenCalled()
}
// A pre-resolved target is what makes the command non-TTY safe.
expect(select).not.toHaveBeenCalled()
})
}
it('runs the picked step when the picker is used', async () => {
const picked: HandoffChoice = 'lovable'
select.mockResolvedValueOnce(picked)
await howToProceedStep.run({ agents: undefined } as InitState)
expect(select).toHaveBeenCalledTimes(1)
expect(runs.lovable).toHaveBeenCalledTimes(1)
expect(runs.lovable.mock.calls[0][0].handoff).toBe('lovable')
})