95 lines
6.6 KiB
TypeScript
95 lines
6.6 KiB
TypeScript
import { currentSalaryMonth, previousSalaryMonth, getPositionSalaryTemplate, getSalaryTemplate, resolveSalaryMonth, salaryDetailsHref, salaryMonthLabel } from '@/lib/performance-salary-templates'
|
||
import { INITIAL_SALARY_POSITIONS } from '@/lib/salary-position-seeds'
|
||
|
||
describe('薪资模板月份与字段', () => {
|
||
test('上海时区跨月及非法查询参数', () => {
|
||
const now = new Date('2026-12-31T16:00:00Z')
|
||
expect(currentSalaryMonth(now)).toBe('2027-01')
|
||
for (const value of [undefined, '', '2026-13', '2026-1', '0000-01', ['2026-09'], '2026-09<script>']) {
|
||
expect(resolveSalaryMonth(value, now)).toBe('2027-01')
|
||
}
|
||
expect(resolveSalaryMonth('2026-09', now)).toBe('2026-09')
|
||
expect(salaryMonthLabel('2027-01', -1)).toBe('2026年12月')
|
||
expect(salaryMonthLabel('2027-01', -2)).toBe('2026年11月')
|
||
expect(salaryDetailsHref('management', '2027-01')).toBe('/workspaces/organization/performance-review?role=management&month=2027-01')
|
||
})
|
||
|
||
test.each([['2026-10', '2026-09'], ['2026-09', '2026-08'], ['2027-01', '2026-12'], ['0099-01', '0098-12']])('市场验证月份%s取上月%s', (month, expected) => {
|
||
expect(previousSalaryMonth(month)).toBe(expected)
|
||
})
|
||
|
||
test('AI每项原始值紧邻综合占比考核得分,删除三项保底字段', () => {
|
||
const template = getSalaryTemplate('ai-planning', '2026-09')
|
||
expect(template.columns).toHaveLength(25)
|
||
expect(template.columns.map(column => column.label)).toEqual(expect.arrayContaining([
|
||
'创意成果市场验证 · 市场验证得分(上月)', '创意成果市场验证 · 考核得分(上月,综合占比7%)',
|
||
'品牌调性评审 · 调研得分', '品牌调性评审 · 考核得分(综合占比25%)',
|
||
'项目按时交付率 · 按时交付率', '项目按时交付率 · 考核得分(综合占比63%)',
|
||
]))
|
||
expect(template.columns.some(column => /Weighted/.test(column.key) || /加权得分|保底提成|实际保底/.test(column.label))).toBe(false)
|
||
})
|
||
|
||
test('摄影保留16列,薪资比较月份跨年', () => {
|
||
const template = getSalaryTemplate('photography', '2027-01')
|
||
expect(template.columns).toHaveLength(16)
|
||
expect(template.grouped).toBe(false)
|
||
expect(template.columns.slice(11, 14).map(column => column.label)).toEqual(['2027年1月合计总薪资', '2026年12月合计薪资', '2026年11月合计薪资'])
|
||
})
|
||
|
||
test('空间视觉恢复原始得分,未确认维度占比不猜测', () => {
|
||
const template = getSalaryTemplate('spatial-visual', '2026-10')
|
||
expect(template.columns).toHaveLength(22)
|
||
expect(template.columns.map(column => column.label)).not.toEqual(expect.arrayContaining(['百分比', '实际绩效']))
|
||
expect(template.groups.find(group => group.key === 'cooperation')?.label).toBe('配合度 · 维度权重5%')
|
||
expect(template.columns.map(column => column.label)).toContain('工作配合度 · 考核得分(综合占比0.3%)')
|
||
})
|
||
|
||
test('管理岗公共表头与策划岗一致,主管指标保留且不含积分或基础薪资遗留列', () => {
|
||
const template = getSalaryTemplate('management', '2027-01')
|
||
const planning = getSalaryTemplate('ai-planning', '2027-01')
|
||
const labels = template.columns.map(column => column.label)
|
||
expect(labels).toHaveLength(24)
|
||
expect(labels.filter(label => ['姓名', '花名', '部门'].includes(label))).toEqual(['花名', '姓名', '部门'])
|
||
expect(labels).not.toContain('保护提成')
|
||
expect(labels).not.toContain('基础薪资')
|
||
expect(template.columns.some(column => column.key === 'salaryBasis' || column.key === 'points')).toBe(false)
|
||
for (const key of ['identity', 'settlement', 'salary', 'remarks']) {
|
||
expect(template.groups.find(group => group.key === key)).toEqual(planning.groups.find(group => group.key === key))
|
||
}
|
||
expect(template.groups.filter(group => ['qualitative', 'quantitative', 'satisfaction'].includes(group.key)).flatMap(group => group.columns).filter(column => column.key.endsWith('Score'))).toHaveLength(6)
|
||
expect(new Set(template.columns.map(column => column.key)).size).toBe(24)
|
||
const supervisor = { ...INITIAL_SALARY_POSITIONS[0].value, id: 'supervisor', revision: 2, personnelCount: 0, updatedAt: '' }
|
||
const configured = getPositionSalaryTemplate(supervisor, '2027-01')
|
||
expect(configured.columns).toHaveLength(24)
|
||
for (const key of ['identity', 'settlement', 'salary', 'remarks']) {
|
||
expect(configured.groups.find(group => group.key === key)).toEqual(planning.groups.find(group => group.key === key))
|
||
}
|
||
expect(configured.columns.some(column => column.key === 'salaryBasis' || column.key === 'points')).toBe(false)
|
||
})
|
||
|
||
test.each(['ai-planning', 'photography', 'spatial-visual', 'management', 'ai-technical'] as const)('%s默认与配置模板保持原始值在前、考核得分在后', role => {
|
||
const position = { ...INITIAL_SALARY_POSITIONS[0].value, salaryRole: role, id: 'job', revision: 1, personnelCount: 0, updatedAt: '' }
|
||
for (const template of [getSalaryTemplate(role, '2026-09'), getPositionSalaryTemplate(position, '2026-09')]) {
|
||
expect(template.columns.some(column => column.key === 'brand' || column.label === '品牌')).toBe(false)
|
||
expect(template.columns[0]).toMatchObject({ key: 'nickname', label: '花名' })
|
||
if (role !== 'photography' || template.grouped) expect(template.columns[1]).toMatchObject({ key: 'name', label: '姓名' })
|
||
expect(template.columns.filter(column => column.key === 'performanceCoefficient')).toHaveLength(1)
|
||
expect(template.columns.some(column => column.key === 'performanceScore' || column.label.includes('绩效得分'))).toBe(false)
|
||
expect(template.columns.find(column => column.key === 'currentTotal')?.label).toBe('2026年9月合计总薪资')
|
||
template.columns.forEach((column, index) => {
|
||
if (!column.key.endsWith('RawValue')) return
|
||
expect(template.columns[index + 1].key).toBe(column.key.replace(/RawValue$/, 'Score'))
|
||
expect(template.columns[index + 1].label).toMatch(/考核得分((?:上月,)?综合占比/)
|
||
})
|
||
expect(template.columns.some(column => /Weighted/.test(column.key) || /加权得分/.test(column.label))).toBe(false)
|
||
}
|
||
const configured = getPositionSalaryTemplate(position, '2026-09')
|
||
for (const metric of position.dimensions.flatMap(dimension => dimension.metrics)) {
|
||
expect(configured.columns.find(column => column.key === `${metric.id}RawValue`)).toMatchObject({
|
||
label: `${metric.name} · ${metric.source.kind === 'survey' ? '调研得分' : metric.source.kind === 'on-time' ? '按时交付率' : '原始得分'}`,
|
||
kind: metric.source.kind === 'on-time' ? 'percent' : 'number',
|
||
})
|
||
}
|
||
})
|
||
})
|