Files
sankey/tests/miniapp.spec.ts
2026-02-14 11:20:38 +08:00

136 lines
5.2 KiB
TypeScript

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']]);
});
it('文件名伪装为 csv 时,仍可根据二进制魔数识别 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('wrong.csv', arrayBuffer);
expect(table.headers).toEqual(['source', 'target', 'value']);
expect(table.rows).toEqual([['A', 'B', '1']]);
});
it('csv 二进制内容应按 utf8 正常解析', () => {
const csvBuffer = Buffer.from('source,target,value\n甲,乙,1', 'utf8');
const arrayBuffer = csvBuffer.buffer.slice(
csvBuffer.byteOffset,
csvBuffer.byteOffset + csvBuffer.byteLength
);
const table = parseTableByFileName('demo.csv', arrayBuffer);
expect(table.headers).toEqual(['source', 'target', 'value']);
expect(table.rows).toEqual([['甲', '乙', '1']]);
});
});