Skip to content

Commit

Permalink
[SIEM] [Cases] Unit tests for case UI components (#63005)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic committed Apr 10, 2020
1 parent 36acb37 commit 55a3cc4
Show file tree
Hide file tree
Showing 44 changed files with 2,117 additions and 360 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const FilterPopoverComponent = ({
{options.map((option, index) => (
<EuiFilterSelectItem
checked={selectedOptions.includes(option) ? 'on' : undefined}
data-test-subj={`options-filter-popover-item-${index}`}
key={`${index}-${option}`}
onClick={toggleSelectedGroupCb.bind(null, option)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,9 @@ const EditableTitleComponent: React.FC<Props> = ({
}, [changedTitle, title]);

const handleOnChange = useCallback(
(e: ChangeEvent<HTMLInputElement>) => {
onTitleChange(e.target.value);
},
[onTitleChange]
(e: ChangeEvent<HTMLInputElement>) => onTitleChange(e.target.value),
[]
);

return editMode ? (
<EuiFlexGroup alignItems="center" gutterSize="m" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
Expand Down Expand Up @@ -107,7 +104,7 @@ const EditableTitleComponent: React.FC<Props> = ({
<Title title={title} />
</EuiFlexItem>
<EuiFlexItem grow={false}>
{isLoading && <MySpinner />}
{isLoading && <MySpinner data-test-subj="editable-title-loading" />}
{!isLoading && (
<MyEuiButtonIcon
isDisabled={disabled}
Expand Down
4 changes: 2 additions & 2 deletions x-pack/legacy/plugins/siem/public/containers/case/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ export const patchComment = async (
return convertToCamelCase<CaseResponse, Case>(decodeCaseResponse(response));
};

export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<boolean> => {
export const deleteCases = async (caseIds: string[], signal: AbortSignal): Promise<string> => {
const response = await KibanaServices.get().http.fetch<string>(CASES_URL, {
method: 'DELETE',
query: { ids: JSON.stringify(caseIds) },
signal,
});
return response === 'true' ? true : false;
return response;
};

export const pushCase = async (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export const useCaseConfigure = ({
setLoading(true);
const res = await getCaseConfigure({ signal: abortCtrl.signal });
if (!didCancel) {
setLoading(false);
if (res != null) {
setConnector(res.connectorId, res.connectorName);
if (setClosureType != null) {
Expand All @@ -73,6 +72,7 @@ export const useCaseConfigure = ({
}
}
}
setLoading(false);
}
} catch (error) {
if (!didCancel) {
Expand Down Expand Up @@ -117,7 +117,6 @@ export const useCaseConfigure = ({
abortCtrl.signal
);
if (!didCancel) {
setPersistLoading(false);
setConnector(res.connectorId);
if (setClosureType) {
setClosureType(res.closureType);
Expand All @@ -131,6 +130,7 @@ export const useCaseConfigure = ({
}

displaySuccessToast(i18n.SUCCESS_CONFIGURE, dispatchToaster);
setPersistLoading(false);
}
} catch (error) {
if (!didCancel) {
Expand Down
9 changes: 4 additions & 5 deletions x-pack/legacy/plugins/siem/public/pages/case/case.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@ import { useGetUserSavedObjectPermissions } from '../../lib/kibana';
import { SpyRoute } from '../../utils/route/spy_routes';
import { AllCases } from './components/all_cases';

import { getSavedObjectReadOnly, CaseCallOut } from './components/callout';
import { savedObjectReadOnly, CaseCallOut } from './components/callout';
import { CaseSavedObjectNoPermissions } from './saved_object_no_permissions';

const infoReadSavedObject = getSavedObjectReadOnly();

export const CasesPage = React.memo(() => {
const userPermissions = useGetUserSavedObjectPermissions();

Expand All @@ -24,10 +22,11 @@ export const CasesPage = React.memo(() => {
<WrapperPage>
{userPermissions != null && !userPermissions?.crud && userPermissions?.read && (
<CaseCallOut
title={infoReadSavedObject.title}
message={infoReadSavedObject.description}
title={savedObjectReadOnly.title}
message={savedObjectReadOnly.description}
/>
)}
<CaseCallOut title={savedObjectReadOnly.title} message={savedObjectReadOnly.description} />
<AllCases userCanCrud={userPermissions?.crud ?? false} />
</WrapperPage>
<SpyRoute />
Expand Down
6 changes: 2 additions & 4 deletions x-pack/legacy/plugins/siem/public/pages/case/case_details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ import { SpyRoute } from '../../utils/route/spy_routes';
import { getCaseUrl } from '../../components/link_to';
import { navTabs } from '../home/home_navigations';
import { CaseView } from './components/case_view';
import { getSavedObjectReadOnly, CaseCallOut } from './components/callout';

const infoReadSavedObject = getSavedObjectReadOnly();
import { savedObjectReadOnly, CaseCallOut } from './components/callout';

export const CaseDetailsPage = React.memo(() => {
const userPermissions = useGetUserSavedObjectPermissions();
Expand All @@ -29,7 +27,7 @@ export const CaseDetailsPage = React.memo(() => {
return caseId != null ? (
<>
{userPermissions != null && !userPermissions?.crud && userPermissions?.read && (
<CaseCallOut title={infoReadSavedObject.title} message={infoReadSavedObject.description} />
<CaseCallOut title={savedObjectReadOnly.title} message={savedObjectReadOnly.description} />
)}
<CaseView caseId={caseId} userCanCrud={userPermissions?.crud ?? false} />
<SpyRoute />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { CaseProps } from '../case_view';
import { Case, Comment, SortFieldCase } from '../../../../containers/case/types';
import { UseGetCasesState } from '../../../../containers/case/use_get_cases';
import { UserAction, UserActionField } from '../../../../../../../../plugins/case/common/api/cases';

const updateCase = jest.fn();
const fetchCase = jest.fn();

const basicCaseId = 'basic-case-id';
const basicCommentId = 'basic-comment-id';
const basicCreatedAt = '2020-02-20T23:06:33.798Z';
const elasticUser = {
fullName: 'Leslie Knope',
username: 'lknope',
email: 'leslie.knope@elastic.co',
};

export const basicComment: Comment = {
comment: 'Solve this fast!',
id: basicCommentId,
createdAt: basicCreatedAt,
createdBy: elasticUser,
pushedAt: null,
pushedBy: null,
updatedAt: '2020-02-20T23:06:33.798Z',
updatedBy: {
username: 'elastic',
},
version: 'WzQ3LDFc',
};

export const basicCase: Case = {
closedAt: null,
closedBy: null,
id: basicCaseId,
comments: [basicComment],
createdAt: '2020-02-13T19:44:23.627Z',
createdBy: elasticUser,
description: 'Security banana Issue',
externalService: null,
status: 'open',
tags: ['defacement'],
title: 'Another horrible breach!!',
totalComment: 1,
updatedAt: '2020-02-19T15:02:57.995Z',
updatedBy: {
username: 'elastic',
},
version: 'WzQ3LDFd',
};

export const caseProps: CaseProps = {
caseId: basicCaseId,
userCanCrud: true,
caseData: basicCase,
fetchCase,
updateCase,
};

export const caseClosedProps: CaseProps = {
...caseProps,
caseData: {
...caseProps.caseData,
closedAt: '2020-02-20T23:06:33.798Z',
closedBy: {
username: 'elastic',
},
status: 'closed',
},
};

export const basicCaseClosed: Case = {
...caseClosedProps.caseData,
};

const basicAction = {
actionAt: basicCreatedAt,
actionBy: elasticUser,
oldValue: null,
newValue: 'what a cool value',
caseId: basicCaseId,
commentId: null,
};
export const caseUserActions = [
{
...basicAction,
actionBy: elasticUser,
actionField: ['comment'],
action: 'create',
actionId: 'tt',
},
];

export const useGetCasesMockState: UseGetCasesState = {
data: {
countClosedCases: 0,
countOpenCases: 5,
cases: [
basicCase,
{
closedAt: null,
closedBy: null,
id: '362a5c10-4e99-11ea-9290-35d05cb55c15',
createdAt: '2020-02-13T19:44:13.328Z',
createdBy: { username: 'elastic' },
comments: [],
description: 'Security banana Issue',
externalService: {
pushedAt: '2020-02-13T19:45:01.901Z',
pushedBy: 'elastic',
connectorId: 'string',
connectorName: 'string',
externalId: 'string',
externalTitle: 'string',
externalUrl: 'string',
},
status: 'open',
tags: ['phishing'],
title: 'Bad email',
totalComment: 0,
updatedAt: '2020-02-13T15:45:01.901Z',
updatedBy: { username: 'elastic' },
version: 'WzQ3LDFd',
},
{
closedAt: null,
closedBy: null,
id: '34f8b9e0-4e99-11ea-9290-35d05cb55c15',
createdAt: '2020-02-13T19:44:11.328Z',
createdBy: { username: 'elastic' },
comments: [],
description: 'Security banana Issue',
externalService: {
pushedAt: '2020-02-13T19:45:01.901Z',
pushedBy: 'elastic',
connectorId: 'string',
connectorName: 'string',
externalId: 'string',
externalTitle: 'string',
externalUrl: 'string',
},
status: 'open',
tags: ['phishing'],
title: 'Bad email',
totalComment: 0,
updatedAt: '2020-02-14T19:45:01.901Z',
updatedBy: { username: 'elastic' },
version: 'WzQ3LDFd',
},
{
closedAt: '2020-02-13T19:44:13.328Z',
closedBy: { username: 'elastic' },
id: '31890e90-4e99-11ea-9290-35d05cb55c15',
createdAt: '2020-02-13T19:44:05.563Z',
createdBy: { username: 'elastic' },
comments: [],
description: 'Security banana Issue',
externalService: null,
status: 'closed',
tags: ['phishing'],
title: 'Uh oh',
totalComment: 0,
updatedAt: null,
updatedBy: null,
version: 'WzQ3LDFd',
},
{
closedAt: null,
closedBy: null,
id: '2f5b3210-4e99-11ea-9290-35d05cb55c15',
createdAt: '2020-02-13T19:44:01.901Z',
createdBy: { username: 'elastic' },
comments: [],
description: 'Security banana Issue',
externalService: null,
status: 'open',
tags: ['phishing'],
title: 'Uh oh',
totalComment: 0,
updatedAt: null,
updatedBy: null,
version: 'WzQ3LDFd',
},
],
page: 1,
perPage: 5,
total: 10,
},
loading: [],
selectedCases: [],
isError: false,
queryParams: {
page: 1,
perPage: 5,
sortField: SortFieldCase.createdAt,
sortOrder: 'desc',
},
filterOptions: { search: '', reporters: [], tags: [], status: 'open' },
};

const basicPush = {
connector_id: 'connector_id',
connector_name: 'connector name',
external_id: 'external_id',
external_title: 'external title',
external_url: 'basicPush.com',
pushed_at: basicCreatedAt,
pushed_by: elasticUser,
};
export const getUserAction = (af: UserActionField, a: UserAction) => ({
...basicAction,
actionId: `${af[0]}-${a}`,
actionField: af,
action: a,
commentId: af[0] === 'comment' ? basicCommentId : null,
newValue:
a === 'push-to-service' && af[0] === 'pushed'
? JSON.stringify(basicPush)
: basicAction.newValue,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export const mockFormHook = {
isSubmitted: false,
isSubmitting: false,
isValid: true,
submit: jest.fn(),
subscribe: jest.fn(),
setFieldValue: jest.fn(),
setFieldErrors: jest.fn(),
getFields: jest.fn(),
getFormData: jest.fn(),
getFieldDefaultValue: jest.fn(),
/* Returns a list of all errors in the form */
getErrors: jest.fn(),
reset: jest.fn(),
__options: {},
__formData$: {},
__addField: jest.fn(),
__removeField: jest.fn(),
__validateFields: jest.fn(),
__updateFormDataAt: jest.fn(),
__readFieldConfigFromSchema: jest.fn(),
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const getFormMock = (sampleData: any) => ({
...mockFormHook,
submit: () =>
Promise.resolve({
data: sampleData,
isValid: true,
}),
getFormData: () => sampleData,
});
Loading

0 comments on commit 55a3cc4

Please sign in to comment.