|
1 | 1 | import { describe, it, expect, afterEach } from 'bun:test'; |
2 | | -import { createMockServer, jsonResponse, type MockServer } from '../../helpers/mock-server'; |
| 2 | +import { createMockServer, jsonResponse, sseResponse, type MockServer } from '../../helpers/mock-server'; |
3 | 3 | import textChatResponse from '../../fixtures/text-chat-response.json'; |
4 | 4 | import type { Config } from '../../../src/config/schema'; |
5 | 5 |
|
@@ -146,6 +146,119 @@ describe('text chat command', () => { |
146 | 146 | } |
147 | 147 | }); |
148 | 148 |
|
| 149 | + it('does not enable default streaming for json output', async () => { |
| 150 | + let requestBody: { stream?: boolean } | undefined; |
| 151 | + server = createMockServer({ |
| 152 | + routes: { |
| 153 | + '/anthropic/v1/messages': async (req) => { |
| 154 | + requestBody = await req.json() as { stream?: boolean }; |
| 155 | + return jsonResponse(textChatResponse); |
| 156 | + }, |
| 157 | + }, |
| 158 | + }); |
| 159 | + |
| 160 | + const { default: chatCommand } = await import('../../../src/commands/text/chat'); |
| 161 | + |
| 162 | + const config: Config = { |
| 163 | + apiKey: 'test-key', |
| 164 | + region: 'global' as const, |
| 165 | + baseUrl: server.url, |
| 166 | + output: 'json', |
| 167 | + timeout: 10, |
| 168 | + verbose: false, |
| 169 | + quiet: false, |
| 170 | + noColor: true, |
| 171 | + yes: false, |
| 172 | + dryRun: false, |
| 173 | + nonInteractive: true, |
| 174 | + async: false, |
| 175 | + }; |
| 176 | + |
| 177 | + const originalIsTTY = process.stdout.isTTY; |
| 178 | + const originalLog = console.log; |
| 179 | + let output = ''; |
| 180 | + Object.defineProperty(process.stdout, 'isTTY', { value: true, configurable: true }); |
| 181 | + console.log = (msg: string) => { output += msg; }; |
| 182 | + |
| 183 | + try { |
| 184 | + await chatCommand.execute(config, { |
| 185 | + message: ['Hello'], |
| 186 | + quiet: false, |
| 187 | + verbose: false, |
| 188 | + noColor: true, |
| 189 | + yes: false, |
| 190 | + dryRun: false, |
| 191 | + help: false, |
| 192 | + nonInteractive: true, |
| 193 | + async: false, |
| 194 | + }); |
| 195 | + |
| 196 | + expect(requestBody?.stream).toBe(false); |
| 197 | + expect(JSON.parse(output).content[0].text).toBe('Hello! How can I help you today?'); |
| 198 | + } finally { |
| 199 | + console.log = originalLog; |
| 200 | + Object.defineProperty(process.stdout, 'isTTY', { value: originalIsTTY, configurable: true }); |
| 201 | + } |
| 202 | + }); |
| 203 | + |
| 204 | + it('emits only final json to stdout for explicit stream json output', async () => { |
| 205 | + server = createMockServer({ |
| 206 | + routes: { |
| 207 | + '/anthropic/v1/messages': () => sseResponse([ |
| 208 | + { data: JSON.stringify({ type: 'content_block_delta', delta: { type: 'text_delta', text: 'Hello' } }) }, |
| 209 | + { data: JSON.stringify({ type: 'content_block_delta', delta: { type: 'text_delta', text: ' world' } }) }, |
| 210 | + ]), |
| 211 | + }, |
| 212 | + }); |
| 213 | + |
| 214 | + const { default: chatCommand } = await import('../../../src/commands/text/chat'); |
| 215 | + |
| 216 | + const config: Config = { |
| 217 | + apiKey: 'test-key', |
| 218 | + region: 'global' as const, |
| 219 | + baseUrl: server.url, |
| 220 | + output: 'json', |
| 221 | + timeout: 10, |
| 222 | + verbose: false, |
| 223 | + quiet: false, |
| 224 | + noColor: true, |
| 225 | + yes: false, |
| 226 | + dryRun: false, |
| 227 | + nonInteractive: true, |
| 228 | + async: false, |
| 229 | + }; |
| 230 | + |
| 231 | + const originalLog = console.log; |
| 232 | + const originalWrite = process.stdout.write; |
| 233 | + let output = ''; |
| 234 | + console.log = (msg: string) => { output += `${msg}\n`; }; |
| 235 | + process.stdout.write = ((chunk: string | Uint8Array) => { |
| 236 | + output += typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf-8'); |
| 237 | + return true; |
| 238 | + }) as typeof process.stdout.write; |
| 239 | + |
| 240 | + try { |
| 241 | + await chatCommand.execute(config, { |
| 242 | + message: ['Hello'], |
| 243 | + stream: true, |
| 244 | + quiet: false, |
| 245 | + verbose: false, |
| 246 | + noColor: true, |
| 247 | + yes: false, |
| 248 | + dryRun: false, |
| 249 | + help: false, |
| 250 | + nonInteractive: true, |
| 251 | + async: false, |
| 252 | + }); |
| 253 | + |
| 254 | + expect(output).toBe('{\n "content": "Hello world"\n}\n'); |
| 255 | + expect(JSON.parse(output).content).toBe('Hello world'); |
| 256 | + } finally { |
| 257 | + console.log = originalLog; |
| 258 | + process.stdout.write = originalWrite; |
| 259 | + } |
| 260 | + }); |
| 261 | + |
149 | 262 | it('--model flag overrides defaultTextModel', async () => { |
150 | 263 | const { default: chatCommand } = await import('../../../src/commands/text/chat'); |
151 | 264 |
|
|
0 commit comments