# Interactive Prompts Testing — `CLIContext` reference

`CLIContext` (in `cli-context.ts`) maintains a single long-lived CLI
process per test that accepts multiple commands. It also exposes a
fluent API for testing CLI commands that read from stdin — interactive
prompts, wizards, confirmation steps.

This document is a cookbook of patterns for the interactive bits.
For unit-test-style assertions on command output, see `cli-result.ts`
and the existing tests under `cli-context.test.ts`.

These examples were originally a `.test.ts` file under `examples/` that
was permanently `describe.skip`'d because the specific commands they
imagined (e.g. `module configure homebridge`, `system setup wizard`)
don't exist in the CLI. They're kept here as illustrative reference,
not as a regression suite.

## Pattern: respond to a single prompt

Use `cli.on(/regex/).respond(text)` after starting a command. The
fluent helper waits for output matching the pattern, then writes the
response to stdin.

```typescript
const commandPromise = cli.run('module configure homebridge');

await cli.on(/Enter hostname:/).respond('iot.local\n');

const result = await commandPromise;
expect(result.exitCode).toBe(0);
```

## Pattern: respond to multiple prompts in sequence

Wizards typically prompt for several fields back-to-back. Chain
`cli.on().respond()` calls; each one waits for its own pattern before
sending input.

```typescript
const commandPromise = cli.run('system init --interactive');

await cli.on(/Enter primary domain:/).respond('example.com\n');
await cli.on(/Enter admin email:/).respond('admin@example.com\n');
await cli.on(/Confirm settings/).respond('yes\n');

const result = await commandPromise;
expect(result.exitCode).toBe(0);
```

## Pattern: conditional responses based on output

Sometimes a command emits a warning or branching prompt only under
certain conditions. Use `cli.expectOutput(/pattern/)` to wait for the
trigger, then decide what to send.

```typescript
const commandPromise = cli.run('module deploy homebridge');

await cli.expectOutput(/Ready to deploy/);

await cli
  .expectOutput(/WARNING/, { timeout: 1000 })
  .then(async () => {
    // Warning appeared — confirm explicitly
    await cli.sendKeys('yes\n');
  })
  .catch(() => {
    // No warning — quick confirm
    cli.sendKeys('y\n');
  });

const result = await commandPromise;
expect(result.exitCode).toBe(0);
```

## Pattern: testing input validation

Provide a bad value, assert the validation error appears, then provide
a good value.

```typescript
const commandPromise = cli.run('machine add');

await cli.on(/Enter hostname:/).respond('invalid hostname!\n');

await cli.expectOutput(/Invalid hostname format/);

await cli.on(/Enter hostname:/).respond('valid-hostname\n');

const result = await commandPromise;
expect(result.exitCode).toBe(0);
```

## Pattern: timeout when a prompt never appears

`expectOutput` rejects with a timeout error if its pattern doesn't
appear within the configured window. Use this to assert the absence
of output.

```typescript
const commandPromise = cli.run('some-command');

await expect(
  cli.expectOutput(/Prompt that never appears/, { timeout: 1000 }),
).rejects.toThrow(/Timeout waiting for pattern/);

await commandPromise;
```

## Pattern: complex multi-step wizard

Combine `expectOutput` (to assert section markers) with `cli.on().respond()`
(to provide values) for full wizard tests.

```typescript
const commandPromise = cli.run('system setup wizard');

// Step 1: network
await cli.expectOutput(/=== Network Configuration ===/);
await cli.on(/Enter subnet/).respond('192.168.0.0/24\n');
await cli.on(/Enter gateway/).respond('192.168.0.1\n');

// Step 2: DNS
await cli.expectOutput(/=== DNS Configuration ===/);
await cli.on(/Primary DNS/).respond('8.8.8.8\n');
await cli.on(/Secondary DNS/).respond('1.1.1.1\n');

// Step 3: confirm
await cli.expectOutput(/=== Review Settings ===/);
await cli.expectOutput(/Network: 192.168.0.0\/24/);
await cli.on(/Confirm/).respond('yes\n');

const result = await commandPromise;
expect(result.exitCode).toBe(0);
expect(result.stdout).toContain('Setup complete');
```

## Pattern: verbose logging while debugging

`cli.setVerbose(true)` makes the harness print every prompt and
response to the test log. Useful for debugging a flaky interactive
test.

```typescript
cli.setVerbose(true);

const commandPromise = cli.run('debug interactive-test');

await cli.on(/Enter value:/).respond('test\n');

const result = await commandPromise;
expect(result.exitCode).toBe(0);
```

## Status

The interactive prompt API is fully implemented and tested:
- ✅ `outputBuffer` is populated with all CLI output
- ✅ `expectOutput()` waits for patterns to appear
- ✅ `sendKeys()` sends input to process stdin
- ✅ `ResponseBuilder` provides the fluent `.on().respond()` API
- ✅ Unit tests in `cli-context.test.ts` and `cli-context-interactive.test.ts`

The API is ready to use for testing real interactive commands. The
patterns above are templates — they don't reference any actual CLI
command, so don't paste them verbatim into a test file expecting them
to run.
