diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx
index e1d7d98ba8c5153..3c1e79fca401df1 100644
--- a/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/case_view/index.test.tsx
@@ -114,34 +114,41 @@ describe('CaseView ', () => {
expect(wrapper.find(`[data-test-subj="case-view-title"]`).first().prop('title')).toEqual(
data.title
);
+
expect(wrapper.find(`[data-test-subj="case-view-status"]`).first().text()).toEqual(
data.status
);
+
expect(
wrapper
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="case-tag-coke"]`)
.first()
.text()
).toEqual(data.tags[0]);
+
expect(
wrapper
.find(`[data-test-subj="case-view-tag-list"] [data-test-subj="case-tag-pepsi"]`)
.first()
.text()
).toEqual(data.tags[1]);
+
expect(wrapper.find(`[data-test-subj="case-view-username"]`).first().text()).toEqual(
data.createdBy.username
);
+
expect(wrapper.contains(`[data-test-subj="case-view-closedAt"]`)).toBe(false);
+
expect(wrapper.find(`[data-test-subj="case-view-createdAt"]`).first().prop('value')).toEqual(
data.createdAt
);
+
expect(
wrapper
.find(`[data-test-subj="description-action"] [data-test-subj="user-action-markdown"]`)
.first()
- .prop('raw')
- ).toEqual(data.description);
+ .text()
+ ).toBe(data.description);
});
});
diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.test.tsx
index 9cf13b6f9930a46..ec065fef6f09b79 100644
--- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.test.tsx
@@ -6,6 +6,9 @@
import React from 'react';
import { mount } from 'enzyme';
+// 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 { act } from 'react-dom/test-utils';
import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router';
import { getFormMock, useFormMock } from '../__mock__/form';
@@ -13,9 +16,6 @@ import { useUpdateComment } from '../../containers/use_update_comment';
import { basicCase, basicPush, getUserAction } from '../../containers/mock';
import { UserActionTree } from '.';
import { TestProviders } from '../../../common/mock';
-// 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 { act } from 'react-dom/test-utils';
const fetchUserActions = jest.fn();
const onUpdateField = jest.fn();
@@ -65,15 +65,18 @@ describe('UserActionTree ', () => {
expect(wrapper.find(`[data-test-subj="user-action-avatar"]`).first().prop('name')).toEqual(
defaultProps.data.createdBy.fullName
);
- expect(wrapper.find(`[data-test-subj="user-action-title"] strong`).first().text()).toEqual(
- defaultProps.data.createdBy.username
- );
+
+ expect(
+ wrapper.find(`[data-test-subj="description-action"] figcaption strong`).first().text()
+ ).toEqual(defaultProps.data.createdBy.username);
});
- it('Renders service now update line with top and bottom when push is required', () => {
+
+ it('Renders service now update line with top and bottom when push is required', async () => {
const ourActions = [
getUserAction(['pushed'], 'push-to-service'),
getUserAction(['comment'], 'update'),
];
+
const props = {
...defaultProps,
caseServices: {
@@ -87,17 +90,22 @@ describe('UserActionTree ', () => {
},
caseUserActions: ourActions,
};
- const wrapper = mount(
-
-
-
-
-
- );
- expect(wrapper.find(`[data-test-subj="show-top-footer"]`).exists()).toBeTruthy();
- expect(wrapper.find(`[data-test-subj="show-bottom-footer"]`).exists()).toBeTruthy();
+
+ await act(async () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toBeTruthy();
+ expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toBeTruthy();
+ });
});
- it('Renders service now update line with top only when push is up to date', () => {
+
+ it('Renders service now update line with top only when push is up to date', async () => {
const ourActions = [getUserAction(['pushed'], 'push-to-service')];
const props = {
...defaultProps,
@@ -112,90 +120,125 @@ describe('UserActionTree ', () => {
},
},
};
- const wrapper = mount(
-
-
-
-
-
- );
- expect(wrapper.find(`[data-test-subj="show-top-footer"]`).exists()).toBeTruthy();
- expect(wrapper.find(`[data-test-subj="show-bottom-footer"]`).exists()).toBeFalsy();
+
+ await act(async () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+ expect(wrapper.find(`[data-test-subj="top-footer"]`).exists()).toBeTruthy();
+ expect(wrapper.find(`[data-test-subj="bottom-footer"]`).exists()).toBeFalsy();
+ });
});
- it('Outlines comment when update move to link is clicked', () => {
+ it('Outlines comment when update move to link is clicked', async () => {
const ourActions = [getUserAction(['comment'], 'create'), getUserAction(['comment'], 'update')];
const props = {
...defaultProps,
caseUserActions: ourActions,
};
- const wrapper = mount(
-
-
-
-
-
- );
- expect(
- wrapper.find(`[data-test-subj="comment-create-action"]`).first().prop('idToOutline')
- ).toEqual('');
- wrapper
- .find(`[data-test-subj="comment-update-action"] [data-test-subj="move-to-link"]`)
- .first()
- .simulate('click');
- expect(
- wrapper.find(`[data-test-subj="comment-create-action"]`).first().prop('idToOutline')
- ).toEqual(ourActions[0].commentId);
+
+ await act(async () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="comment-create-action-${props.data.comments[0].id}"]`)
+ .first()
+ .hasClass('outlined')
+ ).toBeFalsy();
+
+ wrapper
+ .find(
+ `[data-test-subj="comment-update-action-${ourActions[1].actionId}"] [data-test-subj="move-to-link-${props.data.comments[0].id}"]`
+ )
+ .first()
+ .simulate('click');
+
+ await waitFor(() => {
+ wrapper.update();
+ expect(
+ wrapper
+ .find(`[data-test-subj="comment-create-action-${props.data.comments[0].id}"]`)
+ .first()
+ .hasClass('outlined')
+ ).toBeTruthy();
+ });
+ });
});
- it('Switches to markdown when edit is clicked and back to panel when canceled', () => {
- const ourActions = [getUserAction(['comment'], 'create')];
- const props = {
- ...defaultProps,
- caseUserActions: ourActions,
- };
- const wrapper = mount(
-
-
-
-
-
- );
- expect(
+ it('Switches to markdown when edit is clicked and back to panel when canceled', async () => {
+ await waitFor(() => {
+ const ourActions = [getUserAction(['comment'], 'create')];
+ const props = {
+ ...defaultProps,
+ caseUserActions: ourActions,
+ };
+
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ expect(
+ wrapper
+ .find(
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ )
+ .exists()
+ ).toEqual(false);
+
wrapper
.find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="property-actions-ellipses"]`
)
- .exists()
- ).toEqual(false);
- wrapper
- .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-ellipses"]`)
- .first()
- .simulate('click');
- wrapper
- .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-pencil"]`)
- .first()
- .simulate('click');
- expect(
+ .first()
+ .simulate('click');
+
+ wrapper.update();
+
wrapper
.find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="property-actions-pencil"]`
)
- .exists()
- ).toEqual(true);
- wrapper
- .find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-cancel-markdown"]`
- )
- .first()
- .simulate('click');
- expect(
+ .first()
+ .simulate('click');
+
+ expect(
+ wrapper
+ .find(
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ )
+ .exists()
+ ).toEqual(true);
+
wrapper
.find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-cancel-markdown"]`
)
- .exists()
- ).toEqual(false);
+ .first()
+ .simulate('click');
+
+ expect(
+ wrapper
+ .find(
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ )
+ .exists()
+ ).toEqual(false);
+ });
});
it('calls update comment when comment markdown is saved', async () => {
@@ -204,6 +247,7 @@ describe('UserActionTree ', () => {
...defaultProps,
caseUserActions: ourActions,
};
+
const wrapper = mount(
@@ -211,27 +255,35 @@ describe('UserActionTree ', () => {
);
+
wrapper
- .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-ellipses"]`)
+ .find(
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="property-actions-ellipses"]`
+ )
.first()
.simulate('click');
+
wrapper
- .find(`[data-test-subj="comment-create-action"] [data-test-subj="property-actions-pencil"]`)
+ .find(
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="property-actions-pencil"]`
+ )
.first()
.simulate('click');
+
wrapper
.find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-save-markdown"]`
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-save-markdown"]`
)
.first()
.simulate('click');
+
await act(async () => {
await waitFor(() => {
wrapper.update();
expect(
wrapper
.find(
- `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
+ `[data-test-subj="comment-create-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]`
)
.exists()
).toEqual(false);
@@ -256,76 +308,92 @@ describe('UserActionTree ', () => {
);
+
wrapper
.find(`[data-test-subj="description-action"] [data-test-subj="property-actions-ellipses"]`)
.first()
.simulate('click');
+
wrapper
.find(`[data-test-subj="description-action"] [data-test-subj="property-actions-pencil"]`)
.first()
.simulate('click');
- wrapper
- .find(
- `[data-test-subj="user-action-description"] [data-test-subj="user-action-save-markdown"]`
- )
- .first()
- .simulate('click');
+
await act(async () => {
- await waitFor(() => {
- expect(
- wrapper
- .find(
- `[data-test-subj="user-action-${props.data.id}"] [data-test-subj="user-action-markdown-form"]`
- )
- .exists()
- ).toEqual(false);
- expect(onUpdateField).toBeCalledWith({ key: 'description', value: sampleData.content });
- });
+ wrapper
+ .find(`[data-test-subj="description-action"] [data-test-subj="user-action-save-markdown"]`)
+ .first()
+ .simulate('click');
});
+
+ wrapper.update();
+
+ expect(
+ wrapper
+ .find(`[data-test-subj="description-action"] [data-test-subj="user-action-markdown-form"]`)
+ .exists()
+ ).toEqual(false);
+
+ expect(onUpdateField).toBeCalledWith({ key: 'description', value: sampleData.content });
});
- it('quotes', async () => {
- const commentData = {
- comment: '',
- };
- const formHookMock = getFormMock(commentData);
- const setFieldValue = jest.fn();
- useFormMock.mockImplementation(() => ({ form: { ...formHookMock, setFieldValue } }));
- const props = defaultProps;
- const wrapper = mount(
-
-
-
-
-
- );
- wrapper
- .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-ellipses"]`)
- .first()
- .simulate('click');
- wrapper
- .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-quote"]`)
- .first()
- .simulate('click');
- expect(setFieldValue).toBeCalledWith('comment', `> ${props.data.description} \n`);
+ it.skip('quotes', async () => {
+ await act(async () => {
+ const commentData = {
+ comment: '',
+ };
+ const setFieldValue = jest.fn();
+
+ const formHookMock = getFormMock(commentData);
+ useFormMock.mockImplementation(() => ({ form: { ...formHookMock, setFieldValue } }));
+
+ const props = defaultProps;
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ wrapper
+ .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-ellipses"]`)
+ .first()
+ .simulate('click');
+
+ wrapper.update();
+
+ wrapper
+ .find(`[data-test-subj="description-action"] [data-test-subj="property-actions-quote"]`)
+ .first()
+ .simulate('click');
+
+ expect(setFieldValue).toBeCalledWith('comment', `> ${props.data.description} \n`);
+ });
});
- it('Outlines comment when url param is provided', () => {
+
+ it.skip('Outlines comment when url param is provided', async () => {
const commentId = 'neat-comment-id';
- const ourActions = [getUserAction(['comment'], 'create')];
- const props = {
- ...defaultProps,
- caseUserActions: ourActions,
- };
jest.spyOn(routeData, 'useParams').mockReturnValue({ commentId });
- const wrapper = mount(
-
-
-
-
-
- );
- expect(
- wrapper.find(`[data-test-subj="comment-create-action"]`).first().prop('idToOutline')
- ).toEqual(commentId);
+
+ await act(async () => {
+ const ourActions = [getUserAction(['comment'], 'create')];
+ const props = {
+ ...defaultProps,
+ caseUserActions: ourActions,
+ };
+
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ expect(
+ wrapper.find(`[data-test-subj="move-to-link-basic-comment-id"]`).exists()
+ ).toBeTruthy();
+ });
});
});
diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx
index b29fba2a30aa3c8..5cd6f1ad3ecbe4e 100644
--- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/index.tsx
@@ -266,7 +266,7 @@ export const UserActionTree = React.memo(
fullName={comment.createdBy.fullName ?? comment.createdBy.username ?? ''}
/>
),
- 'data-test-subj': 'comment-create-action',
+ 'data-test-subj': `comment-create-action-${comment.id}`,
timestamp: (
,
timelineIcon: action.action === 'add' || action.action === 'delete' ? 'tag' : 'dot',
actions: (
@@ -438,7 +440,7 @@ export const UserActionTree = React.memo(
return (
<>
-
+
{(isLoadingUserActions || isLoadingIds.includes(NEW_ID)) && (
diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_copy_link.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_copy_link.tsx
index 48f097ab768c08c..971d73a73b5355d 100644
--- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_copy_link.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_copy_link.tsx
@@ -32,7 +32,7 @@ const UserActionCopyLinkComponent = ({ id }: UserActionCopyLinkProps) => {
{i18n.COPY_REFERENCE_LINK}
}>
{
);
- wrapper.find(`[data-test-subj="markdown-timeline-link"]`).first().simulate('click');
+
+ wrapper
+ .find(`[data-test-subj="markdown-timeline-link-${timelineId}"]`)
+ .first()
+ .simulate('click');
expect(queryTimelineByIdSpy).toBeCalledWith({
apolloClient: mockUseApolloClient(),
- graphEventId: '',
+ graphEventId: undefined,
timelineId,
updateIsLoading: expect.any(Function),
updateTimeline: expect.any(Function),
@@ -59,11 +64,22 @@ describe('UserActionMarkdown ', () => {
);
- wrapper.find(`[data-test-subj="preview-tab"]`).first().simulate('click');
- wrapper.find(`[data-test-subj="markdown-timeline-link"]`).first().simulate('click');
+
+ // Preview button of Markdown editor
+ wrapper
+ .find(
+ `[data-test-subj="user-action-markdown-form"] .euiMarkdownEditorToolbar .euiButtonEmpty`
+ )
+ .first()
+ .simulate('click');
+
+ wrapper
+ .find(`[data-test-subj="markdown-timeline-link-${timelineId}"]`)
+ .first()
+ .simulate('click');
expect(queryTimelineByIdSpy).toBeCalledWith({
apolloClient: mockUseApolloClient(),
- graphEventId: '',
+ graphEventId: undefined,
timelineId,
updateIsLoading: expect.any(Function),
updateTimeline: expect.any(Function),
diff --git a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_move_to_reference.tsx b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_move_to_reference.tsx
index bd2db0b502b950c..39d016dd69520d1 100644
--- a/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_move_to_reference.tsx
+++ b/x-pack/plugins/security_solution/public/cases/components/user_action_tree/user_action_move_to_reference.tsx
@@ -26,7 +26,7 @@ const UserActionMoveToReferenceComponent = ({
{i18n.MOVE_TO_ORIGINAL_COMMENT}}>
diff --git a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/processor.tsx b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/processor.tsx
index 0a813e54923d0ca..3a5b46df1686ecc 100644
--- a/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/processor.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/markdown_editor/plugins/timeline/processor.tsx
@@ -24,7 +24,7 @@ export const TimelineMarkDownRendererComponent: React.FC<
]);
return (
-
+
{title}