Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Security Solutions][Timeline] Added createFrom in action to hide #98144

Merged
merged 10 commits into from
Apr 29, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,38 @@
*/

import React from 'react';
import { shallow } from 'enzyme';
import { mount, shallow } from 'enzyme';

import { QueryBarDefineRule } from './index';
import { useFormFieldMock } from '../../../../common/mock';
import {
TestProviders,
useFormFieldMock,
mockOpenTimelineQueryResults,
} from '../../../../common/mock';
import { mockHistory, Router } from '../../../../cases/components/__mock__/router';
import { useGetAllTimeline, getAllTimeline } from '../../../../timelines/containers/all';

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

jest.mock('../../../../timelines/containers/all', () => {
const originalModule = jest.requireActual('../../../../timelines/containers/all');
return {
...originalModule,
useGetAllTimeline: jest.fn(),
};
});

describe('QueryBarDefineRule', () => {
beforeEach(() => {
((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({
fetchAllTimeline: jest.fn(),
timelines: getAllTimeline('', mockOpenTimelineQueryResults.timeline ?? []),
loading: false,
totalCount: mockOpenTimelineQueryResults.totalCount,
refetch: jest.fn(),
});
});

it('renders correctly', () => {
const Component = () => {
const field = useFormFieldMock();
Expand All @@ -32,7 +56,36 @@ describe('QueryBarDefineRule', () => {
);
};
const wrapper = shallow(<Component />);

expect(wrapper.dive().find('[data-test-subj="query-bar-define-rule"]')).toHaveLength(1);
});

it('renders import query from saved timeline modal with no timeline action correctly', () => {
const Component = () => {
const field = useFormFieldMock();

return (
<QueryBarDefineRule
browserFields={{}}
isLoading={false}
indexPattern={{ fields: [], title: 'title' }}
onCloseTimelineSearch={jest.fn()}
openTimelineSearch={true}
dataTestSubj="query-bar-define-rule"
idAria="idAria"
field={field}
/>
);
};
const wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<Component />
</Router>
</TestProviders>
);

const firstRow = wrapper.find('[data-test-subj="timelines-table"] table tbody tr').first();
const actionsCell = firstRow.find('.euiTableRowCell').last();
expect(actionsCell.find('.euiTableCellContent').isEmptyRender()).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { EuiFormRow, EuiMutationObserver } from '@elastic/eui';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { Subscription } from 'rxjs';
import styled from 'styled-components';
import deepEqual from 'fast-deep-equal';
Expand Down Expand Up @@ -50,6 +50,8 @@ interface QueryBarDefineRuleProps {
onValidityChange?: (arg: boolean) => void;
}

const actionTimelineToHide: ActionTimelineToShow[] = ['duplicate', 'createFrom'];

const StyledEuiFormRow = styled(EuiFormRow)`
.kbnTypeahead__items {
max-height: 45vh !important;
Expand Down Expand Up @@ -253,8 +255,6 @@ export const QueryBarDefineRule = ({
}
};

const actionTimelineToHide = useMemo<ActionTimelineToShow[]>(() => ['duplicate'], []);

return (
<>
<StyledEuiFormRow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,38 @@ import { waitFor } from '@testing-library/react';
import { AddTimelineButton } from './';
import { useKibana } from '../../../../common/lib/kibana';
import { TimelineId } from '../../../../../common/types/timeline';
import { mockOpenTimelineQueryResults, TestProviders } from '../../../../common/mock';
import { mockHistory, Router } from '../../../../cases/components/__mock__/router';
import { getAllTimeline, useGetAllTimeline } from '../../../containers/all';

jest.mock('../../open_timeline/use_timeline_status', () => {
const originalModule = jest.requireActual('../../open_timeline/use_timeline_status');
return {
...originalModule,
useTimelineStatus: jest.fn().mockReturnValue({
timelineStatus: 'active',
templateTimelineFilter: [],
installPrepackagedTimelines: jest.fn(),
}),
};
});

jest.mock('../../../../common/lib/kibana', () => ({
useKibana: jest.fn(),
useUiSetting$: jest.fn().mockReturnValue([]),
}));
jest.mock('../../../../common/lib/kibana', () => {
const originalModule = jest.requireActual('../../../../common/lib/kibana');
return {
...originalModule,
useKibana: jest.fn(),
useUiSetting$: jest.fn().mockReturnValue([]),
};
});

jest.mock('../../../containers/all', () => {
const originalModule = jest.requireActual('../../../containers/all');
return {
...originalModule,
useGetAllTimeline: jest.fn(),
};
});

jest.mock('../../timeline/properties/new_template_timeline', () => ({
NewTemplateTimeline: jest.fn(() => <div data-test-subj="create-template-btn" />),
Expand All @@ -35,8 +62,7 @@ jest.mock('../../../../common/components/inspect', () => ({
InspectButtonContainer: jest.fn(({ children }) => <div>{children}</div>),
}));

// FLAKY: https://github.com/elastic/kibana/issues/96691
describe.skip('AddTimelineButton', () => {
describe('AddTimelineButton', () => {
let wrapper: ReactWrapper;
const props = {
timelineId: TimelineId.active,
Expand Down Expand Up @@ -67,24 +93,24 @@ describe.skip('AddTimelineButton', () => {
});

test('it renders create timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy()
);
});

test('it renders create timeline template btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy()
);
});

test('it renders Open timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);
});
});

Expand Down Expand Up @@ -113,24 +139,86 @@ describe.skip('AddTimelineButton', () => {
});

test('it renders create timeline btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-default-btn"]').exists()).toBeTruthy()
);
});

test('it renders create timeline template btn', async () => {
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy();
});
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="create-template-btn"]').exists()).toBeTruthy()
);
});

test('it renders Open timeline btn', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);
});
});

describe('open modal', () => {
beforeEach(() => {
(useKibana as jest.Mock).mockReturnValue({
services: {
application: {
getUrlForApp: jest.fn(),
capabilities: {
siem: {
crud: true,
},
},
},
},
});

((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({
fetchAllTimeline: jest.fn(),
timelines: getAllTimeline('', mockOpenTimelineQueryResults.timeline ?? []),
loading: false,
totalCount: mockOpenTimelineQueryResults.totalCount,
refetch: jest.fn(),
});

wrapper = mount(
<TestProviders>
<Router history={mockHistory}>
<AddTimelineButton {...props} />
</Router>
</TestProviders>
);
});

afterEach(() => {
(useKibana as jest.Mock).mockReset();
});

it('should render timelines table', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy();
});

wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click');
await waitFor(() => {
expect(wrapper.find('[data-test-subj="timelines-table"]').exists()).toBeTruthy();
});
});

it('should render correct actions', async () => {
wrapper.find('[data-test-subj="settings-plus-in-circle"]').last().simulate('click');
await waitFor(() =>
expect(wrapper.find('[data-test-subj="open-timeline-button"]').exists()).toBeTruthy()
);

wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click');
await waitFor(() => {
expect(wrapper.find('[data-test-subj="open-duplicate"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="create-from-template"]').exists()).toBeFalsy();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import React, { useCallback, useMemo, useState } from 'react';

import { OpenTimelineModalButton } from '../../open_timeline/open_timeline_modal/open_timeline_modal_button';
import { OpenTimelineModal } from '../../open_timeline/open_timeline_modal';
import { ActionTimelineToShow } from '../../open_timeline/types';
import * as i18n from '../../timeline/properties/translations';
import { NewTimeline } from '../../timeline/properties/helpers';
import { NewTemplateTimeline } from '../../timeline/properties/new_template_timeline';
Expand All @@ -20,6 +21,8 @@ interface AddTimelineButtonComponentProps {

export const ADD_TIMELINE_BUTTON_CLASS_NAME = 'add-timeline-button';

const actionTimelineToHide: ActionTimelineToShow[] = ['createFrom'];

const AddTimelineButtonComponent: React.FC<AddTimelineButtonComponentProps> = ({ timelineId }) => {
const [showActions, setShowActions] = useState(false);
const [showTimelineModal, setShowTimelineModal] = useState(false);
Expand Down Expand Up @@ -83,7 +86,9 @@ const AddTimelineButtonComponent: React.FC<AddTimelineButtonComponentProps> = ({
</EuiPopover>
</EuiFlexItem>

{showTimelineModal ? <OpenTimelineModal onClose={onCloseTimelineModal} /> : null}
{showTimelineModal ? (
<OpenTimelineModal onClose={onCloseTimelineModal} hideActions={actionTimelineToHide} />
) : null}
</>
);
};
Expand Down