import { canDeleteWorkReviewProject, canResubmitWorkReviewProject, canSubmitWorkReview, deriveCompletedWorkReviewStatus, deriveWorkReviewDecision, getWorkReviewEmployeeAliasKeys, getWorkReviewEmployeeIdentityKeys, getWorkReviewEmployeeMaterialUserIds, getWorkReviewReviewerSelectionError, isSameWorkReviewEmployeeAlias, isSameWorkReviewEmployeeIdentity, validateWorkReviewAnnotations, } from '@/lib/work-review-policy' describe('work review policy', () => { test('allows any matched employee level to submit work', () => { expect(canSubmitWorkReview({ levelType: 'P' })).toBe(true) expect(canSubmitWorkReview({ levelType: 'M' })).toBe(true) expect(canSubmitWorkReview({ levelType: null })).toBe(true) expect(canSubmitWorkReview(null)).toBe(false) }) test('only grants project deletion to the wuxie account', () => { expect(canDeleteWorkReviewProject({ username: 'wuxie' })).toBe(true) expect(canDeleteWorkReviewProject({ username: ' WUXIE ' })).toBe(true) expect(canDeleteWorkReviewProject({ username: '无邪' })).toBe(true) expect(canDeleteWorkReviewProject({ username: '无邪管理员' })).toBe(false) expect(canDeleteWorkReviewProject({ username: 'admin' })).toBe(false) expect(canDeleteWorkReviewProject(null)).toBe(false) }) test('requires a distinct manual reviewer in addition to the fixed reviewer', () => { expect(getWorkReviewReviewerSelectionError({ reviewerEmployeeId: null, submitterEmployeeId: 'submitter', finalReviewerEmployeeId: 'yuanze', })).toBe('请选择评审人') expect(getWorkReviewReviewerSelectionError({ reviewerEmployeeId: 'submitter', submitterEmployeeId: 'submitter', finalReviewerEmployeeId: 'yuanze', })).toContain('不能选择自己') expect(getWorkReviewReviewerSelectionError({ reviewerEmployeeId: 'yuanze', submitterEmployeeId: 'submitter', finalReviewerEmployeeId: 'yuanze', })).toContain('元泽已是固定评审人') expect(getWorkReviewReviewerSelectionError({ reviewerEmployeeId: 'reviewer', submitterEmployeeId: 'submitter', finalReviewerEmployeeId: 'yuanze', })).toBeNull() }) test('recognizes historical profiles that belong to the same material account', () => { const current = { id: 'profile-current', dingtalkUserId: 'ding-current', dingEmail: 'wuxie@example.com', jobNumber: 'JS001', sourcePayload: { materialUserId: 'USER-WUXIE' }, } const historical = { id: 'profile-old', sourcePayload: { userId: 'user-wuxie', materialUserEmail: 'old@example.com' }, } expect(getWorkReviewEmployeeMaterialUserIds(historical)).toEqual(['user-wuxie']) expect(getWorkReviewEmployeeIdentityKeys(current)).toContain('user:user-wuxie') expect(isSameWorkReviewEmployeeIdentity(current, historical)).toBe(true) expect(isSameWorkReviewEmployeeIdentity(current, { id: 'profile-other', jobNumber: 'JS002', })).toBe(false) }) test('recognizes simplified and traditional variants of the same employee alias', () => { const current = { flowerName: '无邪', realName: '江林铖', displayName: '无邪' } const historical = { flowerName: '無邪', realName: '無邪', displayName: '無邪' } expect(getWorkReviewEmployeeAliasKeys(historical)).toContain('无邪') expect(isSameWorkReviewEmployeeAlias(current, historical)).toBe(true) expect(isSameWorkReviewEmployeeAlias(current, { flowerName: '若兰' })).toBe(false) }) test('marks one reviewer region as revision required when any image needs changes', () => { expect(deriveWorkReviewDecision([ { decision: 'approved' }, { decision: 'revision_required' }, ])).toBe('revision_required') }) test('does not complete the version until both independent reviewer regions exist', () => { expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'manager', decision: 'approved' }, ])).toBeNull() expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'final_reviewer', decision: 'approved' }, ])).toBeNull() }) test('requires both reviewer regions to approve the final version', () => { expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'manager', decision: 'approved' }, { reviewerRole: 'final_reviewer', decision: 'approved' }, ])).toBe('approved') expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'manager', decision: 'revision_required' }, { reviewerRole: 'final_reviewer', decision: 'approved' }, ])).toBe('revision_required') }) test('completes a manager-only test round immediately after the manager review', () => { expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'manager', decision: 'approved' }, ], ['manager'])).toBe('approved') expect(deriveCompletedWorkReviewStatus([ { reviewerRole: 'manager', decision: 'revision_required' }, ], ['manager'])).toBe('revision_required') }) test('only allows a new version when both project and latest version require changes', () => { const baseProject = { status: 'revision_required', versions: [{ status: 'revision_required' }], permissions: { canResubmit: true }, } expect(canResubmitWorkReviewProject(baseProject)).toBe(true) expect(canResubmitWorkReviewProject({ ...baseProject, status: 'approved', versions: [{ status: 'approved' }], })).toBe(false) expect(canResubmitWorkReviewProject({ ...baseProject, permissions: { canResubmit: false }, })).toBe(false) }) test('normalizes image annotations without storing viewport pixels', () => { expect(validateWorkReviewAnnotations([ { id: 'point-1', x: 0.123456789, y: 0.75, comment: ' 调整人物位置 ' }, { id: 'box-1', x: 0.11111119, y: 0.22222229, x2: 0.55555559, y2: 0.66666669, shape: 'rectangle', color: '#D92D20', comment: ' 框选人物 ', }, ])).toEqual({ ok: true, annotations: [ { id: 'point-1', x: 0.123457, y: 0.75, comment: '调整人物位置' }, { id: 'box-1', x: 0.111111, y: 0.222222, x2: 0.555556, y2: 0.666667, shape: 'rectangle', color: '#d92d20', comment: '框选人物', }, ], }) expect(validateWorkReviewAnnotations(undefined)).toEqual({ ok: true, annotations: [] }) }) test.each([ [[{ id: 'point-1', x: -0.1, y: 0.5, comment: '越界' }], '图片批注位置无效'], [[{ id: 'point-1', x: 0.5, y: '0.5', comment: '类型错误' }], '图片批注位置无效'], [[{ id: 'box-1', x: 0.2, y: 0.2, shape: 'rectangle', color: '#0050cb', comment: '缺少终点' }], '图片框选范围无效'], [[{ id: 'box-1', x: 0.2, y: 0.2, x2: 0.5, y2: 0.5, shape: 'triangle', color: '#0050cb', comment: '形状错误' }], '图片批注形状无效'], [[{ id: 'box-1', x: 0.2, y: 0.2, x2: 0.5, y2: 0.5, shape: 'rectangle', color: '#ff00ff', comment: '颜色错误' }], '图片批注颜色无效'], [[{ id: 'point-1', x: 0.5, y: 0.5, comment: ' ' }], '请填写每个标注点的修改意见'], [[ { id: 'point-1', x: 0.2, y: 0.2, comment: 'A' }, { id: 'point-1', x: 0.4, y: 0.4, comment: 'B' }, ], '图片批注编号无效或重复'], ])('rejects invalid image annotations', (annotations, message) => { const result = validateWorkReviewAnnotations(annotations) expect(result.ok).toBe(false) if (!result.ok) expect(result.error).toBe(message) }) })