@@ -36,62 +36,146 @@ export async function sleep(waitTimeInMs = 100): Promise<void> {
3636 return new Promise ( ( resolve ) => setTimeout ( resolve , waitTimeInMs ) ) ;
3737}
3838
39- export const waitForHoverOutline = async ( ) => {
40- await waitFor ( ( ) => {
41- const hoverOutline = document . querySelector (
42- "[data-testid='visual-builder__hover-outline'][style]"
43- ) ;
44- expect ( hoverOutline ) . not . toBeNull ( ) ;
45- } ) ;
46- }
47- export const waitForBuilderSDKToBeInitialized = async ( visualBuilderPostMessage : EventManager | undefined ) => {
39+ export const waitForHoverOutline = async ( options ?: {
40+ timeout ?: number ;
41+ interval ?: number ;
42+ } ) => {
43+ // First, wait for the outline element to exist (faster check)
44+ await waitFor (
45+ ( ) => {
46+ const hoverOutline = document . querySelector (
47+ "[data-testid='visual-builder__hover-outline']"
48+ ) ;
49+ expect ( hoverOutline ) . not . toBeNull ( ) ;
50+ } ,
51+ {
52+ timeout : options ?. timeout ?? 2000 ,
53+ interval : options ?. interval ?? 5 , // Faster polling: 5ms default
54+ }
55+ ) ;
56+
57+ // Then wait for style attribute to be set (more specific check)
58+ await waitFor (
59+ ( ) => {
60+ const hoverOutline = document . querySelector (
61+ "[data-testid='visual-builder__hover-outline']"
62+ ) as HTMLElement ;
63+ expect ( hoverOutline ) . not . toBeNull ( ) ;
64+ // Check if style has meaningful values (not empty)
65+ const hasStyle =
66+ hoverOutline ?. style &&
67+ ( hoverOutline . style . top ||
68+ hoverOutline . style . left ||
69+ hoverOutline . style . width ||
70+ hoverOutline . style . height ) ;
71+ expect ( hasStyle ) . toBeTruthy ( ) ;
72+ } ,
73+ {
74+ timeout : options ?. timeout ?? 2000 ,
75+ interval : options ?. interval ?? 5 , // Faster polling: 5ms default
76+ }
77+ ) ;
78+ } ;
79+
80+ export const waitForBuilderSDKToBeInitialized = async (
81+ visualBuilderPostMessage : EventManager | undefined
82+ ) => {
4883 await waitFor ( ( ) => {
4984 expect ( visualBuilderPostMessage ?. send ) . toBeCalledWith (
5085 VisualBuilderPostMessageEvents . INIT ,
5186 expect . any ( Object )
5287 ) ;
5388 } ) ;
54- }
89+ } ;
5590interface WaitForClickActionOptions {
5691 skipWaitForFieldType ?: boolean ;
5792}
58- export const triggerAndWaitForClickAction = async ( visualBuilderPostMessage : EventManager | undefined , element : HTMLElement , { skipWaitForFieldType} : WaitForClickActionOptions = { } ) => {
93+ export const triggerAndWaitForClickAction = async (
94+ visualBuilderPostMessage : EventManager | undefined ,
95+ element : HTMLElement ,
96+ { skipWaitForFieldType } : WaitForClickActionOptions = { }
97+ ) => {
5998 await waitForBuilderSDKToBeInitialized ( visualBuilderPostMessage ) ;
6099 await act ( async ( ) => {
61100 await fireEvent . click ( element ) ;
62- } )
63- if ( ! skipWaitForFieldType ) {
101+ } ) ;
102+ if ( ! skipWaitForFieldType ) {
64103 await waitFor ( ( ) => {
65- expect ( element ) . toHaveAttribute ( "data-cslp-field-type" )
66- } )
104+ expect ( element ) . toHaveAttribute ( "data-cslp-field-type" ) ;
105+ } ) ;
67106 }
68- }
107+ } ;
69108export const waitForToolbaxToBeVisible = async ( ) => {
70109 await waitFor ( ( ) => {
71110 const toolbar = document . querySelector (
72111 ".visual-builder__focused-toolbar__field-label-container"
73112 ) ;
74113 expect ( toolbar ) . not . toBeNull ( ) ;
75114 } ) ;
76- }
115+ } ;
116+
117+ export const waitForCursorToBeVisible = async ( options ?: {
118+ timeout ?: number ;
119+ interval ?: number ;
120+ } ) => {
121+ await waitFor (
122+ ( ) => {
123+ const customCursor = document . querySelector (
124+ `[data-testid="visual-builder__cursor"]`
125+ ) ;
126+ if ( ! customCursor ) throw new Error ( "Cursor not found" ) ;
127+ expect ( customCursor . classList . contains ( "visible" ) ) . toBeTruthy ( ) ;
128+ } ,
129+ {
130+ timeout : options ?. timeout ?? 2000 , // Default 2s timeout for cursor to be visible
131+ interval : options ?. interval ?? 10 , // Faster polling: 10ms default
132+ }
133+ ) ;
134+ } ;
135+
136+ export const waitForCursorIcon = async (
137+ icon : string ,
138+ options ?: { timeout ?: number ; interval ?: number }
139+ ) => {
140+ await waitFor (
141+ ( ) => {
142+ const customCursor = document . querySelector (
143+ `[data-testid="visual-builder__cursor"]`
144+ ) ;
145+ if ( ! customCursor ) throw new Error ( "Cursor not found" ) ;
146+ expect ( customCursor ) . toHaveAttribute ( "data-icon" , icon ) ;
147+ } ,
148+ {
149+ timeout : options ?. timeout ?? 1000 , // Reduced from 2s to 1s - mocks resolve immediately
150+ interval : options ?. interval ?? 10 , // Faster polling: 10ms default
151+ }
152+ ) ;
153+ } ;
77154const defaultRect = {
78155 left : 10 ,
79156 right : 20 ,
80157 top : 10 ,
81158 bottom : 20 ,
82159 width : 10 ,
83160 height : 5 ,
84- }
85- export const mockGetBoundingClientRect = ( element : HTMLElement , rect = defaultRect ) => {
86- vi . spyOn ( element , "getBoundingClientRect" ) . mockImplementation ( ( ) => rect as DOMRect ) ;
87- }
161+ } ;
162+ export const mockGetBoundingClientRect = (
163+ element : HTMLElement ,
164+ rect = defaultRect
165+ ) => {
166+ vi . spyOn ( element , "getBoundingClientRect" ) . mockImplementation (
167+ ( ) => rect as DOMRect
168+ ) ;
169+ } ;
88170export const getElementBytestId = ( testId : string ) => {
89171 return document . querySelector ( `[data-testid="${ testId } "]` ) ;
90- }
91- export const asyncRender : ( componentChild : ComponentChild ) => ReturnType < typeof render > = async ( ...args ) => {
172+ } ;
173+ export const asyncRender : (
174+ componentChild : ComponentChild
175+ ) => ReturnType < typeof render > = async ( ...args ) => {
92176 let returnValue : ReturnType < typeof render > ;
93177 await act ( async ( ) => {
94178 returnValue = render ( ...args ) ;
95179 } ) ;
96180 return returnValue ;
97- }
181+ } ;
0 commit comments