Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* 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 { act, render } from '@testing-library/react';
import type { PackageListItem } from '@kbn/fleet-plugin/common';
import { installationStatuses } from '@kbn/fleet-plugin/common/constants';
import {
CONTENT_TEST_ID,
DATA_VIEW_ERROR_TEST_ID,
DATA_VIEW_LOADING_PROMPT_TEST_ID,
SKELETON_TEST_ID,
Wrapper,
} from './wrapper';
import { useKibana } from '../../../common/lib/kibana';

jest.mock('../../../common/lib/kibana');

const packages: PackageListItem[] = [
{
id: 'splunk',
name: 'splunk',
status: installationStatuses.NotInstalled,
title: 'Splunk',
version: '',
},
];

describe('<Wrapper />', () => {
it('should render a loading skeleton while creating the dataView', async () => {
(useKibana as jest.Mock).mockReturnValue({
services: {
data: {
dataViews: {
create: jest.fn(),
clearInstanceCache: jest.fn(),
},
},
},
});

await act(async () => {
const { getByTestId } = render(<Wrapper packages={packages} />);

expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
expect(getByTestId(SKELETON_TEST_ID)).toBeInTheDocument();
});
});

it('should render an error if the dataView fail to be created correctly', async () => {
(useKibana as jest.Mock).mockReturnValue({
services: {
data: {
dataViews: {
create: jest.fn().mockReturnValue(undefined),
clearInstanceCache: jest.fn(),
},
},
},
});

jest.mock('react', () => ({
...jest.requireActual('react'),
useEffect: jest.fn((f) => f()),
}));

await act(async () => {
const { getByTestId } = render(<Wrapper packages={packages} />);

await new Promise(process.nextTick);

expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
expect(getByTestId(DATA_VIEW_ERROR_TEST_ID)).toHaveTextContent('Unable to create data view');
});
});

it('should render the content if the dataView is created correctly', async () => {
(useKibana as jest.Mock).mockReturnValue({
services: {
data: {
dataViews: {
create: jest.fn().mockReturnValue({ id: 'id' }),
clearInstanceCache: jest.fn(),
},
},
},
});

jest.mock('react', () => ({
...jest.requireActual('react'),
useEffect: jest.fn((f) => f()),
}));

await act(async () => {
const { getByTestId } = render(<Wrapper packages={packages} />);

await new Promise(process.nextTick);

expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
expect(getByTestId(CONTENT_TEST_ID)).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,29 @@
* 2.0.
*/

import React, { memo } from 'react';
import React, { memo, useEffect, useState } from 'react';
import {
EuiEmptyPrompt,
EuiHorizontalRule,
EuiSkeletonLoading,
EuiSkeletonRectangle,
EuiSpacer,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common';
import type { PackageListItem } from '@kbn/fleet-plugin/common';
import { EuiText } from '@elastic/eui';
import { useKibana } from '../../../common/lib/kibana';

const DATAVIEW_ERROR = i18n.translate('xpack.securitySolution.alertSummary.dataViewError', {
defaultMessage: 'Unable to create data view',
});

export const DATA_VIEW_LOADING_PROMPT_TEST_ID = 'alert-summary-data-view-loading-prompt';
export const DATA_VIEW_ERROR_TEST_ID = 'alert-summary-data-view-error';
export const SKELETON_TEST_ID = 'alert-summary-skeleton';
export const CONTENT_TEST_ID = 'alert-summary-content';

const dataViewSpec: DataViewSpec = { title: '.alerts-security.alerts-default' };

export interface WrapperProps {
/**
Expand All @@ -19,12 +37,64 @@ export interface WrapperProps {
}

/**
* Creates a new dataView with the alert indices while displaying a loading skeleton.
* Display the alert summary page content if the dataView is correctly created.
* This page is rendered when there are AI for SOC packages installed.
* Creates a new adhoc dataView for the alert summary page. The dataView is created just with the alert indices.
* During the creating, we display a loading skeleton, mimicking the future alert summary page content.
* Once the dataView is correctly created, we render the content.
* If the creation fails, we show an error message.
*/
export const Wrapper = memo(({ packages }: WrapperProps) => {
return <EuiText data-test-subj={DATA_VIEW_LOADING_PROMPT_TEST_ID}>{'Wrapper'}</EuiText>;
const { data } = useKibana().services;
const [dataView, setDataView] = useState<DataView | undefined>(undefined);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
let dv: DataView;
const createDataView = async () => {
dv = await data.dataViews.create(dataViewSpec);
setDataView(dv);
setLoading(false);
};
createDataView();

// clearing after leaving the page
return () => {
if (dv?.id) {
data.dataViews.clearInstanceCache(dv?.id);
}
};
}, [data.dataViews]);

return (
<EuiSkeletonLoading
data-test-subj={DATA_VIEW_LOADING_PROMPT_TEST_ID}
isLoading={loading}
loadingContent={
<div data-test-subj={SKELETON_TEST_ID}>
<EuiSkeletonRectangle height={50} width="100%" />
<EuiHorizontalRule />
<EuiSkeletonRectangle height={50} width="100%" />
<EuiSpacer />
<EuiSkeletonRectangle height={275} width="100%" />
<EuiSpacer />
<EuiSkeletonRectangle height={600} width="100%" />
</div>
}
loadedContent={
<>
{!dataView || !dataView.id ? (
<EuiEmptyPrompt
color="danger"
data-test-subj={DATA_VIEW_ERROR_TEST_ID}
iconType="error"
title={<h2>{DATAVIEW_ERROR}</h2>}
/>
) : (
<div data-test-subj={CONTENT_TEST_ID}>{'wrapper'}</div>
)}
</>
}
/>
);
});

Wrapper.displayName = 'Wrapper';
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@
*/

import React from 'react';
import { render } from '@testing-library/react';
import { act, render } from '@testing-library/react';
import { AlertSummaryPage, LOADING_INTEGRATIONS_TEST_ID } from './alert_summary';
import { useFetchIntegrations } from '../../hooks/alert_summary/use_fetch_integrations';
import { LANDING_PAGE_PROMPT_TEST_ID } from '../../components/alert_summary/landing_page/landing_page';
import { useAddIntegrationsUrl } from '../../../common/hooks/use_add_integrations_url';
import { DATA_VIEW_LOADING_PROMPT_TEST_ID } from '../../components/alert_summary/wrapper';
import { useKibana } from '../../../common/lib/kibana';

jest.mock('../../hooks/alert_summary/use_fetch_integrations');
jest.mock('../../../common/hooks/use_add_integrations_url');
jest.mock('../../../common/lib/kibana');

describe('<AlertSummaryPage />', () => {
it('should render loading logo', () => {
Expand All @@ -40,16 +42,27 @@ describe('<AlertSummaryPage />', () => {
expect(getByTestId(LANDING_PAGE_PROMPT_TEST_ID)).toBeInTheDocument();
});

it('should render wrapper if packages are installed', () => {
it('should render wrapper if packages are installed', async () => {
(useKibana as jest.Mock).mockReturnValue({
services: {
data: {
dataViews: {
create: jest.fn(),
},
},
},
});
(useFetchIntegrations as jest.Mock).mockReturnValue({
availablePackage: [],
installedPackages: [{ id: 'id' }],
isLoading: false,
});

const { getByTestId, queryByTestId } = render(<AlertSummaryPage />);
expect(queryByTestId(LOADING_INTEGRATIONS_TEST_ID)).not.toBeInTheDocument();
expect(queryByTestId(LANDING_PAGE_PROMPT_TEST_ID)).not.toBeInTheDocument();
expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
await act(async () => {
const { getByTestId, queryByTestId } = render(<AlertSummaryPage />);
expect(queryByTestId(LOADING_INTEGRATIONS_TEST_ID)).not.toBeInTheDocument();
expect(queryByTestId(LANDING_PAGE_PROMPT_TEST_ID)).not.toBeInTheDocument();
expect(getByTestId(DATA_VIEW_LOADING_PROMPT_TEST_ID)).toBeInTheDocument();
});
});
});