Files
ReceiptGenerator/tests/export-layout.test.ts
T

35 lines
1.7 KiB
TypeScript

import {expect,it} from 'vitest'
import path from 'node:path'
import {groupReceipts} from '../src/main/export-layout'
import type {Receipt} from '../src/shared/types'
function receipt(school:string|undefined,grade='高一',item='服务费'):Receipt {
return {number:'SJ00000001',date:'2026-10-19',school,grade,customer:'学生',item,amountCents:100,cashier:'',reviewer:''}
}
it('旧记录没有学校年级时保留原客户名称,并落入未分类目录',()=>{
const original={...receipt(undefined),grade:undefined,customer:'以前的客户名称'}
expect(groupReceipts([original])[0].directory).toBe(path.join('未分类学校','未分类年级','服务费'))
expect(original.customer).toBe('以前的客户名称')
})
it('Windows 非法字符、保留名、路径跳转及超长名称生成安全且不混组的目录',()=>{
const schools=['学校/A','学校?A','学校_A','CON','..','ABC','abc','甲'.repeat(80)+'一','甲'.repeat(80)+'二']
const rows=schools.map((school,i)=>({...receipt(school,'../高一','资料:费'),number:String(i)}))
const groups=groupReceipts(rows),root=path.resolve('export-root')
expect(groups).toHaveLength(rows.length)
expect(new Set(groups.map(g=>g.directory.toLowerCase())).size).toBe(rows.length)
for(const group of groups){
expect(path.resolve(root,group.directory).startsWith(root+path.sep)).toBe(true)
const parts=group.directory.split(path.sep)
expect(parts).toHaveLength(3)
for(const part of parts){
expect(part).not.toMatch(/[<>:"/\\|?*\u0000-\u001f]/)
expect(part).not.toMatch(/[. ]$/)
expect(part).not.toMatch(/^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i)
expect(part.length).toBeLessThanOrEqual(80)
}
}
expect(groupReceipts(rows).map(g=>g.directory)).toEqual(groups.map(g=>g.directory))
})