Skip to content

Commit

Permalink
per feedback, rewrote code to include logic in existing helper, updat…
Browse files Browse the repository at this point in the history
…ed tests
  • Loading branch information
yctercero committed Mar 27, 2020
1 parent b56731b commit 23563b8
Show file tree
Hide file tree
Showing 14 changed files with 220 additions and 187 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import {
DEFINITION_INDEX_PATTERNS,
DEFINITION_TIMELINE,
DEFINITION_STEP,
INVESTIGATION_NOTES_MARKDOWN,
INVESTIGATION_NOTES_TOGGLE,
RULE_ABOUT_DETAILS_HEADER_TOGGLE,
RULE_NAME_HEADER,
SCHEDULE_LOOPBACK,
SCHEDULE_RUNS,
SCHEDULE_STEP,
ABOUT_RULE_DESCRIPTION,
ABOUT_INVESTIGATION_NOTES,
INVESTIGATION_NOTES_TOGGLE,
} from '../screens/rule_details';
import {
CUSTOM_RULES_BTN,
Expand Down Expand Up @@ -168,12 +170,12 @@ describe('Signal detection rules, custom', () => {
.invoke('text')
.should('eql', expectedTags);

cy.get(INVESTIGATION_NOTES_TOGGLE)
.eq(1)
cy.get(RULE_ABOUT_DETAILS_HEADER_TOGGLE)
.eq(INVESTIGATION_NOTES_TOGGLE)
.click({ force: true });
cy.get(ABOUT_INVESTIGATION_NOTES)
.invoke('text')
.should('eql', 'test markdown');
.should('eql', INVESTIGATION_NOTES_MARKDOWN);

cy.get(DEFINITION_INDEX_PATTERNS).then(patterns => {
cy.wrap(patterns).each((pattern, index) => {
Expand Down
8 changes: 4 additions & 4 deletions x-pack/legacy/plugins/siem/cypress/screens/create_new_rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export const CUSTOM_QUERY_INPUT = '[data-test-subj="queryInput"]';

export const DEFINE_CONTINUE_BUTTON = '[data-test-subj="define-continue"]';

export const SCHEDULE_CONTINUE_BUTTON = '[data-test-subj="schedule-continue"]';
export const INVESTIGATION_NOTES_TEXTAREA =
'[data-test-subj="detectionEngineStepAboutRuleNote"] textarea';

export const FALSE_POSITIVES_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleFalsePositives"] input';
Expand Down Expand Up @@ -53,11 +54,10 @@ export const RULE_DESCRIPTION_INPUT =
export const RULE_NAME_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleName"] [data-test-subj="input"]';

export const SCHEDULE_CONTINUE_BUTTON = '[data-test-subj="schedule-continue"]';

export const SEVERITY_DROPDOWN =
'[data-test-subj="detectionEngineStepAboutRuleSeverity"] [data-test-subj="select"]';

export const TAGS_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleTags"] [data-test-subj="comboBoxSearchInput"]';

export const INVESTIGATION_NOTES_TEXTAREA =
'[data-test-subj="detectionEngineStepAboutRuleNote"] textarea';
12 changes: 8 additions & 4 deletions x-pack/legacy/plugins/siem/cypress/screens/rule_details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

export const ABOUT_FALSE_POSITIVES = 3;

export const ABOUT_INVESTIGATION_NOTES = '[data-test-subj="stepAboutDetailsNoteContent"]';

export const ABOUT_MITRE = 4;

export const ABOUT_RULE_DESCRIPTION = '[data-test-subj=stepAboutRuleDetailsToggleDescriptionText]';
Expand All @@ -32,10 +34,16 @@ export const DEFINITION_INDEX_PATTERNS =
export const DEFINITION_STEP =
'[data-test-subj=definitionRule] [data-test-subj="listItemColumnStepRuleDescription"] .euiDescriptionList__description';

export const INVESTIGATION_NOTES_MARKDOWN = 'test markdown';

export const INVESTIGATION_NOTES_TOGGLE = 1;

export const MACHINE_LEARNING_JOB_ID = '[data-test-subj="machineLearningJobId"]';

export const MACHINE_LEARNING_JOB_STATUS = '[data-test-subj="machineLearningJobStatus" ]';

export const RULE_ABOUT_DETAILS_HEADER_TOGGLE = '[data-test-subj="stepAboutDetailsToggle"]';

export const RULE_NAME_HEADER = '[data-test-subj="header-page-title"]';

export const RULE_TYPE = 0;
Expand All @@ -45,7 +53,3 @@ export const SCHEDULE_STEP = '[data-test-subj="schedule"] .euiDescriptionList__
export const SCHEDULE_RUNS = 0;

export const SCHEDULE_LOOPBACK = 1;

export const INVESTIGATION_NOTES_TOGGLE = '[data-test-subj="stepAboutDetailsToggle"]';

export const ABOUT_INVESTIGATION_NOTES = '[data-test-subj="stepAboutDetailsNoteContent"]';
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
CUSTOM_QUERY_INPUT,
DEFINE_CONTINUE_BUTTON,
FALSE_POSITIVES_INPUT,
INVESTIGATION_NOTES_TEXTAREA,
MACHINE_LEARNING_DROPDOWN,
MACHINE_LEARNING_LIST,
MACHINE_LEARNING_TYPE,
Expand All @@ -28,7 +29,6 @@ import {
SCHEDULE_CONTINUE_BUTTON,
SEVERITY_DROPDOWN,
TAGS_INPUT,
INVESTIGATION_NOTES_TEXTAREA,
} from '../screens/create_new_rule';

export const createAndActivateRule = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,35 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { cloneDeep, omit } from 'lodash/fp';
import { Dispatch } from 'redux';

import {
mockTimelineResults,
mockTimelineResult,
mockTimelineModel,
} from '../../mock/timeline_results';
import { TimelineResult } from '../../graphql/types';
import { timelineDefaults } from '../../store/timeline/defaults';
import { setTimelineRangeDatePicker as dispatchSetTimelineRangeDatePicker } from '../../store/inputs/actions';
import {
setKqlFilterQueryDraft as dispatchSetKqlFilterQueryDraft,
applyKqlFilterQuery as dispatchApplyKqlFilterQuery,
addTimeline as dispatchAddTimeline,
} from '../../store/timeline/actions';
import { addNotes as dispatchAddNotes } from '../../store/app/actions';
import {
defaultTimelineToTimelineModel,
getNotesCount,
getPinnedEventCount,
isUntitled,
omitTypenameInTimeline,
formatTimelineResultToModel,
dispatchUpdateTimeline,
} from './helpers';
import { OpenTimelineResult } from './types';
import { OpenTimelineResult, DispatchUpdateTimeline } from './types';
import { KueryFilterQueryKind } from '../../store/model';

jest.mock('../../store/inputs/actions');
jest.mock('../../store/timeline/actions');
jest.mock('../../store/app/actions');

describe('helpers', () => {
let mockResults: OpenTimelineResult[];
Expand Down Expand Up @@ -650,31 +662,166 @@ describe('helpers', () => {
});
});

xdescribe('formatTimelineResultToModel', () => {
test('returns object with notes and timeline if timelineToOpen contains notes', () => {
const mockTimeline: TimelineResult = {
...mockTimelineResult,
notes: [
{
noteId: '123',
note: 'some note',
describe('dispatchUpdateTimeline', () => {
const dispatch = jest.fn() as Dispatch;
let timelineDispatch: DispatchUpdateTimeline;

beforeEach(() => {
timelineDispatch = dispatchUpdateTimeline(dispatch);
});

test('it invokes date range picker dispatch', () => {
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimelineModel,
})();

expect(dispatchSetTimelineRangeDatePicker).toHaveBeenCalledWith({
from: 1585233356356,
to: 1585233716356,
});
});

test('it invokes add timeline dispatch', () => {
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimelineModel,
})();

expect(dispatchAddTimeline).toHaveBeenCalledWith({
id: 'timeline-1',
timeline: mockTimelineModel,
});
});

test('it does not invoke kql filter query dispatches if timeline.kqlQuery.filterQuery is null', () => {
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimelineModel,
})();

expect(dispatchSetKqlFilterQueryDraft).not.toHaveBeenCalled();
expect(dispatchApplyKqlFilterQuery).not.toHaveBeenCalled();
});

test('it does not invoke notes dispatch if duplicate is true', () => {
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimelineModel,
})();

expect(dispatchAddNotes).not.toHaveBeenCalled();
});

test('it does not invoke kql filter query dispatches if timeline.kqlQuery.kuery is null', () => {
const mockTimeline = {
...mockTimelineModel,
kqlQuery: {
filterQuery: {
kuery: null,
serializedQuery: 'some-serialized-query',
},
],
filterQueryDraft: null,
},
};
const { notes, timeline } = formatTimelineResultToModel(mockTimeline, false);

expect(notes).toEqual([{ note: 'some note', noteId: '123' }]);
expect(timeline).toEqual(mockTimelineModel);
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimeline,
})();

expect(dispatchSetKqlFilterQueryDraft).not.toHaveBeenCalled();
expect(dispatchApplyKqlFilterQuery).not.toHaveBeenCalled();
});

test('returns object with notes as "undefined" and timeline of type TimelineModel if timelineToOpen contains notes', () => {
const { notes, ...mockTimeline }: TimelineResult = {
...mockTimelineResult,
test('it invokes kql filter query dispatches if timeline.kqlQuery.filterQuery.kuery is not null', () => {
const mockTimeline = {
...mockTimelineModel,
kqlQuery: {
filterQuery: {
kuery: { expression: 'expression', kind: 'kuery' as KueryFilterQueryKind },
serializedQuery: 'some-serialized-query',
},
filterQueryDraft: null,
},
};
const { notes: resultingNotes, timeline } = formatTimelineResultToModel(mockTimeline, false);
timelineDispatch({
duplicate: true,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [],
timeline: mockTimeline,
})();

expect(dispatchSetKqlFilterQueryDraft).toHaveBeenCalledWith({
id: 'timeline-1',
filterQueryDraft: {
kind: 'kuery',
expression: 'expression',
},
});
expect(dispatchApplyKqlFilterQuery).toHaveBeenCalledWith({
id: 'timeline-1',
filterQuery: {
kuery: {
kind: 'kuery',
expression: 'expression',
},
serializedQuery: 'some-serialized-query',
},
});
});

test('it invokes note dispatch if duplicate is false', () => {
timelineDispatch({
duplicate: false,
id: 'timeline-1',
from: 1585233356356,
to: 1585233716356,
notes: [
{
created: 1585233356356,
updated: 1585233356356,
noteId: 'note-id',
note: 'I am a note',
},
],
timeline: mockTimelineModel,
})();

expect(resultingNotes).toBeUndefined();
expect(timeline).toEqual(mockTimelineModel);
expect(dispatchAddNotes).toHaveBeenCalledWith({
notes: [
{
created: new Date('2020-03-26T14:35:56.356Z'),
id: 'note-id',
lastEdit: new Date('2020-03-26T14:35:56.356Z'),
note: 'I am a note',
user: 'unknown',
saveObjectId: 'note-id',
version: undefined,
},
],
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@
*/

import ApolloClient from 'apollo-client';
import { getOr, set } from 'lodash/fp';
import { getOr, set, isEmpty } from 'lodash/fp';
import { Action } from 'typescript-fsa';
import uuid from 'uuid';

import { Dispatch } from 'redux';
import { oneTimelineQuery } from '../../containers/timeline/one/index.gql_query';
import { TimelineResult, GetOneTimeline, NoteResult } from '../../graphql/types';
import { addNotes as dispatchAddNotes } from '../../store/app/actions';
import {
addNotes as dispatchAddNotes,
updateNote as dispatchUpdateNote,
} from '../../store/app/actions';
import { setTimelineRangeDatePicker as dispatchSetTimelineRangeDatePicker } from '../../store/inputs/actions';
import {
setKqlFilterQueryDraft as dispatchSetKqlFilterQueryDraft,
applyKqlFilterQuery as dispatchApplyKqlFilterQuery,
addTimeline as dispatchAddTimeline,
addNote as dispatchAddGlobalTimelineNote,
} from '../../store/timeline/actions';

import { ColumnHeaderOptions, TimelineModel } from '../../store/timeline/model';
Expand All @@ -32,6 +37,7 @@ import {

import { OpenTimelineResult, UpdateTimeline, DispatchUpdateTimeline } from './types';
import { getTimeRangeSettings } from '../../utils/default_date_settings';
import { createNote } from '../notes/helpers';

export const OPEN_TIMELINE_CLASS_NAME = 'open-timeline';

Expand Down Expand Up @@ -250,6 +256,7 @@ export const dispatchUpdateTimeline = (dispatch: Dispatch): DispatchUpdateTimeli
notes,
timeline,
to,
ruleGuide,
}: UpdateTimeline): (() => void) => () => {
dispatch(dispatchSetTimelineRangeDatePicker({ from, to }));
dispatch(dispatchAddTimeline({ id, timeline }));
Expand Down Expand Up @@ -281,6 +288,14 @@ export const dispatchUpdateTimeline = (dispatch: Dispatch): DispatchUpdateTimeli
})
);
}

if (duplicate && ruleGuide && !isEmpty(ruleGuide)) {
const getNewNoteId = (): string => uuid.v4();
const newNote = createNote({ newNote: ruleGuide, getNewNoteId });
dispatch(dispatchUpdateNote({ note: newNote }));
dispatch(dispatchAddGlobalTimelineNote({ noteId: newNote.id, id }));
}

if (!duplicate) {
dispatch(
dispatchAddNotes({
Expand Down
Loading

0 comments on commit 23563b8

Please sign in to comment.