1+ jest . mock (
2+ '../../../../__mocks__/tracker' ,
3+ ( ) => ( {
4+ setup : ( ) => ( {
5+ Tracker : {
6+ autorun : jest . fn ( ( fn ) => {
7+ fn ( )
8+ return {
9+ stop : jest . fn ( ) ,
10+ }
11+ } ) ,
12+ nonreactive : jest . fn ( ( fn ) => fn ( ) ) ,
13+ active : false ,
14+ currentComputation : null ,
15+ Dependency : jest . fn ( ) . mockImplementation ( ( ) => ( {
16+ depend : jest . fn ( ) ,
17+ changed : jest . fn ( ) ,
18+ hasDependents : jest . fn ( ) ,
19+ } ) ) ,
20+ } ,
21+ } ) ,
22+ } ) ,
23+ {
24+ virtual : true ,
25+ }
26+ )
27+
128// Mock the ReactiveDataHelper:
229jest . mock ( '../../../lib/reactiveData/ReactiveDataHelper' , ( ) => {
330 class MockReactiveDataHelper {
@@ -70,7 +97,7 @@ jest.mock('react-i18next', () => ({
7097
7198import React from 'react'
7299// eslint-disable-next-line node/no-unpublished-import
73- import { renderHook , act , render , screen , RenderResult } from '@testing-library/react'
100+ import { renderHook , act , render , screen , waitFor } from '@testing-library/react'
74101// eslint-disable-next-line node/no-unpublished-import
75102import '@testing-library/jest-dom'
76103import { MeteorCall } from '../../../lib/meteorApi'
@@ -122,6 +149,11 @@ describe('PropertiesPanel', () => {
122149 mockSegmentsCollection . remove ( { } )
123150 mockPartsCollection . remove ( { } )
124151 jest . clearAllMocks ( )
152+ jest . useFakeTimers ( )
153+ } )
154+
155+ afterEach ( ( ) => {
156+ jest . useRealTimers ( )
125157 } )
126158
127159 const createMockSegment = ( id : string ) : DBSegment => ( {
@@ -133,12 +165,14 @@ describe('PropertiesPanel', () => {
133165 userEditOperations : [
134166 {
135167 id : 'operation1' ,
136- label : { key : 'TEST_LABEL' } ,
168+ label : { key : 'TEST_LABEL' , namespaces : [ 'blueprint_main-showstyle' ] } ,
137169 type : UserEditingType . ACTION ,
138170 buttonType : UserEditingButtonType . SWITCH ,
139171 isActive : false ,
172+ svgIcon : '<svg></svg>' ,
140173 } ,
141174 ] ,
175+ isHidden : false ,
142176 } )
143177
144178 const createMockPart = ( id : string , segmentId : string ) : DBPart => ( {
@@ -152,7 +186,7 @@ describe('PropertiesPanel', () => {
152186 userEditOperations : [
153187 {
154188 id : 'operation2' ,
155- label : { key : 'TEST_PART_LABEL' } ,
189+ label : { key : 'TEST_PART_LABEL' , namespaces : [ 'blueprint_main-showstyle' ] } ,
156190 type : UserEditingType . ACTION ,
157191 buttonType : UserEditingButtonType . BUTTON ,
158192 isActive : true ,
@@ -168,44 +202,39 @@ describe('PropertiesPanel', () => {
168202
169203 test ( 'renders segment properties when segment is selected' , async ( ) => {
170204 const mockSegment = createMockSegment ( 'segment1' )
171- mockSegmentsCollection . insert ( mockSegment )
172205
173- // Create a custom wrapper that includes both providers
174- const TestWrapper : React . FC < { children : React . ReactNode } > = ( { children } ) => (
175- < SelectedElementProvider > { children } </ SelectedElementProvider >
176- )
206+ mockSegmentsCollection . insert ( mockSegment )
177207
178- // Render both the hook and component in the same provider tree
179- const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper : TestWrapper } )
180- let rendered : RenderResult
208+ expect ( mockSegmentsCollection . findOne ( { _id : mockSegment . _id } ) ) . toBeTruthy ( )
181209
182- await act ( async ( ) => {
183- rendered = render ( < PropertiesPanel /> , { wrapper : TestWrapper } )
184- } )
210+ const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper } )
185211
186- // Update selection
212+ // Update selection and wait for component to update
187213 await act ( async ( ) => {
188214 result . current . clearAndSetSelection ( {
189215 type : 'segment' ,
190216 elementId : mockSegment . _id ,
191217 } )
192218 } )
193- //@ts -expect-error error because avoiding an undefined type
194- if ( ! rendered ) throw new Error ( 'Component not rendered' )
195219
196- // Force a rerender
220+ // Open component after segment is selected (as used in rundownview)
221+ const { container } = render ( < PropertiesPanel /> , { wrapper } )
222+
197223 await act ( async ( ) => {
198- rendered . rerender ( < PropertiesPanel /> )
224+ jest . advanceTimersByTime ( 100 )
199225 } )
200226
201- // Wait for the header element to appear
202- await screen . findByText ( 'SEGMENT : Segment segment1' )
203-
204- const header = rendered . container . querySelector ( '.propertiespanel-pop-up__header' )
205- const switchButton = rendered . container . querySelector ( '.propertiespanel-pop-up__switchbutton' )
227+ console . log ( 'result' , result . current . listSelectedElements ( ) )
228+ // Use findByTestId instead of querySelector
229+ await waitFor (
230+ ( ) => {
231+ expect ( screen . getByText ( `SEGMENT : ${ mockSegment . name } ` ) ) . toBeInTheDocument ( )
232+ } ,
233+ { timeout : 1000 }
234+ )
206235
207- expect ( header ) . toHaveTextContent ( 'SEGMENT : Segment segment1 ')
208- expect ( switchButton ) . toBeTruthy ( )
236+ const button = container . querySelector ( '.propertiespanel-pop-up__button ')
237+ expect ( button ) . toBeInTheDocument ( )
209238 } )
210239
211240 test ( 'renders part properties when part is selected' , async ( ) => {
@@ -215,75 +244,59 @@ describe('PropertiesPanel', () => {
215244 mockSegmentsCollection . insert ( mockSegment )
216245 mockPartsCollection . insert ( mockPart )
217246
218- // Create a custom wrapper that includes both providers
219- const TestWrapper : React . FC < { children : React . ReactNode } > = ( { children } ) => (
220- < SelectedElementProvider > { children } </ SelectedElementProvider >
221- )
222-
223- // Render both the hook and component in the same provider tree
224- const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper : TestWrapper } )
225- let rendered : RenderResult
226-
227- await act ( async ( ) => {
228- rendered = render ( < PropertiesPanel /> , { wrapper : TestWrapper } )
229- } )
247+ const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper } )
230248
231- // Update selection
232249 await act ( async ( ) => {
233250 result . current . clearAndSetSelection ( {
234251 type : 'part' ,
235252 elementId : mockPart . _id ,
236253 } )
237254 } )
255+ // Open component after part is selected (as used in rundownview)
256+ const { container } = render ( < PropertiesPanel /> , { wrapper } )
238257
239- //@ts -expect-error error because avoiding an undefined type
240- if ( ! rendered ) throw new Error ( 'Component not rendered' )
241-
242- // Force a rerender
243- await act ( async ( ) => {
244- rendered . rerender ( < PropertiesPanel /> )
245- } )
246-
247- // Wait for the header element to appear
248- await screen . findByText ( 'PART : Part part1' )
249-
250- const header = rendered . container . querySelector ( '.propertiespanel-pop-up__header' )
251- const button = rendered . container . querySelector ( '.propertiespanel-pop-up__button' )
258+ await waitFor (
259+ ( ) => {
260+ expect ( screen . getByText ( `PART : ${ mockPart . title } ` ) ) . toBeInTheDocument ( )
261+ } ,
262+ { timeout : 1000 }
263+ )
252264
253- expect ( header ) . toHaveTextContent ( 'PART : Part part1 ')
254- expect ( button ) . toBeTruthy ( )
265+ const button = container . querySelector ( '.propertiespanel-pop-up__button ')
266+ expect ( button ) . toBeInTheDocument ( )
255267 } )
256268
257269 test ( 'handles user edit operations for segments' , async ( ) => {
258270 const mockSegment = createMockSegment ( 'segment1' )
259271 mockSegmentsCollection . insert ( mockSegment )
260272
261- // First render the selection hook
262273 const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper } )
263-
264- // Then render the properties panel
265274 const { container } = render ( < PropertiesPanel /> , { wrapper } )
266275
267- // Update selection using the hook result
268- act ( ( ) => {
276+ await act ( async ( ) => {
269277 result . current . clearAndSetSelection ( {
270278 type : 'segment' ,
271279 elementId : mockSegment . _id ,
272280 } )
273281 } )
274282
275- const switchButton = container . querySelector ( '.propertiespanel-pop-up__switchbutton' )
283+ // Wait for the switch button to be available
284+ const switchButton = await waitFor ( ( ) => container . querySelector ( '.propertiespanel-pop-up__switchbutton' ) )
276285 expect ( switchButton ) . toBeTruthy ( )
277286
278287 // Toggle the switch
279- await userEvent . click ( switchButton ! )
288+ await act ( async ( ) => {
289+ await userEvent . click ( switchButton ! )
290+ } )
280291
281292 // Check if commit button is enabled
282293 const commitButton = screen . getByText ( 'COMMIT CHANGES' )
283294 expect ( commitButton ) . toBeEnabled ( )
284295
285296 // Commit changes
286- await userEvent . click ( commitButton )
297+ await act ( async ( ) => {
298+ await userEvent . click ( commitButton )
299+ } )
287300
288301 expect ( MeteorCall . userAction . executeUserChangeOperation ) . toHaveBeenCalledWith (
289302 expect . anything ( ) ,
@@ -305,27 +318,29 @@ describe('PropertiesPanel', () => {
305318 const mockSegment = createMockSegment ( 'segment1' )
306319 mockSegmentsCollection . insert ( mockSegment )
307320
308- // First render the selection hook
309321 const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper } )
310-
311- // Then render the properties panel
312322 const { container } = render ( < PropertiesPanel /> , { wrapper } )
313323
314- // Update selection using the hook result
315- act ( ( ) => {
324+ await act ( async ( ) => {
316325 result . current . clearAndSetSelection ( {
317326 type : 'segment' ,
318327 elementId : mockSegment . _id ,
319328 } )
320329 } )
321330
331+ // Wait for the switch button to be available
332+ const switchButton = await waitFor ( ( ) => container . querySelector ( '.propertiespanel-pop-up__switchbutton' ) )
333+
322334 // Make a change
323- const switchButton = container . querySelector ( '.propertiespanel-pop-up__switchbutton' )
324- await userEvent . click ( switchButton ! )
335+ await act ( async ( ) => {
336+ await userEvent . click ( switchButton ! )
337+ } )
325338
326339 // Click revert button
327340 const revertButton = screen . getByText ( 'REVERT CHANGES' )
328- await userEvent . click ( revertButton )
341+ await act ( async ( ) => {
342+ await userEvent . click ( revertButton )
343+ } )
329344
330345 expect ( MeteorCall . userAction . executeUserChangeOperation ) . toHaveBeenCalledWith (
331346 expect . anything ( ) ,
@@ -340,30 +355,28 @@ describe('PropertiesPanel', () => {
340355 id : 'REVERT_SEGMENT' ,
341356 }
342357 )
343- } )
358+ } , 10000 ) // Increase timeout for this test
344359
345360 test ( 'closes panel when close button is clicked' , async ( ) => {
346361 const mockSegment = createMockSegment ( 'segment1' )
347362 mockSegmentsCollection . insert ( mockSegment )
348363
349- // First render the selection hook
350364 const { result } = renderHook ( ( ) => useSelection ( ) , { wrapper } )
351-
352- // Then render the properties panel
353365 const { container } = render ( < PropertiesPanel /> , { wrapper } )
354366
355- // Update selection using the hook result
356- act ( ( ) => {
367+ await act ( async ( ) => {
357368 result . current . clearAndSetSelection ( {
358369 type : 'segment' ,
359370 elementId : mockSegment . _id ,
360371 } )
361372 } )
362373
363- const closeButton = container . querySelector ( '.propertiespanel-pop-up_close' )
374+ const closeButton = await waitFor ( ( ) => container . querySelector ( '.propertiespanel-pop-up_close' ) )
364375 expect ( closeButton ) . toBeTruthy ( )
365376
366- await userEvent . click ( closeButton ! )
377+ await act ( async ( ) => {
378+ await userEvent . click ( closeButton ! )
379+ } )
367380
368381 expect ( container . querySelector ( '.propertiespanel-pop-up__contents' ) ) . toBeFalsy ( )
369382 } )
0 commit comments