diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 1ed6059c23062..a0c9b38792825 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters @@ -15,7 +15,7 @@ setup(core: CoreSetup, { bfetch, e | Parameter | Type | Description | | --- | --- | --- | | core | CoreSetup<DataStartDependencies, DataPublicPluginStart> | | -| { bfetch, expressions, uiActions, usageCollection } | DataSetupDependencies | | +| { expressions, uiActions, usageCollection } | DataSetupDependencies | | Returns: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.bfetch.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.bfetch.md deleted file mode 100644 index 5b7c635c71529..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.bfetch.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) > [bfetch](./kibana-plugin-plugins-data-public.searchinterceptordeps.bfetch.md) - -## SearchInterceptorDeps.bfetch property - -Signature: - -```typescript -bfetch: BfetchPublicSetup; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md index 543566b783c23..3653394d28b92 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md @@ -14,7 +14,6 @@ export interface SearchInterceptorDeps | Property | Type | Description | | --- | --- | --- | -| [bfetch](./kibana-plugin-plugins-data-public.searchinterceptordeps.bfetch.md) | BfetchPublicSetup | | | [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | CoreSetup['http'] | | | [session](./kibana-plugin-plugins-data-public.searchinterceptordeps.session.md) | ISessionService | | | [startServices](./kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md) | Promise<[CoreStart, any, unknown]> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index b90018c3d9cdd..43129891c5412 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -7,7 +7,7 @@ Signature: ```typescript -setup(core: CoreSetup, { bfetch, expressions, usageCollection }: DataPluginSetupDependencies): { +setup(core: CoreSetup, { expressions, usageCollection }: DataPluginSetupDependencies): { __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { @@ -21,7 +21,7 @@ setup(core: CoreSetup, { bfetch, e | Parameter | Type | Description | | --- | --- | --- | | core | CoreSetup<DataPluginStartDependencies, DataPluginStart> | | -| { bfetch, expressions, usageCollection } | DataPluginSetupDependencies | | +| { expressions, usageCollection } | DataPluginSetupDependencies | | Returns: diff --git a/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts b/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts index 57a7d7fc4f8cb..da6c940c48d0a 100644 --- a/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts +++ b/src/plugins/bfetch/public/batching/create_streaming_batched_function.test.ts @@ -19,7 +19,7 @@ import { createStreamingBatchedFunction } from './create_streaming_batched_function'; import { fetchStreaming as fetchStreamingReal } from '../streaming/fetch_streaming'; -import { AbortError, defer, of } from '../../../kibana_utils/public'; +import { defer, of } from '../../../kibana_utils/public'; import { Subject } from 'rxjs'; const getPromiseState = (promise: Promise): Promise<'resolved' | 'rejected' | 'pending'> => @@ -168,28 +168,6 @@ describe('createStreamingBatchedFunction()', () => { expect(fetchStreaming).toHaveBeenCalledTimes(1); }); - test('ignores a request with an aborted signal', async () => { - const { fetchStreaming } = setup(); - const fn = createStreamingBatchedFunction({ - url: '/test', - fetchStreaming, - maxItemAge: 5, - flushOnMaxItems: 3, - }); - - const abortController = new AbortController(); - abortController.abort(); - - of(fn({ foo: 'bar' }, abortController.signal)); - fn({ baz: 'quix' }); - - await new Promise((r) => setTimeout(r, 6)); - const { body } = fetchStreaming.mock.calls[0][0]; - expect(JSON.parse(body)).toEqual({ - batch: [{ baz: 'quix' }], - }); - }); - test('sends POST request to correct endpoint with items in array batched sorted in call order', async () => { const { fetchStreaming } = setup(); const fn = createStreamingBatchedFunction({ @@ -445,73 +423,6 @@ describe('createStreamingBatchedFunction()', () => { expect(result3).toEqual({ b: '3' }); }); - describe('when requests are aborted', () => { - test('aborts stream when all are aborted', async () => { - const { fetchStreaming } = setup(); - const fn = createStreamingBatchedFunction({ - url: '/test', - fetchStreaming, - maxItemAge: 5, - flushOnMaxItems: 3, - }); - - const abortController = new AbortController(); - const promise = fn({ a: '1' }, abortController.signal); - const promise2 = fn({ a: '2' }, abortController.signal); - await new Promise((r) => setTimeout(r, 6)); - - expect(await isPending(promise)).toBe(true); - expect(await isPending(promise2)).toBe(true); - - abortController.abort(); - await new Promise((r) => setTimeout(r, 6)); - - expect(await isPending(promise)).toBe(false); - expect(await isPending(promise2)).toBe(false); - const [, error] = await of(promise); - const [, error2] = await of(promise2); - expect(error).toBeInstanceOf(AbortError); - expect(error2).toBeInstanceOf(AbortError); - expect(fetchStreaming.mock.calls[0][0].signal.aborted).toBeTruthy(); - }); - - test('rejects promise on abort and lets others continue', async () => { - const { fetchStreaming, stream } = setup(); - const fn = createStreamingBatchedFunction({ - url: '/test', - fetchStreaming, - maxItemAge: 5, - flushOnMaxItems: 3, - }); - - const abortController = new AbortController(); - const promise = fn({ a: '1' }, abortController.signal); - const promise2 = fn({ a: '2' }); - await new Promise((r) => setTimeout(r, 6)); - - expect(await isPending(promise)).toBe(true); - - abortController.abort(); - await new Promise((r) => setTimeout(r, 6)); - - expect(await isPending(promise)).toBe(false); - const [, error] = await of(promise); - expect(error).toBeInstanceOf(AbortError); - - stream.next( - JSON.stringify({ - id: 1, - result: { b: '2' }, - }) + '\n' - ); - - await new Promise((r) => setTimeout(r, 1)); - - const [result2] = await of(promise2); - expect(result2).toEqual({ b: '2' }); - }); - }); - describe('when stream closes prematurely', () => { test('rejects pending promises with CONNECTION error code', async () => { const { fetchStreaming, stream } = setup(); diff --git a/src/plugins/bfetch/public/batching/create_streaming_batched_function.ts b/src/plugins/bfetch/public/batching/create_streaming_batched_function.ts index 4ff12dda1f98e..89793fff6b325 100644 --- a/src/plugins/bfetch/public/batching/create_streaming_batched_function.ts +++ b/src/plugins/bfetch/public/batching/create_streaming_batched_function.ts @@ -17,7 +17,7 @@ * under the License. */ -import { AbortError, abortSignalToPromise, defer } from '../../../kibana_utils/public'; +import { defer, Defer } from '../../../kibana_utils/public'; import { ItemBufferParams, TimedItemBufferParams, @@ -27,7 +27,13 @@ import { } from '../../common'; import { fetchStreaming, split } from '../streaming'; import { normalizeError } from '../../common'; -import { BatchedFunc, BatchItem } from './types'; + +export interface BatchItem { + payload: Payload; + future: Defer; +} + +export type BatchedFunc = (payload: Payload) => Promise; export interface BatchedFunctionProtocolError extends ErrorLike { code: string; @@ -76,67 +82,32 @@ export const createStreamingBatchedFunction = ( flushOnMaxItems = 25, maxItemAge = 10, } = params; - const [fn] = createBatchedFunction({ - onCall: (payload: Payload, signal?: AbortSignal) => { + const [fn] = createBatchedFunction, BatchItem>({ + onCall: (payload: Payload) => { const future = defer(); const entry: BatchItem = { payload, future, - signal, }; return [future.promise, entry]; }, onBatch: async (items) => { try { - // Filter out any items whose signal is already aborted - items = items.filter((item) => { - if (item.signal?.aborted) item.future.reject(new AbortError()); - return !item.signal?.aborted; - }); - - const donePromises: Array> = items.map((item) => { - return new Promise((resolve) => { - const { promise: abortPromise, cleanup } = item.signal - ? abortSignalToPromise(item.signal) - : { - promise: undefined, - cleanup: () => {}, - }; - - const onDone = () => { - resolve(); - cleanup(); - }; - if (abortPromise) - abortPromise.catch(() => { - item.future.reject(new AbortError()); - onDone(); - }); - item.future.promise.then(onDone, onDone); - }); - }); - - // abort when all items were either resolved, rejected or aborted - const abortController = new AbortController(); - let isBatchDone = false; - Promise.all(donePromises).then(() => { - isBatchDone = true; - abortController.abort(); - }); - const batch = items.map((item) => item.payload); - + let responsesReceived = 0; + const batch = items.map(({ payload }) => payload); const { stream } = fetchStreamingInjected({ url, body: JSON.stringify({ batch }), method: 'POST', - signal: abortController.signal, }); stream.pipe(split('\n')).subscribe({ next: (json: string) => { const response = JSON.parse(json) as BatchResponseItem; if (response.error) { + responsesReceived++; items[response.id].future.reject(response.error); } else if (response.result !== undefined) { + responsesReceived++; items[response.id].future.resolve(response.result); } }, @@ -146,7 +117,8 @@ export const createStreamingBatchedFunction = ( for (const { future } of items) future.reject(normalizedError); }, complete: () => { - if (!isBatchDone) { + const streamTerminatedPrematurely = responsesReceived !== items.length; + if (streamTerminatedPrematurely) { const error: BatchedFunctionProtocolError = { message: 'Connection terminated prematurely.', code: 'CONNECTION', diff --git a/src/plugins/bfetch/public/batching/types.ts b/src/plugins/bfetch/public/batching/types.ts deleted file mode 100644 index 68860c5d9eedf..0000000000000 --- a/src/plugins/bfetch/public/batching/types.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Defer } from '../../../kibana_utils/public'; - -export interface BatchItem { - payload: Payload; - future: Defer; - signal?: AbortSignal; -} - -export type BatchedFunc = ( - payload: Payload, - signal?: AbortSignal -) => Promise; diff --git a/src/plugins/bfetch/public/index.ts b/src/plugins/bfetch/public/index.ts index 7ff110105faa0..8707e5a438159 100644 --- a/src/plugins/bfetch/public/index.ts +++ b/src/plugins/bfetch/public/index.ts @@ -23,8 +23,6 @@ import { BfetchPublicPlugin } from './plugin'; export { BfetchPublicSetup, BfetchPublicStart, BfetchPublicContract } from './plugin'; export { split } from './streaming'; -export { BatchedFunc } from './batching/types'; - export function plugin(initializerContext: PluginInitializerContext) { return new BfetchPublicPlugin(initializerContext); } diff --git a/src/plugins/bfetch/public/plugin.ts b/src/plugins/bfetch/public/plugin.ts index 72aaa862b0ad2..5f01957c0908e 100644 --- a/src/plugins/bfetch/public/plugin.ts +++ b/src/plugins/bfetch/public/plugin.ts @@ -22,9 +22,9 @@ import { fetchStreaming as fetchStreamingStatic, FetchStreamingParams } from './ import { removeLeadingSlash } from '../common'; import { createStreamingBatchedFunction, + BatchedFunc, StreamingBatchedFunctionParams, } from './batching/create_streaming_batched_function'; -import { BatchedFunc } from './batching/types'; // eslint-disable-next-line export interface BfetchPublicSetupDependencies {} diff --git a/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts b/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts index 7a6827b8fee8e..27adc6dc8b549 100644 --- a/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts +++ b/src/plugins/bfetch/public/streaming/fetch_streaming.test.ts @@ -132,33 +132,6 @@ test('completes stream observable when request finishes', async () => { expect(spy).toHaveBeenCalledTimes(1); }); -test('completes stream observable when aborted', async () => { - const env = setup(); - const abort = new AbortController(); - const { stream } = fetchStreaming({ - url: 'http://example.com', - signal: abort.signal, - }); - - const spy = jest.fn(); - stream.subscribe({ - complete: spy, - }); - - expect(spy).toHaveBeenCalledTimes(0); - - (env.xhr as any).responseText = 'foo'; - env.xhr.onprogress!({} as any); - - abort.abort(); - - (env.xhr as any).readyState = 4; - (env.xhr as any).status = 200; - env.xhr.onreadystatechange!({} as any); - - expect(spy).toHaveBeenCalledTimes(1); -}); - test('promise throws when request errors', async () => { const env = setup(); const { stream } = fetchStreaming({ diff --git a/src/plugins/bfetch/public/streaming/fetch_streaming.ts b/src/plugins/bfetch/public/streaming/fetch_streaming.ts index 3deee0cf66add..899e8a1824a41 100644 --- a/src/plugins/bfetch/public/streaming/fetch_streaming.ts +++ b/src/plugins/bfetch/public/streaming/fetch_streaming.ts @@ -24,7 +24,6 @@ export interface FetchStreamingParams { headers?: Record; method?: 'GET' | 'POST'; body?: string; - signal?: AbortSignal; } /** @@ -36,7 +35,6 @@ export function fetchStreaming({ headers = {}, method = 'POST', body = '', - signal, }: FetchStreamingParams) { const xhr = new window.XMLHttpRequest(); @@ -47,7 +45,7 @@ export function fetchStreaming({ // Set the HTTP headers Object.entries(headers).forEach(([k, v]) => xhr.setRequestHeader(k, v)); - const stream = fromStreamingXhr(xhr, signal); + const stream = fromStreamingXhr(xhr); // Send the payload to the server xhr.send(body); diff --git a/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts b/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts index b15bf9bdfbbb0..40eb3d5e2556b 100644 --- a/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts +++ b/src/plugins/bfetch/public/streaming/from_streaming_xhr.test.ts @@ -21,7 +21,6 @@ import { fromStreamingXhr } from './from_streaming_xhr'; const createXhr = (): XMLHttpRequest => (({ - abort: () => {}, onprogress: () => {}, onreadystatechange: () => {}, readyState: 0, @@ -101,39 +100,6 @@ test('completes observable when request reaches end state', () => { expect(complete).toHaveBeenCalledTimes(1); }); -test('completes observable when aborted', () => { - const xhr = createXhr(); - const abortController = new AbortController(); - const observable = fromStreamingXhr(xhr, abortController.signal); - - const next = jest.fn(); - const complete = jest.fn(); - observable.subscribe({ - next, - complete, - }); - - (xhr as any).responseText = '1'; - xhr.onprogress!({} as any); - - (xhr as any).responseText = '2'; - xhr.onprogress!({} as any); - - expect(complete).toHaveBeenCalledTimes(0); - - (xhr as any).readyState = 2; - abortController.abort(); - - expect(complete).toHaveBeenCalledTimes(1); - - // Shouldn't trigger additional events - (xhr as any).readyState = 4; - (xhr as any).status = 200; - xhr.onreadystatechange!({} as any); - - expect(complete).toHaveBeenCalledTimes(1); -}); - test('errors observable if request returns with error', () => { const xhr = createXhr(); const observable = fromStreamingXhr(xhr); diff --git a/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts b/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts index 5df1f5258cb2d..bba8151958492 100644 --- a/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts +++ b/src/plugins/bfetch/public/streaming/from_streaming_xhr.ts @@ -26,17 +26,13 @@ import { Observable, Subject } from 'rxjs'; export const fromStreamingXhr = ( xhr: Pick< XMLHttpRequest, - 'onprogress' | 'onreadystatechange' | 'readyState' | 'status' | 'responseText' | 'abort' - >, - signal?: AbortSignal + 'onprogress' | 'onreadystatechange' | 'readyState' | 'status' | 'responseText' + > ): Observable => { const subject = new Subject(); let index = 0; - let aborted = false; const processBatch = () => { - if (aborted) return; - const { responseText } = xhr; if (index >= responseText.length) return; subject.next(responseText.substr(index)); @@ -45,19 +41,7 @@ export const fromStreamingXhr = ( xhr.onprogress = processBatch; - const onBatchAbort = () => { - if (xhr.readyState !== 4) { - aborted = true; - xhr.abort(); - subject.complete(); - if (signal) signal.removeEventListener('abort', onBatchAbort); - } - }; - - if (signal) signal.addEventListener('abort', onBatchAbort); - xhr.onreadystatechange = () => { - if (aborted) return; // Older browsers don't support onprogress, so we need // to call this here, too. It's safe to call this multiple // times even for the same progress event. @@ -65,8 +49,6 @@ export const fromStreamingXhr = ( // 4 is the magic number that means the request is done if (xhr.readyState === 4) { - if (signal) signal.removeEventListener('abort', onBatchAbort); - // 0 indicates a network failure. 400+ messages are considered server errors if (xhr.status === 0 || xhr.status >= 400) { subject.error(new Error(`Batch request failed with status ${xhr.status}`)); diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index 3e4d08c8faa1b..d6f2534bd5e3b 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -4,7 +4,6 @@ "server": true, "ui": true, "requiredPlugins": [ - "bfetch", "expressions", "uiActions" ], diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 0e2920668236f..4334774300698 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -106,7 +106,7 @@ export class DataPublicPlugin public setup( core: CoreSetup, - { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies + { expressions, uiActions, usageCollection }: DataSetupDependencies ): DataPublicPluginSetup { const startServices = createStartServicesGetter(core.getStartServices); @@ -153,7 +153,6 @@ export class DataPublicPlugin ); const searchService = this.searchService.setup(core, { - bfetch, usageCollection, expressions, }); diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 11f7210b8e619..8b32e37511ef6 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -12,7 +12,6 @@ import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch/lib/Transpo import { ApplicationStart } from 'kibana/public'; import { Assign } from '@kbn/utility-types'; import { BehaviorSubject } from 'rxjs'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; import Boom from '@hapi/boom'; import { CoreSetup } from 'src/core/public'; import { CoreSetup as CoreSetup_2 } from 'kibana/public'; @@ -1735,7 +1734,7 @@ export class Plugin implements Plugin_2); // (undocumented) - setup(core: CoreSetup, { bfetch, expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; + setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; // (undocumented) start(core: CoreStart_2, { uiActions }: DataStartDependencies): DataPublicPluginStart; // (undocumented) @@ -2110,8 +2109,6 @@ export class SearchInterceptor { // // @public (undocumented) export interface SearchInterceptorDeps { - // (undocumented) - bfetch: BfetchPublicSetup; // (undocumented) http: CoreSetup_2['http']; // (undocumented) diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index bb5d3f58e6c1e..60274261da25f 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -25,13 +25,9 @@ import { AbortError } from '../../../kibana_utils/public'; import { SearchTimeoutError, PainlessError, TimeoutErrorMode } from './errors'; import { searchServiceMock } from './mocks'; import { ISearchStart } from '.'; -import { bfetchPluginMock } from '../../../bfetch/public/mocks'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; let searchInterceptor: SearchInterceptor; let mockCoreSetup: MockedKeys; -let bfetchSetup: jest.Mocked; -let fetchMock: jest.Mock; const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); jest.useFakeTimers(); @@ -43,11 +39,7 @@ describe('SearchInterceptor', () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); searchMock = searchServiceMock.createStartContract(); - fetchMock = jest.fn(); - bfetchSetup = bfetchPluginMock.createSetupContract(); - bfetchSetup.batchedFunction.mockReturnValue(fetchMock); searchInterceptor = new SearchInterceptor({ - bfetch: bfetchSetup, toasts: mockCoreSetup.notifications.toasts, startServices: new Promise((resolve) => { resolve([mockCoreStart, {}, {}]); @@ -102,7 +94,7 @@ describe('SearchInterceptor', () => { describe('search', () => { test('Observable should resolve if fetch is successful', async () => { const mockResponse: any = { result: 200 }; - fetchMock.mockResolvedValueOnce(mockResponse); + mockCoreSetup.http.fetch.mockResolvedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -113,7 +105,7 @@ describe('SearchInterceptor', () => { describe('Should throw typed errors', () => { test('Observable should fail if fetch has an internal error', async () => { const mockResponse: any = new Error('Internal Error'); - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -129,7 +121,7 @@ describe('SearchInterceptor', () => { message: 'Request timed out', }, }; - fetchMock.mockRejectedValueOnce(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -145,7 +137,7 @@ describe('SearchInterceptor', () => { message: 'Request timed out', }, }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -166,7 +158,7 @@ describe('SearchInterceptor', () => { message: 'Request timed out', }, }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -187,7 +179,7 @@ describe('SearchInterceptor', () => { message: 'Request timed out', }, }; - fetchMock.mockRejectedValue(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -220,7 +212,7 @@ describe('SearchInterceptor', () => { }, }, }; - fetchMock.mockRejectedValueOnce(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -230,7 +222,7 @@ describe('SearchInterceptor', () => { test('Observable should fail if user aborts (test merged signal)', async () => { const abortController = new AbortController(); - fetchMock.mockImplementationOnce((options: any) => { + mockCoreSetup.http.fetch.mockImplementationOnce((options: any) => { return new Promise((resolve, reject) => { options.signal.addEventListener('abort', () => { reject(new AbortError()); @@ -268,7 +260,7 @@ describe('SearchInterceptor', () => { const error = (e: any) => { expect(e).toBeInstanceOf(AbortError); - expect(fetchMock).not.toBeCalled(); + expect(mockCoreSetup.http.fetch).not.toBeCalled(); done(); }; response.subscribe({ error }); diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index ab43a48c7ec77..3fadb723b27cd 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -17,17 +17,17 @@ * under the License. */ -import { get, memoize } from 'lodash'; +import { get, memoize, trimEnd } from 'lodash'; import { BehaviorSubject, throwError, timer, defer, from, Observable, NEVER } from 'rxjs'; import { catchError, finalize } from 'rxjs/operators'; import { PublicMethodsOf } from '@kbn/utility-types'; import { CoreStart, CoreSetup, ToastsSetup } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { BatchedFunc, BfetchPublicSetup } from 'src/plugins/bfetch/public'; import { IKibanaSearchRequest, IKibanaSearchResponse, ISearchOptions, + ES_SEARCH_STRATEGY, ISessionService, } from '../../common'; import { SearchUsageCollector } from './collectors'; @@ -44,7 +44,6 @@ import { toMountPoint } from '../../../kibana_react/public'; import { AbortError, getCombinedAbortSignal } from '../../../kibana_utils/public'; export interface SearchInterceptorDeps { - bfetch: BfetchPublicSetup; http: CoreSetup['http']; uiSettings: CoreSetup['uiSettings']; startServices: Promise<[CoreStart, any, unknown]>; @@ -70,10 +69,6 @@ export class SearchInterceptor { * @internal */ protected application!: CoreStart['application']; - private batchedFetch!: BatchedFunc< - { request: IKibanaSearchRequest; options: ISearchOptions }, - IKibanaSearchResponse - >; /* * @internal @@ -84,10 +79,6 @@ export class SearchInterceptor { this.deps.startServices.then(([coreStart]) => { this.application = coreStart.application; }); - - this.batchedFetch = deps.bfetch.batchedFunction({ - url: '/internal/bsearch', - }); } /* @@ -137,14 +128,24 @@ export class SearchInterceptor { request: IKibanaSearchRequest, options?: ISearchOptions ): Promise { - const { abortSignal, ...requestOptions } = options || {}; - return this.batchedFetch( - { - request, - options: requestOptions, - }, - abortSignal + const { id, ...searchRequest } = request; + const path = trimEnd( + `/internal/search/${options?.strategy ?? ES_SEARCH_STRATEGY}/${id ?? ''}`, + '/' ); + const body = JSON.stringify({ + sessionId: options?.sessionId, + isStored: options?.isStored, + isRestore: options?.isRestore, + ...searchRequest, + }); + + return this.deps.http.fetch({ + method: 'POST', + path, + body, + signal: options?.abortSignal, + }); } /** diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index 3179da4d03a1a..20041a02067d9 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -21,7 +21,6 @@ import { coreMock } from '../../../../core/public/mocks'; import { CoreSetup, CoreStart } from '../../../../core/public'; import { SearchService, SearchServiceSetupDependencies } from './search_service'; -import { bfetchPluginMock } from '../../../bfetch/public/mocks'; describe('Search service', () => { let searchService: SearchService; @@ -40,10 +39,8 @@ describe('Search service', () => { describe('setup()', () => { it('exposes proper contract', async () => { - const bfetch = bfetchPluginMock.createSetupContract(); const setup = searchService.setup(mockCoreSetup, ({ packageInfo: { version: '8' }, - bfetch, expressions: { registerFunction: jest.fn(), registerType: jest.fn() }, } as unknown) as SearchServiceSetupDependencies); expect(setup).toHaveProperty('aggs'); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index b76b5846d3d93..96fb3f91ea85f 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -19,7 +19,6 @@ import { Plugin, CoreSetup, CoreStart, PluginInitializerContext } from 'src/core/public'; import { BehaviorSubject } from 'rxjs'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; import { handleResponse } from './fetch'; @@ -50,7 +49,6 @@ import { aggShardDelay } from '../../common/search/aggs/buckets/shard_delay_fn'; /** @internal */ export interface SearchServiceSetupDependencies { - bfetch: BfetchPublicSetup; expressions: ExpressionsSetup; usageCollection?: UsageCollectionSetup; } @@ -72,7 +70,7 @@ export class SearchService implements Plugin { public setup( { http, getStartServices, notifications, uiSettings }: CoreSetup, - { bfetch, expressions, usageCollection }: SearchServiceSetupDependencies + { expressions, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { this.usageCollector = createUsageCollector(getStartServices, usageCollection); @@ -82,7 +80,6 @@ export class SearchService implements Plugin { * all pending search requests, as well as getting the number of pending search requests. */ this.searchInterceptor = new SearchInterceptor({ - bfetch, toasts: notifications.toasts, http, uiSettings, diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 4082fbe55094c..21a03a49fe058 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -19,7 +19,6 @@ import React from 'react'; import { CoreStart } from 'src/core/public'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; @@ -37,7 +36,6 @@ export interface DataPublicPluginEnhancements { } export interface DataSetupDependencies { - bfetch: BfetchPublicSetup; expressions: ExpressionsSetup; uiActions: UiActionsSetup; usageCollection?: UsageCollectionSetup; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index bba2c368ff7d1..3ec4e7e64e382 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -19,7 +19,6 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from 'src/core/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; -import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { ConfigSchema } from '../config'; import { IndexPatternsService, IndexPatternsServiceStart } from './index_patterns'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './search'; @@ -52,7 +51,6 @@ export interface DataPluginStart { } export interface DataPluginSetupDependencies { - bfetch: BfetchServerSetup; expressions: ExpressionsServerSetup; usageCollection?: UsageCollectionSetup; } @@ -87,7 +85,7 @@ export class DataServerPlugin public setup( core: CoreSetup, - { bfetch, expressions, usageCollection }: DataPluginSetupDependencies + { expressions, usageCollection }: DataPluginSetupDependencies ) { this.indexPatterns.setup(core); this.scriptsService.setup(core); @@ -98,7 +96,6 @@ export class DataServerPlugin core.uiSettings.register(getUiSettings()); const searchSetup = this.searchService.setup(core, { - bfetch, expressions, usageCollection, }); diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index 1671990f77d92..3e2d415eac16f 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -17,7 +17,7 @@ * under the License. */ import { Observable } from 'rxjs'; -import { first, map } from 'rxjs/operators'; +import { first } from 'rxjs/operators'; import type { Logger } from 'kibana/server'; import type { ApiResponse } from '@elastic/elasticsearch'; @@ -30,7 +30,6 @@ import { getDefaultSearchParams, getShardTimeout } from '../es_search'; import type { ISearchStrategy } from '../types'; import type { SearchUsage } from '../collectors/usage'; import type { IEsRawSearchResponse } from '../../../common'; -import { shimHitsTotal } from '..'; export const esSearchStrategyProvider = ( config$: Observable, @@ -55,10 +54,6 @@ export const esSearchStrategyProvider = ( return esClient.asCurrentUser.search(params); }, abortSignal).pipe( toKibanaSearchResponse(), - map((response) => ({ - ...response, - rawResponse: shimHitsTotal(response.rawResponse), - })), trackSearchStatus(logger, usage), includeTotalLoaded() ); diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index 8a52d1d415f9b..0700afd8d6c83 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -25,8 +25,6 @@ import { createFieldFormatsStartMock } from '../field_formats/mocks'; import { createIndexPatternsStartMock } from '../index_patterns/mocks'; import { SearchService, SearchServiceSetupDependencies } from './search_service'; -import { bfetchPluginMock } from '../../../bfetch/server/mocks'; -import { of } from 'rxjs'; describe('Search service', () => { let plugin: SearchService; @@ -37,29 +35,15 @@ describe('Search service', () => { const mockLogger: any = { debug: () => {}, }; - const context = coreMock.createPluginInitializerContext({}); - context.config.create = jest.fn().mockImplementation(() => { - return of({ - search: { - aggs: { - shardDelay: { - enabled: true, - }, - }, - }, - }); - }); - plugin = new SearchService(context, mockLogger); + plugin = new SearchService(coreMock.createPluginInitializerContext({}), mockLogger); mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); }); describe('setup()', () => { it('exposes proper contract', async () => { - const bfetch = bfetchPluginMock.createSetupContract(); const setup = plugin.setup(mockCoreSetup, ({ packageInfo: { version: '8' }, - bfetch, expressions: { registerFunction: jest.fn(), registerType: jest.fn(), diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index b8ffd0645055c..b44980164d097 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -29,8 +29,7 @@ import { SharedGlobalConfig, StartServicesAccessor, } from 'src/core/server'; -import { catchError, first, switchMap } from 'rxjs/operators'; -import { BfetchServerSetup } from 'src/plugins/bfetch/server'; +import { first, switchMap } from 'rxjs/operators'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { ISearchSetup, @@ -86,7 +85,6 @@ type StrategyMap = Record>; /** @internal */ export interface SearchServiceSetupDependencies { - bfetch: BfetchServerSetup; expressions: ExpressionsServerSetup; usageCollection?: UsageCollectionSetup; } @@ -108,7 +106,6 @@ export class SearchService implements Plugin { private readonly searchSourceService = new SearchSourceService(); private defaultSearchStrategyName: string = ES_SEARCH_STRATEGY; private searchStrategies: StrategyMap = {}; - private coreStart?: CoreStart; private sessionService: BackgroundSessionService = new BackgroundSessionService(); constructor( @@ -118,7 +115,7 @@ export class SearchService implements Plugin { public setup( core: CoreSetup<{}, DataPluginStart>, - { bfetch, expressions, usageCollection }: SearchServiceSetupDependencies + { expressions, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { const usage = usageCollection ? usageProvider(core) : undefined; @@ -131,13 +128,10 @@ export class SearchService implements Plugin { registerMsearchRoute(router, routeDependencies); registerSessionRoutes(router); - core.getStartServices().then(([coreStart]) => { - this.coreStart = coreStart; - }); - core.http.registerRouteHandlerContext('search', async (context, request) => { - const search = this.asScopedProvider(this.coreStart!)(request); - const session = this.sessionService.asScopedProvider(this.coreStart!)(request); + const [coreStart] = await core.getStartServices(); + const search = this.asScopedProvider(coreStart)(request); + const session = this.sessionService.asScopedProvider(coreStart)(request); return { ...search, session }; }); @@ -152,36 +146,6 @@ export class SearchService implements Plugin { ) ); - bfetch.addBatchProcessingRoute<{ request: any; options?: ISearchOptions }, any>( - '/internal/bsearch', - (request) => { - const search = this.asScopedProvider(this.coreStart!)(request); - - return { - onBatchItem: async ({ request: requestData, options }) => { - return search - .search(requestData, options) - .pipe( - first(), - catchError((err) => { - // eslint-disable-next-line no-throw-literal - throw { - statusCode: err.statusCode || 500, - body: { - message: err.message, - attributes: { - error: err.body?.error || err.message, - }, - }, - }; - }) - ) - .toPromise(); - }, - }; - } - ); - core.savedObjects.registerType(searchTelemetry); if (usageCollection) { registerUsageCollector(usageCollection, this.initializerContext); diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index f63565b21aafb..feced957ddac4 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -9,7 +9,6 @@ import { Adapters } from 'src/plugins/inspector/common'; import { ApiResponse } from '@elastic/elasticsearch'; import { Assign } from '@kbn/utility-types'; import { BehaviorSubject } from 'rxjs'; -import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { ConfigDeprecationProvider } from '@kbn/config'; import { CoreSetup } from 'src/core/server'; import { CoreSetup as CoreSetup_2 } from 'kibana/server'; @@ -959,7 +958,7 @@ export function parseInterval(interval: string): moment.Duration | null; export class Plugin implements Plugin_2 { constructor(initializerContext: PluginInitializerContext_2); // (undocumented) - setup(core: CoreSetup, { bfetch, expressions, usageCollection }: DataPluginSetupDependencies): { + setup(core: CoreSetup, { expressions, usageCollection }: DataPluginSetupDependencies): { __enhance: (enhancements: DataEnhancements) => void; search: ISearchSetup; fieldFormats: { @@ -1257,7 +1256,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:284:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:287:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index_patterns/index_patterns_service.ts:58:14 - (ae-forgotten-export) The symbol "IndexPatternsService" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/plugin.ts:90:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/plugin.ts:88:66 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // src/plugins/data/server/search/types.ts:104:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/server/ui_settings.ts b/src/plugins/data/server/ui_settings.ts index f5360f626ac66..9393700a0e771 100644 --- a/src/plugins/data/server/ui_settings.ts +++ b/src/plugins/data/server/ui_settings.ts @@ -267,13 +267,14 @@ export function getUiSettings(): Record> { }, [UI_SETTINGS.COURIER_BATCH_SEARCHES]: { name: i18n.translate('data.advancedSettings.courier.batchSearchesTitle', { - defaultMessage: 'Use legacy search', + defaultMessage: 'Batch concurrent searches', }), value: false, type: 'boolean', description: i18n.translate('data.advancedSettings.courier.batchSearchesText', { - defaultMessage: `Kibana uses a new search and batching infrastructure. - Enable this option if you prefer to fallback to the legacy synchronous behavior`, + defaultMessage: `When disabled, dashboard panels will load individually, and search requests will terminate when users navigate + away or update the query. When enabled, dashboard panels will load together when all of the data is loaded, and + searches will not terminate.`, }), deprecation: { message: i18n.translate('data.advancedSettings.courier.batchSearchesTextDeprecation', { diff --git a/src/plugins/embeddable/public/public.api.md b/src/plugins/embeddable/public/public.api.md index 023cb3d19b632..f3f3682404e32 100644 --- a/src/plugins/embeddable/public/public.api.md +++ b/src/plugins/embeddable/public/public.api.md @@ -12,7 +12,6 @@ import { ApiResponse as ApiResponse_2 } from '@elastic/elasticsearch'; import { ApplicationStart as ApplicationStart_2 } from 'kibana/public'; import { Assign } from '@kbn/utility-types'; import { BehaviorSubject } from 'rxjs'; -import { BfetchPublicSetup } from 'src/plugins/bfetch/public'; import Boom from '@hapi/boom'; import { CoreSetup as CoreSetup_2 } from 'src/core/public'; import { CoreSetup as CoreSetup_3 } from 'kibana/public'; diff --git a/x-pack/plugins/data_enhanced/kibana.json b/x-pack/plugins/data_enhanced/kibana.json index eea0101ec4ed7..bc7c8410d3df1 100644 --- a/x-pack/plugins/data_enhanced/kibana.json +++ b/x-pack/plugins/data_enhanced/kibana.json @@ -6,7 +6,6 @@ "xpack", "data_enhanced" ], "requiredPlugins": [ - "bfetch", "data", "features" ], diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index fa3206446f9fc..948858a5ed4c1 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -7,7 +7,6 @@ import React from 'react'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { BfetchPublicSetup } from '../../../../src/plugins/bfetch/public'; import { setAutocompleteService } from './services'; import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete'; @@ -17,7 +16,6 @@ import { createConnectedBackgroundSessionIndicator } from './search'; import { ConfigSchema } from '../config'; export interface DataEnhancedSetupDependencies { - bfetch: BfetchPublicSetup; data: DataPublicPluginSetup; } export interface DataEnhancedStartDependencies { @@ -35,7 +33,7 @@ export class DataEnhancedPlugin public setup( core: CoreSetup, - { bfetch, data }: DataEnhancedSetupDependencies + { data }: DataEnhancedSetupDependencies ) { data.autocomplete.addQuerySuggestionProvider( KUERY_LANGUAGE_NAME, @@ -43,7 +41,6 @@ export class DataEnhancedPlugin ); this.enhancedSearchInterceptor = new EnhancedSearchInterceptor({ - bfetch, toasts: core.notifications.toasts, http: core.http, uiSettings: core.uiSettings, diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts index 3659c1a04b2b4..044489d58eb0e 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts @@ -11,7 +11,6 @@ import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; import { AbortError } from '../../../../../src/plugins/kibana_utils/public'; import { SearchTimeoutError } from 'src/plugins/data/public'; import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; -import { bfetchPluginMock } from '../../../../../src/plugins/bfetch/public/mocks'; const timeTravel = (msToRun = 0) => { jest.advanceTimersByTime(msToRun); @@ -25,13 +24,12 @@ const complete = jest.fn(); let searchInterceptor: EnhancedSearchInterceptor; let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; -let fetchMock: jest.Mock; jest.useFakeTimers(); function mockFetchImplementation(responses: any[]) { let i = 0; - fetchMock.mockImplementation(() => { + mockCoreSetup.http.fetch.mockImplementation(() => { const { time = 0, value = {}, isError = false } = responses[i++]; return new Promise((resolve, reject) => setTimeout(() => { @@ -48,7 +46,6 @@ describe('EnhancedSearchInterceptor', () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); const dataPluginMockStart = dataPluginMock.createStartContract(); - fetchMock = jest.fn(); mockCoreSetup.uiSettings.get.mockImplementation((name: string) => { switch (name) { @@ -77,11 +74,7 @@ describe('EnhancedSearchInterceptor', () => { ]); }); - const bfetchMock = bfetchPluginMock.createSetupContract(); - bfetchMock.batchedFunction.mockReturnValue(fetchMock); - searchInterceptor = new EnhancedSearchInterceptor({ - bfetch: bfetchMock, toasts: mockCoreSetup.notifications.toasts, startServices: mockPromise as any, http: mockCoreSetup.http, @@ -254,7 +247,7 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); @@ -278,7 +271,7 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(SearchTimeoutError); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); }); @@ -310,7 +303,7 @@ describe('EnhancedSearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response @@ -318,7 +311,7 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(SearchTimeoutError); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); @@ -352,7 +345,7 @@ describe('EnhancedSearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response @@ -360,7 +353,7 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBe(responses[1].value); - expect(fetchMock).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); }); @@ -392,7 +385,9 @@ describe('EnhancedSearchInterceptor', () => { await timeTravel(); - const areAllRequestsAborted = fetchMock.mock.calls.every(([_, signal]) => signal?.aborted); + const areAllRequestsAborted = mockCoreSetup.http.fetch.mock.calls.every( + ([{ signal }]) => signal?.aborted + ); expect(areAllRequestsAborted).toBe(true); expect(mockUsageCollector.trackQueriesCancelled).toBeCalledTimes(1); });