import { describe, it, expect } from 'vitest'; import { StepTransitionValidator } from '../../../../src/packages/domain/services/StepTransitionValidator'; import { StepId } from '../../../../src/packages/domain/value-objects/StepId'; import { SessionState } from '../../../../src/packages/domain/value-objects/SessionState'; describe('StepTransitionValidator Service', () => { describe('canTransition', () => { it('should allow sequential forward transition', () => { const currentStep = StepId.create(1); const nextStep = StepId.create(2); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(true); expect(result.error).toBeUndefined(); }); it('should reject transition when not IN_PROGRESS', () => { const currentStep = StepId.create(1); const nextStep = StepId.create(2); const state = SessionState.create('PENDING'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(false); expect(result.error).toBe('Session must be in progress to transition steps'); }); it('should reject skipping steps', () => { const currentStep = StepId.create(1); const nextStep = StepId.create(3); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(false); expect(result.error).toBe('Cannot skip steps - must progress sequentially'); }); it('should reject backward transitions', () => { const currentStep = StepId.create(5); const nextStep = StepId.create(4); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(false); expect(result.error).toBe('Cannot move backward - steps must progress forward only'); }); it('should reject same step transition', () => { const currentStep = StepId.create(5); const nextStep = StepId.create(5); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(false); expect(result.error).toBe('Already at this step'); }); it('should allow transition through modal steps', () => { const currentStep = StepId.create(5); const nextStep = StepId.create(6); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(true); }); it('should allow transition from modal step to next', () => { const currentStep = StepId.create(6); const nextStep = StepId.create(7); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(true); }); }); describe('validateModalStepTransition', () => { it('should allow entering modal step 6', () => { const currentStep = StepId.create(5); const nextStep = StepId.create(6); const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep); expect(result.isValid).toBe(true); }); it('should allow entering modal step 9', () => { const currentStep = StepId.create(8); const nextStep = StepId.create(9); const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep); expect(result.isValid).toBe(true); }); it('should allow entering modal step 12', () => { const currentStep = StepId.create(11); const nextStep = StepId.create(12); const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep); expect(result.isValid).toBe(true); }); it('should allow exiting modal step 6', () => { const currentStep = StepId.create(6); const nextStep = StepId.create(7); const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep); expect(result.isValid).toBe(true); }); it('should allow non-modal transitions', () => { const currentStep = StepId.create(1); const nextStep = StepId.create(2); const result = StepTransitionValidator.validateModalStepTransition(currentStep, nextStep); expect(result.isValid).toBe(true); }); }); describe('shouldStopAtStep18', () => { it('should return true when transitioning to step 18', () => { const nextStep = StepId.create(18); const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep); expect(shouldStop).toBe(true); }); it('should return false for steps before 18', () => { const nextStep = StepId.create(17); const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep); expect(shouldStop).toBe(false); }); it('should return false for early steps', () => { const nextStep = StepId.create(1); const shouldStop = StepTransitionValidator.shouldStopAtStep18(nextStep); expect(shouldStop).toBe(false); }); }); describe('getStepDescription', () => { it('should return description for step 1', () => { const step = StepId.create(1); const description = StepTransitionValidator.getStepDescription(step); expect(description).toBe('Navigate to Hosted Racing page'); }); it('should return description for step 6 (modal)', () => { const step = StepId.create(6); const description = StepTransitionValidator.getStepDescription(step); expect(description).toBe('Add Admin (Modal)'); }); it('should return description for step 18 (final)', () => { const step = StepId.create(18); const description = StepTransitionValidator.getStepDescription(step); expect(description).toBe('Track Conditions (STOP - Manual Submit Required)'); }); it('should return descriptions for all modal steps', () => { const modalSteps = [6, 9, 12]; modalSteps.forEach(stepNum => { const step = StepId.create(stepNum); const description = StepTransitionValidator.getStepDescription(step); expect(description).toContain('(Modal)'); }); }); }); describe('edge cases', () => { it('should handle rapid sequential transitions', () => { const state = SessionState.create('IN_PROGRESS'); let currentStep = StepId.create(1); for (let i = 2; i <= 18; i++) { const nextStep = StepId.create(i); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(true); currentStep = nextStep; } }); it('should prevent transitions from terminal states', () => { const terminalStates = ['COMPLETED', 'FAILED', 'STOPPED_AT_STEP_18'] as const; terminalStates.forEach(stateValue => { const currentStep = StepId.create(10); const nextStep = StepId.create(11); const state = SessionState.create(stateValue); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(false); }); }); it('should allow transition from PAUSED when resumed', () => { const currentStep = StepId.create(5); const nextStep = StepId.create(6); const state = SessionState.create('IN_PROGRESS'); const result = StepTransitionValidator.canTransition(currentStep, nextStep, state); expect(result.isValid).toBe(true); }); }); });