/** * [v2.2.318] 하위 질문 체크리스트 — "물음 3개에 하나도 직접 답하지 않는" 실사례 가드. */ import { extractSubQuestions, clauseKeyTokens, buildSubQuestionBlock, checkSubQuestionCoverage, formatSubQuestionFooter, } from '../src/intelligence/subQuestions'; const PROMPT = 'https://www.koritips.com 분석해줘. 어떠한 주제로 블로그가 운영되고 있는지, 글의 퀄리티는 어떠한지, 검색해서 들어온 사람이 글을 읽고 도움이 되었을지'; describe('extractSubQuestions', () => { test('실사례 프롬프트에서 물음 3개 추출', () => { const qs = extractSubQuestions(PROMPT); expect(qs.length).toBe(3); expect(qs[0]).toContain('주제'); expect(qs[1]).toContain('퀄리티'); expect(qs[2]).toContain('도움'); }); test('물음이 1개뿐이면 빈 목록 (본문 전체가 답)', () => { expect(extractSubQuestions('이 코드가 왜 느린지 알려줘')).toEqual([]); expect(extractSubQuestions('안녕하세요')).toEqual([]); }); }); describe('clauseKeyTokens / coverage', () => { test('특징 토큰에서 조사·의문사 제거', () => { const keys = clauseKeyTokens('글의 퀄리티는 어떠한지'); expect(keys).toContain('퀄리티'); expect(keys).not.toContain('어떠한'); }); test('실사례 답변(평가 형용사만) → 퀄리티·도움 물음 누락 감지', () => { const answer = 'koritips.com은 기술 아카이브로서의 가치가 매우 높습니다. 신뢰성과 지속 가능성, 타겟 명확성 측면에서 높은 평가를 받을 수 있습니다.'; const cov = checkSubQuestionCoverage(PROMPT, answer); expect(cov.total).toBe(3); expect(cov.missing.length).toBeGreaterThanOrEqual(2); expect(formatSubQuestionFooter(cov)).toContain('미답변 물음'); }); test('각 물음에 답한 답변은 통과', () => { const answer = '주제는 블로그 운영 팁입니다. 글의 퀄리티는 단계별 스크린샷이 있어 높습니다. 검색 유입자에게 실질적 도움이 됩니다.'; expect(checkSubQuestionCoverage(PROMPT, answer).missing).toEqual([]); }); }); describe('buildSubQuestionBlock', () => { test('물음 2개 이상이면 체크리스트 블록 생성', () => { const blk = buildSubQuestionBlock(PROMPT); expect(blk).toContain('[하위 질문 체크리스트'); expect(blk).toContain('1.'); expect(blk).toContain('구체 근거'); }); test('단일 질문은 빈 문자열', () => { expect(buildSubQuestionBlock('서버 상태 확인해줘')).toBe(''); }); });