Files
connectai/tests/integration/mockLLMClient.test.ts
T
g1nation 0a97324f1b feat: v2.2.92 → v2.2.158 — god-file 분해 + Stocks feature + 대화 연속성
R56–R59: agent.ts 2731→1529줄 god-file 분해 (25 modules)
  · attrParsers + LLM 메서드 8개 (callNonStreaming, streamChatOnce 등)
  · executeActions 415줄 → 8 handler 그룹 (file/run/list/brain/calendar/sheets/tasks)
  · handlePrompt 1100줄 → 7 phase 모듈 (system prompt + budget + autoContinue 등)

R50–R55: extension.ts 1145→349줄 (telegram/settings/provider commands 분리)

Stocks feature 신규: /stocks slash command (v2.2.152~158)
  · .astra/stocks.json 저장소 + Yahoo Finance 현재가 갱신
  · 8 키워드 필터 (ROE/성장성/유동성/수익성/영업효율/기술력/안정성/PBR)
  · Naver 시가총액 페이지 JSON API (m.stock.naver.com) 발굴
  · LLM Top 5 매력도 분석 + Telegram 자동 보고서
  · KST 09:00/15:00 watcher 자동 모니터링

대화 연속성 (v2.2.150~157):
  · [PRIOR TURN CONCLUSION] block 으로 직전 결론 anchor
  · thin follow-up 분류 → boilerplate 헤더 suppression
  · slash 명령 결과 chatHistory mirror (capture wrapper)
  · echo/parrot 금지 system prompt rule

기타: /stocks 슬래시 자동완성 dropdown UI, Naver JSON API 전환 (cheerio 제거)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 09:59:32 +09:00

87 lines
2.9 KiB
TypeScript

/**
* MockLLMClient 자체의 sanity test.
*
* 이게 통과하면 dispatcher / ceoPlanner / ChunkedWriter 등 IAIService 를 받는
* 코드가 *실제 LLM 없이* 단위 / integration 테스트 가능.
*
* 향후 dispatcher 의 multi-stage flow 같은 큰 integration 테스트는 이 mock 을
* 주입해서 실제 fetch 없이 검증.
*/
import { MockLLMClient } from '../helpers/mockLLMClient';
describe('MockLLMClient', () => {
test('큐된 응답을 순차적으로 소비한다', async () => {
const ai = new MockLLMClient();
ai.setNextResponse('first');
ai.setNextResponse('second');
const r1 = await ai.chat({ user: 'a' });
const r2 = await ai.chat({ user: 'b' });
expect(r1.content).toBe('first');
expect(r2.content).toBe('second');
expect(ai.calls).toHaveLength(2);
expect(ai.calls[0].user).toBe('a');
expect(ai.calls[1].user).toBe('b');
});
test('큐가 비면 responder 함수로 동적 응답', async () => {
const ai = new MockLLMClient();
ai.setResponder((req) =>
req.user.includes('summary') ? '요약 결과' : '일반 답변',
);
const r1 = await ai.chat({ user: 'give me summary' });
const r2 = await ai.chat({ user: 'hello' });
expect(r1.content).toBe('요약 결과');
expect(r2.content).toBe('일반 답변');
});
test('큐가 responder 보다 우선', async () => {
const ai = new MockLLMClient();
ai.setResponder(() => 'from responder');
ai.setNextResponse('from queue');
const r1 = await ai.chat({ user: 'x' });
const r2 = await ai.chat({ user: 'y' });
expect(r1.content).toBe('from queue');
expect(r2.content).toBe('from responder');
});
test('signal 이 이미 abort 된 상태면 AbortError 던진다', async () => {
const ai = new MockLLMClient();
const ctrl = new AbortController();
ctrl.abort();
await expect(ai.chat({ user: 'x', signal: ctrl.signal })).rejects.toThrow(/AbortError/);
// 호출은 기록됨 (signalAborted: true).
expect(ai.calls).toHaveLength(1);
expect(ai.calls[0].signalAborted).toBe(true);
});
test('legacy call(prompt) 도 동작', async () => {
const ai = new MockLLMClient();
ai.setNextResponse('plain');
const result = await ai.call('hi');
expect(result).toBe('plain');
expect(ai.calls).toHaveLength(1);
});
test('reset() 으로 상태 초기화', async () => {
const ai = new MockLLMClient();
ai.setNextResponse('x');
await ai.chat({ user: 'a' });
ai.reset();
expect(ai.calls).toHaveLength(0);
// 큐도 비었으니 기본 fallback 응답.
const r = await ai.chat({ user: 'b' });
expect(r.content).toContain('mock response');
});
});