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}