文件
OmniCard/backend/test/modules/crm/analytics-export.test.ts

102 行
3.5 KiB
TypeScript

import {
CardAnalyticsExportService,
escapeCsvCell,
generateCsvContent,
RadarExportRow,
} from '../../../src/modules/crm/service/analytics-export';
describe('Point 50: 访客雷达多维数据报表 CSV 导出引擎 (RFC 4180)', () => {
let service: CardAnalyticsExportService;
beforeEach(() => {
service = new CardAnalyticsExportService();
});
describe('1. escapeCsvCell (RFC 4180 单元格转义规范)', () => {
it('包含逗号、换行或双引号的单元格必须用双引号包裹且内部双引号翻倍', () => {
expect(escapeCsvCell('Hello, World')).toBe('"Hello, World"');
expect(escapeCsvCell('Line 1\nLine 2')).toBe('"Line 1\nLine 2"');
expect(escapeCsvCell('She said "Hi"')).toBe('"She said ""Hi"""');
});
it('普通纯文本单元格无需包裹双引号', () => {
expect(escapeCsvCell('Arthur Pendelton')).toBe('Arthur Pendelton');
expect(escapeCsvCell('Dubai')).toBe('Dubai');
expect(escapeCsvCell(100)).toBe('100');
});
it('空值、null 或 undefined 应返回空字符串', () => {
expect(escapeCsvCell('')).toBe('');
expect(escapeCsvCell(null)).toBe('');
expect(escapeCsvCell(undefined)).toBe('');
});
});
describe('2. generateCsvContent (UTF-8 BOM 与多语言表头自适应)', () => {
const mockRows: RadarExportRow[] = [
{
visitorId: 'vis-001',
name: 'Sheikh Mansour',
country: 'AE',
city: 'Abu Dhabi',
stayDurationSeconds: 154,
radarScore: 92,
trafficChannel: 'nfc_tap',
visitedAt: '2026-09-20 14:30:00',
},
{
visitorId: 'vis-002',
name: 'Elena, Rostova',
country: 'SE',
city: 'Stockholm',
stayDurationSeconds: 65,
radarScore: 68,
trafficChannel: 'whatsapp_chat',
visitedAt: '2026-09-20 15:10:00',
},
];
it('导出的 CSV 必须以 UTF-8 BOM (\\uFEFF) 开头以防止 Excel 乱码', () => {
const csv = generateCsvContent(mockRows, 'en');
expect(csv.startsWith('\uFEFF')).toBe(true);
});
it('英语表头应包含准确的 RFC 4180 列名', () => {
const csv = generateCsvContent(mockRows, 'en');
expect(csv).toContain('Visitor ID,Name,Country,City,Stay (Seconds),Radar Score,Channel,Visited Time');
expect(csv).toContain('"Elena, Rostova"'); // 包含逗号被正确转义
});
it('阿拉伯语表头应输出规范阿语文案', () => {
const csv = generateCsvContent(mockRows, 'ar');
expect(csv).toContain('معرف الزائر,الاسم,الدولة');
});
it('中文表头应输出清晰中文列名', () => {
const csv = generateCsvContent(mockRows, 'zh');
expect(csv).toContain('访客标识,姓名,国家,城市,停留时长(秒),意向评分,访问渠道,访问时间');
});
});
describe('3. CardAnalyticsExportService 报表导出元数据', () => {
it('应生成包含文件名与行数统计的导出包', async () => {
const result = await service.exportRadarDataset([
{
visitorId: 'vis-101',
name: 'David',
country: 'GB',
city: 'London',
stayDurationSeconds: 200,
radarScore: 85,
trafficChannel: 'linkedin_share',
visitedAt: '2026-09-20 16:00:00',
},
], 'en');
expect(result.fileName).toMatch(/radar_export_.*\.csv/);
expect(result.rowCount).toBe(1);
expect(result.csvContent.length).toBeGreaterThan(0);
});
});
});