@@ -22,7 +22,7 @@ import * as searchPhaseException from '../../../common/search/test_data/search_p
2222import * as resourceNotFoundException from '../../../common/search/test_data/resource_not_found_exception.json' ;
2323import { BehaviorSubject } from 'rxjs' ;
2424import { dataPluginMock } from '../../mocks' ;
25- import { UI_SETTINGS } from '../../../common' ;
25+ import { ESQL_ASYNC_SEARCH_STRATEGY , UI_SETTINGS } from '../../../common' ;
2626import type { SearchServiceStartDependencies } from '../search_service' ;
2727import type { Start as InspectorStart } from '@kbn/inspector-plugin/public' ;
2828import { SearchTimeoutError , TimeoutErrorMode } from './timeout_error' ;
@@ -292,7 +292,207 @@ describe('SearchInterceptor', () => {
292292 expect ( error ) . not . toHaveBeenCalled ( ) ;
293293 } ) ;
294294
295- test ( 'should make secondary request if first call returns partial result' , async ( ) => {
295+ test ( 'should make secondary request if first call returns partial result (ES|QL)' , async ( ) => {
296+ const responses = [
297+ {
298+ time : 10 ,
299+ value : {
300+ body : {
301+ id : '1' ,
302+ is_running : true ,
303+ documents_found : 0 ,
304+ values_loaded : 0 ,
305+ all_columns : [ ] ,
306+ columns : [ ] ,
307+ values : [ ] ,
308+ _clusters : { } ,
309+ } ,
310+ } ,
311+ } ,
312+ {
313+ time : 20 ,
314+ value : {
315+ body : {
316+ id : '1' ,
317+ is_running : false ,
318+ took : 8 ,
319+ is_partial : false ,
320+ documents_found : 5 ,
321+ values_loaded : 5 ,
322+ all_columns : [
323+ {
324+ name : 'results' ,
325+ type : 'long' ,
326+ } ,
327+ {
328+ name : 'timestamp' ,
329+ type : 'date' ,
330+ } ,
331+ ] ,
332+ columns : [
333+ {
334+ name : 'results' ,
335+ type : 'long' ,
336+ } ,
337+ {
338+ name : 'timestamp' ,
339+ type : 'date' ,
340+ } ,
341+ ] ,
342+ values : [
343+ [ 1 , '2025-11-17T11:00:00.000Z' ] ,
344+ [ 1 , '2025-11-17T09:30:00.000Z' ] ,
345+ [ 1 , '2025-11-17T12:00:00.000Z' ] ,
346+ [ 1 , '2025-11-17T11:30:00.000Z' ] ,
347+ [ 1 , '2025-11-17T16:30:00.000Z' ] ,
348+ ] ,
349+ } ,
350+ } ,
351+ } ,
352+ ] ;
353+
354+ mockCoreSetup . http . post . mockImplementation ( getHttpMock ( responses ) ) ;
355+
356+ const response = searchInterceptor . search (
357+ {
358+ params : {
359+ query :
360+ 'FROM kibana_sample_data_logs | LIMIT 5 |EVAL DELAY(1s)\n| STATS results = COUNT(*) BY timestamp = BUCKET(@timestamp, 30 minute)' ,
361+ locale : 'en' ,
362+ include_execution_metadata : true ,
363+ filter : {
364+ bool : {
365+ must : [ ] ,
366+ filter : [
367+ {
368+ range : {
369+ '@timestamp' : {
370+ format : 'strict_date_optional_time' ,
371+ gte : '2025-11-17T07:00:00.000Z' ,
372+ lte : '2025-11-18T06:59:59.999Z' ,
373+ } ,
374+ } ,
375+ } ,
376+ ] ,
377+ should : [ ] ,
378+ must_not : [ ] ,
379+ } ,
380+ } ,
381+ dropNullColumns : true ,
382+ } ,
383+ } ,
384+ { pollInterval : 0 , strategy : ESQL_ASYNC_SEARCH_STRATEGY }
385+ ) ;
386+ response . subscribe ( { next, error, complete } ) ;
387+
388+ await timeTravel ( 10 ) ;
389+
390+ expect ( next ) . toHaveBeenCalled ( ) ;
391+ expect ( next . mock . calls [ 0 ] [ 0 ] ) . toMatchInlineSnapshot ( `
392+ Object {
393+ "id": "1",
394+ "isPartial": undefined,
395+ "isRestored": false,
396+ "isRunning": true,
397+ "rawResponse": Object {
398+ "_clusters": Object {},
399+ "all_columns": Array [],
400+ "columns": Array [],
401+ "documents_found": 0,
402+ "id": "1",
403+ "is_running": true,
404+ "values": Array [],
405+ "values_loaded": 0,
406+ },
407+ "requestParams": Object {},
408+ "warning": undefined,
409+ }
410+ ` ) ;
411+ expect ( complete ) . not . toHaveBeenCalled ( ) ;
412+ expect ( error ) . not . toHaveBeenCalled ( ) ;
413+
414+ await timeTravel ( 20 ) ;
415+
416+ expect ( next ) . toHaveBeenCalledTimes ( 2 ) ;
417+ expect ( next . mock . calls [ 1 ] [ 0 ] ) . toMatchInlineSnapshot ( `
418+ Object {
419+ "id": "1",
420+ "isPartial": false,
421+ "isRestored": false,
422+ "isRunning": false,
423+ "rawResponse": Object {
424+ "all_columns": Array [
425+ Object {
426+ "name": "results",
427+ "type": "long",
428+ },
429+ Object {
430+ "name": "timestamp",
431+ "type": "date",
432+ },
433+ ],
434+ "columns": Array [
435+ Object {
436+ "name": "results",
437+ "type": "long",
438+ },
439+ Object {
440+ "name": "timestamp",
441+ "type": "date",
442+ },
443+ ],
444+ "documents_found": 5,
445+ "id": "1",
446+ "is_partial": false,
447+ "is_running": false,
448+ "took": 8,
449+ "values": Array [
450+ Array [
451+ 1,
452+ "2025-11-17T11:00:00.000Z",
453+ ],
454+ Array [
455+ 1,
456+ "2025-11-17T09:30:00.000Z",
457+ ],
458+ Array [
459+ 1,
460+ "2025-11-17T12:00:00.000Z",
461+ ],
462+ Array [
463+ 1,
464+ "2025-11-17T11:30:00.000Z",
465+ ],
466+ Array [
467+ 1,
468+ "2025-11-17T16:30:00.000Z",
469+ ],
470+ ],
471+ "values_loaded": 5,
472+ },
473+ "requestParams": Object {},
474+ "warning": undefined,
475+ }
476+ ` ) ;
477+ expect ( complete ) . toHaveBeenCalled ( ) ;
478+ expect ( error ) . not . toHaveBeenCalled ( ) ;
479+
480+ // check that the query and filter weren't included in the polling request
481+ expect ( mockCoreSetup . http . post ) . toHaveBeenCalledTimes ( 2 ) ;
482+ const firstRequest = (
483+ mockCoreSetup . http . post . mock . calls [ 0 ] as unknown as [ string , HttpFetchOptions ]
484+ ) [ 1 ] ;
485+ expect ( JSON . parse ( firstRequest ?. body as string ) . params . query ) . toBeDefined ( ) ;
486+ expect ( JSON . parse ( firstRequest ?. body as string ) . params . filter ) . toBeDefined ( ) ;
487+
488+ const secondRequest = (
489+ mockCoreSetup . http . post . mock . calls [ 1 ] as unknown as [ string , HttpFetchOptions ]
490+ ) [ 1 ] ;
491+ expect ( JSON . parse ( secondRequest ?. body as string ) . params . query ) . not . toBeDefined ( ) ;
492+ expect ( JSON . parse ( secondRequest ?. body as string ) . params . filter ) . not . toBeDefined ( ) ;
493+ } ) ;
494+
495+ test ( 'should make secondary request if first call returns partial result (DSL)' , async ( ) => {
296496 const responses = [
297497 {
298498 time : 10 ,
0 commit comments