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 Solution] Set default template timelines' filter to 'timeline' #74051

Merged
merged 1 commit into from
Aug 3, 2020
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
Expand Up @@ -4,29 +4,48 @@
* you may not use this file except in compliance with the Elastic License.
*/

/* eslint-disable react/display-name */

import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { mount } from 'enzyme';
import { MockedProvider } from 'react-apollo/test-utils';
import React from 'react';

// we don't have the types for waitFor just yet, so using "as waitFor" until when we do
import { wait as waitFor } from '@testing-library/react';
import { useHistory, useParams } from 'react-router-dom';

import '../../../common/mock/match_media';
import { SecurityPageName } from '../../../app/types';
import { TimelineType } from '../../../../common/types/timeline';

import { TestProviders, apolloClient } from '../../../common/mock/test_providers';
import { mockOpenTimelineQueryResults } from '../../../common/mock/timeline_results';
import { getTimelineTabsUrl } from '../../../common/components/link_to';

import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines_page';
import { useGetAllTimeline, getAllTimeline } from '../../containers/all';

import { NotePreviews } from './note_previews';
import { OPEN_TIMELINE_CLASS_NAME } from './helpers';

import { StatefulOpenTimeline } from '.';

import { useGetAllTimeline, getAllTimeline } from '../../containers/all';
import { TimelineTabsStyle } from './types';
import {
useTimelineTypes,
UseTimelineTypesArgs,
UseTimelineTypesResult,
} from './use_timeline_types';

import { useParams } from 'react-router-dom';
import { TimelineType } from '../../../../common/types/timeline';
jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');

jest.mock('../../../common/lib/kibana');
jest.mock('../../../common/components/link_to');
return {
...originalModule,
useParams: jest.fn(),
useHistory: jest.fn(),
};
});

