@@ -15,6 +15,42 @@ import {
1515} from './components' ;
1616import { defineComponents } from '../utils/register' ;
1717
18+ /**
19+ * Wait for all elements to be fully initialized and their query updates to complete
20+ * @param elements Array of IgcNgElement instances to wait for
21+ * @param timeoutMs Optional timeout in milliseconds (default: 5000)
22+ */
23+ async function waitForElementsReady ( elements : IgcNgElement [ ] , timeoutMs : number = 5000 ) : Promise < void > {
24+ const timeout = timer ( timeoutMs ) . toPromise ( ) ;
25+ const initPromises = elements . map ( async ( element ) => {
26+ try {
27+ // Wait for component ref to be ready
28+ await element . ngElementStrategy [ ComponentRefKey ] ;
29+ // Wait for any pending query updates
30+ if ( typeof ( element . ngElementStrategy as any ) . waitForQueryUpdates === 'function' ) {
31+ await ( element . ngElementStrategy as any ) . waitForQueryUpdates ( ) ;
32+ }
33+ } catch ( error ) {
34+ // Element might not have the strategy or methods, just continue
35+ console . warn ( 'Element initialization warning:' , error ) ;
36+ }
37+ } ) ;
38+
39+ await Promise . race ( [
40+ Promise . all ( initPromises ) ,
41+ timeout . then ( ( ) => { throw new Error ( `Elements initialization timed out after ${ timeoutMs } ms` ) ; } )
42+ ] ) ;
43+ }
44+
45+ /**
46+ * Wait for a single element to be fully initialized and its query updates to complete
47+ * @param element IgcNgElement instance to wait for
48+ * @param timeoutMs Optional timeout in milliseconds (default: 5000)
49+ */
50+ async function waitForElementReady ( element : IgcNgElement , timeoutMs : number = 5000 ) : Promise < void > {
51+ await waitForElementsReady ( [ element ] , timeoutMs ) ;
52+ }
53+
1854describe ( 'Elements: ' , ( ) => {
1955 let testContainer : HTMLDivElement ;
2056
@@ -48,15 +84,16 @@ describe('Elements: ', () => {
4884 const columnEl = document . createElement ( "igc-column" ) as IgcNgElement ;
4985 gridEl . appendChild ( columnEl ) ;
5086
51- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
52- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
87+ // Wait for both elements to be fully initialized and query updates to complete
88+ await waitForElementsReady ( [ gridEl , columnEl ] ) ;
5389
5490 const gridComponent = ( await gridEl . ngElementStrategy [ ComponentRefKey ] ) . instance as IgxGridComponent ;
5591 const columnComponent = ( await columnEl . ngElementStrategy [ ComponentRefKey ] ) . instance as IgxColumnComponent ;
5692 expect ( gridComponent . columnList . toArray ( ) ) . toContain ( columnComponent ) ;
5793
5894 columnEl . remove ( ) ;
59- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY: DESTROY + QUERY */ * 3 ) ) ;
95+ // Wait for the query update after removal
96+ await ( gridEl . ngElementStrategy as any ) . waitForQueryUpdates ( ) ;
6097 expect ( gridComponent . columnList . toArray ( ) ) . toEqual ( [ ] ) ;
6198 } ) ;
6299
@@ -73,12 +110,12 @@ describe('Elements: ', () => {
73110 </ div > ` ;
74111 }
75112
76- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
77- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
113+ // Wait for grid and column to be fully initialized
114+ await waitForElementsReady ( [ gridEl as unknown as IgcNgElement , columnEl ] ) ;
78115
79116 // sigh (。﹏。*)
80117 ( gridEl as any ) . toggleRow ( '1' ) ;
81- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
118+ await waitForElementReady ( gridEl as unknown as IgcNgElement ) ;
82119
83120 let detailGrid = document . querySelector < IgcNgElement > ( '#child1' ) ;
84121 expect ( detailGrid ) . toBeDefined ( ) ;
@@ -87,9 +124,9 @@ describe('Elements: ', () => {
87124
88125 // close and re-expand row detail:
89126 ( gridEl as any ) . toggleRow ( '1' ) ;
90- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
127+ await waitForElementReady ( gridEl as unknown as IgcNgElement ) ;
91128 ( gridEl as any ) . toggleRow ( '1' ) ;
92- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
129+ await waitForElementReady ( gridEl as unknown as IgcNgElement ) ;
93130
94131 detailGrid = document . querySelector < IgcNgElement > ( '#child1' ) ;
95132 expect ( detailGrid ) . toBeDefined ( ) ;
@@ -116,8 +153,8 @@ describe('Elements: ', () => {
116153 const hgridComponent = ( await hgridEl . ngElementStrategy [ ComponentRefKey ] ) . instance as IgxHierarchicalGridComponent ;
117154 hgridComponent . data = hgridData ;
118155
119- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
120- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
156+ // Wait for all elements to be fully initialized and query updates to complete
157+ await waitForElementsReady ( [ hgridEl , columnProjectId , columnName , columnStartDate ] ) ;
121158
122159 expect ( hgridComponent . dataView . length ) . toBeGreaterThan ( 0 ) ;
123160 } ) ;
@@ -163,8 +200,8 @@ describe('Elements: ', () => {
163200 } ) ;
164201 testContainer . appendChild ( gridEl ) ;
165202
166- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
167- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
203+ // Wait for all elements to be fully initialized and query updates to complete
204+ await waitForElementsReady ( [ gridEl as unknown as IgcNgElement , columnID as unknown as IgcNgElement , columnName as unknown as IgcNgElement ] ) ;
168205
169206 const header = document . getElementsByTagName ( "igx-grid-header" ) . item ( 0 ) as HTMLElement ;
170207 expect ( header . innerText ) . toEqual ( 'Templated ProductID' ) ;
@@ -179,8 +216,8 @@ describe('Elements: ', () => {
179216
180217 testContainer . appendChild ( gridEl ) ;
181218
182- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
183- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 2 ) ) ;
219+ // Wait for all elements to be fully initialized and query updates to complete
220+ await waitForElementsReady ( [ gridEl as unknown as IgcNgElement , stateComponent as unknown as IgcNgElement ] ) ;
184221 expect ( ( ) => stateComponent . getStateAsString ( ) ) . not . toThrow ( ) ;
185222 } ) ;
186223
@@ -201,19 +238,21 @@ describe('Elements: ', () => {
201238 </igc-grid>` ;
202239 testContainer . innerHTML = innerHtml ;
203240
204- // TODO: Better way to wait - potentially expose the queue or observable for update on the strategy
205- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 3 ) ) ;
206-
207241 const grid = document . querySelector < IgcNgElement & InstanceType < typeof IgcGridComponent > > ( '#testGrid' ) ;
208242 const thirdGroup = document . querySelector < IgcNgElement > ( 'igc-column-layout[header="Product Stock"]' ) ;
209243 const secondGroup = document . querySelector < IgcNgElement > ( 'igc-column-layout[header="Product Details"]' ) ;
244+
245+ // Wait for all elements to be fully initialized
246+ const allElements = [ grid , thirdGroup , secondGroup , ...Array . from ( document . querySelectorAll < IgcNgElement > ( 'igc-column' ) ) ] ;
247+ await waitForElementsReady ( allElements . filter ( el => el ) as IgcNgElement [ ] ) ;
210248
211249 expect ( grid . columns . length ) . toEqual ( 8 ) ;
212250 expect ( grid . getColumnByName ( 'ProductID' ) ) . toBeTruthy ( ) ;
213251 expect ( grid . getColumnByVisibleIndex ( 1 ) . field ) . toEqual ( 'ProductName' ) ;
214252
215253 grid . removeChild ( secondGroup ) ;
216- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 3 ) ) ;
254+ // Wait for query updates after removal
255+ await ( grid . ngElementStrategy as any ) . waitForQueryUpdates ( ) ;
217256
218257 expect ( grid . columns . length ) . toEqual ( 4 ) ;
219258 expect ( grid . getColumnByName ( 'ProductID' ) ) . toBeTruthy ( ) ;
@@ -225,7 +264,8 @@ describe('Elements: ', () => {
225264 newColumn . setAttribute ( 'field' , 'ProductName' ) ;
226265 newGroup . appendChild ( newColumn ) ;
227266 grid . insertBefore ( newGroup , thirdGroup ) ;
228- await firstValueFrom ( timer ( 10 /* SCHEDULE_DELAY */ * 3 ) ) ;
267+ // Wait for new elements to be initialized and query updates to complete
268+ await waitForElementsReady ( [ newGroup as unknown as IgcNgElement , newColumn as unknown as IgcNgElement ] ) ;
229269
230270 expect ( grid . columns . length ) . toEqual ( 6 ) ;
231271 expect ( grid . getColumnByVisibleIndex ( 1 ) . field ) . toEqual ( 'ProductName' ) ;
0 commit comments