From 9b250a5a0ad7f24decbe4ec4ac69e02c320e8341 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Sun, 7 Jun 2020 21:03:36 +0300 Subject: [PATCH] Add unit tests --- .../cases/components/callout/callout.test.tsx | 70 +++++++++ .../cases/components/callout/callout.tsx | 6 +- .../cases/components/callout/helpers.test.tsx | 28 ++++ .../cases/components/callout/helpers.tsx | 4 + .../cases/components/callout/index.test.tsx | 138 ++++++++++++------ .../public/cases/components/callout/index.tsx | 4 +- 6 files changed, 199 insertions(+), 51 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/cases/components/callout/callout.test.tsx create mode 100644 x-pack/plugins/security_solution/public/cases/components/callout/helpers.test.tsx diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/callout.test.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/callout.test.tsx new file mode 100644 index 000000000000000..abda8d1d8ebdf71 --- /dev/null +++ b/x-pack/plugins/security_solution/public/cases/components/callout/callout.test.tsx @@ -0,0 +1,70 @@ +/* + * 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 React from 'react'; +import { mount } from 'enzyme'; + +import { CallOut } from './callout'; +import { ErrorMessage } from './types'; + +describe('Callout', () => { + const defaultProps = { + id: 'md5-hex', + type: 'primary' as NonNullable, + title: 'a tittle', + messages: [ + { + id: 'generic-error', + title: 'message-one', + description:

{'error'}

, + }, + ], + showCallOut: true, + handleDismissCallout: jest.fn(), + }; + + it('It renders the callout', () => { + const wrapper = mount(); + expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeTruthy(); + expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).exists()).toBeTruthy(); + }); + + it('hides the callout', () => { + const wrapper = mount(); + expect(wrapper.find(`[data-test-subj="case-callout-md5-hex"]`).exists()).toBeFalsy(); + }); + + it('does not shows any messages when the list is empty', () => { + const wrapper = mount(); + expect(wrapper.find(`[data-test-subj="callout-messages-md5-hex"]`).exists()).toBeFalsy(); + }); + + it('transform the button color correctly', () => { + let wrapper = mount(); + expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('color')).toBe( + 'primary' + ); + + wrapper = mount(); + expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('color')).toBe( + 'secondary' + ); + + wrapper = mount(); + expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).first().prop('color')).toBe( + 'danger' + ); + }); + + it('dismiss the button correctly', () => { + const wrapper = mount(); + expect(wrapper.find(`[data-test-subj="callout-dismiss-md5-hex"]`).exists()).toBeTruthy(); + wrapper.find(`button[data-test-subj="callout-dismiss-md5-hex"]`).simulate('click'); + wrapper.update(); + expect(defaultProps.handleDismissCallout).toHaveBeenCalledWith('md5-hex'); + }); +}); diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/callout.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/callout.tsx index 69ec74a46ae8038..cfb031a2de1d287 100644 --- a/x-pack/plugins/security_solution/public/cases/components/callout/callout.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/callout/callout.tsx @@ -31,12 +31,12 @@ const CallOutComponent = ({ const handleCallOut = useCallback(() => handleDismissCallout(id), [handleDismissCallout]); return showCallOut ? ( - + {!isEmpty(messages) && ( - + )} diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/helpers.test.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/helpers.test.tsx new file mode 100644 index 000000000000000..c5fb7f3fa44770c --- /dev/null +++ b/x-pack/plugins/security_solution/public/cases/components/callout/helpers.test.tsx @@ -0,0 +1,28 @@ +/* + * 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 md5 from 'md5'; +import { createCalloutId } from './helpers'; + +describe('createCalloutId', () => { + it('creates id correctly with one id', () => { + const digest = md5('one'); + const id = createCalloutId(['one']); + expect(id).toBe(digest); + }); + + it('creates id correctly with multiples ids', () => { + const digest = md5('one|two|three'); + const id = createCalloutId(['one', 'two', 'three']); + expect(id).toBe(digest); + }); + + it('creates id correctly with multiples ids and delimiter', () => { + const digest = md5('one,two,three'); + const id = createCalloutId(['one', 'two', 'three'], ','); + expect(id).toBe(digest); + }); +}); diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/helpers.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/helpers.tsx index 323710427447324..0ae0ab10459493f 100644 --- a/x-pack/plugins/security_solution/public/cases/components/callout/helpers.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/callout/helpers.tsx @@ -4,9 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import md5 from 'md5'; import * as i18n from './translations'; export const savedObjectReadOnly = { title: i18n.READ_ONLY_SAVED_OBJECT_TITLE, description: i18n.READ_ONLY_SAVED_OBJECT_MSG, }; + +export const createCalloutId = (ids: string[], delimiter: string = '|'): string => + md5(ids.join(delimiter)); diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/index.test.tsx index ee3faeb2ceeb550..c1ebb7c2c0fdaaa 100644 --- a/x-pack/plugins/security_solution/public/cases/components/callout/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/callout/index.test.tsx @@ -7,20 +7,40 @@ import React from 'react'; import { mount } from 'enzyme'; +import { useSecurityLocalStorage } from '../../../common/containers/use_local_storage'; +import { TestProviders } from '../../../common/mock'; +import { createCalloutId } from './helpers'; import { CaseCallOut } from '.'; +jest.mock('../../../common/containers/use_local_storage'); + +const useSecurityLocalStorageMock = useSecurityLocalStorage as jest.Mock; +const securityLocalStorageMock = { + getCallouts: jest.fn(() => []), + persistDismissCallout: jest.fn(), +}; + const defaultProps = { title: 'hey title', }; describe('CaseCallOut ', () => { + beforeEach(() => { + useSecurityLocalStorageMock.mockReset(); + useSecurityLocalStorageMock.mockImplementation(() => securityLocalStorageMock); + }); + it('Renders single message callout', () => { const props = { ...defaultProps, message: 'we have one message', }; - const wrapper = mount(); + const wrapper = mount( + + + + ); expect(wrapper.find(`[data-test-subj="callout-message-primary"]`).last().exists()).toBeTruthy(); }); @@ -28,83 +48,109 @@ describe('CaseCallOut ', () => { it('Renders multi message callout', () => { const props = { ...defaultProps, + message: 'we have one message', messages: [ - { ...defaultProps, description:

{'we have two messages'}

}, - { ...defaultProps, description:

{'for real'}

}, + { id: 'message-one', title: 'title', description:

{'we have two messages'}

}, + { id: 'message-two', title: 'title', description:

{'for real'}

}, ], }; - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-message-primary"]`).last().exists()).toBeFalsy(); - expect( - wrapper.find(`[data-test-subj="callout-messages-primary"]`).last().exists() - ).toBeTruthy(); + const wrapper = mount( + + + + ); + + const id = createCalloutId(['message-one', 'message-two', 'generic-message-error']); + + expect(wrapper.find(`[data-test-subj="callout-messages-${id}"]`).last().exists()).toBeTruthy(); }); - it('it shows the correct type of callouts', () => { + it('shows the correct type of callouts', () => { const props = { ...defaultProps, messages: [ { - ...defaultProps, + id: 'message-one', + title: 'title one', description:

{'we have two messages'}

, errorType: 'danger' as 'primary' | 'success' | 'warning' | 'danger', }, - { ...defaultProps, description:

{'for real'}

}, + { id: 'message-two', title: 'title two', description:

{'for real'}

}, ], }; - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="callout-messages-danger"]`).last().exists()).toBeTruthy(); + const wrapper = mount( + + + + ); + + const idDanger = createCalloutId(['message-one']); + const idPrimary = createCalloutId(['message-two']); + + expect( + wrapper.find(`[data-test-subj="case-callout-${idPrimary}"]`).last().exists() + ).toBeTruthy(); expect( - wrapper.find(`[data-test-subj="callout-messages-primary"]`).last().exists() + wrapper.find(`[data-test-subj="case-callout-${idDanger}"]`).last().exists() ).toBeTruthy(); }); - it('it applies the correct color to button', () => { + it('Dismisses callout', () => { const props = { ...defaultProps, - messages: [ - { - ...defaultProps, - description:

{'one'}

, - errorType: 'danger' as 'primary' | 'success' | 'warning' | 'danger', - }, - { - ...defaultProps, - description:

{'two'}

, - errorType: 'success' as 'primary' | 'success' | 'warning' | 'danger', - }, - { - ...defaultProps, - description:

{'three'}

, - errorType: 'primary' as 'primary' | 'success' | 'warning' | 'danger', - }, - ], + message: 'we have one message', }; + const wrapper = mount( + + + + ); - const wrapper = mount(); + const id = createCalloutId(['generic-message-error']); - expect(wrapper.find(`[data-test-subj="callout-dismiss-danger"]`).first().prop('color')).toBe( - 'danger' - ); + expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).last().exists()).toBeTruthy(); + wrapper.find(`[data-test-subj="callout-dismiss-${id}"]`).last().simulate('click'); + expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).exists()).toBeFalsy(); + }); - expect(wrapper.find(`[data-test-subj="callout-dismiss-success"]`).first().prop('color')).toBe( - 'secondary' - ); + it('persist the callout when dismissed', () => { + const props = { + ...defaultProps, + message: 'we have one message', + }; - expect(wrapper.find(`[data-test-subj="callout-dismiss-primary"]`).first().prop('color')).toBe( - 'primary' + const wrapper = mount( + + + ); + + const id = createCalloutId(['generic-message-error']); + expect(securityLocalStorageMock.getCallouts).toHaveBeenCalledWith('case'); + wrapper.find(`[data-test-subj="callout-dismiss-${id}"]`).last().simulate('click'); + expect(securityLocalStorageMock.persistDismissCallout).toHaveBeenCalledWith('case', id); }); - it('Dismisses callout', () => { + it('do not show the callout if is in the localStorage', () => { const props = { ...defaultProps, message: 'we have one message', }; - const wrapper = mount(); - expect(wrapper.find(`[data-test-subj="case-call-out-primary"]`).exists()).toBeTruthy(); - wrapper.find(`[data-test-subj="callout-dismiss-primary"]`).last().simulate('click'); - expect(wrapper.find(`[data-test-subj="case-call-out-primary"]`).exists()).toBeFalsy(); + + const id = createCalloutId(['generic-message-error']); + + useSecurityLocalStorageMock.mockImplementation(() => ({ + ...securityLocalStorageMock, + getCallouts: jest.fn(() => [id]), + })); + + const wrapper = mount( + + + + ); + + expect(wrapper.find(`[data-test-subj="case-callout-${id}"]`).last().exists()).toBeFalsy(); }); }); diff --git a/x-pack/plugins/security_solution/public/cases/components/callout/index.tsx b/x-pack/plugins/security_solution/public/cases/components/callout/index.tsx index 2ea5ff769dd6a8f..c76e6e54ef53f91 100644 --- a/x-pack/plugins/security_solution/public/cases/components/callout/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/callout/index.tsx @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import md5 from 'md5'; import { EuiSpacer } from '@elastic/eui'; import React, { memo, useCallback, useState } from 'react'; import { useSecurityLocalStorage } from '../../../common/containers/use_local_storage'; import { CallOut } from './callout'; import { ErrorMessage } from './types'; +import { createCalloutId } from './helpers'; export * from './helpers'; @@ -82,7 +82,7 @@ const CaseCallOutComponent = ({ title, message, messages }: CaseCallOutProps) => <> {(Object.keys(groupedByTypeErrorMessages) as Array).map( (type: NonNullable) => { - const id = md5(groupedByTypeErrorMessages[type].messagesId.join('|')); + const id = createCalloutId(groupedByTypeErrorMessages[type].messagesId); return (