jest.mock('./helpers', () => {
const originalModule = jest.requireActual('./helpers');
Expand All @@ -41,24 +60,31 @@ jest.mock('../../containers/all', () => {
return {
...originalModule,
useGetAllTimeline: jest.fn(),
getAllTimeline: originalModule.getAllTimeline,
};
});

jest.mock('react-router-dom', () => {
const originalModule = jest.requireActual('react-router-dom');
jest.mock('../../../common/lib/kibana');
jest.mock('../../../common/components/link_to');

jest.mock('../../../common/components/link_to', () => {
const originalModule = jest.requireActual('../../../common/components/link_to');
return {
...originalModule,
useParams: jest.fn(),
useHistory: jest.fn().mockReturnValue([]),
getTimelineTabsUrl: jest.fn(),
useFormatUrl: jest.fn().mockReturnValue({ formatUrl: jest.fn(), search: 'urlSearch' }),
};
});

describe('StatefulOpenTimeline', () => {
const title = 'All Timelines / Open Timelines';
let mockHistory: History[];
beforeEach(() => {
(useParams as jest.Mock).mockReturnValue({ tabName: TimelineType.default });
(useParams as jest.Mock).mockReturnValue({
tabName: TimelineType.default,
pageName: SecurityPageName.timelines,
});
mockHistory = [];
(useHistory as jest.Mock).mockReturnValue(mockHistory);
((useGetAllTimeline as unknown) as jest.Mock).mockReturnValue({
fetchAllTimeline: jest.fn(),
timelines: getAllTimeline(
Expand All @@ -71,6 +97,13 @@ describe('StatefulOpenTimeline', () => {
});
});

afterEach(() => {
(getTimelineTabsUrl as jest.Mock).mockClear();
(useParams as jest.Mock).mockClear();
(useHistory as jest.Mock).mockClear();
mockHistory = [];
});

test('it has the expected initial state', () => {
const wrapper = mount(
<TestProviders>
Expand Down Expand Up @@ -101,6 +134,109 @@ describe('StatefulOpenTimeline', () => {
});
});

describe("Template timelines' tab", () => {
test("should land on correct timelines' tab with url timelines/default", () => {
const { result } = renderHook<UseTimelineTypesArgs, UseTimelineTypesResult>(
() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 0 }),
{
wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
}
);

expect(result.current.timelineType).toBe(TimelineType.default);
});

test("should land on correct timelines' tab with url timelines/template", () => {
(useParams as jest.Mock).mockReturnValue({
tabName: TimelineType.template,
pageName: SecurityPageName.timelines,
});

const { result } = renderHook<UseTimelineTypesArgs, UseTimelineTypesResult>(
() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 0 }),
{
wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
}
);

expect(result.current.timelineType).toBe(TimelineType.template);
});

test("should land on correct templates' tab after switching tab", () => {
(useParams as jest.Mock).mockReturnValue({
tabName: TimelineType.template,
pageName: SecurityPageName.timelines,
});

const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={false}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
/>
</MockedProvider>
</TestProviders>
);
wrapper
.find(`[data-test-subj="timeline-${TimelineTabsStyle.tab}-${TimelineType.template}"]`)
.first()
.simulate('click');
act(() => {
expect(history.length).toBeGreaterThan(0);
});
});

test("should selecting correct timelines' filter", () => {
(useParams as jest.Mock).mockReturnValue({
tabName: 'mockTabName',
pageName: SecurityPageName.case,
});

const { result } = renderHook<UseTimelineTypesArgs, UseTimelineTypesResult>(
() => useTimelineTypes({ defaultTimelineCount: 0, templateTimelineCount: 0 }),
{
wrapper: ({ children }) => <TestProviders> {children}</TestProviders>,
}
);

expect(result.current.timelineType).toBe(TimelineType.default);
});

test('should not change url after switching filter', () => {
(useParams as jest.Mock).mockReturnValue({
tabName: 'mockTabName',
pageName: SecurityPageName.case,
});

const wrapper = mount(
<TestProviders>
<MockedProvider mocks={mockOpenTimelineQueryResults} addTypename={false}>
<StatefulOpenTimeline
data-test-subj="stateful-timeline"
apolloClient={apolloClient}
isModal={true}
defaultPageSize={DEFAULT_SEARCH_RESULTS_PER_PAGE}
title={title}
/>
</MockedProvider>
</TestProviders>
);
wrapper
.find(
`[data-test-subj="open-timeline-modal-body-${TimelineTabsStyle.filter}-${TimelineType.template}"]`
)
.first()
.simulate('click');
act(() => {
expect(mockHistory.length).toEqual(0);
});
});
});

describe('#onQueryChange', () => {
test('it updates the query state with the expected trimmed value when the user enters a query', () => {
const wrapper = mount(
Expand Down Expand Up @@ -482,9 +618,13 @@ describe('StatefulOpenTimeline', () => {
</TestProviders>
);

expect(wrapper.find('[data-test-subj="open-timeline-modal-body-filters"]').exists()).toEqual(
true
);
expect(
wrapper
.find(
`[data-test-subj="open-timeline-modal-body-${TimelineTabsStyle.filter}-${TimelineType.default}"]`
)
.exists()
).toEqual(true);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export const useTimelineTypes = ({
const { formatUrl, search: urlSearch } = useFormatUrl(SecurityPageName.timelines);
const { tabName } = useParams<{ pageName: SecurityPageName; tabName: string }>();
const [timelineType, setTimelineTypes] = useState<TimelineTypeLiteralWithNull>(
tabName === TimelineType.default || tabName === TimelineType.template ? tabName : null
tabName === TimelineType.default || tabName === TimelineType.template
? tabName
: TimelineType.default
);

const goToTimeline = useCallback(
Expand Down Expand Up @@ -114,6 +116,7 @@ export const useTimelineTypes = ({
<EuiTabs data-test-subj="open-timeline-subtabs">
{getFilterOrTabs(TimelineTabsStyle.tab).map((tab: TimelineTab) => (
<EuiTab
data-test-subj={`timeline-${TimelineTabsStyle.tab}-${tab.id}`}
isSelected={tab.id === tabName}
disabled={tab.disabled}
key={`timeline-${TimelineTabsStyle.tab}-${tab.id}`}
Expand All @@ -136,7 +139,7 @@ export const useTimelineTypes = ({
const timelineFilters = useMemo(() => {
return getFilterOrTabs(TimelineTabsStyle.filter).map((tab: TimelineTab) => (
<EuiFilterButton
data-test-subj="open-timeline-modal-body-filters"
data-test-subj={`open-timeline-modal-body-${TimelineTabsStyle.filter}-${tab.id}`}
hasActiveFilters={tab.id === timelineType}
key={`timeline-${TimelineTabsStyle.filter}-${tab.id}`}
numFilters={tab.count}
Expand Down