import { ComparisonOperator, ConditionsLogic, Employee, HeadType, ProjectRole, RouteStepStatus, TemplateRouteStep } from '../models'; import { describeStepCondition, describeStepExecutor, detectExecutorKind } from './stepExecutor'; function step(overrides: Partial): TemplateRouteStep { return { id: 1, orderNo: 1, executorEmail: null, position: null, projectRole: null, headType: null, status: RouteStepStatus.Approval, routeId: 1, allowReassignToOtherApprovers: false, conditions: [], conditionsLogic: ConditionsLogic.And, slaHours: null, askOverdueReason: null, ...overrides }; } describe('detectExecutorKind', () => { it('email имеет приоритет над остальными способами', () => { expect(detectExecutorKind({ executorEmail: 'a@tnsu.kz', position: 'Директор' })).toBe('email'); }); it('при отсутствии email — position', () => { expect(detectExecutorKind({ position: 'Директор' })).toBe('position'); }); it('при отсутствии email/position — projectRole, если он не None', () => { expect(detectExecutorKind({ projectRole: ProjectRole.Planner })).toBe('projectRole'); }); it('projectRole=None не считается заданным способом', () => { expect(detectExecutorKind({ projectRole: ProjectRole.None })).toBe('headType'); }); it('если ничего не задано — headType (последний вариант по умолчанию)', () => { expect(detectExecutorKind({})).toBe('headType'); }); }); describe('describeStepExecutor', () => { const employees: Employee[] = [ { fio: 'Горбенко Павел', email: 'gorbenko.pavel@tnsu.kz', position: 'Разработчик', company: 'ТОО TANSU Construction', companies: ['ТОО TANSU Construction'] } ]; it('для email найденного сотрудника показывает ФИО, а должность и email — отдельной строкой', () => { const result = describeStepExecutor(step({ executorEmail: 'gorbenko.pavel@tnsu.kz' }), employees); expect(result).toEqual({ primary: 'Горбенко Павел', secondary: 'Разработчик · gorbenko.pavel@tnsu.kz' }); }); // Должность в справочнике заполнена не у всех — тогда подпись не должна // начинаться с висящего разделителя. it('для сотрудника без должности в подписи остаётся только email', () => { const result = describeStepExecutor(step({ executorEmail: 'nopos@tnsu.kz' }), [ { fio: 'Без Должности', email: 'nopos@tnsu.kz', position: '', company: '', companies: [] } ]); expect(result).toEqual({ primary: 'Без Должности', secondary: 'nopos@tnsu.kz' }); }); it('для email, которого нет в справочнике, показывает сам email без secondary', () => { const result = describeStepExecutor(step({ executorEmail: 'unknown@tnsu.kz' }), employees); expect(result).toEqual({ primary: 'unknown@tnsu.kz' }); }); it('для шага по должности показывает должность', () => { const result = describeStepExecutor(step({ position: 'Главный бухгалтер' }), employees); expect(result.primary).toBe('Главный бухгалтер'); }); it('для шага по проектной роли показывает подпись роли', () => { const result = describeStepExecutor(step({ projectRole: ProjectRole.Planner }), employees); expect(result.primary).toEqual(expect.stringContaining('Роль:')); }); it('для шага по типу руководителя показывает подпись типа', () => { const result = describeStepExecutor(step({ headType: HeadType.Chief }), employees); expect(result.primary).toEqual(expect.stringContaining('Руководитель:')); }); it('если у шага вообще не задан исполнитель — пустое значение', () => { const result = describeStepExecutor(step({}), employees); expect(result.secondary).toBeUndefined(); }); }); describe('describeStepCondition', () => { it('undefined, если условий нет', () => { expect(describeStepCondition(step({}))).toBeUndefined(); }); it('собирает "поле оператор значение", если условие одно', () => { const result = describeStepCondition( step({ conditions: [{ fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '100' }] }) ); expect(result).toBe('Amount > 100'); }); it('несколько условий склеиваются через "И"', () => { const result = describeStepCondition( step({ conditions: [ { fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '1000' }, { fieldName: 'Priority', operation: ComparisonOperator.Equal, value: 'Urgent' } ], conditionsLogic: ConditionsLogic.And }) ); expect(result).toBe('Amount > 1000 И Priority = Urgent'); }); it('несколько условий склеиваются через "ИЛИ"', () => { const result = describeStepCondition( step({ conditions: [ { fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '1000' }, { fieldName: 'Priority', operation: ComparisonOperator.Equal, value: 'Urgent' } ], conditionsLogic: ConditionsLogic.Or }) ); expect(result).toBe('Amount > 1000 ИЛИ Priority = Urgent'); }); });