@@ -178,29 +178,39 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
178178 } ) ;
179179
180180 it ( 'should refetch employment after inviting the contractor' , async ( ) => {
181- const refetchEmploymentMock = vi . fn ( ) ;
182- mockRender . mockImplementation ( ( { contractorOnboardingBag, components } ) => {
183- contractorOnboardingBag . refetchEmployment = refetchEmploymentMock ;
184- const { OnboardingInvite } = components ;
185- return (
186- < OnboardingInvite
187- data-testid = 'onboarding-invite'
188- onSuccess = { mockSuccess }
189- onError = { mockError }
190- onSubmit = { mockSubmit }
191- render = { ( ) => 'Invite Contractor' }
192- />
193- ) ;
194- } ) ;
181+ const getEmploymentSpy = vi . fn ( ) ;
195182
183+ server . use (
184+ http . get ( '*/v1/employments/:id' , ( { request } ) => {
185+ getEmploymentSpy ( request . url ) ;
186+ return HttpResponse . json ( mockContractorEmploymentResponse ) ;
187+ } ) ,
188+ ) ;
196189 render ( < ContractorOnboardingFlow { ...defaultProps } /> , {
197190 wrapper : TestProviders ,
198191 } ) ;
199- const button = await screen . findByTestId ( 'onboarding-invite' ) ;
192+
193+ // CRITICAL: Wait for initial load to complete
194+ await waitForElementToBeRemoved ( ( ) => screen . getByTestId ( 'spinner' ) ) ;
195+
196+ // Verify initial employment fetch happened
197+ expect ( getEmploymentSpy ) . toHaveBeenCalledTimes ( 1 ) ;
198+
199+ // Find and click the button
200+ const button = screen . getByText ( / I n v i t e C o n t r a c t o r / i) ;
200201 fireEvent . click ( button ) ;
202+ // Wait for the invite to complete and verify refetch happened
203+ await waitFor ( ( ) => {
204+ expect ( mockSubmit ) . toHaveBeenCalled ( ) ;
205+ } ) ;
201206
202207 await waitFor ( ( ) => {
203- expect ( refetchEmploymentMock ) . toHaveBeenCalled ( ) ;
208+ expect ( mockSuccess ) . toHaveBeenCalled ( ) ;
209+ } ) ;
210+
211+ // Verify employment was fetched again (refetch happened)
212+ await waitFor ( ( ) => {
213+ expect ( getEmploymentSpy ) . toHaveBeenCalledTimes ( 2 ) ;
204214 } ) ;
205215 } ) ;
206216
@@ -273,6 +283,86 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
273283 expect ( button ) . toBeInTheDocument ( ) ;
274284 expect ( button ) . toHaveTextContent ( 'Default Button' ) ;
275285 } ) ;
286+
287+ it ( 'should disable button when employment status is "invited"' , async ( ) => {
288+ server . use (
289+ http . get ( '*/v1/employments/*' , ( ) => {
290+ return HttpResponse . json ( {
291+ ...mockContractorEmploymentResponse ,
292+ data : {
293+ ...mockContractorEmploymentResponse . data ,
294+ employment : {
295+ ...mockContractorEmploymentResponse . data . employment ,
296+ status : 'invited' ,
297+ } ,
298+ } ,
299+ } ) ;
300+ } ) ,
301+ ) ;
302+
303+ mockRender . mockImplementation ( ( { components } ) => {
304+ const { OnboardingInvite } = components ;
305+ return (
306+ < OnboardingInvite
307+ data-testid = 'onboarding-invite'
308+ onSuccess = { mockSuccess }
309+ onError = { mockError }
310+ onSubmit = { mockSubmit }
311+ render = { ( ) => 'Invite Contractor' }
312+ />
313+ ) ;
314+ } ) ;
315+
316+ render ( < ContractorOnboardingFlow { ...defaultProps } /> , {
317+ wrapper : TestProviders ,
318+ } ) ;
319+
320+ const button = await screen . findByTestId ( 'onboarding-invite' ) ;
321+
322+ await waitFor ( ( ) => {
323+ expect ( button ) . toBeDisabled ( ) ;
324+ } ) ;
325+ } ) ;
326+
327+ it ( 'should disable button when employment status is "created_awaiting_reserve"' , async ( ) => {
328+ server . use (
329+ http . get ( '*/v1/employments/*' , ( ) => {
330+ return HttpResponse . json ( {
331+ ...mockContractorEmploymentResponse ,
332+ data : {
333+ ...mockContractorEmploymentResponse . data ,
334+ employment : {
335+ ...mockContractorEmploymentResponse . data . employment ,
336+ status : 'created_awaiting_reserve' ,
337+ } ,
338+ } ,
339+ } ) ;
340+ } ) ,
341+ ) ;
342+
343+ mockRender . mockImplementation ( ( { components } ) => {
344+ const { OnboardingInvite } = components ;
345+ return (
346+ < OnboardingInvite
347+ data-testid = 'onboarding-invite'
348+ onSuccess = { mockSuccess }
349+ onError = { mockError }
350+ onSubmit = { mockSubmit }
351+ render = { ( ) => 'Invite Contractor' }
352+ />
353+ ) ;
354+ } ) ;
355+
356+ render ( < ContractorOnboardingFlow { ...defaultProps } /> , {
357+ wrapper : TestProviders ,
358+ } ) ;
359+
360+ const button = await screen . findByTestId ( 'onboarding-invite' ) ;
361+
362+ await waitFor ( ( ) => {
363+ expect ( button ) . toBeDisabled ( ) ;
364+ } ) ;
365+ } ) ;
276366 } ) ;
277367
278368 describe ( 'render prop functionality' , ( ) => {
@@ -352,16 +442,17 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
352442 expect ( customButton ) . toBeInTheDocument ( ) ;
353443 expect ( customButton ) . toHaveTextContent ( 'Custom Button Label' ) ;
354444
355- // Verify custom button received correct props
356- expect ( MockCustomButton ) . toHaveBeenCalledWith (
357- expect . objectContaining ( {
358- className : 'test-class' ,
359- disabled : false ,
360- onClick : expect . any ( Function ) ,
361- children : 'Custom Button Label' ,
362- } ) ,
363- { } ,
364- ) ;
445+ await waitFor ( ( ) => {
446+ expect ( MockCustomButton ) . toHaveBeenCalledWith (
447+ expect . objectContaining ( {
448+ className : 'test-class' ,
449+ disabled : false ,
450+ onClick : expect . any ( Function ) ,
451+ children : 'Custom Button Label' ,
452+ } ) ,
453+ { } ,
454+ ) ;
455+ } ) ;
365456 } ) ;
366457
367458 it ( 'should apply disabled state correctly to custom button' , async ( ) => {
@@ -418,7 +509,9 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
418509 } ) ;
419510
420511 const customButton = await screen . findByTestId ( 'custom-button' ) ;
421- expect ( customButton ) . not . toBeDisabled ( ) ; // Initially not disabled
512+ await waitFor ( ( ) => {
513+ expect ( customButton ) . not . toBeDisabled ( ) ;
514+ } ) ;
422515
423516 fireEvent . click ( customButton ) ;
424517
@@ -453,6 +546,15 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
453546 wrapper : customWrapper ,
454547 } ) ;
455548
549+ await waitFor ( ( ) => {
550+ expect ( MockCustomButton ) . toHaveBeenCalledWith (
551+ expect . objectContaining ( {
552+ disabled : false ,
553+ } ) ,
554+ expect . anything ( ) ,
555+ ) ;
556+ } ) ;
557+
456558 const customButton = await screen . findByTestId ( 'custom-button' ) ;
457559 fireEvent . click ( customButton ) ;
458560
@@ -492,6 +594,15 @@ describe('ContractorOnboarding - OnboardingInvite', () => {
492594
493595 await screen . findByTestId ( 'custom-button' ) ;
494596
597+ await waitFor ( ( ) => {
598+ expect ( MockCustomButton ) . toHaveBeenCalledWith (
599+ expect . objectContaining ( {
600+ disabled : false ,
601+ } ) ,
602+ expect . anything ( ) ,
603+ ) ;
604+ } ) ;
605+
495606 expect ( MockCustomButton ) . toHaveBeenCalledWith (
496607 expect . objectContaining ( {
497608 'data-testid' : 'custom-button' ,
0 commit comments