import { describe, it, expect } from 'vitest'; import { PageStateValidator } from 'apps/companion/main/automation/domain/services/PageStateValidator'; import { StepTransitionValidator } from 'apps/companion/main/automation/domain/services/StepTransitionValidator'; import { StepId } from 'apps/companion/main/automation/domain/value-objects/StepId'; import { SessionState } from 'apps/companion/main/automation/domain/value-objects/SessionState'; describe('Validator conformance (integration)', () => { describe('PageStateValidator with hosted-session selectors', () => { it('reports missing DOM markers with descriptive message', () => { const validator = new PageStateValidator(); const actualState = (selector: string) => { return selector === '#set-cars'; }; const result = validator.validateState(actualState, { expectedStep: 'track', requiredSelectors: ['#set-track', '#track-search'], }); expect(result.isOk()).toBe(true); const value = result.unwrap(); expect(value.isValid).toBe(false); expect(value.expectedStep).toBe('track'); expect(value.missingSelectors).toEqual(['#set-track', '#track-search']); expect(value.message).toBe( 'Page state mismatch: Expected to be on "track" page but missing required elements', ); }); it('reports unexpected DOM markers when forbidden selectors are present', () => { const validator = new PageStateValidator(); const actualState = (selector: string) => { return ['#set-cars', '#set-track'].includes(selector); }; const result = validator.validateState(actualState, { expectedStep: 'cars', requiredSelectors: ['#set-cars'], forbiddenSelectors: ['#set-track'], }); expect(result.isOk()).toBe(true); const value = result.unwrap(); expect(value.isValid).toBe(false); expect(value.expectedStep).toBe('cars'); expect(value.unexpectedSelectors).toEqual(['#set-track']); expect(value.message).toBe( 'Page state mismatch: Found unexpected elements on "cars" page', ); }); }); describe('StepTransitionValidator with hosted-session steps', () => { it('rejects illegal forward jumps with clear error', () => { const currentStep = StepId.create(3); const nextStep = StepId.create(9); 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('rejects backward jumps with clear error', () => { const currentStep = StepId.create(11); const nextStep = StepId.create(8); 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('provides descriptive step descriptions for hosted steps', () => { const step3 = StepTransitionValidator.getStepDescription( StepId.create(3), ); const step11 = StepTransitionValidator.getStepDescription( StepId.create(11), ); const finalStep = StepTransitionValidator.getStepDescription( StepId.create(17), ); expect(step3).toBe('Fill Race Information'); expect(step11).toBe('Set Track'); expect(finalStep).toBe( 'Track Conditions (STOP - Manual Submit Required)', ); }); }); });