# Ticket 6.1 — Integration Test Scenarios

**Phase**: 6 — Testing & Polish
**Priority**: High
**Depends on**: 0.3 (incremental from M1 onward — see Milestone Checkpoint Testing below)

## Description

Comprehensive integration test scenarios that verify the full flow from browser → relay → OpenCode and back. These tests use the mock OpenCode server, mock WebSocket client, and sample event fixtures established in **ticket 0.3**.

> **Note**: The test *infrastructure* (Vitest config, mock server, mock client, fixtures, helpers) is set up in ticket 0.3 (Phase 0) to enable TDD from day one. This ticket adds the comprehensive integration test *scenarios* that exercise all flows end-to-end once Phases 1-2 are complete.

Unit tests for individual components are written alongside each ticket (TDD). This ticket covers the **cross-cutting integration scenarios** that test multiple components working together.

## Acceptance Criteria

### AC1: Full message flow test

```gherkin
Given the relay is connected to the mock OpenCode server
When a WebSocket client sends { type: "message", text: "Hello" }
Then the relay forwards the message to mock OpenCode's prompt endpoint
And the mock emits SSE events (thinking → delta → tool_start → tool_result → done)
And the WebSocket client receives the translated messages in order:
  1. { type: "status", status: "processing" }
  2. { type: "thinking_start" }
  3. { type: "thinking_delta", text: "..." }
  4. { type: "thinking_stop" }
  5. { type: "delta", text: "..." }
  6. { type: "tool_start", id, name }
  7. { type: "tool_result", id, content }
  8. { type: "done", code: 0 }
```

### AC2: Permission flow test

```gherkin
Given the relay is running
When the mock emits a permission.asked SSE event
Then the WebSocket client receives { type: "permission_request", ... }
When the client responds with { type: "permission_response", requestId, decision: "allow" }
Then the relay POSTs to mock OpenCode's /permission/:id/reply with { reply: "once" }
And the mock confirms the permission was resolved
And the client receives { type: "permission_resolved", ... }
```

### AC3: Session lifecycle test

```gherkin
Given the relay is running
When the client sends { type: "new_session" }
Then a session is created on mock OpenCode
When the client sends { type: "switch_session", id: "other" }
Then the relay loads history from mock OpenCode
When the client sends { type: "delete_session", id: "other" }
Then the session is removed on mock OpenCode
```

### AC4: Reconnection test

```gherkin
Given the relay is connected to mock OpenCode's SSE stream
When the SSE connection drops
Then the relay reconnects within 5 seconds
And no events are lost (mock tracks event IDs)
And WebSocket clients are NOT disconnected during SSE reconnection
```

### AC5: Multi-client test

```gherkin
Given 3 WebSocket clients are connected
When one client sends a message
Then all 3 receive the agent's response
When one client approves a permission
Then the other 2 see the resolution
```

### AC6: Question flow test

```gherkin
Given the relay is running
When the mock emits a question.asked SSE event
Then the WebSocket client receives { type: "ask_user", ... } with mapped fields
When the client responds with { type: "ask_user_response", toolId, answers }
Then the relay POSTs to mock OpenCode's /question/:id/reply with converted answers
And the client receives { type: "ask_user_resolved", ... }
```

### AC7: Error scenario tests

```gherkin
Given the relay is running
When the mock OpenCode server returns a 500 error on prompt
Then the relay sends { type: "error", message: "..." } to the WebSocket client
And the relay does NOT crash

When the mock OpenCode server shuts down unexpectedly
Then the relay detects the disconnection
And it sends an error notification to connected browsers
And it attempts to reconnect
```

## Testable Components

| Component | Test Type | What to Assert |
|-----------|-----------|----------------|
| Full message flow | Fixture | Correct sequence of messages browser ↔ relay ↔ mock |
| Permission flow | Fixture | Request → response → resolution with decision mapping |
| Question flow | Fixture | Ask → answer → resolution with format conversion |
| Session CRUD | Fixture | Create, switch, delete all work via REST |
| SSE reconnection | Fixture | Reconnects, no event loss, clients stay connected |
| Multi-client broadcast | Fixture | All clients receive events |
| Error scenarios | Fixture | Relay handles errors gracefully, doesn't crash |

## Test Files

```
test/integration/
├── message-flow.test.ts          # AC1: full message round-trip
├── permission-flow.test.ts       # AC2: permission request/response/resolution
├── session-lifecycle.test.ts     # AC3: create/switch/delete sessions
├── reconnection.test.ts          # AC4: SSE drop and reconnect
├── multi-client.test.ts          # AC5: broadcast to multiple clients
├── question-flow.test.ts         # AC6: question ask/answer/resolution
└── error-scenarios.test.ts       # AC7: error handling and recovery
```

All tests use the infrastructure from ticket 0.3:
- `test/fixtures/mock-opencode-server.ts` — mock HTTP + SSE server
- `test/fixtures/mock-ws-client.ts` — mock WebSocket client
- `test/fixtures/sample-events.ts` — canned SSE event sequences
- `test/helpers/setup.ts` — test lifecycle helpers
- `test/helpers/assertions.ts` — custom Vitest assertion matchers

## Milestone Checkpoint Testing

Integration tests should be written **incrementally at each milestone**, not saved until the end. This prevents integration bugs from compounding across phases undetected.

| Milestone | When to Write | Integration Tests to Add | Count |
|-----------|---------------|-------------------------|-------|
| **M1 — Walking skeleton** | After ticket 0.7 | Basic pipeline: spawn → SSE → translate → WebSocket → browser receives text | 1-2 |
| **M2 — Proof of concept** | After Phase 1 + 2.1–2.2 | AC1 (full message flow), AC4 (reconnection) | 2-3 |
| **M3 — Functional relay** | After 1.5, 1.6, 2.3–2.4 | AC2 (permission flow), AC3 (session lifecycle), AC5 (multi-client), AC6 (question flow) | 4-5 |
| **M4 — Feature parity** | After Phase 4 | AC7 (error scenarios), plus E2E tests for frontend ↔ relay ↔ mock | 3-5 |
| **M5+ — OpenCode extras** | After Phase 5 | Agent switching, model picker, forking flows | 2-3 |

**Action**: After each milestone, add the corresponding integration tests before moving to the next milestone. The `test/integration/` directory grows incrementally, not in a big-bang at the end.

## Notes

- Uses **Vitest** (configured in ticket 0.3)
- All tests are **TypeScript** (`.test.ts`)
- Mock server is fast to start/stop for each test (< 100ms)
- Tests should complete in < 30 seconds total
- No real AI API calls — fully deterministic
- Unit tests for individual modules are written in their respective tickets (TDD); this ticket is for cross-cutting integration scenarios only
- **Priority change**: This ticket's depends-on says "All Phase 1-2 tickets" but the checkpoint approach means the first integration tests are written much earlier (after M1). Update depends-on to reflect incremental delivery.
