import { readFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { resolve } from 'node:path'; import { describe, expect, it } from 'vitest'; import * as XLSX from 'xlsx'; const require = createRequire(import.meta.url); const { parseTableByFileName, parseXlsxBuffer } = require('../miniapp/utils/sankey.js') as { parseTableByFileName: (fileName: string, payload: string | ArrayBuffer) => { headers: string[]; rows: string[][]; }; parseXlsxBuffer: (buffer: ArrayBuffer) => { headers: string[]; rows: string[][]; }; }; describe('miniapp utils sankey', () => { it('按文件后缀分流解析 csv', () => { const table = parseTableByFileName('demo.csv', 'source,value,target\nA,12,T1'); expect(table.headers).toEqual(['source', 'value', 'target']); expect(table.rows).toEqual([['A', '12', 'T1']]); }); it('按文件后缀分流解析 xlsx', () => { const filePath = resolve(process.cwd(), 'data/example0.xlsx'); const buffer = readFileSync(filePath); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseTableByFileName('demo.xlsx', arrayBuffer); expect(table.headers.length).toBeGreaterThan(1); expect(table.rows.length).toBeGreaterThan(0); }); it('直接解析 xlsx buffer', () => { const filePath = resolve(process.cwd(), 'data/example0.xlsx'); const buffer = readFileSync(filePath); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseXlsxBuffer(arrayBuffer); expect(table.headers.length).toBeGreaterThan(1); expect(table.rows.length).toBeGreaterThan(0); }); it('xlsx !ref 范围虚高时,不应错误膨胀行列数量', () => { const sheet = XLSX.utils.aoa_to_sheet([ ['source', 'target', 'value'], ['A', 'B', 1] ]); sheet['!ref'] = 'A1:H20'; const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, sheet, 'S1'); const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' }); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseXlsxBuffer(arrayBuffer); expect(table.headers).toEqual(['source', 'target', 'value']); expect(table.rows).toEqual([['A', 'B', '1']]); }); it('xlsx 中 0 值应被正确保留', () => { const sheet = XLSX.utils.aoa_to_sheet([ ['source', 'target', 'value'], ['A', 'B', 0] ]); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, sheet, 'S1'); const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' }); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseXlsxBuffer(arrayBuffer); expect(table.rows).toEqual([['A', 'B', '0']]); }); it('xlsx 中常见中文乱码应尝试自动恢复', () => { const sheet = XLSX.utils.aoa_to_sheet([['人數'], ['张三']]); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, sheet, 'S1'); const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' }); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseXlsxBuffer(arrayBuffer); expect(table.headers).toEqual(['人數']); expect(table.rows).toEqual([['张三']]); }); it('文件名后缀缺失时,仍可根据二进制魔数识别 xlsx', () => { const sheet = XLSX.utils.aoa_to_sheet([ ['source', 'target', 'value'], ['A', 'B', 1] ]); const workbook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(workbook, sheet, 'S1'); const buffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'buffer' }); const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); const table = parseTableByFileName('upload.bin', arrayBuffer); expect(table.headers).toEqual(['source', 'target', 'value']); expect(table.rows).toEqual([['A', 'B', '1']]); }); });