From 1e488c828bc689a97100a52d4c8e20d6c04c79ed Mon Sep 17 00:00:00 2001 From: "Eyo O. Eyo" <7893459+eokoneyo@users.noreply.github.com> Date: Tue, 26 Nov 2024 21:47:11 +0100 Subject: [PATCH] [React18] Migrate test suites to account for testing library upgrades security-detection-rule-management (#201177) This PR migrates test suites that use `renderHook` from the library `@testing-library/react-hooks` to adopt the equivalent and replacement of `renderHook` from the export that is now available from `@testing-library/react`. This work is required for the planned migration to react18. ## Context In this PR, usages of `waitForNextUpdate` that previously could have been destructured from `renderHook` are now been replaced with `waitFor` exported from `@testing-library/react`, furthermore `waitFor` that would also have been destructured from the same renderHook result is now been replaced with `waitFor` from the export of `@testing-library/react`. ***Why is `waitFor` a sufficient enough replacement for `waitForNextUpdate`, and better for testing values subject to async computations?*** WaitFor will retry the provided callback if an error is returned, till the configured timeout elapses. By default the retry interval is `50ms` with a timeout value of `1000ms` that effectively translates to at least 20 retries for assertions placed within waitFor. See https://testing-library.com/docs/dom-testing-library/api-async/#waitfor for more information. This however means that for person's writing tests, said person has to be explicit about expectations that describe the internal state of the hook being tested. This implies checking for instance when a react query hook is being rendered, there's an assertion that said hook isn't loading anymore. In this PR you'd notice that this pattern has been adopted, with most existing assertions following an invocation of `waitForNextUpdate` being placed within a `waitFor` invocation. In some cases the replacement is simply a `waitFor(() => new Promise((resolve) => resolve(null)))` (many thanks to @kapral18, for point out exactly why this works), where this suffices the assertions that follow aren't placed within a waitFor so this PR doesn't get larger than it needs to be. It's also worth pointing out this PR might also contain changes to test and application code to improve said existing test. ### What to do next? 1. Review the changes in this PR. 2. If you think the changes are correct, approve the PR. ## Any questions? If you have any questions or need help with this PR, please leave comments in this PR. Co-authored-by: Elastic Machine --- .../hooks/use_enable_data_feed.test.tsx | 11 +-- .../hooks/use_security_jobs.test.ts | 22 +++--- .../use_redirect_legacy_url.test.ts | 5 +- .../use_rule_details_tabs.test.tsx | 2 +- .../bulk_actions/use_bulk_export.test.ts | 2 +- .../use_execute_bulk_action.test.ts | 2 +- .../logic/use_alert_suppression.test.tsx | 3 +- .../use_dissasociate_exception_list.test.ts | 15 +--- .../logic/use_rule_indices.test.ts | 2 +- .../rules_table/rules_table_context.test.tsx | 2 +- .../use_rules_table_saved_state.test.ts | 2 +- .../use_sync_rules_table_saved_state.test.tsx | 2 +- .../use_execution_events.test.tsx | 76 +++++++++---------- .../use_execution_results.test.tsx | 17 ++--- .../use_integrations.test.tsx | 17 ++--- .../rules/use_rule_from_timeline.test.ts | 42 +++++----- 16 files changed, 103 insertions(+), 119 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx index 5d1d2ab2eaba7..16f9640807b53 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useEnableDataFeed } from './use_enable_data_feed'; import { TestProviders } from '../../../mock'; @@ -78,21 +78,18 @@ describe('useSecurityJobsHelpers', () => { resolvePromiseCb = resolve; }) ); - const { result, waitForNextUpdate } = renderHook(() => useEnableDataFeed(), { + const { result } = renderHook(() => useEnableDataFeed(), { wrapper, }); expect(result.current.isLoading).toBe(false); await act(async () => { const enableDataFeedPromise = result.current.enableDatafeed(JOB, TIMESTAMP); - - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(true); - resolvePromiseCb({}); await enableDataFeedPromise; - expect(result.current.isLoading).toBe(false); }); + + await waitFor(() => expect(result.current.isLoading).toBe(false)); }); it('does not call setupMlJob if job is already installed', async () => { diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts index 1451054fb882f..af3120a4e7b93 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; import { useAppToasts } from '../../../hooks/use_app_toasts'; @@ -71,33 +71,31 @@ describe('useSecurityJobs', () => { bucketSpanSeconds: 900, }; - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(), { + const { result } = renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); - await waitForNextUpdate(); - - expect(result.current.jobs).toHaveLength(6); + await waitFor(() => expect(result.current.jobs).toHaveLength(6)); expect(result.current.jobs).toEqual(expect.arrayContaining([expectedSecurityJob])); }); it('returns those permissions', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(), { + const { result } = renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); - await waitForNextUpdate(); - - expect(result.current.isMlAdmin).toEqual(true); - expect(result.current.isLicensed).toEqual(true); + await waitFor(() => { + expect(result.current.isMlAdmin).toEqual(true); + expect(result.current.isLicensed).toEqual(true); + }); }); it('renders a toast error if an ML call fails', async () => { (getModules as jest.Mock).mockRejectedValue('whoops'); - const { waitFor } = renderHook(() => useSecurityJobs(), { + renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); // addError might be called after an arbitrary number of renders, so we - // need to use waitFor here instead of waitForNextUpdate + // need to use waitFor here instead of waitFor await waitFor(() => { expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', { title: 'Security job fetch failure', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts index 2e005cd7ca03b..eac29becca314 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts @@ -4,10 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -/* eslint-disable no-restricted-imports */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { renderHook, cleanup } from '@testing-library/react'; +// eslint-disable-next-line no-restricted-imports import type { UseLegacyUrlRedirectParams } from './use_redirect_legacy_url'; +// eslint-disable-next-line no-restricted-imports import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import type { Rule } from '../../../rule_management/logic'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx index 1dec9aa36d21a..6f616f23d1cec 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { cleanup, renderHook } from '@testing-library/react-hooks'; +import { renderHook, cleanup } from '@testing-library/react'; import type { UseRuleDetailsTabsProps } from './use_rule_details_tabs'; import { RuleDetailTabs, useRuleDetailsTabs } from './use_rule_details_tabs'; import type { Rule } from '../../../rule_management/logic'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts index 968b40c7a6026..6cd50548f5d04 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useRulesTableContextOptional } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts index 6309d8b629bc2..ee9b43af4355d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx index 949c957bf83c1..27615ef2d489a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; + +import { renderHook } from '@testing-library/react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { useAlertSuppression } from './use_alert_suppression'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts index 553f8734b4540..37acd41f98229 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import * as api from '../api/api'; import { getRulesSchemaMock } from '../../../../common/api/detection_engine/model/rule_schema/mocks'; -import type { - ReturnUseDisassociateExceptionList, - UseDisassociateExceptionListProps, -} from './use_disassociate_exception_list'; import { useDisassociateExceptionList } from './use_disassociate_exception_list'; const mockKibanaHttpService = coreMock.createStart().http; @@ -33,10 +29,7 @@ describe('useDisassociateExceptionList', () => { test('initializes hook', async () => { await act(async () => { - const { result, waitForNextUpdate } = renderHook< - UseDisassociateExceptionListProps, - ReturnUseDisassociateExceptionList - >(() => + const { result } = renderHook(() => useDisassociateExceptionList({ http: mockKibanaHttpService, ruleRuleId: 'rule_id', @@ -45,9 +38,7 @@ describe('useDisassociateExceptionList', () => { }) ); - await waitForNextUpdate(); - - expect(result.current).toEqual([false, null]); + await waitFor(() => expect(result.current).toEqual([false, null])); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts index cdb6e805d18c8..e62428f9f17d2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useRuleIndices } from './use_rule_indices'; import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx index f6fb298feb3d4..f948931f1c393 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useUiSetting$ } from '../../../../../common/lib/kibana'; import type { Rule, RulesSnoozeSettingsMap } from '../../../../rule_management/logic'; import { useFindRules } from '../../../../rule_management/logic/use_find_rules'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts index 6330c1ad207c3..1ed7f4e76c742 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { RULES_TABLE_MAX_PAGE_SIZE } from '../../../../../../common/constants'; import type { RulesTableStorageSavedState, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx index a8e570fd22713..d4593b64d60e4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useReplaceUrlParams } from '../../../../../common/utils/global_query_string/helpers'; import { useKibana } from '../../../../../common/lib/kibana'; import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx index f0480cbef8f3b..ec8a06c621f02 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { LogLevelEnum, @@ -39,9 +39,9 @@ describe('useExecutionEvents', () => { it('calls the API via fetchRuleExecutionEvents', async () => { const fetchRuleExecutionEvents = jest.spyOn(api, 'fetchRuleExecutionEvents'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchRuleExecutionEvents).toHaveBeenCalledTimes(1); expect(fetchRuleExecutionEvents).toHaveBeenLastCalledWith( @@ -50,7 +50,7 @@ describe('useExecutionEvents', () => { }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -58,28 +58,28 @@ describe('useExecutionEvents', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); - - // It switches to a success state - expect(result.current.isLoading).toEqual(false); - expect(result.current.isSuccess).toEqual(true); - expect(result.current.isError).toEqual(false); - expect(result.current.data).toEqual({ - events: [ - { - timestamp: '2021-12-29T10:42:59.996Z', - sequence: 0, - level: LogLevelEnum.info, - type: RuleExecutionEventTypeEnum['status-change'], - execution_id: 'execution-id-1', - message: 'Rule changed status to "succeeded". Rule execution completed without errors', + await waitFor(() => { + // It switches to a success state + expect(result.current.isLoading).toEqual(false); + expect(result.current.isSuccess).toEqual(true); + expect(result.current.isError).toEqual(false); + expect(result.current.data).toEqual({ + events: [ + { + timestamp: '2021-12-29T10:42:59.996Z', + sequence: 0, + level: LogLevelEnum.info, + type: RuleExecutionEventTypeEnum['status-change'], + execution_id: 'execution-id-1', + message: 'Rule changed status to "succeeded". Rule execution completed without errors', + }, + ], + pagination: { + page: 1, + per_page: 20, + total: 1, }, - ], - pagination: { - page: 1, - per_page: 20, - total: 1, - }, + }); }); }); @@ -87,7 +87,7 @@ describe('useExecutionEvents', () => { const exception = new Error('Boom!'); jest.spyOn(api, 'fetchRuleExecutionEvents').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -95,18 +95,18 @@ describe('useExecutionEvents', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); - - // It switches to an error state - expect(result.current.isLoading).toEqual(false); - expect(result.current.isSuccess).toEqual(false); - expect(result.current.isError).toEqual(true); - expect(result.current.error).toEqual(exception); - - // And shows a toast with the caught exception - expect(useToasts().addError).toHaveBeenCalledTimes(1); - expect(useToasts().addError).toHaveBeenCalledWith(exception, { - title: 'Failed to fetch rule execution events', + await waitFor(() => { + // It switches to an error state + expect(result.current.isLoading).toEqual(false); + expect(result.current.isSuccess).toEqual(false); + expect(result.current.isError).toEqual(true); + expect(result.current.error).toEqual(exception); + + // And shows a toast with the caught exception + expect(useToasts().addError).toHaveBeenCalledTimes(1); + expect(useToasts().addError).toHaveBeenCalledWith(exception, { + title: 'Failed to fetch rule execution events', + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx index d5d2e2409e2a3..7e5da70ad0b3d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { useExecutionResults } from './use_execution_results'; import { useToasts } from '../../../../common/lib/kibana'; @@ -48,18 +48,17 @@ describe('useExecutionResults', () => { it('calls the API via fetchRuleExecutionResults', async () => { const fetchRuleExecutionResults = jest.spyOn(api, 'fetchRuleExecutionResults'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); + await waitFor(() => expect(fetchRuleExecutionResults).toHaveBeenCalledTimes(1)); - expect(fetchRuleExecutionResults).toHaveBeenCalledTimes(1); expect(fetchRuleExecutionResults).toHaveBeenLastCalledWith( expect.objectContaining({ ruleId: SOME_RULE_ID }) ); }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -67,10 +66,9 @@ describe('useExecutionResults', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to a success state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(true); expect(result.current.isError).toEqual(false); expect(result.current.data).toEqual({ @@ -107,7 +105,7 @@ describe('useExecutionResults', () => { const exception = new Error('Boom!'); jest.spyOn(api, 'fetchRuleExecutionResults').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -115,10 +113,9 @@ describe('useExecutionResults', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to an error state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(false); expect(result.current.isError).toEqual(true); expect(result.current.error).toEqual(exception); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx index eba2248f82a4d..710cb86970a46 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { useIntegrations } from './use_integrations'; @@ -39,11 +39,9 @@ describe('useIntegrations', () => { it('calls the API via fetchAllIntegrations', async () => { const fetchAllIntegrations = jest.spyOn(fleetIntegrationsApi, 'fetchAllIntegrations'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); - - expect(fetchAllIntegrations).toHaveBeenCalledTimes(1); + await waitFor(() => expect(fetchAllIntegrations).toHaveBeenCalledTimes(1)); }); it('does not call the API when skip is true', async () => { @@ -55,7 +53,7 @@ describe('useIntegrations', () => { }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -63,10 +61,9 @@ describe('useIntegrations', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to a success state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(true); expect(result.current.isError).toEqual(false); expect(result.current.data).toEqual([ @@ -105,7 +102,7 @@ describe('useIntegrations', () => { const exception = new Error('Boom!'); jest.spyOn(fleetIntegrationsApi, 'fetchAllIntegrations').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -113,7 +110,7 @@ describe('useIntegrations', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); // It switches to an error state expect(result.current.isLoading).toEqual(false); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts index 2a07746a6d67a..ba939fabe1e99 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useRuleFromTimeline } from './use_rule_from_timeline'; import { useGetInitialUrlParamValue } from '../../../../common/utils/global_query_string/helpers'; @@ -117,10 +117,11 @@ describe('useRuleFromTimeline', () => { }); it('does not reset timeline sourcerer if it originally had same data view as the timeline used in the rule', async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); - expect(setRuleQuery).toHaveBeenCalled(); + await waitFor(() => { + expect(setRuleQuery).toHaveBeenCalled(); + }); }); }); @@ -147,9 +148,9 @@ describe('useRuleFromTimeline', () => { }); it('if timeline id in URL, set active timeline data view to from timeline data view', async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(setRuleQuery).toHaveBeenCalled(); expect(mockDispatch).toHaveBeenCalledTimes(2); @@ -167,9 +168,9 @@ describe('useRuleFromTimeline', () => { (useGetInitialUrlParamValue as jest.Mock) .mockReturnValueOnce(() => timelineId) .mockReturnValue(() => undefined); - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.loading).toEqual(false); expect(setRuleQuery).toHaveBeenCalledWith({ index: ['awesome-*'], @@ -235,9 +236,9 @@ describe('useRuleFromTimeline', () => { (useGetInitialUrlParamValue as jest.Mock) .mockReturnValueOnce(() => undefined) .mockReturnValue(() => timelineId); - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.loading).toEqual(false); expect(setRuleQuery).toHaveBeenCalledWith({ index: ['awesome-*'], @@ -327,16 +328,17 @@ describe('useRuleFromTimeline', () => { }); it('resets timeline sourcerer if it originally had different data view from the timeline used in the rule', async () => { - const { waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); - await waitForNextUpdate(); - expect(setRuleQuery).toHaveBeenCalled(); - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW', - payload: { - id: 'timeline', - selectedDataViewId: 'security-solution', - selectedPatterns: ['auditbeat-*'], - }, + renderHook(() => useRuleFromTimeline(setRuleQuery)); + await waitFor(() => { + expect(setRuleQuery).toHaveBeenCalled(); + expect(mockDispatch).toHaveBeenNthCalledWith(2, { + type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW', + payload: { + id: 'timeline', + selectedDataViewId: 'security-solution', + selectedPatterns: ['auditbeat-*'], + }, + }); }); }); });