131 lines
4.7 KiB
TypeScript
131 lines
4.7 KiB
TypeScript
import ExcelJS from 'exceljs'
|
||
import {
|
||
buildPerformanceSurveyDashboardWorkbook,
|
||
buildPerformanceSurveyExportTable,
|
||
choosePerformanceSurveyExportDestination,
|
||
sanitizePerformanceSurveyExportFileName,
|
||
savePerformanceSurveyDashboardWorkbook,
|
||
type PerformanceSurveyDashboardExportData,
|
||
} from '@/lib/performance-survey-dashboard-export'
|
||
|
||
const exportData: PerformanceSurveyDashboardExportData = {
|
||
month: '2026-07',
|
||
filters: { positionGroupCode: 'brand_creative_manager' },
|
||
selectedPositionGroup: { code: 'brand_creative_manager', name: '品牌创意主管' },
|
||
positionGroups: [{ code: 'brand_creative_manager', name: '品牌创意主管' }],
|
||
templates: [
|
||
{ code: 'visual_review', name: '品牌调性视觉评分', maxTotal: 120 },
|
||
{ code: 'coordination', name: '跨部门协同', maxTotal: 120 },
|
||
{ code: 'cooperation', name: '工作配合度', maxTotal: 120 },
|
||
],
|
||
public: {
|
||
rows: [
|
||
{
|
||
month: '2026-07',
|
||
employee: {
|
||
displayName: '伯言',
|
||
jobNumber: 'JS15040602',
|
||
departmentName: '品牌创意A部',
|
||
positionLevel: 'M2',
|
||
},
|
||
cells: {
|
||
visual_review: { score: null, surveyCount: 1, positionGroupCode: 'brand_creative_manager' },
|
||
coordination: { score: 114.5, surveyCount: 1, positionGroupCode: 'brand_creative_manager' },
|
||
cooperation: { score: 98, surveyCount: 1, positionGroupCode: 'brand_creative_manager' },
|
||
},
|
||
},
|
||
],
|
||
},
|
||
}
|
||
|
||
describe('performance survey dashboard xlsx export', () => {
|
||
test('keeps numeric scores numeric and marks pending assessments clearly', () => {
|
||
const table = buildPerformanceSurveyExportTable(exportData)
|
||
|
||
expect(table.headers).toEqual([
|
||
'序号',
|
||
'岗位',
|
||
'考核月份',
|
||
'姓名',
|
||
'工号',
|
||
'组织',
|
||
'职级',
|
||
'品牌调性视觉评分(满分120)',
|
||
'跨部门协同(满分120)',
|
||
'工作配合度(满分120)',
|
||
])
|
||
expect(table.rows[0]).toEqual([
|
||
1,
|
||
'品牌创意主管',
|
||
'2026-07',
|
||
'伯言',
|
||
'JS15040602',
|
||
'品牌创意A部',
|
||
'M2',
|
||
'待评分',
|
||
114.5,
|
||
98,
|
||
])
|
||
})
|
||
|
||
test('creates a WPS-compatible workbook with title, filters and score rows', async () => {
|
||
const workbook = await buildPerformanceSurveyDashboardWorkbook(exportData)
|
||
const buffer = await workbook.xlsx.writeBuffer()
|
||
const reloaded = new ExcelJS.Workbook()
|
||
await reloaded.xlsx.load(buffer)
|
||
|
||
const worksheet = reloaded.worksheets[0]
|
||
expect(worksheet.name).toBe('2026-07_品牌创意主管')
|
||
expect(worksheet.getCell('A1').value).toBe('2026-07 · 品牌创意主管考核调研得分')
|
||
expect(worksheet.getCell('A5').value).toBe(1)
|
||
expect(worksheet.getCell('H5').value).toBe('待评分')
|
||
expect(worksheet.getCell('I5').value).toBe(114.5)
|
||
expect(worksheet.autoFilter).toBe('A4:J4')
|
||
})
|
||
|
||
test('sanitizes file-system reserved characters', () => {
|
||
expect(sanitizePerformanceSurveyExportFileName('考核:品牌/设计*主管'))
|
||
.toBe('考核_品牌_设计_主管.xlsx')
|
||
})
|
||
|
||
test('keeps the browser context when opening the native save picker', async () => {
|
||
const handle = { createWritable: jest.fn() }
|
||
const picker = jest.fn(function (this: unknown) {
|
||
expect(this).toBe(window)
|
||
return Promise.resolve(handle)
|
||
})
|
||
Object.defineProperty(window, 'showSaveFilePicker', {
|
||
configurable: true,
|
||
value: picker,
|
||
})
|
||
|
||
await expect(choosePerformanceSurveyExportDestination('考核调研.xlsx'))
|
||
.resolves.toEqual({ kind: 'file-system', handle })
|
||
expect(picker).toHaveBeenCalledWith(expect.objectContaining({
|
||
suggestedName: '考核调研.xlsx',
|
||
}))
|
||
|
||
delete (window as typeof window & { showSaveFilePicker?: unknown }).showSaveFilePicker
|
||
})
|
||
|
||
test('uses a native blob download when the save picker is unavailable', async () => {
|
||
const createObjectURL = jest.fn(() => 'blob:performance-survey-export')
|
||
const revokeObjectURL = jest.fn()
|
||
Object.defineProperty(URL, 'createObjectURL', { configurable: true, value: createObjectURL })
|
||
Object.defineProperty(URL, 'revokeObjectURL', { configurable: true, value: revokeObjectURL })
|
||
const click = jest.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => {})
|
||
|
||
await savePerformanceSurveyDashboardWorkbook(
|
||
exportData,
|
||
'考核调研_品牌创意主管_2026-07.xlsx',
|
||
{ kind: 'download' },
|
||
)
|
||
|
||
expect(createObjectURL).toHaveBeenCalledWith(expect.any(Blob))
|
||
expect(click).toHaveBeenCalledTimes(1)
|
||
await new Promise((resolve) => window.setTimeout(resolve, 0))
|
||
expect(revokeObjectURL).toHaveBeenCalledWith('blob:performance-survey-export')
|
||
click.mockRestore()
|
||
})
|
||
})
|