gongxiangp2/lib/__tests__/performance-salary-templates.test.ts

95 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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',
})
}
})
})