diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.test.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.test.tsx
new file mode 100644
index 0000000000000..f4ee33446d504
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.test.tsx
@@ -0,0 +1,80 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { ThemeProvider } from 'styled-components';
+import { I18nProvider } from '@kbn/i18n/react';
+import { ExceptionItemsSummary } from './exception_items_summary';
+import * as reactTestingLibrary from '@testing-library/react';
+import { getMockTheme } from '../../../../../../../../public/common/lib/kibana/kibana_react.mock';
+import { GetExceptionSummaryResponse } from '../../../../../../../../common/endpoint/types';
+
+const mockTheme = getMockTheme({
+ eui: {
+ paddingSizes: { m: '2' },
+ },
+});
+
+const getStatValue = (el: reactTestingLibrary.RenderResult, stat: string) => {
+ return el.getByText(stat)!.nextSibling?.lastChild?.textContent;
+};
+
+describe('Fleet event filters card', () => {
+ const renderComponent: (
+ stats: GetExceptionSummaryResponse
+ ) => reactTestingLibrary.RenderResult = (stats) => {
+ const Wrapper: React.FC = ({ children }) => (
+
+ {children}
+
+ );
+ const component = reactTestingLibrary.render(, {
+ wrapper: Wrapper,
+ });
+ return component;
+ };
+ it('should renders correctly', () => {
+ const summary: GetExceptionSummaryResponse = {
+ windows: 3,
+ linux: 2,
+ macos: 2,
+ total: 7,
+ };
+ const component = renderComponent(summary);
+
+ expect(component.getByText('Windows')).not.toBeNull();
+ expect(getStatValue(component, 'Windows')).toEqual(summary.windows.toString());
+
+ expect(component.getByText('Linux')).not.toBeNull();
+ expect(getStatValue(component, 'Linux')).toEqual(summary.linux.toString());
+
+ expect(component.getByText('Mac')).not.toBeNull();
+ expect(getStatValue(component, 'Mac')).toEqual(summary.macos.toString());
+
+ expect(component.getByText('Total')).not.toBeNull();
+ expect(getStatValue(component, 'Total')).toEqual(summary.total.toString());
+ });
+ it('should renders correctly when missing some stats', () => {
+ const summary: Partial = {
+ windows: 3,
+ total: 3,
+ };
+ const component = renderComponent(summary as GetExceptionSummaryResponse);
+
+ expect(component.getByText('Windows')).not.toBeNull();
+ expect(getStatValue(component, 'Windows')).toEqual('3');
+
+ expect(component.getByText('Linux')).not.toBeNull();
+ expect(getStatValue(component, 'Linux')).toEqual('0');
+
+ expect(component.getByText('Mac')).not.toBeNull();
+ expect(getStatValue(component, 'Mac')).toEqual('0');
+
+ expect(component.getByText('Total')).not.toBeNull();
+ expect(getStatValue(component, 'Total')).toEqual('3');
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx
index f42304ffb89ae..ed3d9967f318e 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/exception_items_summary.tsx
@@ -47,7 +47,7 @@ export const ExceptionItemsSummary = memo(({ stats }
{SUMMARY_KEYS.map((stat) => {
return (
-
+
{
+ const originalModule = jest.requireActual(
+ '../../../../../../../../../../../src/plugins/kibana_react/public'
+ );
+ const useKibana = jest.fn().mockImplementation(() => ({
+ services: {
+ http: {},
+ data: {},
+ notifications: {},
+ application: {
+ getUrlForApp: jest.fn(),
+ },
+ },
+ }));
+
+ return {
+ ...originalModule,
+ useKibana,
+ };
+});
+
+jest.mock('../../../../../../../common/lib/kibana');
+
+const mockTheme = getMockTheme({
+ eui: {
+ paddingSizes: { m: '2' },
+ },
+});
+
+const EventFiltersHttpServiceMock = EventFiltersHttpService as jest.Mock;
+const useToastsMock = useToasts as jest.Mock;
+
+const summary: GetExceptionSummaryResponse = {
+ windows: 3,
+ linux: 2,
+ macos: 2,
+ total: 7,
+};
+
+describe('Fleet event filters card', () => {
+ let promise: Promise;
+ let addDanger: jest.Mock = jest.fn();
+ const renderComponent: () => Promise = async () => {
+ const Wrapper: React.FC = ({ children }) => (
+
+ {children}
+
+ );
+ // @ts-ignore
+ const component = reactTestingLibrary.render(, { wrapper: Wrapper });
+ try {
+ // @ts-ignore
+ await reactTestingLibrary.act(() => promise);
+ } catch (err) {
+ return component;
+ }
+ return component;
+ };
+ beforeAll(() => {
+ useToastsMock.mockImplementation(() => {
+ return {
+ addDanger,
+ };
+ });
+ });
+ beforeEach(() => {
+ promise = Promise.resolve(summary);
+ addDanger = jest.fn();
+ });
+ afterEach(() => {
+ EventFiltersHttpServiceMock.mockReset();
+ });
+ it('should render correctly', async () => {
+ EventFiltersHttpServiceMock.mockImplementationOnce(() => {
+ return {
+ getSummary: () => jest.fn(() => promise),
+ };
+ });
+ const component = await renderComponent();
+ expect(component.getByText('Event Filters')).not.toBeNull();
+ expect(component.getByText('Manage event filters')).not.toBeNull();
+ });
+ it('should render an error toast when api call fails', async () => {
+ expect(addDanger).toBeCalledTimes(0);
+ promise = Promise.reject(new Error('error test'));
+ EventFiltersHttpServiceMock.mockImplementationOnce(() => {
+ return {
+ getSummary: () => promise,
+ };
+ });
+ const component = await renderComponent();
+ expect(component.getByText('Event Filters')).not.toBeNull();
+ expect(component.getByText('Manage event filters')).not.toBeNull();
+ await reactTestingLibrary.waitFor(() => expect(addDanger).toBeCalledTimes(1));
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx
index 6f368a89eb5f9..40d10004788e4 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_event_filters_card.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { memo, useMemo, useState, useEffect } from 'react';
+import React, { memo, useMemo, useState, useEffect, useRef } from 'react';
import { ApplicationStart, CoreStart } from 'kibana/public';
import { EuiPanel, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -36,12 +36,16 @@ export const FleetEventFiltersCard = memo(
const [stats, setStats] = useState();
const eventFiltersListUrlPath = getEventFiltersListPath();
const eventFiltersApi = useMemo(() => new EventFiltersHttpService(http), [http]);
+ const isMounted = useRef();
useEffect(() => {
+ isMounted.current = true;
const fetchStats = async () => {
try {
const summary = await eventFiltersApi.getSummary();
- setStats(summary);
+ if (isMounted.current) {
+ setStats(summary);
+ }
} catch (error) {
toasts.addDanger(
i18n.translate(
@@ -55,6 +59,9 @@ export const FleetEventFiltersCard = memo(
}
};
fetchStats();
+ return () => {
+ isMounted.current = false;
+ };
}, [eventFiltersApi, toasts]);
const eventFiltersRouteState = useMemo(() => {
@@ -79,7 +86,7 @@ export const FleetEventFiltersCard = memo(
return (
-
+
(
-
+
-
+
<>
{
+ const originalModule = jest.requireActual(
+ '../../../../../../../../../../../src/plugins/kibana_react/public'
+ );
+ const useKibana = jest.fn().mockImplementation(() => ({
+ services: {
+ http: {},
+ data: {},
+ notifications: {},
+ application: {
+ getUrlForApp: jest.fn(),
+ },
+ },
+ }));
+
+ return {
+ ...originalModule,
+ useKibana,
+ };
+});
+
+jest.mock('../../../../../../../common/lib/kibana');
+
+const mockTheme = getMockTheme({
+ eui: {
+ paddingSizes: { m: '2' },
+ },
+});
+
+const TrustedAppsHttpServiceMock = TrustedAppsHttpService as jest.Mock;
+const useToastsMock = useToasts as jest.Mock;
+
+const summary: GetExceptionSummaryResponse = {
+ windows: 3,
+ linux: 2,
+ macos: 2,
+ total: 7,
+};
+
+describe('Fleet trusted apps card', () => {
+ let promise: Promise;
+ let addDanger: jest.Mock = jest.fn();
+ const renderComponent: () => Promise = async () => {
+ const Wrapper: React.FC = ({ children }) => (
+
+ {children}
+
+ );
+ // @ts-ignore
+ const component = reactTestingLibrary.render(, { wrapper: Wrapper });
+ try {
+ // @ts-ignore
+ await reactTestingLibrary.act(() => promise);
+ } catch (err) {
+ return component;
+ }
+ return component;
+ };
+
+ beforeAll(() => {
+ useToastsMock.mockImplementation(() => {
+ return {
+ addDanger,
+ };
+ });
+ });
+ beforeEach(() => {
+ promise = Promise.resolve(summary);
+ addDanger = jest.fn();
+ });
+ afterEach(() => {
+ TrustedAppsHttpServiceMock.mockReset();
+ });
+ it('should render correctly', async () => {
+ TrustedAppsHttpServiceMock.mockImplementationOnce(() => {
+ return {
+ getTrustedAppsSummary: () => jest.fn(() => promise),
+ };
+ });
+ const component = await renderComponent();
+ expect(component.getByText('Trusted Applications')).not.toBeNull();
+ expect(component.getByText('Manage trusted applications')).not.toBeNull();
+ });
+ it('should render an error toast when api call fails', async () => {
+ expect(addDanger).toBeCalledTimes(0);
+ promise = Promise.reject(new Error('error test'));
+ TrustedAppsHttpServiceMock.mockImplementationOnce(() => {
+ return {
+ getTrustedAppsSummary: () => promise,
+ };
+ });
+ const component = await renderComponent();
+ expect(component.getByText('Trusted Applications')).not.toBeNull();
+ expect(component.getByText('Manage trusted applications')).not.toBeNull();
+ await reactTestingLibrary.waitFor(() => expect(addDanger).toBeCalledTimes(1));
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx
index ec1479643999a..b1464d23e00fb 100644
--- a/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/ingest_manager_integration/endpoint_package_custom_extension/components/fleet_trusted_apps_card.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { memo, useMemo, useState, useEffect } from 'react';
+import React, { memo, useMemo, useState, useEffect, useRef } from 'react';
import { ApplicationStart, CoreStart } from 'kibana/public';
import { EuiPanel, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -38,12 +38,16 @@ export const FleetTrustedAppsCard = memo((
const toasts = useToasts();
const [stats, setStats] = useState();
const trustedAppsApi = useMemo(() => new TrustedAppsHttpService(http), [http]);
+ const isMounted = useRef();
useEffect(() => {
+ isMounted.current = true;
const fetchStats = async () => {
try {
const response = await trustedAppsApi.getTrustedAppsSummary();
- setStats(response);
+ if (isMounted) {
+ setStats(response);
+ }
} catch (error) {
toasts.addDanger(
i18n.translate(
@@ -57,6 +61,9 @@ export const FleetTrustedAppsCard = memo((
}
};
fetchStats();
+ return () => {
+ isMounted.current = false;
+ };
}, [toasts, trustedAppsApi]);
const trustedAppsListUrlPath = getTrustedAppsListPath();
@@ -82,7 +89,7 @@ export const FleetTrustedAppsCard = memo((
return (
-
+
((
-
+
-
+
<>
`
- grid-area: ${({ gridArea }) => gridArea};
- align-items: ${({ alignItems }) => alignItems ?? 'center'};
+ grid-area: ${({ gridarea }) => gridarea};
+ align-items: ${({ alignitems }) => alignitems ?? 'center'};
margin: 0px;
padding: 12px;
`;