diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index d96929ec183d8d..3e582ee9b20c8e 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -22,8 +22,9 @@ import { SUB_PLUGINS_REDUCER, mockGlobalState, createSecuritySolutionStorageMock import { ExperimentalFeatures } from '../../../../common/experimental_features'; import { PLUGIN_ID } from '../../../../../fleet/common'; import { APP_ID } from '../../../../common/constants'; -import { KibanaContextProvider } from '../../lib/kibana'; +import { KibanaContextProvider, KibanaServices } from '../../lib/kibana'; import { MANAGEMENT_APP_ID } from '../../../management/common/constants'; +import { fleetGetPackageListHttpMock } from '../../../management/pages/endpoint_hosts/mocks'; type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult; @@ -120,6 +121,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { ); + const render: UiRender = (ui, options) => { return reactRender(ui, { wrapper: AppWrapper as React.ComponentType, @@ -134,6 +136,23 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { }); }; + // Initialize the singleton `KibanaServices` with global services created for this test instance. + // The module (`../../lib/kibana`) could have been mocked at the test level via `jest.mock()`, + // and if so, then we set the return value of `KibanaServices.get` instead of calling `KibanaServices.init()` + const globalKibanaServicesParams = { + ...startServices, + kibanaVersion: '8.0.0', + }; + + if (jest.isMockFunction(KibanaServices.get)) { + (KibanaServices.get as jest.Mock).mockReturnValue(globalKibanaServicesParams); + } else { + KibanaServices.init(globalKibanaServicesParams); + } + + // Some APIs need to be mocked right from the start because they are called as soon as the store is initialized + applyDefaultCoreHttpMocks(coreStart.http); + return { store, history, @@ -166,3 +185,10 @@ const createCoreStartMock = (): ReturnType => { return coreStart; }; + +const applyDefaultCoreHttpMocks = (http: AppContextTestRender['coreStart']['http']) => { + // Need to mock getting the endpoint package from the fleet API because it is used as soon + // as the store middleware for Endpoint list is initialized, thus mocking it here would avoid + // unnecessary errors being output to the console + fleetGetPackageListHttpMock(http, { ignoreUnMockedApiRouteErrors: true }); +}; diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/http_handler_mock_factory.ts b/x-pack/plugins/security_solution/public/common/mock/endpoint/http_handler_mock_factory.ts index dc93ea8168a3f6..c064b1808734d5 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/http_handler_mock_factory.ts +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/http_handler_mock_factory.ts @@ -82,7 +82,8 @@ type HttpMethods = keyof Pick< const HTTP_METHODS: HttpMethods[] = ['delete', 'fetch', 'get', 'post', 'put', 'head', 'patch']; export type ApiHandlerMock = ( - http: jest.Mocked + http: jest.Mocked, + options?: { ignoreUnMockedApiRouteErrors?: boolean } ) => MockedApi; interface RouteMock { @@ -132,8 +133,9 @@ export type ApiHandlerMockFactoryProps< export const httpHandlerMockFactory = ( mocks: ApiHandlerMockFactoryProps ): ApiHandlerMock => { - return (http) => { + return (http, options) => { let inflightApiCalls = 0; + const { ignoreUnMockedApiRouteErrors = false } = options ?? {}; const apiDoneListeners: Array<() => void> = []; const markApiCallAsHandled = async (delay?: RouteMock['delay']) => { inflightApiCalls++; @@ -221,6 +223,10 @@ export const httpHandlerMockFactory = GetAgentPoliciesResponse; +export type FleetGetPackageListHttpMockInterface = ResponseProvidersInterface<{ packageList: () => GetPackagesResponse; }>; -export const fleetApisHttpMock = httpHandlerMockFactory([ +export const fleetGetPackageListHttpMock = httpHandlerMockFactory( + [ + { + id: 'packageList', + method: 'get', + path: EPM_API_ROUTES.LIST_PATTERN, + handler() { + const generator = new EndpointDocGenerator('seed'); + + return { + response: [generator.generateEpmPackage()], + }; + }, + }, + ] +); + +export type FleetGetAgentPolicyListHttpMockInterface = ResponseProvidersInterface<{ + agentPolicy: () => GetAgentPoliciesResponse; +}>; +export const fleetGetAgentPolicyListHttpMock = httpHandlerMockFactory([ { id: 'agentPolicy', path: AGENT_POLICY_API_ROUTES.LIST_PATTERN, @@ -127,18 +146,13 @@ export const fleetApisHttpMock = httpHandlerMockFactory([ + fleetGetPackageListHttpMock, + fleetGetAgentPolicyListHttpMock, ]); type EndpointPageHttpMockInterface = EndpointMetadataHttpMocksInterface & diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts index 40b843a676d9c5..8d257678a425d0 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts @@ -13,6 +13,7 @@ import { HostResultList, HostStatus, MetadataQueryStrategyVersions, + PendingActionsResponse, } from '../../../../../common/endpoint/types'; import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data'; import { @@ -28,6 +29,8 @@ import { GetAgentsResponse, } from '../../../../../../fleet/common/types/rest_spec'; import { GetPolicyListResponse } from '../../policy/types'; +import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pending_actions/mocks'; +import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants'; const generator = new EndpointDocGenerator('seed'); @@ -159,6 +162,11 @@ const endpointListApiPathHandlerMocks = ({ perPage: 10, }; }, + + // Pending Actions + [ACTION_STATUS_ROUTE]: (): PendingActionsResponse => { + return pendingActionsResponseMock(); + }, }; // Build a GET route handler for each endpoint details based on the list of Endpoints passed on input diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx index 1ac5c289c87cf7..7153f0a09868ad 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx @@ -79,6 +79,7 @@ describe('when on the endpoint list page', () => { afterAll(() => { abortSpy.mockRestore(); }); + beforeEach(() => { const mockedContext = createAppRootMockRenderer(); ({ history, store, coreStart, middlewareSpy } = mockedContext); @@ -910,7 +911,10 @@ describe('when on the endpoint list page', () => { history.push('/endpoints?selected_endpoint=1&show=isolate'); }); renderResult = await renderAndWaitForData(); + // Need to reset `http.post` and adjust it so that the mock for http host + // isolation api does not output error noise to the console coreStart.http.post.mockReset(); + coreStart.http.post.mockImplementation(async () => null); isolateApiMock = hostIsolationHttpMocks(coreStart.http); });