@@ -115,33 +115,38 @@ vi.mock("../../utils/visualBuilderPostMessage", () => ({
115115 if ( Array . isArray ( fields ) ) {
116116 fields . forEach ( ( field : any ) => {
117117 // Return display name for every field to ensure dataLoading completes
118- if ( field . cslpValue === "mockFieldCslp" ) {
119- result [ field . cslpValue ] = "Field 0" ;
118+ // Use cslpValue as the key to match component's expectation
119+ const cslpValue = field ?. cslpValue || field ?. cslp || "" ;
120+ if ( ! cslpValue ) {
121+ // Skip if no cslpValue
122+ return ;
123+ }
124+ if ( cslpValue === "mockFieldCslp" ) {
125+ result [ cslpValue ] = "Field 0" ;
120126 } else if (
121- field . cslpValue ===
127+ cslpValue ===
122128 "contentTypeUid.entryUid.locale.parentPath1"
123129 ) {
124- result [ field . cslpValue ] = "Field 1" ;
130+ result [ cslpValue ] = "Field 1" ;
125131 } else if (
126- field . cslpValue ===
132+ cslpValue ===
127133 "contentTypeUid.entryUid.locale.parentPath2"
128134 ) {
129- result [ field . cslpValue ] = "Field 2" ;
135+ result [ cslpValue ] = "Field 2" ;
130136 } else if (
131- field . cslpValue ===
137+ cslpValue ===
132138 "contentTypeUid.entryUid.locale.parentPath3"
133139 ) {
134- result [ field . cslpValue ] = "Field 3" ;
140+ result [ cslpValue ] = "Field 3" ;
135141 } else {
136- // Fallback: use field path or cslpValue as display name
137- result [ field . cslpValue ] =
138- field . cslpValue ||
139- field . fieldPath ||
140- "Unknown Field" ;
142+ // Fallback: use cslpValue as display name to ensure we always return something
143+ result [ cslpValue ] = cslpValue ;
141144 }
142145 } ) ;
143146 }
144- // Return immediately resolved promise (no delay)
147+ // Ensure we return at least as many keys as fields requested
148+ // This is critical for dataLoading to become false
149+ // Component checks: Object.keys(displayNames || {})?.length === allPaths.length
145150 return Promise . resolve ( result ) ;
146151 } else if (
147152 eventName ===
@@ -303,6 +308,63 @@ describe("FieldLabelWrapperComponent", () => {
303308 reason : "" ,
304309 } ) ;
305310
311+ // Reset visualBuilderPostMessage mock to ensure it returns display names correctly
312+ vi . mocked ( visualBuilderPostMessage ! . send ) . mockImplementation (
313+ ( eventName : string , fields : any ) => {
314+ // Use enum values for comparison
315+ if (
316+ eventName ===
317+ VisualBuilderPostMessageEvents . GET_FIELD_DISPLAY_NAMES
318+ ) {
319+ // Always return display names for all requested fields immediately
320+ const result : Record < string , string > = { } ;
321+ if ( Array . isArray ( fields ) ) {
322+ fields . forEach ( ( field : any ) => {
323+ const cslpValue =
324+ field ?. cslpValue || field ?. cslp || "" ;
325+ if ( ! cslpValue ) return ;
326+ if ( cslpValue === "mockFieldCslp" ) {
327+ result [ cslpValue ] = "Field 0" ;
328+ } else if (
329+ cslpValue ===
330+ "contentTypeUid.entryUid.locale.parentPath1"
331+ ) {
332+ result [ cslpValue ] = "Field 1" ;
333+ } else if (
334+ cslpValue ===
335+ "contentTypeUid.entryUid.locale.parentPath2"
336+ ) {
337+ result [ cslpValue ] = "Field 2" ;
338+ } else if (
339+ cslpValue ===
340+ "contentTypeUid.entryUid.locale.parentPath3"
341+ ) {
342+ result [ cslpValue ] = "Field 3" ;
343+ } else {
344+ result [ cslpValue ] = cslpValue ;
345+ }
346+ } ) ;
347+ }
348+ return Promise . resolve ( result ) ;
349+ } else if (
350+ eventName ===
351+ VisualBuilderPostMessageEvents . GET_CONTENT_TYPE_NAME ||
352+ eventName === "get-content-type-name"
353+ ) {
354+ return Promise . resolve ( {
355+ contentTypeName : "Page CT" ,
356+ } ) ;
357+ } else if (
358+ eventName ===
359+ VisualBuilderPostMessageEvents . REFERENCE_MAP ||
360+ eventName === "get-reference-map"
361+ ) {
362+ return Promise . resolve ( { } ) ;
363+ }
364+ return Promise . resolve ( { } ) ;
365+ }
366+ ) ;
367+
306368 // Pre-set field schema in cache to avoid async fetch delay
307369 // This makes FieldSchemaMap.getFieldSchema resolve immediately from cache
308370 FieldSchemaMap . setFieldSchema ( mockFieldMetadata . content_type_uid , {
@@ -406,14 +468,16 @@ describe("FieldLabelWrapperComponent", () => {
406468 />
407469 ) ;
408470
409- // Use act() to ensure React processes all state updates
471+ // Use act() with queueMicrotask for faster resolution
410472 await act ( async ( ) => {
411- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
473+ await new Promise < void > ( ( resolve ) =>
474+ queueMicrotask ( ( ) => resolve ( ) )
475+ ) ;
412476 } ) ;
413477
414478 // Use findByTestId which is optimized for async queries
415479 const fieldLabel = ( await findByTestId (
416- container ,
480+ container as HTMLElement ,
417481 "visual-builder__focused-toolbar__field-label-wrapper" ,
418482 { } ,
419483 { timeout : 1000 }
@@ -433,22 +497,22 @@ describe("FieldLabelWrapperComponent", () => {
433497 />
434498 ) ;
435499
436- // Use act() to ensure React processes all state updates
500+ // Use act() with queueMicrotask for faster resolution
437501 await act ( async ( ) => {
438- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
502+ await new Promise < void > ( ( resolve ) =>
503+ queueMicrotask ( ( ) => resolve ( ) )
504+ ) ;
439505 } ) ;
440506
441507 // Wait for component to mount and isFieldDisabled to be called
442- await waitFor (
443- ( ) => {
444- const fieldLabel = container . querySelector (
445- '[data-testid="visual-builder__focused-toolbar__field-label-wrapper"]'
446- ) ;
447- if ( ! fieldLabel ) throw new Error ( "Field label not found" ) ;
448- expect ( isFieldDisabled ) . toHaveBeenCalled ( ) ;
449- } ,
450- { timeout : 1000 , interval : 10 }
508+ // Use findByTestId for better performance than querySelector
509+ await findByTestId (
510+ container as HTMLElement ,
511+ "visual-builder__focused-toolbar__field-label-wrapper" ,
512+ { } ,
513+ { timeout : 1000 }
451514 ) ;
515+ expect ( isFieldDisabled ) . toHaveBeenCalled ( ) ;
452516
453517 expect ( isFieldDisabled ) . toHaveBeenCalledWith (
454518 singleLineFieldSchema , // Now using the actual schema we pre-set
@@ -513,9 +577,11 @@ describe("FieldLabelWrapperComponent", () => {
513577 />
514578 ) ;
515579
516- // Use act() to ensure React processes all state updates
580+ // Use act() with queueMicrotask for faster resolution
517581 await act ( async ( ) => {
518- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
582+ await new Promise < void > ( ( resolve ) =>
583+ queueMicrotask ( ( ) => resolve ( ) )
584+ ) ;
519585 } ) ;
520586
521587 // When loading, component returns LoadingIcon, not the main structure
@@ -533,7 +599,7 @@ describe("FieldLabelWrapperComponent", () => {
533599 ) ;
534600 } ) ;
535601
536- test . skip ( "renders VariantIndicator when field has variant" , async ( ) => {
602+ test ( "renders VariantIndicator when field has variant" , async ( ) => {
537603 const variantFieldMetadata = {
538604 ...mockFieldMetadata ,
539605 variant : "variant-uid-123" ,
@@ -548,19 +614,23 @@ describe("FieldLabelWrapperComponent", () => {
548614 />
549615 ) ;
550616
551- // Wait for data loading to complete by checking for button to be enabled
617+ // Wait for component to finish loading (button enabled) and variant indicator to appear
618+ // Reduced timeout to 1000ms since mocks resolve immediately
552619 await waitFor (
553620 ( ) => {
554621 const button = container . querySelector ( "button" ) ;
555- expect ( button ) . not . toBeDisabled ( ) ;
622+ if ( ! button || button . hasAttribute ( "disabled" ) ) {
623+ throw new Error ( "Button still disabled" ) ;
624+ }
625+ const variantIndicator = container . querySelector (
626+ "[data-testid='variant-indicator']"
627+ ) ;
628+ if ( ! variantIndicator ) {
629+ throw new Error ( "Variant indicator not found" ) ;
630+ }
556631 } ,
557- { timeout : 5000 , interval : 5 } // Reduced timeout from 15s to 5s with faster polling
558- ) ;
559-
560- const variantIndicator = container . querySelector (
561- "[data-testid='variant-indicator']"
632+ { timeout : 1000 , interval : 5 }
562633 ) ;
563- expect ( variantIndicator ) . toBeInTheDocument ( ) ;
564634 } ) ;
565635
566636 test ( "does not render VariantIndicator when field has no variant" , async ( ) => {
@@ -590,7 +660,7 @@ describe("FieldLabelWrapperComponent", () => {
590660 expect ( variantIndicator ) . not . toBeInTheDocument ( ) ;
591661 } ) ;
592662
593- test . skip ( "applies variant CSS classes when field has variant" , async ( ) => {
663+ test ( "applies variant CSS classes when field has variant" , async ( ) => {
594664 const variantFieldMetadata = {
595665 ...mockFieldMetadata ,
596666 variant : "variant-uid-123" ,
@@ -605,28 +675,25 @@ describe("FieldLabelWrapperComponent", () => {
605675 />
606676 ) ;
607677
608- // Wait for data loading to complete first
609- await waitFor (
610- ( ) => {
611- const fieldLabelWrapper = container . querySelector (
612- "[data-testid='visual-builder__focused-toolbar__field-label-wrapper']"
613- ) ;
614- expect ( fieldLabelWrapper ) . toBeInTheDocument ( ) ;
615- } ,
616- { timeout : 5000 , interval : 5 } // Reduced timeout from 25s to 5s with faster polling
617- ) ;
618-
619- // Then check for variant class
678+ // Wait for component to finish loading (button enabled) and variant class to appear
679+ // Reduced timeout to 1000ms since mocks resolve immediately
620680 await waitFor (
621681 ( ) => {
682+ const button = container . querySelector ( "button" ) ;
683+ if ( ! button || button . hasAttribute ( "disabled" ) ) {
684+ throw new Error ( "Button still disabled" ) ;
685+ }
622686 const fieldLabelWrapper = container . querySelector (
623687 "[data-testid='visual-builder__focused-toolbar__field-label-wrapper']"
624688 ) ;
689+ if ( ! fieldLabelWrapper ) {
690+ throw new Error ( "Field label wrapper not found" ) ;
691+ }
625692 expect ( fieldLabelWrapper ) . toHaveClass (
626693 "visual-builder__focused-toolbar--variant"
627694 ) ;
628695 } ,
629- { timeout : 2000 , interval : 5 } // Reduced timeout from 5s to 2s with faster polling
696+ { timeout : 1000 , interval : 5 }
630697 ) ;
631698 } ) ;
632699
@@ -640,20 +707,25 @@ describe("FieldLabelWrapperComponent", () => {
640707 />
641708 ) ;
642709
643- // Use act() to ensure React processes all state updates
644- await act ( async ( ) => {
645- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
646- } ) ;
647-
648- // Use findByTestId which is optimized for async queries
649- const fieldLabelWrapper = ( await findByTestId (
650- container ,
651- "visual-builder__focused-toolbar__field-label-wrapper" ,
652- { } ,
653- { timeout : 1000 }
654- ) ) as HTMLElement ;
655- expect ( fieldLabelWrapper ) . not . toHaveClass (
656- "visual-builder__focused-toolbar--variant"
710+ // Wait for component to finish loading and verify variant class is not present
711+ // Using waitFor to check both button enabled and class absence in one pass
712+ await waitFor (
713+ ( ) => {
714+ const button = container . querySelector ( "button" ) ;
715+ if ( ! button || button . hasAttribute ( "disabled" ) ) {
716+ throw new Error ( "Button still disabled" ) ;
717+ }
718+ const fieldLabelWrapper = container . querySelector (
719+ "[data-testid='visual-builder__focused-toolbar__field-label-wrapper']"
720+ ) ;
721+ if ( ! fieldLabelWrapper ) {
722+ throw new Error ( "Field label wrapper not found" ) ;
723+ }
724+ expect ( fieldLabelWrapper ) . not . toHaveClass (
725+ "visual-builder__focused-toolbar--variant"
726+ ) ;
727+ } ,
728+ { timeout : 1000 , interval : 5 }
657729 ) ;
658730 } ) ;
659731} ) ;
0 commit comments