| 1 | import { describe, expect, it } from 'vitest' |
| 2 | |
| 3 | import { convertCsvTextToMarkdown } from '../../../src/main/io/document-csv-to-markdown' |
| 4 | import { |
| 5 | deriveOutlinePageCandidates, |
| 6 | scanDocumentOutline |
| 7 | } from '../../../src/main/io/document-outline-scan' |
| 8 | |
| 9 | describe('document CSV to Markdown conversion', () => { |
| 10 | it('converts grouped CSV files into heading-backed markdown tables', () => { |
| 11 | const markdown = convertCsvTextToMarkdown( |
| 12 | [ |
| 13 | '部门,季度,收入,负责人', |
| 14 | '销售,Q1,120,张三', |
| 15 | '销售,Q2,150,张三', |
| 16 | '市场,Q1,80,李四', |
| 17 | '市场,Q2,90,李四' |
| 18 | ].join('\n'), |
| 19 | { title: '季度收入' } |
| 20 | ) |
| 21 | const scan = scanDocumentOutline(markdown) |
| 22 | const candidates = deriveOutlinePageCandidates(scan) |
| 23 | |
| 24 | expect(markdown).toContain('# 季度收入') |
| 25 | expect(markdown).toContain('- 字段:部门、季度、收入、负责人') |
| 26 | expect(markdown).toContain('## 按部门拆分') |
| 27 | expect(markdown).toContain('### 销售') |
| 28 | expect(markdown).not.toContain('CSV Table') |
| 29 | expect(markdown).not.toContain('Grouped by') |
| 30 | expect(markdown).toContain('| 部门 | 季度 | 收入 | 负责人 |') |
| 31 | expect(scan.headingCount).toBe(4) |
| 32 | expect(candidates.map((candidate) => candidate.sourceHeading)).toEqual([ |
| 33 | '## 按部门拆分', |
| 34 | '### 销售', |
| 35 | '### 市场' |
| 36 | ]) |
| 37 | expect(candidates[0].reason).toContain('销售、市场') |
| 38 | }) |
| 39 | |
| 40 | it('keeps ungrouped CSV files as a markdown table section', () => { |
| 41 | const markdown = convertCsvTextToMarkdown( |
| 42 | ['日期,指标,数值', '2026-01-01,DAU,100', '2026-01-02,DAU,105'].join('\n'), |
| 43 | { title: 'daily metrics.csv' } |
| 44 | ) |
| 45 | const scan = scanDocumentOutline(markdown) |
| 46 | const candidates = deriveOutlinePageCandidates(scan) |
| 47 | |
| 48 | expect(markdown).toContain('# daily metrics.csv') |
| 49 | expect(markdown).toContain('## 日期、指标、数值') |
| 50 | expect(markdown).not.toContain('CSV Table') |
| 51 | expect(markdown).toContain('| 日期 | 指标 | 数值 |') |
| 52 | expect(candidates.map((candidate) => candidate.sourceHeading)).toEqual(['## 日期、指标、数值']) |
| 53 | }) |
| 54 | |
| 55 | it('infers grouping from repeated values instead of hardcoded header names', () => { |
| 56 | const markdown = convertCsvTextToMarkdown( |
| 57 | [ |
| 58 | '业务线,客户,金额', |
| 59 | '新能源,A 公司,120', |
| 60 | '新能源,B 公司,130', |
| 61 | '售后,C 公司,80', |
| 62 | '售后,D 公司,90' |
| 63 | ].join('\n'), |
| 64 | { title: '客户收入' } |
| 65 | ) |
| 66 | const scan = scanDocumentOutline(markdown) |
| 67 | const candidates = deriveOutlinePageCandidates(scan) |
| 68 | |
| 69 | expect(markdown).toContain('## 按业务线拆分') |
| 70 | expect(markdown).toContain('### 新能源') |
| 71 | expect(markdown).toContain('### 售后') |
| 72 | expect(candidates.map((candidate) => candidate.sourceHeading)).toEqual([ |
| 73 | '## 按业务线拆分', |
| 74 | '### 新能源', |
| 75 | '### 售后' |
| 76 | ]) |
| 77 | expect(candidates[0].reason).toContain('新能源、售后') |
| 78 | }) |
| 79 | |
| 80 | it('preserves quoted commas and markdown table pipes safely', () => { |
| 81 | const markdown = convertCsvTextToMarkdown( |
| 82 | ['部门,说明', '销售,"包含,逗号"', '市场,"A|B 测试"'].join('\n'), |
| 83 | { title: 'quoted values' } |
| 84 | ) |
| 85 | |
| 86 | expect(markdown).toContain('| 销售 | 包含,逗号 |') |
| 87 | expect(markdown).toContain('| 市场 | A\\|B 测试 |') |
| 88 | }) |
| 89 | }) |
| 90 |