Files
ReceiptGenerator/tests/workbook-fields.test.ts
T

51 lines
3.3 KiB
TypeScript

import {it,expect,beforeEach,afterEach} from 'vitest'
import ExcelJS from 'exceljs'
import {mkdtemp,rm} from 'node:fs/promises'
import {tmpdir} from 'node:os'
import path from 'node:path'
import {XlsxReader,createWorkbookTemplate} from '../src/main/workbooks'
import {Ledger} from '../src/main/ledger'
import {defaultSettings} from '../src/shared/settings'
let dir:string
const headers=['收款日期','学校','年级','姓名','收费项目','金额','出纳','复核']
beforeEach(async()=>{dir=await mkdtemp(path.join(tmpdir(),'receipt-fields-'))})
afterEach(async()=>{await rm(dir,{recursive:true,force:true})})
async function workbook(row:unknown[],columns=headers){
const file=path.join(dir,'data.xlsx'),book=new ExcelJS.Workbook(),sheet=book.addWorksheet('收据数据')
sheet.addRow(columns);sheet.addRow(row);await book.xlsx.writeFile(file);return file
}
it('下载模板包含学校、年级、姓名,金额列和筛选范围随之调整',async()=>{
const file=path.join(dir,'template.xlsx');await createWorkbookTemplate(file)
const book=new ExcelJS.Workbook();await book.xlsx.readFile(file);const sheet=book.worksheets[0]
expect(sheet.getRow(1).values).toEqual([undefined,...headers])
expect(sheet.getColumn(6).numFmt).toBe('0.00');expect(sheet.autoFilter).toBe('A1:H1')
const draft=await new XlsxReader().read(file)
expect(draft.rows[0].errors).toEqual([])
expect(draft.rows[0].receipt.customer).toBe('某某学校 初二年级 张三')
})
it('三列去除首尾空白后,用单个空格拼接,并保留原字段用于扩展',async()=>{
const file=await workbook(['2026-10-16',' 巴南中学 ',' 高2028届 ',' 张三 ','服务费',3500])
const draft=await new XlsxReader().read(file),receipt=draft.rows[0].receipt
expect(receipt.customer).toBe('巴南中学 高2028届 张三')
expect(receipt).toMatchObject({school:'巴南中学',grade:'高2028届',studentName:'张三'})
expect(draft.rows[0].errors).toEqual([])
const store=new Ledger(path.join(dir,'db.sqlite'));await store.open()
const batch=await store.reserve({name:'data.xlsx',hash:'hash'},[receipt],defaultSettings(),null)
expect(store.get(batch.id).receipts[0]).toMatchObject({school:'巴南中学',grade:'高2028届',studentName:'张三',customer:'巴南中学 高2028届 张三'})
})
it.each([[1,'学校'],[2,'年级'],[3,'姓名']] as const)('%s 列缺失时,定位具体必填字段',async(index,label)=>{
const row:unknown[]=['2026-10-16','学校','年级','张三','服务费',3500];row[index]=' '
const draft=await new XlsxReader().read(await workbook(row))
expect(draft.rows[0].errors).toContain(label+'不能为空')
})
it('缺少拆分后的表头时提示重新下载模板',async()=>{
const file=await workbook(['2026-10-16','学校 年级 张三','服务费',3500],['收款日期','客户名称','收费项目','金额'])
await expect(new XlsxReader().read(file)).rejects.toThrow('第一行缺少表头:学校、年级、姓名')
})
it('按表头识别三列,而非依赖固定列序',async()=>{
const file=await workbook(['张三',3500,'高2028届','2026-10-16','服务费','学校'],['姓名','金额','年级','收款日期','收费项目','学校'])
const draft=await new XlsxReader().read(file)
expect(draft.rows[0].receipt.customer).toBe('学校 高2028届 张三')
expect(draft.rows[0].errors).toEqual([])
})