@@ -2634,6 +2634,84 @@ describe('ContractorOnboardingFlow', () => {
26342634 } ) ;
26352635 } ) ;
26362636
2637+ describe ( 'Contract Details 422 Errors' , ( ) => {
2638+ it ( 'should highlight fields and show error message when contract details submission fails with 422' , async ( ) => {
2639+ const employmentId = generateUniqueEmploymentId ( ) ;
2640+
2641+ // Mock the contract document creation to fail with 422
2642+ server . use (
2643+ http . post ( '*/v1/contractors/employments/*/contract-documents' , ( ) => {
2644+ return HttpResponse . json (
2645+ {
2646+ errors : {
2647+ 'service_duration.expiration_date' : [
2648+ 'date must be after start date' ,
2649+ ] ,
2650+ } ,
2651+ } ,
2652+ { status : 422 } ,
2653+ ) ;
2654+ } ) ,
2655+ ) ;
2656+
2657+ mockRender . mockImplementation (
2658+ createMockRenderImplementation ( MultiStepFormWithoutCountry ) ,
2659+ ) ;
2660+
2661+ render (
2662+ < ContractorOnboardingFlow
2663+ employmentId = { employmentId }
2664+ countryCode = 'PRT'
2665+ skipSteps = { [ 'select_country' ] }
2666+ { ...defaultProps }
2667+ /> ,
2668+ { wrapper : TestProviders } ,
2669+ ) ;
2670+
2671+ // Navigate to contract details step
2672+ await screen . findByText ( / S t e p : B a s i c I n f o r m a t i o n / i) ;
2673+ await waitForElementToBeRemoved ( ( ) => screen . getByTestId ( 'spinner' ) ) ;
2674+
2675+ await fillBasicInformation ( ) ;
2676+
2677+ let nextButton = screen . getByText ( / N e x t S t e p / i) ;
2678+ nextButton . click ( ) ;
2679+
2680+ await screen . findByText ( / S t e p : P r i c i n g P l a n / i) ;
2681+
2682+ await fillContractorSubscription ( ) ;
2683+
2684+ nextButton = screen . getByText ( / N e x t S t e p / i) ;
2685+ nextButton . click ( ) ;
2686+
2687+ await screen . findByText ( / S t e p : C o n t r a c t D e t a i l s / i) ;
2688+
2689+ // Fill contract details
2690+ await fillContractDetails ( ) ;
2691+
2692+ nextButton = screen . getByText ( / N e x t S t e p / i) ;
2693+ nextButton . click ( ) ;
2694+
2695+ // Wait for the error callback
2696+ await waitFor ( ( ) => {
2697+ expect ( mockOnError ) . toHaveBeenCalled ( ) ;
2698+ } ) ;
2699+
2700+ // Verify we stay on the contract details step
2701+ await screen . findByText ( / S t e p : C o n t r a c t D e t a i l s / i) ;
2702+
2703+ // Assert the field is highlighted (has aria-invalid attribute)
2704+ const serviceEndDateField = screen . getByTestId (
2705+ 'service_duration.expiration_date' ,
2706+ ) ;
2707+ expect ( serviceEndDateField ) . toBeInTheDocument ( ) ;
2708+ expect ( serviceEndDateField ) . toHaveAttribute ( 'aria-invalid' , 'true' ) ;
2709+ expect (
2710+ screen . getByText ( / d a t e m u s t b e a f t e r s t a r t d a t e / i) ,
2711+ ) . toBeInTheDocument ( ) ;
2712+ } ) ;
2713+ } ) ;
2714+
26372715 describe ( 'AI Validation Errors' , ( ) => {
26382716 it ( 'should display AI validation warning statement when contract document creation fails with non-skippable error for COR' , async ( ) => {
26392717 const employmentId = generateUniqueEmploymentId ( ) ;
0 commit comments