customer-journey-smoke-test.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. const assert = require('assert');
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-customer-journey-'));
  6. process.env.QIWEI_OUTPUTS_DIR = tempDir;
  7. async function main() {
  8. let updateCall = null;
  9. const conversation = {
  10. id: 'conversation-1',
  11. channelId: 'external-test-1',
  12. displayName: '测试客户',
  13. maskedId: 'ex***-1',
  14. source: 'live',
  15. mode: 'review',
  16. analysis: { completenessScore: 50 },
  17. messages: [
  18. { id: 'm1', role: 'customer', source: 'live', content: '预算 15 万,想了解企业服务方案', timestamp: '2026-07-17T00:00:00Z' },
  19. { id: 'm2', role: 'human', source: 'live', content: '收到,我先确认您的计划时间。', timestamp: '2026-07-17T00:05:00Z' },
  20. ],
  21. customerIntelligence: {
  22. profile: { need: '企业服务方案', budgetWan: 15, timeline: '待确认' },
  23. profileEvidence: {
  24. need: { text: '想了解企业服务方案', sourceMessageId: 'm1', source: 'live-message', updatedAt: '2026-07-17T00:00:00Z' },
  25. },
  26. tags: ['企业客户'],
  27. tasks: [{ id: 't1', title: '确认计划时间', status: 'open', evidence: '计划时间未确认', updatedAt: '2026-07-17T00:10:00Z' }],
  28. alerts: [{ id: 'a1', title: '重点跟进', severity: 'high', status: 'open', evidence: '客户已明确需求和预算', updatedAt: '2026-07-17T00:11:00Z' }],
  29. summary: { openTasks: 1, openAlerts: 1, highAlerts: 1 },
  30. },
  31. lastMessageAt: '2026-07-17T00:05:00Z',
  32. updatedAt: '2026-07-17T00:11:00Z',
  33. };
  34. const { createCustomerMasterService } = require('../mcp/src/dashboard/customer-master-service');
  35. const service = createCustomerMasterService({
  36. projectionPath: path.join(tempDir, 'customers', 'index.json'),
  37. getConversations: () => ({ data: { conversations: [conversation] } }),
  38. updateCustomerProfile: (customerId, input) => {
  39. updateCall = { customerId, input };
  40. conversation.customerIntelligence.profile = { ...conversation.customerIntelligence.profile, ...(input.profile || {}) };
  41. return { status: 'ok', assistantMessage: '客户主档已更新。', summary: { updated: true } };
  42. },
  43. });
  44. const hub = service.hub();
  45. const customer = hub.data.customers[0];
  46. assert.equal(hub.status, 'ok');
  47. assert.equal(hub.summary.customerCount, 1);
  48. assert.equal(hub.summary.priorityCount, 1);
  49. assert.equal(customer.stage.key, 'priority');
  50. assert.equal(customer.evidenceCoverage, 33);
  51. assert(customer.nextActions.some(item => item.id === 'confirm-purpose') === false);
  52. assert(customer.nextActions.some(item => item.id === 'confirm-timeline'));
  53. assert(customer.timeline.some(item => item.type === 'inbound-message'));
  54. assert(customer.timeline.some(item => item.type === 'outbound-message'));
  55. assert(customer.timeline.some(item => item.type === 'task'));
  56. assert(customer.timeline.some(item => item.type === 'alert'));
  57. assert.equal(customer.openTaskCount, 1);
  58. assert.equal(customer.highAlertCount, 1);
  59. assert.equal(fs.existsSync(path.join(tempDir, 'customers', 'index.json')), true);
  60. const updated = service.update(conversation.id, { profile: { timeline: '本月内' }, reason: '客户确认' });
  61. assert.equal(updated.status, 'ok');
  62. assert.equal(updateCall.customerId, conversation.id);
  63. assert.equal(updateCall.input.profile.timeline, '本月内');
  64. process.stdout.write(`${JSON.stringify({
  65. status: 'ok',
  66. checks: 16,
  67. customerCount: hub.summary.customerCount,
  68. nextActions: customer.nextActions.length,
  69. timelineEvents: customer.timeline.length,
  70. }, null, 2)}\n`);
  71. }
  72. main().catch(error => {
  73. process.stderr.write(`${error.stack || error.message}\n`);
  74. process.exitCode = 1;
  75. }).finally(() => {
  76. try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
  77. });