77 * License v3.0 only", or the "Server Side Public License, v 1".
88 */
99
10- import { waitFor } from '@testing-library/react' ;
1110import type { DataTableRecord } from '@kbn/discover-utils/types' ;
1211import type { AggregateQuery , Query } from '@kbn/es-query' ;
1312import { dataViewMock } from '@kbn/discover-utils/src/__mocks__' ;
1413import { VIEW_MODE } from '@kbn/saved-search-plugin/public' ;
1514import type { EsHitRecord } from '@kbn/discover-utils' ;
1615import { buildDataTableRecord } from '@kbn/discover-utils' ;
1716import { FetchStatus } from '../../../types' ;
17+ import type { InternalStateMockToolkit } from '../../../../__mocks__/discover_state.mock' ;
1818import { getDiscoverInternalStateMock } from '../../../../__mocks__/discover_state.mock' ;
1919import { savedSearchMock } from '../../../../__mocks__/saved_search' ;
2020import { internalStateActions } from '../redux' ;
2121import type { DiscoverAppState } from '../redux' ;
2222import { dataViewAdHoc } from '../../../../__mocks__/data_view_complex' ;
23+ import type { DiscoverDataStateContainer } from '../discover_data_state_container' ;
24+
25+ // Track resources from the last test for cleanup in afterEach
26+ let lastTestToolkit : InternalStateMockToolkit | undefined ;
27+ let lastTestDataState : DiscoverDataStateContainer | undefined ;
2328
2429async function getTestProps ( {
2530 query,
@@ -43,6 +48,10 @@ async function getTestProps({
4348 skipWaitForDataFetching : true ,
4449 } ) ;
4550
51+ // Track for cleanup in afterEach
52+ lastTestToolkit = toolkit ;
53+ lastTestDataState = dataState ;
54+
4655 toolkit . internalState . dispatch (
4756 toolkit . injectCurrentTab ( internalStateActions . updateAppState ) ( {
4857 appState : { columns : [ ] , ...appState } ,
@@ -116,13 +125,23 @@ const setupTest = async ({
116125// Testing buildEsqlFetchSubscribe through the state container
117126// since the logic is pretty intertwined with the state management
118127describe ( 'buildEsqlFetchSubscribe' , ( ) => {
128+ afterEach ( ( ) => {
129+ // Cancel pending URL state storage updates (uses Promise.resolve().then(flush) batching)
130+ // and stop leaked throttled middleware timers (lodash.throttle with 300ms trailing setTimeout)
131+ lastTestToolkit ?. stateStorageContainer . cancel ( ) ;
132+ // Cancel running queries and abort controllers in the data state container
133+ lastTestDataState ?. cancel ( ) ;
134+ lastTestToolkit = undefined ;
135+ lastTestDataState = undefined ;
136+ jest . restoreAllMocks ( ) ;
137+ } ) ;
119138 test ( 'an ES|QL query should change state when loading and finished' , async ( ) => {
120139 const { replaceUrlState, dataState, tabId } = await setupTest ( ) ;
121140
122141 replaceUrlState . mockClear ( ) ;
123142
124143 dataState . data$ . documents$ . next ( msgComplete ) ;
125- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
144+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
126145 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
127146 tabId,
128147 appState : { columns : [ 'field1' , 'field2' ] } ,
@@ -136,7 +155,7 @@ describe('buildEsqlFetchSubscribe', () => {
136155 } ,
137156 } ) ;
138157
139- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ) ;
158+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ;
140159 } ) ;
141160
142161 test ( 'should change viewMode to undefined (default) if it was PATTERN_LEVEL' , async ( ) => {
@@ -146,7 +165,7 @@ describe('buildEsqlFetchSubscribe', () => {
146165 } ,
147166 } ) ;
148167
149- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
168+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
150169 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
151170 tabId,
152171 appState : { viewMode : undefined } ,
@@ -171,13 +190,10 @@ describe('buildEsqlFetchSubscribe', () => {
171190 // transformational command
172191 query : { esql : 'from the-data-view-title | keep field1' } ,
173192 } ) ;
174- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
175-
176- await waitFor ( ( ) => {
177- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
178- tabId,
179- appState : { columns : [ 'field1' ] } ,
180- } ) ;
193+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
194+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
195+ tabId,
196+ appState : { columns : [ 'field1' ] } ,
181197 } ) ;
182198 } ) ;
183199
@@ -198,21 +214,18 @@ describe('buildEsqlFetchSubscribe', () => {
198214 ] ,
199215 query : { esql : 'from the-data-view-2' } ,
200216 } ) ;
201- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
202-
203- await waitFor ( ( ) => {
204- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
205- tabId,
206- appState : { columns : [ 'field1' ] } ,
207- } ) ;
217+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
218+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
219+ tabId,
220+ appState : { columns : [ 'field1' ] } ,
208221 } ) ;
209222 } ) ;
210223
211224 test ( 'changing a ES|QL query with no transformational commands should not change state when loading and finished if index pattern and columns are the same' , async ( ) => {
212225 const { replaceUrlState, dataState, tabId } = await setupTest ( { } ) ;
213226 const documents$ = dataState . data$ . documents$ ;
214227 documents$ . next ( msgComplete ) ;
215- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
228+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
216229 replaceUrlState . mockClear ( ) ;
217230
218231 documents$ . next ( {
@@ -227,7 +240,7 @@ describe('buildEsqlFetchSubscribe', () => {
227240 // non transformational command, same columns as msgComplete
228241 query : { esql : 'from the-data-view-title | where field1 > 0' } ,
229242 } ) ;
230- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ) ;
243+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ;
231244 replaceUrlState . mockClear ( ) ;
232245
233246 documents$ . next ( {
@@ -242,23 +255,18 @@ describe('buildEsqlFetchSubscribe', () => {
242255 // non transformational command, different index
243256 query : { esql : 'from the-data-view-title2 | where field1 > 0' } ,
244257 } ) ;
245- await waitFor (
246- ( ) => {
247- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
248- tabId,
249- appState : { columns : [ 'field1' , 'field2' ] } ,
250- } ) ;
251- } ,
252- { timeout : 5000 }
253- ) ;
258+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
259+ tabId,
260+ appState : { columns : [ 'field1' , 'field2' ] } ,
261+ } ) ;
254262 } ) ;
255263
256264 test ( 'only changing an ES|QL query with same result columns should not change columns' , async ( ) => {
257265 const { replaceUrlState, dataState, tabId } = await setupTest ( { } ) ;
258266 const documents$ = dataState . data$ . documents$ ;
259267
260268 documents$ . next ( msgComplete ) ;
261- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
269+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
262270 replaceUrlState . mockClear ( ) ;
263271
264272 documents$ . next ( {
@@ -272,12 +280,10 @@ describe('buildEsqlFetchSubscribe', () => {
272280 ] ,
273281 query : { esql : 'from the-data-view-title | keep field1' } ,
274282 } ) ;
275- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
276- await waitFor ( ( ) => {
277- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
278- tabId,
279- appState : { columns : [ 'field1' ] } ,
280- } ) ;
283+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
284+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
285+ tabId,
286+ appState : { columns : [ 'field1' ] } ,
281287 } ) ;
282288 replaceUrlState . mockClear ( ) ;
283289
@@ -293,15 +299,15 @@ describe('buildEsqlFetchSubscribe', () => {
293299 query : { esql : 'from the-data-view-title | keep field 1 | WHERE field1=1' } ,
294300 } ) ;
295301
296- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ) ;
302+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 0 ) ;
297303 } ) ;
298304
299305 test ( 'if its not an ES|QL query coming along, it should be ignored' , async ( ) => {
300306 const { replaceUrlState, dataState, tabId } = await setupTest ( { } ) ;
301307 const documents$ = dataState . data$ . documents$ ;
302308
303309 documents$ . next ( msgComplete ) ;
304- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
310+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
305311 replaceUrlState . mockClear ( ) ;
306312
307313 documents$ . next ( {
@@ -327,11 +333,9 @@ describe('buildEsqlFetchSubscribe', () => {
327333 query : { esql : 'from the-data-view-title | keep field 1 | WHERE field1=1' } ,
328334 } ) ;
329335
330- await waitFor ( ( ) => {
331- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
332- tabId,
333- appState : { columns : [ 'field1' ] } ,
334- } ) ;
336+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
337+ tabId,
338+ appState : { columns : [ 'field1' ] } ,
335339 } ) ;
336340 } ) ;
337341
@@ -356,12 +360,10 @@ describe('buildEsqlFetchSubscribe', () => {
356360 query : { esql : 'from the-data-view-title | keep field 1 | WHERE field1=1' } ,
357361 } ) ;
358362
359- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
360- await waitFor ( ( ) => {
361- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
362- tabId,
363- appState : { columns : [ 'field1' , 'field2' ] } ,
364- } ) ;
363+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
364+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
365+ tabId,
366+ appState : { columns : [ 'field1' , 'field2' ] } ,
365367 } ) ;
366368 replaceUrlState . mockClear ( ) ;
367369
@@ -376,7 +378,7 @@ describe('buildEsqlFetchSubscribe', () => {
376378 ] ,
377379 query : { esql : 'from the-data-view-title | keep field1' } ,
378380 } ) ;
379- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
381+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
380382 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
381383 tabId,
382384 appState : { columns : [ 'field1' ] } ,
@@ -405,12 +407,10 @@ describe('buildEsqlFetchSubscribe', () => {
405407 query : { esql : 'from the-data-view-title | keep field 1' } ,
406408 } ) ;
407409
408- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
409- await waitFor ( ( ) => {
410- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
411- tabId,
412- appState : { columns : [ 'field1' ] } ,
413- } ) ;
410+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
411+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
412+ tabId,
413+ appState : { columns : [ 'field1' ] } ,
414414 } ) ;
415415 } ) ;
416416
@@ -457,7 +457,7 @@ describe('buildEsqlFetchSubscribe', () => {
457457 ] ,
458458 query : { esql : 'from the-data-view-title | WHERE field2=1' } ,
459459 } ) ;
460- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
460+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
461461 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
462462 tabId,
463463 appState : { columns : [ 'field1' , 'field2' ] } ,
@@ -479,7 +479,7 @@ describe('buildEsqlFetchSubscribe', () => {
479479 ] ,
480480 query : { esql : 'from the-data-view-title | WHERE field2=1' } ,
481481 } ) ;
482- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
482+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
483483 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
484484 tabId,
485485 appState : { columns : [ 'field1' , 'field2' ] } ,
@@ -496,7 +496,7 @@ describe('buildEsqlFetchSubscribe', () => {
496496 ] ,
497497 query : { esql : 'from the-data-view-title | keep field1' } ,
498498 } ) ;
499- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
499+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
500500 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
501501 tabId,
502502 appState : { columns : [ 'field1' ] } ,
@@ -527,7 +527,7 @@ describe('buildEsqlFetchSubscribe', () => {
527527 ] ,
528528 query : { esql : 'from the-data-view-title | WHERE field1=2' } ,
529529 } ) ;
530- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
530+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
531531 toolkit . internalState . dispatch (
532532 toolkit . injectCurrentTab ( internalStateActions . updateAppState ) ( {
533533 appState : { columns : [ 'field1' , 'field2' ] } ,
@@ -561,7 +561,7 @@ describe('buildEsqlFetchSubscribe', () => {
561561 query : { esql : 'from the-data-view-title | keep field1' } ,
562562 } ) ;
563563
564- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
564+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
565565 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
566566 tabId,
567567 appState : { columns : [ 'field1' ] } ,
@@ -573,7 +573,7 @@ describe('buildEsqlFetchSubscribe', () => {
573573 const documents$ = dataState . data$ . documents$ ;
574574
575575 documents$ . next ( msgComplete ) ;
576- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
576+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
577577 replaceUrlState . mockClear ( ) ;
578578
579579 documents$ . next ( {
@@ -592,13 +592,10 @@ describe('buildEsqlFetchSubscribe', () => {
592592 dataView : dataViewAdHoc ,
593593 } )
594594 ) ;
595- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
596-
597- await waitFor ( ( ) => {
598- expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
599- tabId,
600- appState : { columns : [ 'field1' ] } ,
601- } ) ;
595+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
596+ expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
597+ tabId,
598+ appState : { columns : [ 'field1' ] } ,
602599 } ) ;
603600 } ) ;
604601
@@ -622,9 +619,7 @@ describe('buildEsqlFetchSubscribe', () => {
622619 fetchStatus : FetchStatus . LOADING ,
623620 query : { esql : 'from pattern1' } ,
624621 } ) ;
625- await waitFor ( ( ) =>
626- expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'all' )
627- ) ;
622+ expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'all' ) ;
628623 documents$ . next ( {
629624 fetchStatus : FetchStatus . PARTIAL ,
630625 query : { esql : 'from pattern1' } ,
@@ -643,9 +638,7 @@ describe('buildEsqlFetchSubscribe', () => {
643638 fetchStatus : FetchStatus . LOADING ,
644639 query : { esql : 'from pattern1' } ,
645640 } ) ;
646- await waitFor ( ( ) =>
647- expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'none' )
648- ) ;
641+ expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'none' ) ;
649642 documents$ . next ( {
650643 fetchStatus : FetchStatus . PARTIAL ,
651644 query : { esql : 'from pattern1' } ,
@@ -659,9 +652,7 @@ describe('buildEsqlFetchSubscribe', () => {
659652 fetchStatus : FetchStatus . LOADING ,
660653 query : { esql : 'from pattern2' } ,
661654 } ) ;
662- await waitFor ( ( ) =>
663- expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'all' )
664- ) ;
655+ expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'all' ) ;
665656 documents$ . next ( {
666657 fetchStatus : FetchStatus . PARTIAL ,
667658 query : { esql : 'from pattern2' } ,
@@ -714,7 +705,7 @@ describe('buildEsqlFetchSubscribe', () => {
714705 query : { esql : 'from the-data-view-title' } ,
715706 } ) ;
716707
717- await waitFor ( ( ) => expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ) ;
708+ expect ( replaceUrlState ) . toHaveBeenCalledTimes ( 1 ) ;
718709 expect ( replaceUrlState ) . toHaveBeenCalledWith ( {
719710 tabId,
720711 appState : { columns : expectedColumns } ,
@@ -732,16 +723,12 @@ describe('buildEsqlFetchSubscribe', () => {
732723 query : { esql : 'from pattern' } ,
733724 result : result1 ,
734725 } ) ;
735- await waitFor ( ( ) =>
736- expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'none' )
737- ) ;
726+ expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( 'none' ) ;
738727 documents$ . next ( {
739728 fetchStatus : FetchStatus . PARTIAL ,
740729 query : { esql : 'from pattern' } ,
741730 result : result2 ,
742731 } ) ;
743- await waitFor ( ( ) =>
744- expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( [ 'columns' ] )
745- ) ;
732+ expect ( toolkit . getCurrentTab ( ) . defaultProfileState . fieldsToReset ) . toEqual ( [ 'columns' ] ) ;
746733 } ) ;
747734} ) ;
0 commit comments