From a376898bba272921cf8fa17f5ed0f2fc0812aba6 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Mon, 20 Jul 2020 19:27:38 -0600 Subject: [PATCH] [SIEM] Uses faster wait from testing-library and removes duplicate older wait idiom (#72509) (#72549) ## Summary * Removes the older wait pattern that does a block no matter what * Utilizes the improved and better pattern for test-library's waitFor which will test immediately and then poll for results * Changes everything to put their expect statement within the waitFor * Once the waitFor is in TypeScript/JS we can change the import statement to use that If you get a timeout or error this is what it looks like now which improves the developer experience in some ways but does degrade things in others as it suggests that everything is timeout related. However, developers should inspect the values and remove the waitFor() and re-run their tests if they think that they have a real problem during development. Screen Shot 2020-07-20 at 12 40 39 PM See the API for more information: https://testing-library.com/docs/dom-testing-library/api-async#waitfor But in short we should be using: ```ts await waitFor(() => expect(...)); ``` throughout our code at this point and the waitFor will loop quickly and efficiently until it either times out or gets the condition expected. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios --- .../components/add_comment/index.test.tsx | 13 +- .../cases/components/case_view/index.test.tsx | 125 +++---- .../cases/components/create/index.test.tsx | 7 +- .../components/edit_connector/index.test.tsx | 26 +- .../cases/components/tag_list/index.test.tsx | 13 +- .../user_action_tree/index.test.tsx | 55 ++-- .../events_viewer/events_viewer.test.tsx | 70 ++-- .../components/events_viewer/index.test.tsx | 17 +- .../components/url_state/index.test.tsx | 42 +-- .../public/common/lib/helpers/index.tsx | 6 - .../rules/step_about_rule/index.test.tsx | 105 +++--- .../detection_engine/rules/all/index.test.tsx | 21 +- .../first_last_seen_host/index.test.tsx | 58 ++-- .../alerts_by_category/index.test.tsx | 63 ++-- .../components/overview_host/index.test.tsx | 14 +- .../overview_network/index.test.tsx | 14 +- .../components/open_timeline/index.test.tsx | 304 +++++++++--------- .../open_timeline_modal/index.test.tsx | 18 +- .../open_timeline_modal_button.test.tsx | 25 +- .../components/timeline/body/index.test.tsx | 24 +- .../components/timeline/index.test.tsx | 25 +- .../timeline/epic_local_storage.test.tsx | 24 +- 22 files changed, 578 insertions(+), 491 deletions(-) diff --git a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx index 5da75033d17fa..88969c3ae5fb3 100644 --- a/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/add_comment/index.test.tsx @@ -15,7 +15,9 @@ import { Router, routeData, mockHistory, mockLocation } from '../__mock__/router import { useInsertTimeline } from '../../../timelines/components/timeline/insert_timeline_popover/use_insert_timeline'; import { usePostComment } from '../../containers/use_post_comment'; import { useForm } from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'; -import { wait } from '../../../common/lib/helpers'; + +// 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'; jest.mock( '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form' @@ -84,10 +86,11 @@ describe('AddComment ', () => { expect(wrapper.find(`[data-test-subj="loading-spinner"]`).exists()).toBeFalsy(); wrapper.find(`[data-test-subj="submit-comment"]`).first().simulate('click'); - await wait(); - expect(onCommentSaving).toBeCalled(); - expect(postComment).toBeCalledWith(sampleData, onCommentPosted); - expect(formHookMock.reset).toBeCalled(); + await waitFor(() => { + expect(onCommentSaving).toBeCalled(); + expect(postComment).toBeCalledWith(sampleData, onCommentPosted); + expect(formHookMock.reset).toBeCalled(); + }); }); it('should render spinner and disable submit when loading', () => { 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 4e29db4022e65..278b972ada970 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 @@ -15,7 +15,9 @@ import { TestProviders } from '../../../common/mock'; import { useUpdateCase } from '../../containers/use_update_case'; import { useGetCase } from '../../containers/use_get_case'; import { useGetCaseUserActions } from '../../containers/use_get_case_user_actions'; -import { wait } from '../../../common/lib/helpers'; + +// 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 { useConnectors } from '../../containers/configure/use_connectors'; import { connectorsMock } from '../../containers/configure/mock'; @@ -108,30 +110,33 @@ describe('CaseView ', () => { ); - await wait(); - 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"]`) - .first() - .text() - ).toEqual(data.tags[0]); - 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); + await waitFor(() => { + 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"]`) + .first() + .text() + ).toEqual(data.tags[0]); + 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); + }); }); it('should show closed indicators in header when case is closed', async () => { @@ -146,14 +151,15 @@ describe('CaseView ', () => { ); - await wait(); - expect(wrapper.contains(`[data-test-subj="case-view-createdAt"]`)).toBe(false); - expect(wrapper.find(`[data-test-subj="case-view-closedAt"]`).first().prop('value')).toEqual( - basicCaseClosed.closedAt - ); - expect(wrapper.find(`[data-test-subj="case-view-status"]`).first().text()).toEqual( - basicCaseClosed.status - ); + await waitFor(() => { + expect(wrapper.contains(`[data-test-subj="case-view-createdAt"]`)).toBe(false); + expect(wrapper.find(`[data-test-subj="case-view-closedAt"]`).first().prop('value')).toEqual( + basicCaseClosed.closedAt + ); + expect(wrapper.find(`[data-test-subj="case-view-status"]`).first().text()).toEqual( + basicCaseClosed.status + ); + }); }); it('should dispatch update state when button is toggled', async () => { @@ -164,11 +170,12 @@ describe('CaseView ', () => { ); - await wait(); - wrapper - .find('input[data-test-subj="toggle-case-status"]') - .simulate('change', { target: { checked: true } }); - expect(updateCaseProperty).toHaveBeenCalled(); + await waitFor(() => { + wrapper + .find('input[data-test-subj="toggle-case-status"]') + .simulate('change', { target: { checked: true } }); + expect(updateCaseProperty).toHaveBeenCalled(); + }); }); it('should display EditableTitle isLoading', () => { @@ -296,17 +303,17 @@ describe('CaseView ', () => { ); - await wait(); + await waitFor(() => { + expect( + wrapper.find('[data-test-subj="has-data-to-push-button"]').first().exists() + ).toBeTruthy(); - expect( - wrapper.find('[data-test-subj="has-data-to-push-button"]').first().exists() - ).toBeTruthy(); + wrapper.find('[data-test-subj="push-to-external-service"]').first().simulate('click'); - wrapper.find('[data-test-subj="push-to-external-service"]').first().simulate('click'); + wrapper.update(); - wrapper.update(); - - expect(postPushToService).toHaveBeenCalled(); + expect(postPushToService).toHaveBeenCalled(); + }); }); it('should return null if error', () => { @@ -424,17 +431,19 @@ describe('CaseView ', () => { ); - await wait(); - wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); - wrapper.update(); - wrapper.find('button[data-test-subj="dropdown-connector-servicenow-2"]').simulate('click'); - wrapper.update(); - wrapper.find(`[data-test-subj="edit-connectors-submit"]`).last().simulate('click'); - wrapper.update(); - await wait(); - wrapper.update(); - expect( - wrapper.find('[data-test-subj="dropdown-connectors"]').at(0).prop('valueOfSelected') - ).toBe('servicenow-1'); + await waitFor(() => { + wrapper.find('button[data-test-subj="dropdown-connectors"]').simulate('click'); + wrapper.update(); + wrapper.find('button[data-test-subj="dropdown-connector-servicenow-2"]').simulate('click'); + wrapper.update(); + wrapper.find(`[data-test-subj="edit-connectors-submit"]`).last().simulate('click'); + wrapper.update(); + }); + await waitFor(() => { + wrapper.update(); + expect( + wrapper.find('[data-test-subj="dropdown-connectors"]').at(0).prop('valueOfSelected') + ).toBe('servicenow-1'); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/cases/components/create/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/create/index.test.tsx index 25c12a53f2f5b..aefb196e0678d 100644 --- a/x-pack/plugins/security_solution/public/cases/components/create/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/create/index.test.tsx @@ -19,7 +19,9 @@ import { useGetTags } from '../../containers/use_get_tags'; jest.mock('../../../timelines/components/timeline/insert_timeline_popover/use_insert_timeline'); jest.mock('../../containers/use_post_case'); import { useForm } from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'; -import { wait } from '../../../common/lib/helpers'; + +// 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'; jest.mock( '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form' @@ -97,8 +99,7 @@ describe('Create case', () => { ); wrapper.find(`[data-test-subj="create-case-submit"]`).first().simulate('click'); - await wait(); - expect(postCase).toBeCalledWith(sampleData); + await waitFor(() => expect(postCase).toBeCalledWith(sampleData)); }); it('should redirect to all cases on cancel click', () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.test.tsx index 564ce2e19df00..e531b71e8c90c 100644 --- a/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/edit_connector/index.test.tsx @@ -11,7 +11,8 @@ import { EditConnector } from './index'; import { getFormMock, useFormMock } from '../__mock__/form'; import { TestProviders } from '../../../common/mock'; import { connectorsMock } from '../../containers/configure/mock'; -import { wait } from '../../../common/lib/helpers'; +// 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'; jest.mock( '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form' @@ -68,8 +69,7 @@ describe('EditConnector ', () => { await act(async () => { wrapper.find(`[data-test-subj="edit-connectors-submit"]`).last().simulate('click'); - await wait(); - expect(onSubmit.mock.calls[0][0]).toBe(sampleConnector); + await waitFor(() => expect(onSubmit.mock.calls[0][0]).toBe(sampleConnector)); }); }); @@ -92,10 +92,11 @@ describe('EditConnector ', () => { await act(async () => { wrapper.find(`[data-test-subj="edit-connectors-submit"]`).last().simulate('click'); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); + expect(formHookMock.setFieldValue).toHaveBeenCalledWith('connector', 'none'); + }); }); - expect(formHookMock.setFieldValue).toHaveBeenCalledWith('connector', 'none'); }); it('Resets selector on cancel', async () => { @@ -115,12 +116,13 @@ describe('EditConnector ', () => { await act(async () => { wrapper.find(`[data-test-subj="edit-connectors-cancel"]`).last().simulate('click'); - await wait(); - wrapper.update(); - expect(formHookMock.setFieldValue).toBeCalledWith( - 'connector', - defaultProps.selectedConnector - ); + await waitFor(() => { + wrapper.update(); + expect(formHookMock.setFieldValue).toBeCalledWith( + 'connector', + defaultProps.selectedConnector + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/cases/components/tag_list/index.test.tsx b/x-pack/plugins/security_solution/public/cases/components/tag_list/index.test.tsx index 950dd6f377945..939ddfde8b9dc 100644 --- a/x-pack/plugins/security_solution/public/cases/components/tag_list/index.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/tag_list/index.test.tsx @@ -11,7 +11,8 @@ import { act } from 'react-dom/test-utils'; import { TagList } from '.'; import { getFormMock } from '../__mock__/form'; import { TestProviders } from '../../../common/mock'; -import { wait } from '../../../common/lib/helpers'; +// 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 { useForm } from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form'; import { useGetTags } from '../../containers/use_get_tags'; @@ -77,8 +78,7 @@ describe('TagList ', () => { wrapper.find(`[data-test-subj="tag-list-edit-button"]`).last().simulate('click'); await act(async () => { wrapper.find(`[data-test-subj="edit-tags-submit"]`).last().simulate('click'); - await wait(); - expect(onSubmit).toBeCalledWith(sampleTags); + await waitFor(() => expect(onSubmit).toBeCalledWith(sampleTags)); }); }); it('Tag options render with new tags added', () => { @@ -107,9 +107,10 @@ describe('TagList ', () => { await act(async () => { expect(wrapper.find(`[data-test-subj="case-tag"]`).last().exists()).toBeFalsy(); wrapper.find(`[data-test-subj="edit-tags-cancel"]`).last().simulate('click'); - await wait(); - wrapper.update(); - expect(wrapper.find(`[data-test-subj="case-tag"]`).last().exists()).toBeTruthy(); + await waitFor(() => { + wrapper.update(); + expect(wrapper.find(`[data-test-subj="case-tag"]`).last().exists()).toBeTruthy(); + }); }); }); it('Renders disabled button', () => { 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 23f1fb222a841..9cf13b6f9930a 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 @@ -13,7 +13,8 @@ import { useUpdateComment } from '../../containers/use_update_comment'; import { basicCase, basicPush, getUserAction } from '../../containers/mock'; import { UserActionTree } from '.'; import { TestProviders } from '../../../common/mock'; -import { wait } from '../../../common/lib/helpers'; +// 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(); @@ -225,22 +226,23 @@ describe('UserActionTree ', () => { .first() .simulate('click'); await act(async () => { - await wait(); - wrapper.update(); - expect( - wrapper - .find( - `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]` - ) - .exists() - ).toEqual(false); - expect(patchComment).toBeCalledWith({ - commentUpdate: sampleData.content, - caseId: props.data.id, - commentId: props.data.comments[0].id, - fetchUserActions, - updateCase, - version: props.data.comments[0].version, + await waitFor(() => { + wrapper.update(); + expect( + wrapper + .find( + `[data-test-subj="user-action-${props.data.comments[0].id}"] [data-test-subj="user-action-markdown-form"]` + ) + .exists() + ).toEqual(false); + expect(patchComment).toBeCalledWith({ + commentUpdate: sampleData.content, + caseId: props.data.id, + commentId: props.data.comments[0].id, + fetchUserActions, + updateCase, + version: props.data.comments[0].version, + }); }); }); }); @@ -269,15 +271,16 @@ describe('UserActionTree ', () => { .first() .simulate('click'); await act(async () => { - await wait(); - 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 }); + 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 }); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx index 2a7cbff5ee149..049953e21febd 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx @@ -10,7 +10,8 @@ import useResizeObserver from 'use-resize-observer/polyfilled'; import '../../mock/match_media'; import { mockIndexPattern, TestProviders } from '../../mock'; -import { wait } from '../../lib/helpers'; +// 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 { mockEventViewerResponse } from './mock'; import { StatefulEventsViewer } from '.'; @@ -60,12 +61,13 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().text()).toEqual( - 'Showing: 12 events' - ); + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().text()).toEqual( + 'Showing: 12 events' + ); + }); }); test('it does NOT render fetch index pattern is loading', async () => { @@ -84,10 +86,13 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe(false); + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe( + false + ); + }); }); test('it does NOT render when start is empty', async () => { @@ -106,10 +111,13 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe(false); + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe( + false + ); + }); }); test('it does NOT render when end is empty', async () => { @@ -128,10 +136,13 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe(false); + expect(wrapper.find(`[data-test-subj="header-section-subtitle"]`).first().exists()).toBe( + false + ); + }); }); test('it renders the Fields Browser as a settings gear', async () => { @@ -148,10 +159,11 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="show-field-browser"]`).first().exists()).toBe(true); + expect(wrapper.find(`[data-test-subj="show-field-browser"]`).first().exists()).toBe(true); + }); }); test('it renders the footer containing the Load More button', async () => { @@ -168,10 +180,11 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`[data-test-subj="TimelineMoreButton"]`).first().exists()).toBe(true); + expect(wrapper.find(`[data-test-subj="TimelineMoreButton"]`).first().exists()).toBe(true); + }); }); defaultHeaders.forEach((header) => { @@ -189,14 +202,15 @@ describe('EventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - defaultHeaders.forEach((h) => - expect(wrapper.find(`[data-test-subj="header-text-${header.id}"]`).first().exists()).toBe( - true - ) - ); + defaultHeaders.forEach((h) => + expect(wrapper.find(`[data-test-subj="header-text-${header.id}"]`).first().exists()).toBe( + true + ) + ); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx index 1ab390a85ec50..4509d01e82e25 100644 --- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.test.tsx @@ -9,7 +9,8 @@ import { MockedProvider } from 'react-apollo/test-utils'; import useResizeObserver from 'use-resize-observer/polyfilled'; import '../../mock/match_media'; -import { wait } from '../../lib/helpers'; +// 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 { mockIndexPattern, TestProviders } from '../../mock'; import { useMountAppended } from '../../utils/use_mount_appended'; @@ -54,10 +55,11 @@ describe('StatefulEventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find('[data-test-subj="events-viewer-panel"]').first().exists()).toBe(true); + expect(wrapper.find('[data-test-subj="events-viewer-panel"]').first().exists()).toBe(true); + }); }); // InspectButtonContainer controls displaying InspectButton components @@ -75,9 +77,10 @@ describe('StatefulEventsViewer', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true); + expect(wrapper.find(`InspectButtonContainer`).exists()).toBe(true); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/url_state/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/url_state/index.test.tsx index 9d0d9e7b250a0..72df9d613abac 100644 --- a/x-pack/plugins/security_solution/public/common/components/url_state/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/url_state/index.test.tsx @@ -21,7 +21,8 @@ import { } from './test_dependencies'; import { UrlStateContainerPropTypes } from './types'; import { useUrlStateHooks } from './use_url_state'; -import { wait } from '../../lib/helpers'; +// 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'; let mockProps: UrlStateContainerPropTypes; @@ -194,29 +195,32 @@ describe('UrlStateContainer', () => { }).relativeTimeSearch.undefinedQuery, }); wrapper.update(); - await wait(); if (CONSTANTS.detectionsPage === page) { - expect(mockSetRelativeRangeDatePicker.mock.calls[3][0]).toEqual({ - from: '2020-01-01T00:00:00.000Z', - fromStr: 'now-1d/d', - kind: 'relative', - to: '2020-01-01T00:00:00.000Z', - toStr: 'now-1d/d', - id: 'global', - }); + await waitFor(() => { + expect(mockSetRelativeRangeDatePicker.mock.calls[3][0]).toEqual({ + from: '2020-01-01T00:00:00.000Z', + fromStr: 'now-1d/d', + kind: 'relative', + to: '2020-01-01T00:00:00.000Z', + toStr: 'now-1d/d', + id: 'global', + }); - expect(mockSetRelativeRangeDatePicker.mock.calls[2][0]).toEqual({ - from: 1558732849370, - fromStr: 'now-15m', - kind: 'relative', - to: 1558733749370, - toStr: 'now', - id: 'timeline', + expect(mockSetRelativeRangeDatePicker.mock.calls[2][0]).toEqual({ + from: 1558732849370, + fromStr: 'now-15m', + kind: 'relative', + to: 1558733749370, + toStr: 'now', + id: 'timeline', + }); }); } else { - // There is no change in url state, so that's expected we only have two actions - expect(mockSetRelativeRangeDatePicker.mock.calls.length).toEqual(2); + await waitFor(() => { + // There is no change in url state, so that's expected we only have two actions + expect(mockSetRelativeRangeDatePicker.mock.calls.length).toEqual(2); + }); } } ); diff --git a/x-pack/plugins/security_solution/public/common/lib/helpers/index.tsx b/x-pack/plugins/security_solution/public/common/lib/helpers/index.tsx index 07e706ac2a9af..96b0343efdf72 100644 --- a/x-pack/plugins/security_solution/public/common/lib/helpers/index.tsx +++ b/x-pack/plugins/security_solution/public/common/lib/helpers/index.tsx @@ -19,12 +19,6 @@ export type WrapArrayIfExitts = (value: Many) => T[] | undefined; export const asArrayIfExists: WrapArrayIfExitts = (value) => !isUndefined(value) ? castArray(value) : undefined; -export const wait = (delay = 0): Promise => { - return new Promise((resolve) => { - return setTimeout(resolve, delay); - }); -}; - /** * Creates a Union Type for all the values of an object */ diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx index 9b2e0069f0ac0..a86c1b7ce1bea 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule/index.test.tsx @@ -13,7 +13,8 @@ import { StepAboutRule } from '.'; import { mockAboutStepRule } from '../../../pages/detection_engine/rules/all/__mocks__/mock'; import { StepRuleDescription } from '../description_step'; import { stepAboutDefaultValue } from './default_value'; -import { wait } from '@testing-library/react'; +// 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 { AboutStepRule } from '../../../pages/detection_engine/rules/types'; const theme = () => ({ eui: euiDarkVars, darkMode: true }); @@ -162,31 +163,32 @@ describe('StepAboutRuleComponent', () => { .simulate('change', { target: { value: 'Test name text' } }); wrapper.find('button[data-test-subj="about-continue"]').first().simulate('click').update(); - await wait(); - const expected: Omit = { - author: [], - isAssociatedToEndpointList: false, - isBuildingBlock: false, - license: '', - ruleNameOverride: '', - timestampOverride: '', - description: 'Test description text', - falsePositives: [''], - name: 'Test name text', - note: '', - references: [''], - riskScore: { value: 50, mapping: [] }, - severity: { value: 'low', mapping: [] }, - tags: [], - threat: [ - { - framework: 'MITRE ATT&CK', - tactic: { id: 'none', name: 'none', reference: 'none' }, - technique: [], - }, - ], - }; - expect(stepDataMock.mock.calls[1][1]).toEqual(expected); + await waitFor(() => { + const expected: Omit = { + author: [], + isAssociatedToEndpointList: false, + isBuildingBlock: false, + license: '', + ruleNameOverride: '', + timestampOverride: '', + description: 'Test description text', + falsePositives: [''], + name: 'Test name text', + note: '', + references: [''], + riskScore: { value: 50, mapping: [] }, + severity: { value: 'low', mapping: [] }, + tags: [], + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { id: 'none', name: 'none', reference: 'none' }, + technique: [], + }, + ], + }; + expect(stepDataMock.mock.calls[1][1]).toEqual(expected); + }); }); test('it allows user to set the risk score as a number (and not a string)', async () => { @@ -221,30 +223,31 @@ describe('StepAboutRuleComponent', () => { .simulate('change', { target: { value: '80' } }); wrapper.find('[data-test-subj="about-continue"]').first().simulate('click').update(); - await wait(); - const expected: Omit = { - author: [], - isAssociatedToEndpointList: false, - isBuildingBlock: false, - license: '', - ruleNameOverride: '', - timestampOverride: '', - description: 'Test description text', - falsePositives: [''], - name: 'Test name text', - note: '', - references: [''], - riskScore: { value: 80, mapping: [] }, - severity: { value: 'low', mapping: [] }, - tags: [], - threat: [ - { - framework: 'MITRE ATT&CK', - tactic: { id: 'none', name: 'none', reference: 'none' }, - technique: [], - }, - ], - }; - expect(stepDataMock.mock.calls[1][1]).toEqual(expected); + await waitFor(() => { + const expected: Omit = { + author: [], + isAssociatedToEndpointList: false, + isBuildingBlock: false, + license: '', + ruleNameOverride: '', + timestampOverride: '', + description: 'Test description text', + falsePositives: [''], + name: 'Test name text', + note: '', + references: [''], + riskScore: { value: 80, mapping: [] }, + severity: { value: 'low', mapping: [] }, + tags: [], + threat: [ + { + framework: 'MITRE ATT&CK', + tactic: { id: 'none', name: 'none', reference: 'none' }, + technique: [], + }, + ], + }; + expect(stepDataMock.mock.calls[1][1]).toEqual(expected); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx index 58344e9e97534..b07caa754aec9 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.test.tsx @@ -11,7 +11,8 @@ import { act } from 'react-dom/test-utils'; import '../../../../../common/mock/match_media'; import { createKibanaContextProviderMock } from '../../../../../common/mock/kibana_react'; import { TestProviders } from '../../../../../common/mock'; -import { wait } from '../../../../../common/lib/helpers'; +// 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 { AllRules } from './index'; jest.mock('react-router-dom', () => { @@ -202,10 +203,10 @@ describe('AllRules', () => { ); await act(async () => { - await wait(); - - expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeFalsy(); - expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeTruthy(); + await waitFor(() => { + expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeFalsy(); + expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeTruthy(); + }); }); }); @@ -234,11 +235,11 @@ describe('AllRules', () => { monitoringTab.simulate('click'); await act(async () => { - wrapper.update(); - await wait(); - - expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeTruthy(); - expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeFalsy(); + await waitFor(() => { + wrapper.update(); + expect(wrapper.exists('[data-test-subj="monitoring-table"]')).toBeTruthy(); + expect(wrapper.exists('[data-test-subj="rules-table"]')).toBeFalsy(); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/hosts/components/first_last_seen_host/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/first_last_seen_host/index.test.tsx index 9715c1cb5c8b4..a2f53be721816 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/first_last_seen_host/index.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/first_last_seen_host/index.test.tsx @@ -7,10 +7,11 @@ import { cloneDeep } from 'lodash/fp'; import React from 'react'; import { MockedProvider } from 'react-apollo/test-utils'; -import { render, act } from '@testing-library/react'; + +// we don't have the types for waitFor just yet, so using "as waitFor" until when we do +import { render, act, wait as waitFor } from '@testing-library/react'; import { mockFirstLastSeenHostQuery } from '../../containers/hosts/first_last_seen/mock'; -import { wait } from '../../../common/lib/helpers'; import { TestProviders } from '../../../common/mock'; import { FirstLastSeenHost, FirstLastSeenHostType } from '.'; @@ -51,10 +52,12 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - - expect(container.innerHTML).toBe( - `
${firstSeen}
` + await act(() => + waitFor(() => { + expect(container.innerHTML).toBe( + `
${firstSeen}
` + ); + }) ); }); @@ -66,9 +69,12 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - expect(container.innerHTML).toBe( - `
${lastSeen}
` + await act(() => + waitFor(() => { + expect(container.innerHTML).toBe( + `
${lastSeen}
` + ); + }) ); }); @@ -83,10 +89,12 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - - expect(container.innerHTML).toBe( - `
${lastSeen}
` + await act(() => + waitFor(() => { + expect(container.innerHTML).toBe( + `
${lastSeen}
` + ); + }) ); }); @@ -101,10 +109,12 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - - expect(container.innerHTML).toBe( - `
${firstSeen}
` + await act(() => + waitFor(() => { + expect(container.innerHTML).toBe( + `
${firstSeen}
` + ); + }) ); }); @@ -118,8 +128,11 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - expect(container.textContent).toBe('something-invalid'); + await act(() => + waitFor(() => { + expect(container.textContent).toBe('something-invalid'); + }) + ); }); test('Last Seen With a bad date time string', async () => { @@ -132,7 +145,10 @@ describe('FirstLastSeen Component', () => { ); - await act(() => wait()); - expect(container.textContent).toBe('something-invalid'); + await act(() => + waitFor(() => { + expect(container.textContent).toBe('something-invalid'); + }) + ); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.test.tsx index 63126da0b9bb5..f7f1fbc30aeb7 100644 --- a/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/alerts_by_category/index.test.tsx @@ -13,7 +13,8 @@ import { ThemeProvider } from 'styled-components'; import '../../../common/mock/match_media'; import { useQuery } from '../../../common/containers/matrix_histogram'; -import { wait } from '../../../common/lib/helpers'; +// 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 { mockIndexPattern, TestProviders } from '../../../common/mock'; import { AlertsByCategory } from '.'; @@ -57,34 +58,45 @@ describe('Alerts by category', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); + }); }); - test('it renders the expected title', () => { - expect(wrapper.find('[data-test-subj="header-section-title"]').text()).toEqual( - 'External alert trend' - ); + test('it renders the expected title', async () => { + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-section-title"]').text()).toEqual( + 'External alert trend' + ); + }); }); - test('it renders the subtitle (to prevent layout thrashing)', () => { - expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').exists()).toBe(true); + test('it renders the subtitle (to prevent layout thrashing)', async () => { + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').exists()).toBe(true); + }); }); - test('it renders the expected filter fields', () => { - const expectedOptions = ['event.category', 'event.module']; + test('it renders the expected filter fields', async () => { + await waitFor(() => { + const expectedOptions = ['event.category', 'event.module']; - expectedOptions.forEach((option) => { - expect(wrapper.find(`option[value="${option}"]`).text()).toEqual(option); + expectedOptions.forEach((option) => { + expect(wrapper.find(`option[value="${option}"]`).text()).toEqual(option); + }); }); }); - test('it renders the `View alerts` button', () => { - expect(wrapper.find('[data-test-subj="view-alerts"]').exists()).toBe(true); + test('it renders the `View alerts` button', async () => { + await waitFor(() => { + expect(wrapper.find('[data-test-subj="view-alerts"]').exists()).toBe(true); + }); }); - test('it does NOT render the bar chart when data is not available', () => { - expect(wrapper.find(`.echChart`).exists()).toBe(false); + test('it does NOT render the bar chart when data is not available', async () => { + await waitFor(() => { + expect(wrapper.find(`.echChart`).exists()).toBe(false); + }); }); }); @@ -119,18 +131,21 @@ describe('Alerts by category', () => { ); - await wait(); wrapper.update(); }); - test('it renders the expected subtitle', () => { - expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').text()).toEqual( - 'Showing: 6 external alerts' - ); + test('it renders the expected subtitle', async () => { + await waitFor(() => { + expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').text()).toEqual( + 'Showing: 6 external alerts' + ); + }); }); - test('it renders the bar chart when data is available', () => { - expect(wrapper.find(`.echChart`).exists()).toBe(true); + test('it renders the bar chart when data is available', async () => { + await waitFor(() => { + expect(wrapper.find(`.echChart`).exists()).toBe(true); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_host/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_host/index.test.tsx index 30874e8874760..5ff78c9b29cf5 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_host/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_host/index.test.tsx @@ -24,7 +24,8 @@ import { createStore, State } from '../../../common/store'; import { overviewHostQuery } from '../../containers/overview_host/index.gql_query'; import { GetOverviewHostQuery } from '../../../graphql/types'; -import { wait } from '../../../common/lib/helpers'; +// 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'; jest.mock('../../../common/lib/kibana'); jest.mock('../../../common/components/link_to'); @@ -147,11 +148,12 @@ describe('OverviewHost', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').first().text()).toEqual( - 'Showing: 16 events' - ); + expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').first().text()).toEqual( + 'Showing: 16 events' + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_network/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_network/index.test.tsx index 9ac4f7125f34d..0bb887b38a4b1 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_network/index.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_network/index.test.tsx @@ -22,7 +22,8 @@ import { OverviewNetwork } from '.'; import { createStore, State } from '../../../common/store'; import { overviewNetworkQuery } from '../../containers/overview_network/index.gql_query'; import { GetOverviewHostQuery } from '../../../graphql/types'; -import { wait } from '../../../common/lib/helpers'; +// 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'; jest.mock('../../../common/components/link_to'); const mockNavigateToApp = jest.fn(); @@ -155,12 +156,13 @@ describe('OverviewNetwork', () => { ); - await wait(); - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').first().text()).toEqual( - 'Showing: 9 events' - ); + expect(wrapper.find('[data-test-subj="header-panel-subtitle"]').first().text()).toEqual( + 'Showing: 9 events' + ); + }); }); it('it renders View Network', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.test.tsx index e671244d97b57..6c1c88f511edb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/index.test.tsx @@ -8,7 +8,8 @@ import { mount } from 'enzyme'; import { MockedProvider } from 'react-apollo/test-utils'; import React from 'react'; -import { wait } from '../../../common/lib/helpers'; +// 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 '../../../common/mock/match_media'; import { TestProviders, apolloClient } from '../../../common/mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../../common/mock/timeline_results'; @@ -119,15 +120,15 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find('[data-test-subj="search-bar"] input') - .simulate('keyup', { key: 'Enter', target: { value: ' abcd ' } }); + await waitFor(() => { + wrapper + .find('[data-test-subj="search-bar"] input') + .simulate('keyup', { key: 'Enter', target: { value: ' abcd ' } }); - expect(wrapper.find('[data-test-subj="query-message"]').first().text()).toContain( - 'Showing: 11 timelines with' - ); + expect(wrapper.find('[data-test-subj="query-message"]').first().text()).toContain( + 'Showing: 11 timelines with' + ); + }); }); test('echos (renders) the query when the user enters a query', async () => { @@ -144,15 +145,15 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find('[data-test-subj="search-bar"] input') - .simulate('keyup', { key: 'Enter', target: { value: ' abcd ' } }); + await waitFor(() => { + wrapper + .find('[data-test-subj="search-bar"] input') + .simulate('keyup', { key: 'Enter', target: { value: ' abcd ' } }); - expect(wrapper.find('[data-test-subj="selectable-query-text"]').first().text()).toEqual( - 'with "abcd"' - ); + expect(wrapper.find('[data-test-subj="selectable-query-text"]').first().text()).toEqual( + 'with "abcd"' + ); + }); }); }); @@ -171,12 +172,12 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - expect( - wrapper.find(`.${OPEN_TIMELINE_CLASS_NAME} input`).first().getDOMNode().id === - document.activeElement!.id - ).toBe(true); + await waitFor(() => { + expect( + wrapper.find(`.${OPEN_TIMELINE_CLASS_NAME} input`).first().getDOMNode().id === + document.activeElement!.id + ).toBe(true); + }); }); }); @@ -198,26 +199,26 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find('.euiCheckbox__input') - .first() - .simulate('change', { target: { checked: true } }); - - wrapper.find('[data-test-subj="favorite-selected"]').first().simulate('click'); - - expect(addTimelinesToFavorites).toHaveBeenCalledWith([ - 'saved-timeline-11', - 'saved-timeline-10', - 'saved-timeline-9', - 'saved-timeline-8', - 'saved-timeline-6', - 'saved-timeline-5', - 'saved-timeline-4', - 'saved-timeline-3', - 'saved-timeline-2', - ]); + await waitFor(() => { + wrapper + .find('.euiCheckbox__input') + .first() + .simulate('change', { target: { checked: true } }); + + wrapper.find('[data-test-subj="favorite-selected"]').first().simulate('click'); + + expect(addTimelinesToFavorites).toHaveBeenCalledWith([ + 'saved-timeline-11', + 'saved-timeline-10', + 'saved-timeline-9', + 'saved-timeline-8', + 'saved-timeline-6', + 'saved-timeline-5', + 'saved-timeline-4', + 'saved-timeline-3', + 'saved-timeline-2', + ]); + }); }); }); @@ -239,26 +240,26 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find('.euiCheckbox__input') - .first() - .simulate('change', { target: { checked: true } }); - - wrapper.find('[data-test-subj="delete-selected"]').first().simulate('click'); - - expect(deleteTimelines).toHaveBeenCalledWith([ - 'saved-timeline-11', - 'saved-timeline-10', - 'saved-timeline-9', - 'saved-timeline-8', - 'saved-timeline-6', - 'saved-timeline-5', - 'saved-timeline-4', - 'saved-timeline-3', - 'saved-timeline-2', - ]); + await waitFor(() => { + wrapper + .find('.euiCheckbox__input') + .first() + .simulate('change', { target: { checked: true } }); + + wrapper.find('[data-test-subj="delete-selected"]').first().simulate('click'); + + expect(deleteTimelines).toHaveBeenCalledWith([ + 'saved-timeline-11', + 'saved-timeline-10', + 'saved-timeline-9', + 'saved-timeline-8', + 'saved-timeline-6', + 'saved-timeline-5', + 'saved-timeline-4', + 'saved-timeline-3', + 'saved-timeline-2', + ]); + }); }); }); @@ -278,19 +279,19 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find('.euiCheckbox__input') - .first() - .simulate('change', { target: { checked: true } }); + await waitFor(() => { + wrapper + .find('.euiCheckbox__input') + .first() + .simulate('change', { target: { checked: true } }); - const selectedItems: [] = wrapper - .find('[data-test-subj="open-timeline"]') - .last() - .prop('selectedItems'); + const selectedItems: [] = wrapper + .find('[data-test-subj="open-timeline"]') + .last() + .prop('selectedItems'); - expect(selectedItems.length).toEqual(13); // 13 because we did mock 13 timelines in the query + expect(selectedItems.length).toEqual(13); // 13 because we did mock 13 timelines in the query + }); }); }); @@ -366,29 +367,37 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - wrapper.update(); - - expect( - wrapper.find('[data-test-subj="open-timeline"]').last().prop('itemIdToExpandedNotesRowMap') - ).toEqual({}); - - wrapper.find('[data-test-subj="expand-notes"]').first().simulate('click'); - - expect( - wrapper.find('[data-test-subj="open-timeline"]').last().prop('itemIdToExpandedNotesRowMap') - ).toEqual({ - '10849df0-7b44-11e9-a608-ab3d811609': ( - ({ ...note, savedObjectId: note.noteId }) - ) - : [] - } - /> - ), + await waitFor(() => { + wrapper.update(); + + expect( + wrapper + .find('[data-test-subj="open-timeline"]') + .last() + .prop('itemIdToExpandedNotesRowMap') + ).toEqual({}); + + wrapper.find('[data-test-subj="expand-notes"]').first().simulate('click'); + + expect( + wrapper + .find('[data-test-subj="open-timeline"]') + .last() + .prop('itemIdToExpandedNotesRowMap') + ).toEqual({ + '10849df0-7b44-11e9-a608-ab3d811609': ( + ({ ...note, savedObjectId: note.noteId }) + ) + : [] + } + /> + ), + }); }); }); @@ -407,21 +416,21 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper.update(); + await waitFor(() => { + wrapper.update(); - wrapper.find('[data-test-subj="expand-notes"]').first().simulate('click'); - expect(wrapper.find('[data-test-subj="note-previews-container"]').exists()).toEqual(true); - expect(wrapper.find('[data-test-subj="updated-by"]').exists()).toEqual(true); + wrapper.find('[data-test-subj="expand-notes"]').first().simulate('click'); + expect(wrapper.find('[data-test-subj="note-previews-container"]').exists()).toEqual(true); + expect(wrapper.find('[data-test-subj="updated-by"]').exists()).toEqual(true); - expect( - wrapper - .find('[data-test-subj="note-previews-container"]') - .find('[data-test-subj="updated-by"]') - .first() - .text() - ).toEqual('elastic'); + expect( + wrapper + .find('[data-test-subj="note-previews-container"]') + .find('[data-test-subj="updated-by"]') + .first() + .text() + ).toEqual('elastic'); + }); }); /** @@ -442,11 +451,11 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - expect(wrapper.find(`[data-test-subj="timeline-${TimelineTabsStyle.tab}"]`).exists()).toEqual( - true - ); + await waitFor(() => { + expect( + wrapper.find(`[data-test-subj="timeline-${TimelineTabsStyle.tab}"]`).exists() + ).toEqual(true); + }); }); }); @@ -467,13 +476,14 @@ describe('StatefulOpenTimeline', () => { ); const getSelectedItem = (): [] => wrapper.find('[data-test-subj="open-timeline"]').last().prop('selectedItems'); - await wait(); - expect(getSelectedItem().length).toEqual(0); - wrapper - .find('.euiCheckbox__input') - .first() - .simulate('change', { target: { checked: true } }); - expect(getSelectedItem().length).toEqual(13); + await waitFor(() => { + expect(getSelectedItem().length).toEqual(0); + wrapper + .find('.euiCheckbox__input') + .first() + .simulate('change', { target: { checked: true } }); + expect(getSelectedItem().length).toEqual(13); + }); }); }); @@ -492,13 +502,13 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find('[data-test-subj="query-message"]').first().text()).toContain( - 'Showing: 11 timelines ' - ); + expect(wrapper.find('[data-test-subj="query-message"]').first().text()).toContain( + 'Showing: 11 timelines ' + ); + }); }); // TODO - Have been skip because we need to re-implement the test as the component changed @@ -519,21 +529,21 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); - - wrapper - .find( - `[data-test-subj="title-${ - mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].savedObjectId - }"]` - ) - .first() - .simulate('click'); - - expect(onOpenTimeline).toHaveBeenCalledWith({ - duplicate: false, - timelineId: mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0] - .savedObjectId, + await waitFor(() => { + wrapper + .find( + `[data-test-subj="title-${ + mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0].savedObjectId + }"]` + ) + .first() + .simulate('click'); + + expect(onOpenTimeline).toHaveBeenCalledWith({ + duplicate: false, + timelineId: mockOpenTimelineQueryResults[0].result.data!.getAllTimeline.timeline[0] + .savedObjectId, + }); }); }); @@ -555,10 +565,10 @@ describe('StatefulOpenTimeline', () => { ); - await wait(); + await waitFor(() => { + wrapper.find('[data-test-subj="open-duplicate"]').first().simulate('click'); - wrapper.find('[data-test-subj="open-duplicate"]').first().simulate('click'); - - expect(onOpenTimeline).toBeCalledWith({ duplicate: true, timelineId: 'saved-timeline-11' }); + expect(onOpenTimeline).toBeCalledWith({ duplicate: true, timelineId: 'saved-timeline-11' }); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.test.tsx index 8382af6056ca7..3017f553d59d5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/index.test.tsx @@ -10,7 +10,8 @@ import React from 'react'; import { MockedProvider } from 'react-apollo/test-utils'; import { ThemeProvider } from 'styled-components'; -import { wait } from '../../../../common/lib/helpers'; +// 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 { TestProviderWithoutDragAndDrop } from '../../../../common/mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../../../common/mock/timeline_results'; import { useGetAllTimeline, getAllTimeline } from '../../../containers/all'; @@ -64,10 +65,15 @@ describe('OpenTimelineModal', () => { ); - await wait(); + await waitFor( + () => { + wrapper.update(); - wrapper.update(); - - expect(wrapper.find('div[data-test-subj="open-timeline-modal"].euiModal').length).toEqual(1); - }); + expect(wrapper.find('div[data-test-subj="open-timeline-modal"].euiModal').length).toEqual( + 1 + ); + }, + { timeout: 10000 } + ); + }, 20000); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx index 80bca8096f615..a3f180ce84c58 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline_modal/open_timeline_modal_button.test.tsx @@ -10,7 +10,8 @@ import React from 'react'; import { MockedProvider } from 'react-apollo/test-utils'; import { ThemeProvider } from 'styled-components'; -import { wait } from '../../../../common/lib/helpers'; +// 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 { TestProviderWithoutDragAndDrop } from '../../../../common/mock/test_providers'; import { mockOpenTimelineQueryResults } from '../../../../common/mock/timeline_results'; import * as i18n from '../translations'; @@ -29,13 +30,13 @@ describe('OpenTimelineModalButton', () => { ); - await wait(); - - wrapper.update(); + await waitFor(() => { + wrapper.update(); - expect(wrapper.find('[data-test-subj="open-timeline-button"]').first().text()).toEqual( - i18n.OPEN_TIMELINE - ); + expect(wrapper.find('[data-test-subj="open-timeline-button"]').first().text()).toEqual( + i18n.OPEN_TIMELINE + ); + }); }); describe('onClick prop', () => { @@ -51,13 +52,13 @@ describe('OpenTimelineModalButton', () => { ); - await wait(); - - wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click'); + await waitFor(() => { + wrapper.find('[data-test-subj="open-timeline-button"]').first().simulate('click'); - wrapper.update(); + wrapper.update(); - expect(onClick).toBeCalled(); + expect(onClick).toBeCalled(); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx index b36f1dcc03261..5a98263cbd3fd 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/index.test.tsx @@ -16,7 +16,8 @@ import { TestProviders } from '../../../../common/mock/test_providers'; import { Body, BodyProps } from '.'; import { columnRenderers, rowRenderers } from './renderers'; import { Sort } from './sort'; -import { wait } from '../../../../common/lib/helpers'; +// 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 { useMountAppended } from '../../../../common/utils/use_mount_appended'; import { SELECTOR_TIMELINE_BODY_CLASS_NAME, TimelineBody } from '../styles'; import { TimelineType } from '../../../../../common/types/timeline'; @@ -130,16 +131,17 @@ describe('Body', () => { ); wrapper.update(); - await wait(); - wrapper.update(); - headersJustTimestamp.forEach(() => { - expect( - wrapper - .find('[data-test-subj="data-driven-columns"]') - .first() - .find('[data-test-subj="localized-date-tool-tip"]') - .exists() - ).toEqual(true); + await waitFor(() => { + wrapper.update(); + headersJustTimestamp.forEach(() => { + expect( + wrapper + .find('[data-test-subj="data-driven-columns"]') + .first() + .find('[data-test-subj="localized-date-tool-tip"]') + .exists() + ).toEqual(true); + }); }); }, 20000); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx index 8b75f8b398ac1..51edf7336c4e7 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/index.test.tsx @@ -16,7 +16,8 @@ import { ReturnSignalIndex, } from '../../../detections/containers/detection_engine/alerts/use_signal_index'; import { mocksSource } from '../../../common/containers/source/mock'; -import { wait } from '../../../common/lib/helpers'; +// 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 { defaultHeaders, mockTimelineData, TestProviders } from '../../../common/mock'; import { Direction } from '../../../graphql/types'; import { timelineQuery } from '../../containers/index.gql_query'; @@ -124,12 +125,13 @@ describe('StatefulTimeline', () => { ); await act(async () => { - await wait(); - wrapper.update(); - const timeline = wrapper.find(Timeline); - expect(timeline.props().indexToAdd).toEqual([ - 'no-alert-index-049FC71A-4C2C-446F-9901-37XMC5024C51', - ]); + await waitFor(() => { + wrapper.update(); + const timeline = wrapper.find(Timeline); + expect(timeline.props().indexToAdd).toEqual([ + 'no-alert-index-049FC71A-4C2C-446F-9901-37XMC5024C51', + ]); + }); }); }); @@ -147,10 +149,11 @@ describe('StatefulTimeline', () => { ); await act(async () => { - await wait(); - wrapper.update(); - const timeline = wrapper.find(Timeline); - expect(timeline.props().indexToAdd).toEqual(['mock-siem-signals-index']); + await waitFor(() => { + wrapper.update(); + const timeline = wrapper.find(Timeline); + expect(timeline.props().indexToAdd).toEqual(['mock-siem-signals-index']); + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx index 1e0e85d4a48d9..06dd6f44bea94 100644 --- a/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/store/timeline/epic_local_storage.test.tsx @@ -7,6 +7,8 @@ import React from 'react'; import { shallow } from 'enzyme'; +// we don't have the types for waitFor just yet, so using "as waitFor" for when we do +import { wait as waitFor } from '@testing-library/react'; import '../../../common/mock/match_media'; import { mockGlobalState, @@ -44,10 +46,6 @@ import { TimelineStatus, TimelineType } from '../../../../common/types/timeline' jest.mock('../../containers/local_storage'); -const wait = (ms: number = 500): Promise => { - return new Promise((resolve) => setTimeout(resolve, ms)); -}; - const addTimelineInStorageMock = addTimelineInStorage as jest.Mock; describe('epicLocalStorage', () => { @@ -128,8 +126,7 @@ describe('epicLocalStorage', () => { ); store.dispatch(upsertColumn({ id: 'test', index: 1, column: defaultHeaders[0] })); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); it('persist timeline when removing a column ', async () => { @@ -139,8 +136,7 @@ describe('epicLocalStorage', () => { ); store.dispatch(removeColumn({ id: 'test', columnId: '@timestamp' })); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); it('persists resizing of a column', async () => { @@ -150,8 +146,7 @@ describe('epicLocalStorage', () => { ); store.dispatch(applyDeltaToColumnWidth({ id: 'test', columnId: '@timestamp', delta: 80 })); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); it('persist the resetting of the fields', async () => { @@ -161,8 +156,7 @@ describe('epicLocalStorage', () => { ); store.dispatch(updateColumns({ id: 'test', columns: defaultHeaders })); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); it('persist items per page', async () => { @@ -172,8 +166,7 @@ describe('epicLocalStorage', () => { ); store.dispatch(updateItemsPerPage({ id: 'test', itemsPerPage: 50 })); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); it('persist the sorting of a column', async () => { @@ -191,7 +184,6 @@ describe('epicLocalStorage', () => { }, }) ); - await wait(); - expect(addTimelineInStorageMock).toHaveBeenCalled(); + await waitFor(() => expect(addTimelineInStorageMock).toHaveBeenCalled()); }); });