import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { analyzeCopilot, followUpMessage, scoreDisc, type DiscAnswers, } from '../../../packages/shared/src/behavior'; function all(type: DiscAnswers[string]): DiscAnswers { return { '1': type, '2': type, '3': type, '4': type, '5': type, '6': type, '7': type, '8': type }; } describe('امتیاز DISC', () => { it('گزینه D فقط امتیاز D را زیاد می‌کند', () => { const result = scoreDisc(all('D')); assert.equal(result.scores.D, 8); assert.equal(result.scores.I, 0); assert.equal(result.scores.S, 0); assert.equal(result.scores.C, 0); assert.equal(result.label, 'D'); assert.equal(result.percents.D, 100); }); it('هر چهار تیپ را جدا جمع می‌کند', () => { const result = scoreDisc({ '1': 'D', '2': 'I', '3': 'S', '4': 'C', '5': 'D', '6': 'I' }); assert.deepEqual(result.scores, { D: 2, I: 2, S: 1, C: 1 }); assert.equal(result.validCount, 6); assert.equal(result.label, 'D/I'); }); it('در تساوی نتیجه ترکیبی می‌دهد', () => { const result = scoreDisc({ '1': 'S', '2': 'C', '3': 'S', '4': 'C' }); assert.equal(result.reliable, true); assert.equal(result.label, 'S/C'); }); it('با کمتر از چهار پاسخ نتیجه قابل اتکا نمی‌دهد', () => { const result = scoreDisc({ '1': 'D', '2': 'D', '3': 'D' }); assert.equal(result.reliable, false); assert.equal(result.label, 'اطلاعات ناکافی برای نتیجه قابل اتکا'); assert.deepEqual(result.primaryTypes, []); }); }); describe('دستیار فروش', () => { it('برای نیاز ندارم سؤال کشف نیاز می‌دهد و قیمت نمی‌سازد', () => { const analysis = analyzeCopilot({ topic: 'objection', goal: 'discover_need', customerStatement: 'فعلاً نیازی ندارم؛ همین روش فعلی برای من جواب می‌دهد.', facts: { customerName: 'مهدی', stageName: 'سرنخ جدید' }, }); assert.equal(analysis.objection_category, 'no_need'); assert.match(analysis.recommended_question, /روش فعلی/); assert.doesNotMatch(analysis.suggested_response, /\d{3,}/); assert.equal(analysis.disc_context, null); }); it('DISC تازه را راهنما می‌کند نه تشخیص قطعی', () => { const analysis = analyzeCopilot({ topic: 'pricing', goal: 'follow_price', customerStatement: 'قیمتتان بالاست.', facts: { customerName: 'مهدی', priceOffered: null, disc: { label: 'D', primaryTypes: ['D'], reliable: true, assessedAt: new Date().toISOString(), }, }, }); assert.equal(analysis.disc_context?.used, true); assert.match(analysis.suggested_response, /کوتاه می‌گویم/); assert.match(analysis.confidence_note, /قطعی/); assert.match(analysis.suggested_response, /عدد یا تخفیف جدیدی پیشنهاد نمی‌شود/); }); it('حرف کوتاه را قطعی تحلیل نمی‌کند', () => { const analysis = analyzeCopilot({ topic: 'intro', goal: 'discover_need', customerStatement: 'نه', facts: {}, }); assert.equal(analysis.needs_more_input, true); assert.equal(analysis.suggested_response, ''); }); it('متن پیگیری قیمت را از خودش نمی‌سازد', () => { const analysis = analyzeCopilot({ topic: 'pricing', goal: 'follow_price', customerStatement: 'باید فکر کنم.', facts: { customerName: 'سارا', productName: 'منتکت' }, }); const text = followUpMessage('price_followup', { customerName: 'سارا', productName: 'منتکت' }, analysis); assert.match(text, /منتکت/); assert.match(text, /عدد قیمت را اینجا تکرار نمی‌کنم/); }); });