[React18] Migrate test suites to account for testing library upgrades security-solution (#201176)

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 <elasticmachine@users.noreply.github.com>
This commit is contained in:
Eyo O. Eyo 2024-12-30 15:23:51 +01:00 committed by GitHub
parent 2656adbc87
commit f3d7fa7d12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
93 changed files with 665 additions and 824 deletions

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { usePanelSideNavItems } from './use_panel_side_nav_items';
import { SecurityPageName } from '@kbn/security-solution-navigation';

View file

@ -5,13 +5,10 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { mockQuery, mockAlertCountByRuleResult, parsedAlertCountByRuleResult } from './mock_data';
import type {
UseAlertCountByRuleByStatus,
UseAlertCountByRuleByStatusProps,
} from './use_alert_count_by_rule_by_status';
import type { UseAlertCountByRuleByStatusProps } from './use_alert_count_by_rule_by_status';
import { useAlertCountByRuleByStatus } from './use_alert_count_by_rule_by_status';
const dateNow = new Date('2022-04-15T12:00:00.000Z').valueOf();
@ -53,7 +50,7 @@ jest.mock('../../../detections/containers/detection_engine/alerts/use_signal_ind
const renderUseAlertCountByRuleByStatus = (
overrides: Partial<UseAlertCountByRuleByStatusProps> = {}
) =>
renderHook<UseAlertCountByRuleByStatusProps, ReturnType<UseAlertCountByRuleByStatus>>(() =>
renderHook(() =>
useAlertCountByRuleByStatus({
skip: false,
field: 'test_field',

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import React from 'react';
import { TestProviders } from '../../../../mock';

View file

@ -8,7 +8,7 @@ import { createSearchSourceMock } from '@kbn/data-plugin/public/mocks';
import { discoverPluginMock } from '@kbn/discover-plugin/public/mocks';
import { dataViewMock } from '@kbn/discover-utils/src/__mocks__';
import type { SavedSearch } from '@kbn/saved-search-plugin/common';
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, act, renderHook } from '@testing-library/react';
import { createMockStore, mockGlobalState, TestProviders } from '../../mock';
import { useDiscoverInTimelineActions } from './use_discover_in_timeline_actions';
import type { Filter } from '@kbn/es-query';
@ -20,9 +20,6 @@ import * as timelineActions from '../../../timelines/store/actions';
import type { ComponentType, FC, PropsWithChildren } from 'react';
import React from 'react';
import type { DataView } from '@kbn/data-views-plugin/common';
import TestRenderer from 'react-test-renderer';
const { act } = TestRenderer;
let mockDiscoverStateContainerRef = {
current: discoverPluginMock.getDiscoverStateMock({}),
@ -148,7 +145,7 @@ describe('useDiscoverInTimelineActions', () => {
});
describe('getAppStateFromSavedSearch', () => {
it('should reach out to discover to convert app state from saved search', async () => {
const { result, waitFor } = renderTestHook();
const { result } = renderTestHook();
const { appState } = result.current.getAppStateFromSavedSearch(savedSearchMock);
await waitFor(() => {
expect(appState).toMatchObject(
@ -178,7 +175,7 @@ describe('useDiscoverInTimelineActions', () => {
describe('resetDiscoverAppState', () => {
it('should reset Discover AppState to a default state', async () => {
const { result, waitFor } = renderTestHook();
const { result } = renderTestHook();
await result.current.resetDiscoverAppState();
await waitFor(() => {
const appState = mockDiscoverStateContainerRef.current.appState.getState();
@ -186,7 +183,7 @@ describe('useDiscoverInTimelineActions', () => {
});
});
it('should reset Discover time to a default state', async () => {
const { result, waitFor } = renderTestHook();
const { result } = renderTestHook();
await result.current.resetDiscoverAppState();
await waitFor(() => {
const globalState = mockDiscoverStateContainerRef.current.globalState.get();
@ -197,6 +194,15 @@ describe('useDiscoverInTimelineActions', () => {
describe('updateSavedSearch', () => {
it('should add defaults to the savedSearch before updating saved search', async () => {
const { result } = renderTestHook();
await waitFor(() =>
expect(result.current).toEqual(
expect.objectContaining({
updateSavedSearch: expect.any(Function),
})
)
);
await act(async () => {
await result.current.updateSavedSearch(savedSearchMock, TimelineId.active);
});
@ -216,6 +222,7 @@ describe('useDiscoverInTimelineActions', () => {
})
);
});
it('should initialize saved search when it is not set on the timeline model yet', async () => {
const localMockState: State = {
...mockGlobalState,
@ -235,6 +242,13 @@ describe('useDiscoverInTimelineActions', () => {
const LocalTestProvider = getTestProviderWithCustomState(localMockState);
const { result } = renderTestHook(LocalTestProvider);
await waitFor(() =>
expect(result.current).toEqual(
expect.objectContaining({
updateSavedSearch: expect.any(Function),
})
)
);
await act(async () => {
await result.current.updateSavedSearch(savedSearchMock, TimelineId.active);
});
@ -269,6 +283,13 @@ describe('useDiscoverInTimelineActions', () => {
const LocalTestProvider = getTestProviderWithCustomState(localMockState);
const { result } = renderTestHook(LocalTestProvider);
await waitFor(() =>
expect(result.current).toEqual(
expect.objectContaining({
updateSavedSearch: expect.any(Function),
})
)
);
await act(async () => {
await result.current.updateSavedSearch(changedSavedSearchMock, TimelineId.active);
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { APP_ID } from '../../../../common/constants';
import { DEFAULT_STACK_BY_FIELD } from '../../../detections/components/alerts_kpis/common/config';

View file

@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { act, waitFor, renderHook } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import { useAggregatedAnomaliesByJob, AnomalyEntity } from './use_anomalies_search';
@ -70,16 +71,11 @@ describe('useAggregatedAnomaliesByJob', () => {
});
it('refetch calls useSecurityJobs().refetch', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook(
() => useAggregatedAnomaliesByJob({ skip: false, from, to }),
{
wrapper: TestProviders,
}
);
await waitForNextUpdate();
const { result } = renderHook(() => useAggregatedAnomaliesByJob({ skip: false, from, to }), {
wrapper: TestProviders,
});
act(() => {
result.current.refetch();
});
@ -87,20 +83,15 @@ describe('useAggregatedAnomaliesByJob', () => {
});
it('returns formated data', async () => {
await act(async () => {
const jobCount = { key: jobId, doc_count: 99 };
mockAnomaliesSearch.mockResolvedValue({
aggregations: { number_of_anomalies: { buckets: [jobCount] } },
});
const { result, waitForNextUpdate } = renderHook(
() => useAggregatedAnomaliesByJob({ skip: false, from, to }),
{
wrapper: TestProviders,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
const jobCount = { key: jobId, doc_count: 99 };
mockAnomaliesSearch.mockResolvedValue({
aggregations: { number_of_anomalies: { buckets: [jobCount] } },
});
const { result } = renderHook(() => useAggregatedAnomaliesByJob({ skip: false, from, to }), {
wrapper: TestProviders,
});
await waitFor(() =>
expect(result.current.data).toEqual(
expect.arrayContaining([
{
@ -110,55 +101,50 @@ describe('useAggregatedAnomaliesByJob', () => {
entity: AnomalyEntity.Host,
},
])
);
});
)
);
});
it('returns jobs sorted by name', async () => {
await act(async () => {
const firstJobId = 'v3_windows_anomalous_script';
const secondJobId = 'auth_rare_source_ip_for_a_user';
const fistJobCount = { key: firstJobId, doc_count: 99 };
const secondJobCount = { key: secondJobId, doc_count: 99 };
const firstJobSecurityName = '0000001';
const secondJobSecurityName = '0000002';
const firstJob = {
id: firstJobId,
jobState: 'started',
datafeedState: 'started',
customSettings: {
security_app_display_name: firstJobSecurityName,
},
};
const secondJob = {
id: secondJobId,
jobState: 'started',
datafeedState: 'started',
customSettings: {
security_app_display_name: secondJobSecurityName,
},
};
const firstJobId = 'v3_windows_anomalous_script';
const secondJobId = 'auth_rare_source_ip_for_a_user';
const fistJobCount = { key: firstJobId, doc_count: 99 };
const secondJobCount = { key: secondJobId, doc_count: 99 };
const firstJobSecurityName = '0000001';
const secondJobSecurityName = '0000002';
const firstJob = {
id: firstJobId,
jobState: 'started',
datafeedState: 'started',
customSettings: {
security_app_display_name: firstJobSecurityName,
},
};
const secondJob = {
id: secondJobId,
jobState: 'started',
datafeedState: 'started',
customSettings: {
security_app_display_name: secondJobSecurityName,
},
};
mockAnomaliesSearch.mockResolvedValue({
aggregations: { number_of_anomalies: { buckets: [fistJobCount, secondJobCount] } },
});
mockAnomaliesSearch.mockResolvedValue({
aggregations: { number_of_anomalies: { buckets: [fistJobCount, secondJobCount] } },
});
mockUseSecurityJobs.mockReturnValue({
loading: false,
isMlAdmin: true,
jobs: [firstJob, secondJob],
refetch: useSecurityJobsRefetch,
});
mockUseSecurityJobs.mockReturnValue({
loading: false,
isMlAdmin: true,
jobs: [firstJob, secondJob],
refetch: useSecurityJobsRefetch,
});
const { result, waitForNextUpdate } = renderHook(
() => useAggregatedAnomaliesByJob({ skip: false, from, to }),
{
wrapper: TestProviders,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAggregatedAnomaliesByJob({ skip: false, from, to }), {
wrapper: TestProviders,
});
await waitFor(() => {
const names = result.current.data.map(({ name }) => name);
expect(names[0]).toEqual(firstJobSecurityName);
@ -167,18 +153,11 @@ describe('useAggregatedAnomaliesByJob', () => {
});
it('does not throw error when aggregations is undefined', async () => {
await act(async () => {
mockAnomaliesSearch.mockResolvedValue({});
const { waitForNextUpdate } = renderHook(
() => useAggregatedAnomaliesByJob({ skip: false, from, to }),
{
wrapper: TestProviders,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
expect(mockAddToastError).not.toBeCalled();
mockAnomaliesSearch.mockResolvedValue({});
renderHook(() => useAggregatedAnomaliesByJob({ skip: false, from, to }), {
wrapper: TestProviders,
});
await waitFor(() => expect(mockAddToastError).not.toBeCalled());
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions';
import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license';
@ -38,12 +38,12 @@ describe('useInstalledSecurityJobs', () => {
});
it('returns jobs and permissions', async () => {
const { result, waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs(), {
const { result } = renderHook(() => useInstalledSecurityJobs(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
expect(result.current.jobs).toHaveLength(3);
await waitFor(() => expect(result.current.jobs).toHaveLength(3));
expect(result.current.jobs).toEqual(
expect.arrayContaining([
{
@ -71,25 +71,26 @@ describe('useInstalledSecurityJobs', () => {
});
it('filters out non-security jobs', async () => {
const { result, waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs(), {
const { result } = renderHook(() => useInstalledSecurityJobs(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
await waitFor(() => expect(result.current.jobs.length).toBeGreaterThan(0));
expect(result.current.jobs.length).toBeGreaterThan(0);
expect(result.current.jobs.every(isSecurityJob)).toEqual(true);
});
it('renders a toast error if the ML call fails', async () => {
(getJobsSummary as jest.Mock).mockRejectedValue('whoops');
const { waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs(), {
renderHook(() => useInstalledSecurityJobs(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', {
title: 'Security job fetch failure',
});
await waitFor(() =>
expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', {
title: 'Security job fetch failure',
})
);
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import { buildMockJobsSummary, getJobsSummaryResponseMock } from '../../ml_popover/api.mock';
import { useInstalledSecurityJobs } from './use_installed_security_jobs';

View file

@ -6,7 +6,7 @@
*/
import React from 'react';
import { render, act } from '@testing-library/react';
import { render } from '@testing-library/react';
import { mockAnomalies } from '../mock';
import { cloneDeep } from 'lodash/fp';
import { ExplorerLink } from './create_explorer_link';
@ -27,23 +27,21 @@ describe('create_explorer_link', () => {
const ml = { locator };
const http = { basePath: { get: jest.fn(() => {}) } };
await act(async () => {
const { findByText } = render(
<KibanaContextProvider services={{ ml, http }}>
<ExplorerLink
linkName={'Open in Anomaly Explorer'}
startDate={'1970'}
endDate={'3000'}
score={anomalies.anomalies[0]}
/>
</KibanaContextProvider>
);
const { findByText } = render(
<KibanaContextProvider services={{ ml, http }}>
<ExplorerLink
linkName={'Open in Anomaly Explorer'}
startDate={'1970'}
endDate={'3000'}
score={anomalies.anomalies[0]}
/>
</KibanaContextProvider>
);
const url = (await findByText('Open in Anomaly Explorer')).getAttribute('href');
const url = (await findByText('Open in Anomaly Explorer')).getAttribute('href');
expect(url).toEqual(
"/app/ml/explorer?_g=(ml:(jobIds:!(job-1)),refreshInterval:(pause:!t,value:0),time:(from:'1970-01-01T00:00:00.000Z',mode:absolute,to:'3000-01-01T00:00:00.000Z'))&_a=(explorer:(mlExplorerFilter:(),mlExplorerSwimlane:()))"
);
});
expect(url).toEqual(
"/app/ml/explorer?_g=(ml:(jobIds:!(job-1)),refreshInterval:(pause:!t,value:0),time:(from:'1970-01-01T00:00:00.000Z',mode:absolute,to:'3000-01-01T00:00:00.000Z'))&_a=(explorer:(mlExplorerFilter:(),mlExplorerSwimlane:()))"
);
});
});

View file

@ -8,8 +8,7 @@
import { ALERT_WORKFLOW_ASSIGNEE_IDS } from '@kbn/rule-data-utils';
import type { BulkActionsConfig } from '@kbn/triggers-actions-ui-plugin/public/types';
import type { TimelineItem } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/bulk_actions/components/toolbar';
import { act, fireEvent, render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { act, fireEvent, render, renderHook } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import type {

View file

@ -6,8 +6,7 @@
*/
import { ALERT_WORKFLOW_TAGS } from '@kbn/rule-data-utils';
import { act, fireEvent, render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { act, fireEvent, render, renderHook } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import type {
UseBulkAlertTagsItemsProps,

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RenderHookResult, RenderResult } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react-hooks';
import type { RenderHookResult } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import { securityMock } from '@kbn/security-plugin/public/mocks';
import type { AuthenticatedUser } from '@kbn/security-plugin/common';
@ -38,9 +38,9 @@ const licenseServiceMock = licenseService as jest.Mocked<typeof licenseService>;
describe('When using useEndpointPrivileges hook', () => {
let authenticatedUser: AuthenticatedUser;
let result: RenderResult<EndpointPrivileges>;
let result: RenderHookResult<EndpointPrivileges, void>['result'];
let unmount: ReturnType<typeof renderHook>['unmount'];
let render: () => RenderHookResult<void, EndpointPrivileges>;
let render: () => RenderHookResult<EndpointPrivileges, void>;
beforeEach(() => {
authenticatedUser = securityMock.createMockAuthenticatedUser({

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { securityMock } from '@kbn/security-plugin/public/mocks';
import { mockUserProfiles } from './mock';
@ -39,16 +39,13 @@ describe('useBulkGetUserProfiles hook', () => {
const userProfiles = useKibana().services.security.userProfiles;
const spyOnUserProfiles = jest.spyOn(userProfiles, 'bulkGet');
const assigneesIds = new Set(['user1']);
const { result, waitForNextUpdate } = renderHook(
() => useBulkGetUserProfiles({ uids: assigneesIds }),
{
wrapper: TestProviders,
}
);
await waitForNextUpdate();
const { result } = renderHook(() => useBulkGetUserProfiles({ uids: assigneesIds }), {
wrapper: TestProviders,
});
await waitFor(() => expect(result.current.isLoading).toEqual(false));
expect(spyOnUserProfiles).toHaveBeenCalledTimes(1);
expect(result.current.isLoading).toEqual(false);
expect(result.current.data).toEqual(mockUserProfiles);
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { securityMock } from '@kbn/security-plugin/public/mocks';
import { mockCurrentUserProfile } from './mock';
@ -38,13 +38,12 @@ describe('useGetCurrentUserProfile hook', () => {
it('returns current user', async () => {
const userProfiles = useKibana().services.security.userProfiles;
const spyOnUserProfiles = jest.spyOn(userProfiles, 'getCurrent');
const { result, waitForNextUpdate } = renderHook(() => useGetCurrentUserProfile(), {
const { result } = renderHook(() => useGetCurrentUserProfile(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
await waitFor(() => expect(result.current.isLoading).toEqual(false));
expect(spyOnUserProfiles).toHaveBeenCalledTimes(1);
expect(result.current.isLoading).toEqual(false);
expect(result.current.data).toEqual(mockCurrentUserProfile);
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { useSuggestUsers } from './use_suggest_users';
import * as api from './api';
@ -27,12 +27,11 @@ describe('useSuggestUsers hook', () => {
it('returns an array of userProfiles', async () => {
const spyOnUserProfiles = jest.spyOn(api, 'suggestUsers');
const { result, waitForNextUpdate } = renderHook(() => useSuggestUsers({ searchTerm: '' }), {
const { result } = renderHook(() => useSuggestUsers({ searchTerm: '' }), {
wrapper: TestProviders,
});
await waitForNextUpdate();
await waitFor(() => expect(result.current.isLoading).toEqual(false));
expect(spyOnUserProfiles).toHaveBeenCalledTimes(1);
expect(result.current.isLoading).toEqual(false);
expect(result.current.data).toEqual(mockUserProfiles);
});
});

View file

@ -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 { mockExtraFilter, wrapper } from '../../../mocks';
import { useLensAttributes } from '../../../use_lens_attributes';

View file

@ -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 { wrapper } from '../../../mocks';
import { useLensAttributes } from '../../../use_lens_attributes';

View file

@ -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 { wrapper } from '../../../mocks';
import { useLensAttributes } from '../../../use_lens_attributes';

View file

@ -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 { mockRulePreviewFilter, wrapper } from '../../../mocks';
import { useLensAttributes } from '../../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { useRouteSpy } from '../../../../utils/route/use_route_spy';
import { wrapper } from '../../mocks';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RenderResult } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react-hooks';
import type { RenderHookResult } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import type { LensAttributes } from '../../types';
@ -34,7 +34,7 @@ jest.mock('../../../../utils/route/use_route_spy', () => ({
}));
describe('getDnsTopDomainsLensAttributes', () => {
let result: RenderResult<LensAttributes | null>;
let result: RenderHookResult<LensAttributes | null, unknown>['result'];
const render = () => {
const hookRenderResponse = renderHook(
() =>

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { wrapper } from '../../mocks';
import { useLensAttributes } from '../../use_lens_attributes';

View file

@ -48,7 +48,7 @@ const mockCreateStoreWithQueryFilters = () => {
return createMockStore(myState);
};
export const wrapper = ({ children }: { children: React.ReactElement }) => (
export const wrapper = ({ children }: React.PropsWithChildren) => (
<TestProviders store={mockCreateStoreWithQueryFilters()}>{children}</TestProviders>
);

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import React from 'react';
import { mockAttributes } from './mocks';
import { DEFAULT_ACTIONS, useActions } from './use_actions';

View file

@ -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 { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__';
import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric';
import { useAddToExistingCase } from './use_add_to_existing_case';

View file

@ -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 { useKibana as mockUseKibana } from '../../lib/kibana/__mocks__';
import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric';
import { useAddToNewCase } from './use_add_to_new_case';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { getExternalAlertLensAttributes } from './lens_attributes/common/external_alert';
import { useLensAttributes } from './use_lens_attributes';

View file

@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { toMountPoint } from '@kbn/react-kibana-mount';
import { useSaveToLibrary } from './use_save_to_library';
import { useKibana } from '../../lib/kibana';

View file

@ -7,7 +7,7 @@
import { createMockStore, mockGlobalState, TestProviders } from '../../mock';
import { useVisualizationResponse } from './use_visualization_response';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import React from 'react';
import { parseVisualizationData } from './utils';

View file

@ -5,33 +5,19 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { noop } from 'lodash/fp';
import type { UseTimelineLastEventTimeArgs } from '.';
import { waitFor, renderHook } from '@testing-library/react';
import { BehaviorSubject } from 'rxjs';
import { useTimelineLastEventTime } from '.';
import { LastEventIndexKey } from '../../../../../common/search_strategy';
import { useKibana } from '../../../lib/kibana';
const mockSearchStrategy = jest.fn();
const mockUseKibana = {
services: {
data: {
search: {
search: mockSearchStrategy.mockReturnValue({
unsubscribe: jest.fn(),
subscribe: jest.fn(({ next, error }) => {
const mockData = {
lastSeen: '1 minute ago',
};
try {
next(mockData);
/* eslint-disable no-empty */
} catch (e) {}
return {
unsubscribe: jest.fn(),
};
}),
}),
search: mockSearchStrategy,
},
},
notifications: {
@ -53,67 +39,68 @@ jest.mock('../../../lib/kibana', () => ({
}));
describe('useTimelineLastEventTime', () => {
let searchStrategy$: BehaviorSubject<{ lastSeen: string | null; errorMessage?: string }>;
beforeEach(() => {
jest.clearAllMocks();
jest.useFakeTimers({ legacyFakeTimers: true });
searchStrategy$ = new BehaviorSubject<{ lastSeen: string | null; errorMessage?: string }>({
lastSeen: null,
});
mockSearchStrategy.mockReturnValue(searchStrategy$.asObservable());
(useKibana as jest.Mock).mockReturnValue(mockUseKibana);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should init', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
string,
[boolean, UseTimelineLastEventTimeArgs]
>(() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
await waitForNextUpdate();
expect(result.current).toEqual([
false,
{ errorMessage: undefined, lastSeen: null, refetch: noop },
]);
});
const { result } = renderHook(() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
expect(result.current).toEqual([
false,
{ errorMessage: undefined, lastSeen: null, refetch: expect.any(Function) },
]);
});
it('should call search strategy', async () => {
await act(async () => {
const { waitForNextUpdate } = renderHook<string, [boolean, UseTimelineLastEventTimeArgs]>(
() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
await waitForNextUpdate();
await waitForNextUpdate();
renderHook(() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
await waitFor(() =>
expect(mockSearchStrategy.mock.calls[0][0]).toEqual({
defaultIndex: [],
details: {},
factoryQueryType: 'eventsLastEventTime',
indexKey: 'hostDetails',
});
});
})
);
});
it('should set response', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
string,
[boolean, UseTimelineLastEventTimeArgs]
>(() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
await waitForNextUpdate();
await waitForNextUpdate();
expect(result.current[1].lastSeen).toEqual('1 minute ago');
searchStrategy$.next({
lastSeen: '1 minute ago',
});
const { result } = renderHook(() =>
useTimelineLastEventTime({
indexKey: LastEventIndexKey.hostDetails,
details: {},
indexNames: [],
})
);
await waitFor(() => expect(result.current[1].lastSeen).toEqual('1 minute ago'));
});
});

View file

@ -5,9 +5,8 @@
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { act, waitFor, renderHook } from '@testing-library/react';
import { useKibana } from '../../lib/kibana';
import type { UseMessagesStorage } from './use_messages_storage';
import { useMessagesStorage } from './use_messages_storage';
jest.mock('../../lib/kibana');
@ -18,81 +17,71 @@ describe('useLocalStorage', () => {
});
it('should return an empty array when there is no messages', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { getMessages } = result.current;
const { result } = renderHook(() => useMessagesStorage());
const { getMessages } = result.current;
await waitFor(() => {
expect(getMessages('case')).toEqual([]);
});
});
it('should add a message', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { getMessages, addMessage } = result.current;
const { result } = renderHook(() => useMessagesStorage());
const { getMessages, addMessage } = result.current;
act(() => {
addMessage('case', 'id-1');
expect(getMessages('case')).toEqual(['id-1']);
});
await waitFor(() => expect(getMessages('case')).toEqual(['id-1']));
});
it('should add multiple messages', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { getMessages, addMessage } = result.current;
const { result } = renderHook(() => useMessagesStorage());
const { getMessages, addMessage } = result.current;
act(() => {
addMessage('case', 'id-1');
addMessage('case', 'id-2');
expect(getMessages('case')).toEqual(['id-1', 'id-2']);
});
await waitFor(() => expect(getMessages('case')).toEqual(['id-1', 'id-2']));
});
it('should remove a message', async () => {
const { result } = renderHook(() => useMessagesStorage());
const { getMessages, addMessage, removeMessage } = result.current;
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { getMessages, addMessage, removeMessage } = result.current;
addMessage('case', 'id-1');
addMessage('case', 'id-2');
removeMessage('case', 'id-2');
expect(getMessages('case')).toEqual(['id-1']);
});
await waitFor(() => expect(getMessages('case')).toEqual(['id-1']));
});
it('should return presence of a message', async () => {
const { result } = renderHook(() => useMessagesStorage());
const { hasMessage, addMessage, removeMessage } = result.current;
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { hasMessage, addMessage, removeMessage } = result.current;
addMessage('case', 'id-1');
addMessage('case', 'id-2');
removeMessage('case', 'id-2');
});
await waitFor(() => {
expect(hasMessage('case', 'id-1')).toEqual(true);
expect(hasMessage('case', 'id-2')).toEqual(false);
});
});
it('should clear all messages', async () => {
const { result } = renderHook(() => useMessagesStorage());
const { getMessages, addMessage, clearAllMessages } = result.current;
await act(async () => {
const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() =>
useMessagesStorage()
);
await waitForNextUpdate();
const { getMessages, addMessage, clearAllMessages } = result.current;
addMessage('case', 'id-1');
addMessage('case', 'id-2');
clearAllMessages('case');
expect(getMessages('case')).toEqual([]);
});
await waitFor(() => expect(getMessages('case')).toEqual([]));
});
});

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RenderResult, WaitForNextUpdate } from '@testing-library/react-hooks';
import { renderHook, act, cleanup } from '@testing-library/react-hooks';
import type { RenderHookResult } from '@testing-library/react';
import { waitFor, act, cleanup, renderHook } from '@testing-library/react';
import type { QueryToggle } from '.';
import { useQueryToggle } from '.';
import type { RouteSpyState } from '../../utils/route/types';
@ -26,8 +26,8 @@ jest.mock('../../utils/route/use_route_spy', () => ({
}));
describe('useQueryToggle', () => {
let result: RenderResult<QueryToggle>;
let waitForNextUpdate: WaitForNextUpdate;
let result: RenderHookResult<QueryToggle, unknown>['result'];
const mockSet = jest.fn();
beforeAll(() => {
(useKibana as jest.Mock).mockReturnValue({
@ -43,11 +43,9 @@ describe('useQueryToggle', () => {
jest.clearAllMocks();
});
it('Toggles local storage', async () => {
await act(async () => {
({ result, waitForNextUpdate } = renderHook(() => useQueryToggle('queryId')));
await waitForNextUpdate();
expect(result.current.toggleStatus).toEqual(true);
});
({ result } = renderHook(() => useQueryToggle('queryId')));
await waitFor(() => expect(result.current.toggleStatus).toEqual(true));
act(() => {
result.current.setToggleStatus(false);
});
@ -56,11 +54,9 @@ describe('useQueryToggle', () => {
cleanup();
});
it('null storage key, do not set', async () => {
await act(async () => {
({ result, waitForNextUpdate } = renderHook(() => useQueryToggle()));
await waitForNextUpdate();
expect(result.current.toggleStatus).toEqual(true);
});
({ result } = renderHook(() => useQueryToggle()));
await waitFor(() => expect(result.current.toggleStatus).toEqual(true));
act(() => {
result.current.setToggleStatus(false);
});

View file

@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import { useUserRelatedHosts } from '.';
import { useSearchStrategy } from '../../use_search_strategy';

View file

@ -4,7 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { TestProviders } from '../../../mock';
import { useHostRelatedUsers } from '.';
import { useSearchStrategy } from '../../use_search_strategy';

View file

@ -5,12 +5,11 @@
* 2.0.
*/
import type { PropsWithChildren } from 'react';
import type { IndexFieldSearch } from './use_data_view';
import { useDataView } from './use_data_view';
import { mocksSource } from './mock';
import { mockGlobalState, TestProviders } from '../../mock';
import { act, renderHook } from '@testing-library/react-hooks';
import { act, renderHook } from '@testing-library/react';
import { useKibana } from '../../lib/kibana';
const mockDispatch = jest.fn();
@ -84,14 +83,11 @@ describe('source/index.tsx', () => {
});
});
it('sets field data for data view', async () => {
const { result } = renderHook(() => useDataView(), {
wrapper: TestProviders,
});
await act(async () => {
const { waitForNextUpdate, result } = renderHook<
PropsWithChildren<{}>,
{ indexFieldsSearch: IndexFieldSearch }
>(() => useDataView(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
await result.current.indexFieldsSearch({ dataViewId: 'neato' });
});
expect(mockDispatch.mock.calls[0][0]).toEqual({
@ -105,14 +101,12 @@ describe('source/index.tsx', () => {
it('should reuse the result for dataView info when cleanCache not passed', async () => {
let indexFieldsSearch: IndexFieldSearch;
const { result } = renderHook(() => useDataView(), {
wrapper: TestProviders,
});
await act(async () => {
const { waitForNextUpdate, result } = renderHook<
PropsWithChildren<{}>,
{ indexFieldsSearch: IndexFieldSearch }
>(() => useDataView(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
indexFieldsSearch = result.current.indexFieldsSearch;
});
@ -134,14 +128,11 @@ describe('source/index.tsx', () => {
it('should not reuse the result for dataView info when cleanCache passed', async () => {
let indexFieldsSearch: IndexFieldSearch;
const { result } = renderHook(() => useDataView(), {
wrapper: TestProviders,
});
await act(async () => {
const { waitForNextUpdate, result } = renderHook<
PropsWithChildren<{}>,
{ indexFieldsSearch: IndexFieldSearch }
>(() => useDataView(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
indexFieldsSearch = result.current.indexFieldsSearch;
});

View file

@ -5,10 +5,9 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { Direction } from '../../../../common/search_strategy';
import type { FirstLastSeenProps } from '../../components/first_last_seen/first_last_seen';
import type { UseFirstLastSeen } from './use_first_last_seen';
import { useFirstLastSeen } from './use_first_last_seen';
@ -22,7 +21,7 @@ const mockUseSearchStrategy = useSearchStrategy as jest.Mock;
const mockSearch = jest.fn();
const renderUseFirstLastSeen = (overrides?: Partial<UseFirstLastSeen>) =>
renderHook<FirstLastSeenProps, ReturnType<typeof useFirstLastSeen>>(() =>
renderHook(() =>
useFirstLastSeen({
order: Direction.asc,
field: 'host.name',

View file

@ -7,81 +7,77 @@
import React, { useEffect } from 'react';
import { TestProviders } from '../../mock';
import type { RenderResult, WaitForNextUpdate } from '@testing-library/react-hooks';
import { renderHook, act, cleanup } from '@testing-library/react-hooks';
import type { RenderHookResult } from '@testing-library/react';
import { waitFor, act, cleanup, renderHook } from '@testing-library/react';
import type { GlobalFullScreen } from '.';
import { useGlobalFullScreen } from '.';
describe('useFullScreen', () => {
describe('with no data-grid present in the dom', () => {
let result: RenderResult<GlobalFullScreen>;
let waitForNextUpdate: WaitForNextUpdate;
let result: RenderHookResult<GlobalFullScreen, unknown>['result'];
test('Default values with no data grid in the dom', async () => {
await act(async () => {
const WrapperContainer: React.FC<{ children?: React.ReactNode }> = ({ children }) => (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
({ result, waitForNextUpdate } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
await waitForNextUpdate();
expect(result.current.globalFullScreen).toEqual(false);
});
const WrapperContainer = ({ children }: React.PropsWithChildren) => (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
({ result } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
await waitFor(() => expect(result.current.globalFullScreen).toEqual(false));
act(() => {
result.current.setGlobalFullScreen(true);
});
expect(result.current.globalFullScreen).toEqual(true);
cleanup();
});
});
describe('with a mock full screen data-grid in the dom', () => {
let result: RenderResult<GlobalFullScreen>;
let waitForNextUpdate: WaitForNextUpdate;
let result: RenderHookResult<GlobalFullScreen, unknown>['result'];
afterEach(() => {
cleanup();
});
test('setting globalFullScreen to true should not remove the chrome removal class and data grid remains open and full screen', async () => {
await act(async () => {
const WrapperContainer: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
useEffect(() => {
document.body.classList.add('euiDataGrid__restrictBody');
}, []);
return (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
};
({ result, waitForNextUpdate } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
await waitForNextUpdate();
});
const WrapperContainer: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
useEffect(() => {
document.body.classList.add('euiDataGrid__restrictBody');
}, []);
return (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
};
({ result } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
act(() => {
result.current.setGlobalFullScreen(true);
});
expect(document.querySelector('.euiDataGrid__restrictBody')).toBeTruthy();
});
test('setting globalFullScreen to false should remove the chrome removal class and data grid remains open and full screen', async () => {
await act(async () => {
const WrapperContainer: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
useEffect(() => {
document.body.classList.add('euiDataGrid__restrictBody');
}, []);
return (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
};
({ result, waitForNextUpdate } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
await waitForNextUpdate();
});
const WrapperContainer: React.FC<React.PropsWithChildren> = ({ children }) => {
useEffect(() => {
document.body.classList.add('euiDataGrid__restrictBody');
}, []);
return (
<div className="euiDataGrid--fullScreen">
<TestProviders>{children}</TestProviders>
</div>
);
};
({ result } = renderHook(() => useGlobalFullScreen(), {
wrapper: WrapperContainer,
}));
act(() => {
result.current.setGlobalFullScreen(false);
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { useGlobalTime } from '.';

View file

@ -6,7 +6,8 @@
*/
import { useSearch, useSearchStrategy } from '.';
import { act, renderHook } from '@testing-library/react-hooks';
import { renderHook, act } from '@testing-library/react';
import { useObservable } from '@kbn/securitysolution-hook-utils';
import type {

View file

@ -7,7 +7,7 @@
import { useQueryTimelineById } from '../../../timelines/components/open_timeline/helpers';
import { useQueryTimelineByIdOnUrlChange } from './use_query_timeline_by_id_on_url_change';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { timelineDefaults } from '../../../timelines/store/defaults';
jest.mock('../use_experimental_features');

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import type { IEsError } from '@kbn/search-errors';
import type { KibanaError, SecurityAppError } from '@kbn/securitysolution-t-grid';

View file

@ -5,8 +5,7 @@
* 2.0.
*/
import type { PropsWithChildren } from 'react';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { TestProviders } from '../mock';
import { SourcererScopeName } from '../../sourcerer/store/model';
import { DEFAULT_DATA_VIEW_ID } from '../../../common/constants';
@ -17,10 +16,7 @@ describe('useDataViewId', () => {
it.each(Object.values(SourcererScopeName))(
'should return the data view id for %s scope',
(scope) => {
const { result } = renderHook<
PropsWithChildren<{ scope: SourcererScopeName }>,
string | undefined
>((props) => useDataViewId(props.scope), {
const { result } = renderHook((props) => useDataViewId(props.scope), {
initialProps: { scope },
wrapper: TestProviders,
});
@ -33,10 +29,7 @@ describe('useDataViewId', () => {
.spyOn(sourcererSelectors, 'sourcererScopeSelectedDataViewId')
.mockImplementationOnce(() => null);
const { result } = renderHook<
PropsWithChildren<{ scope: SourcererScopeName }>,
string | undefined
>((props) => useDataViewId(props.scope), {
const { result } = renderHook((props) => useDataViewId(props.scope), {
initialProps: { scope: SourcererScopeName.default },
wrapper: TestProviders,
});

View file

@ -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 { useErrorToast } from './use_error_toast';
jest.mock('./use_app_toasts');

View file

@ -5,9 +5,9 @@
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { act, waitFor, renderHook } from '@testing-library/react';
import type { RequestName } from './request_names';
import type { OptionsParam, RequestFnParam, Result } from './use_fetch';
import type { OptionsParam } from './use_fetch';
import { useFetch } from './use_fetch';
export const mockEndTracking = jest.fn();
@ -28,14 +28,10 @@ type Parameters = typeof parameters;
const response = 'someData';
const mockFetchFn = jest.fn(async (_: Parameters) => response);
type UseFetchParams = [RequestName, RequestFnParam<Parameters, string>, OptionsParam<Parameters>];
const abortController = new AbortController();
const renderUseFetch = (options?: OptionsParam<Parameters>) =>
renderHook<UseFetchParams, Result<Parameters, string, unknown>>(() =>
useFetch(requestName, mockFetchFn, options)
);
renderHook(() => useFetch(requestName, mockFetchFn, options));
describe('useFetch', () => {
beforeEach(() => {
@ -55,7 +51,7 @@ describe('useFetch', () => {
});
it('should call fetch', async () => {
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
expect(result.current.data).toEqual(undefined);
expect(result.current.isLoading).toEqual(false);
@ -63,17 +59,17 @@ describe('useFetch', () => {
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
await waitFor(() => expect(result.current.isLoading).toEqual(false));
expect(result.current.data).toEqual(response);
expect(result.current.isLoading).toEqual(false);
expect(result.current.error).toEqual(undefined);
expect(mockFetchFn).toHaveBeenCalledWith(parameters, abortController.signal);
});
it('should call fetch if initialParameters option defined', async () => {
const { result, waitForNextUpdate } = renderUseFetch({ initialParameters: parameters });
const { result } = renderUseFetch({ initialParameters: parameters });
expect(result.current.data).toEqual(undefined);
expect(result.current.isLoading).toEqual(true);
@ -81,32 +77,28 @@ describe('useFetch', () => {
expect(mockFetchFn).toHaveBeenCalledWith(parameters, abortController.signal);
await act(async () => {
await waitForNextUpdate();
});
await waitFor(() => expect(result.current.isLoading).toEqual(false));
expect(result.current.data).toEqual(response);
expect(result.current.isLoading).toEqual(false);
expect(result.current.error).toEqual(undefined);
});
it('should refetch with same parameters', async () => {
const { result, waitForNextUpdate } = renderUseFetch({ initialParameters: parameters });
const { result } = renderUseFetch({ initialParameters: parameters });
expect(mockFetchFn).toHaveBeenCalledTimes(1);
expect(mockFetchFn).toHaveBeenCalledWith(parameters, abortController.signal);
await act(async () => {
result.current.refetch();
await waitForNextUpdate();
});
expect(mockFetchFn).toHaveBeenCalledTimes(1);
await waitFor(() => expect(mockFetchFn).toHaveBeenCalledTimes(1));
expect(mockFetchFn).toHaveBeenCalledWith(parameters, abortController.signal);
});
it('should not call fetch if disabled option defined', async () => {
const { result, waitForNextUpdate } = renderUseFetch({
const { result } = renderUseFetch({
initialParameters: parameters,
disabled: true,
});
@ -119,11 +111,11 @@ describe('useFetch', () => {
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
await waitFor(() => expect(result.current.isLoading).toEqual(true));
expect(result.current.data).toEqual(undefined);
expect(result.current.isLoading).toEqual(true);
expect(result.current.error).toEqual(undefined);
expect(mockFetchFn).not.toHaveBeenCalled();
});
@ -134,16 +126,15 @@ describe('useFetch', () => {
return response;
});
const { result, waitForNextUpdate, unmount } = renderUseFetch();
const { result, unmount } = renderUseFetch();
expect(result.current.data).toEqual(undefined);
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(result.current.data).toEqual(undefined);
await waitFor(() => expect(result.current.data).toEqual(undefined));
});
it('should ignore state change if error but component is unmounted', async () => {
@ -152,35 +143,32 @@ describe('useFetch', () => {
throw new Error();
});
const { result, waitForNextUpdate, unmount } = renderUseFetch();
const { result, unmount } = renderUseFetch();
expect(result.current.error).toEqual(undefined);
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(result.current.error).toEqual(undefined);
await waitFor(() => expect(result.current.error).toEqual(undefined));
});
it('should abort initial request if fetch is called', async () => {
const firstAbortCtrl = new AbortController();
const abortSpy = jest.spyOn(window, 'AbortController').mockReturnValueOnce(firstAbortCtrl);
const { result, waitForNextUpdate } = renderUseFetch({ initialParameters: parameters });
const { result } = renderUseFetch({ initialParameters: parameters });
mockFetchFn.mockImplementationOnce(async () => {
result.current.fetch(parameters);
return response;
});
await act(async () => {
await waitForNextUpdate();
await waitFor(() => {
expect(firstAbortCtrl.signal.aborted).toEqual(true);
});
expect(firstAbortCtrl.signal.aborted).toEqual(true);
abortSpy.mockRestore();
});
@ -188,7 +176,7 @@ describe('useFetch', () => {
const firstAbortCtrl = new AbortController();
const abortSpy = jest.spyOn(window, 'AbortController').mockReturnValueOnce(firstAbortCtrl);
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
mockFetchFn.mockImplementationOnce(async () => {
result.current.fetch(parameters);
@ -197,9 +185,10 @@ describe('useFetch', () => {
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
await waitFor(() => expect(firstAbortCtrl.signal.aborted).toEqual(true));
expect(firstAbortCtrl.signal.aborted).toEqual(true);
abortSpy.mockRestore();
@ -207,51 +196,50 @@ describe('useFetch', () => {
describe('APM tracking', () => {
it('should track with request name', async () => {
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(mockStartTracking).toHaveBeenCalledTimes(1);
await waitFor(() => expect(mockStartTracking).toHaveBeenCalledTimes(1));
expect(mockStartTracking).toHaveBeenCalledWith({ name: requestName });
});
it('should track each request', async () => {
const { result, waitForNextUpdate } = renderUseFetch({
const { result } = renderUseFetch({
initialParameters: parameters,
});
await act(async () => {
await waitForNextUpdate();
await waitFor(() => {
expect(mockFetchFn).toHaveBeenCalledTimes(1);
expect(mockStartTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockStartTracking).toHaveBeenCalledWith({ name: requestName });
});
expect(mockFetchFn).toHaveBeenCalledTimes(1);
expect(mockStartTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockStartTracking).toHaveBeenCalledWith({ name: requestName });
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(mockFetchFn).toHaveBeenCalledTimes(2);
await waitFor(() => expect(mockFetchFn).toHaveBeenCalledTimes(2));
expect(mockStartTracking).toHaveBeenCalledTimes(2);
expect(mockEndTracking).toHaveBeenCalledTimes(2);
});
it('should end success', async () => {
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('success');
await waitFor(() => {
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('success');
});
});
it('should end aborted', async () => {
@ -263,15 +251,16 @@ describe('useFetch', () => {
throw Error('request aborted');
});
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('aborted');
await waitFor(() => {
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('aborted');
});
abortSpy.mockRestore();
});
@ -281,15 +270,16 @@ describe('useFetch', () => {
throw Error('request error');
});
const { result, waitForNextUpdate } = renderUseFetch();
const { result } = renderUseFetch();
await act(async () => {
result.current.fetch(parameters);
await waitForNextUpdate();
});
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('error');
await waitFor(() => {
expect(mockEndTracking).toHaveBeenCalledTimes(1);
expect(mockEndTracking).toHaveBeenCalledWith('error');
});
});
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { TestProviders } from '../mock';
import { useGlobalFilterQuery } from './use_global_filter_query';
import type { Filter, Query } from '@kbn/es-query';

View file

@ -10,8 +10,7 @@
// but is simply documenting the current behavior.
import React from 'react';
import { render } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { render, renderHook } from '@testing-library/react';
import type { Store } from 'redux';
import { createMockStore, kibanaMock, mockGlobalState, TestProviders } from '../mock';
@ -211,8 +210,8 @@ describe('useInvalidFilterQuery', () => {
initialProps: props,
wrapper: getWrapper(store),
});
rerender();
rerender();
rerender(props);
rerender(props);
expect(kibanaMock.notifications.toasts.addError).toHaveBeenCalledTimes(1);
});

View file

@ -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 { SecurityPageName } from '../../app/types';
import { useNavigateToAlertsPageWithFilters } from './use_navigate_to_alerts_page_with_filters';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { useLocation } from 'react-router-dom';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { useDeepEqualSelector } from './use_selector';
import { useKibana } from '../lib/kibana';
import { useResolveConflict } from './use_resolve_conflict';
@ -61,7 +61,7 @@ describe('useResolveConflict', () => {
graphEventId: 'current-graph-event-id',
show: false,
}));
const { result } = renderHook<{}, JSX.Element | null>(() => useResolveConflict());
const { result } = renderHook(() => useResolveConflict());
expect(mockGetLegacyUrlConflict).not.toHaveBeenCalled();
expect(result.current).toEqual(null);
});
@ -78,7 +78,7 @@ describe('useResolveConflict', () => {
graphEventId: 'current-graph-event-id',
show: false,
}));
const { result } = renderHook<{}, JSX.Element | null>(() => useResolveConflict());
const { result } = renderHook(() => useResolveConflict());
expect(mockGetLegacyUrlConflict).not.toHaveBeenCalled();
expect(result.current).toEqual(null);
});
@ -92,7 +92,7 @@ describe('useResolveConflict', () => {
alias_target_id: 'new-id',
},
}));
const { result } = renderHook<{}, JSX.Element | null>(() => useResolveConflict());
const { result } = renderHook(() => useResolveConflict());
expect(mockGetLegacyUrlConflict).not.toHaveBeenCalled();
expect(result.current).toEqual(null);
});
@ -108,7 +108,7 @@ describe('useResolveConflict', () => {
},
}));
mockGetLegacyUrlConflict.mockImplementation(() => mockTextContent);
const { result } = renderHook<{}, JSX.Element | null>(() => useResolveConflict());
const { result } = renderHook(() => useResolveConflict());
expect(mockGetLegacyUrlConflict).toHaveBeenCalledWith({
objectNoun: 'timeline',
currentObjectId: '04e8ffb0-2c2a-11ec-949c-39005af91f70',
@ -142,7 +142,7 @@ describe('useResolveConflict', () => {
}));
mockGetLegacyUrlConflict.mockImplementation(() => mockTextContent);
renderHook(() => useResolveConflict());
const { result } = renderHook<{}, JSX.Element | null>(() => useResolveConflict());
const { result } = renderHook(() => useResolveConflict());
expect(mockGetLegacyUrlConflict).toHaveBeenCalledWith({
objectNoun: 'timeline',
currentObjectId: 'current-saved-object-id',

View file

@ -6,7 +6,7 @@
*/
import { useLocation } from 'react-router-dom';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { useDeepEqualSelector } from './use_selector';
import { useKibana } from '../lib/kibana';
import { useResolveRedirect } from './use_resolve_redirect';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import type { FC, PropsWithChildren } from 'react';
import React from 'react';
import { SecurityPageName } from '../../../common';
@ -36,6 +36,8 @@ const RenderWrapper: FC<PropsWithChildren<unknown>> = ({ children }) => {
describe('use_upselling', () => {
test('useUpsellingComponent returns sections', () => {
const getSectionsValueSpy = jest.spyOn(mockUpselling, 'getSectionsValue');
mockUpselling.setSections({
entity_analytics_panel: TestComponent,
});
@ -44,7 +46,7 @@ describe('use_upselling', () => {
wrapper: RenderWrapper,
});
expect(result.current).toBe(TestComponent);
expect(result.all.length).toBe(1); // assert that it should not cause unnecessary re-renders
expect(getSectionsValueSpy).toHaveBeenCalledTimes(1); // assert that it should not cause unnecessary re-renders
});
test('useUpsellingPage returns pages', () => {
@ -59,6 +61,8 @@ describe('use_upselling', () => {
});
test('useUpsellingMessage returns messages', () => {
const getMessagesValueSpy = jest.spyOn(mockUpselling, 'getMessagesValue');
const testMessage = 'test message';
mockUpselling.setMessages({
investigation_guide: testMessage,
@ -68,7 +72,7 @@ describe('use_upselling', () => {
wrapper: RenderWrapper,
});
expect(result.current).toBe(testMessage);
expect(result.all.length).toBe(1); // assert that it should not cause unnecessary re-renders
expect(getMessagesValueSpy).toHaveBeenCalledTimes(1); // assert that it should not cause unnecessary re-renders
});
test('useUpsellingMessage returns undefined when upsellingMessageId not found', () => {

View file

@ -10,7 +10,7 @@ import type { Capabilities } from '@kbn/core/types';
import { mockGlobalState, TestProviders } from '../mock';
import type { ILicense, LicenseType } from '@kbn/licensing-plugin/common/types';
import type { AppLinkItems, LinkItem, LinksPermissions } from './types';
import { act, renderHook } from '@testing-library/react-hooks';
import { act, waitFor, renderHook } from '@testing-library/react';
import {
useAppLinks,
getAncestorLinksInfo,
@ -83,10 +83,9 @@ const mockLicense = {
const mockUiSettingsClient = uiSettingsServiceMock.createStartContract();
const renderUseAppLinks = () =>
renderHook<{}, AppLinkItems>(() => useAppLinks(), { wrapper: TestProviders });
const renderUseAppLinks = () => renderHook(() => useAppLinks(), { wrapper: TestProviders });
const renderUseLinkExists = (id: SecurityPageName) =>
renderHook<React.PropsWithChildren<SecurityPageName>, boolean>(() => useLinkExists(id), {
renderHook(() => useLinkExists(id), {
wrapper: TestProviders,
});
@ -110,7 +109,7 @@ describe('Security links', () => {
});
it('should filter not allowed links', async () => {
const { result, waitForNextUpdate } = renderUseAppLinks();
const { result } = renderUseAppLinks();
// this link should not be excluded, the test checks all conditions are passed
const networkLinkItem = {
id: SecurityPageName.network,
@ -182,17 +181,16 @@ describe('Security links', () => {
uiSettingsClient: mockUiSettingsClient,
}
);
await waitForNextUpdate();
});
expect(result.current).toStrictEqual([networkLinkItem]);
await waitFor(() => expect(result.current).toStrictEqual([networkLinkItem]));
});
it('should return unauthorized page when page has upselling (serverless)', async () => {
const upselling = new UpsellingService();
upselling.setPages({ [SecurityPageName.network]: () => <span /> });
const { result, waitForNextUpdate } = renderUseAppLinks();
const { result } = renderUseAppLinks();
const networkLinkItem = {
id: SecurityPageName.network,
title: 'Network',
@ -249,16 +247,17 @@ describe('Security links', () => {
uiSettingsClient: mockUiSettingsClient,
}
);
await waitForNextUpdate();
});
expect(result.current).toStrictEqual([{ ...networkLinkItem, unauthorized: true }]);
await waitFor(() =>
expect(result.current).toStrictEqual([{ ...networkLinkItem, unauthorized: true }])
);
});
it('should return unauthorized page when page has upselling (ESS)', async () => {
const upselling = new UpsellingService();
upselling.setPages({ [SecurityPageName.network]: () => <span /> });
const { result, waitForNextUpdate } = renderUseAppLinks();
const { result } = renderUseAppLinks();
const hostLinkItem = {
id: SecurityPageName.hosts,
title: 'Hosts',
@ -278,9 +277,11 @@ describe('Security links', () => {
upselling: mockUpselling,
uiSettingsClient: mockUiSettingsClient,
});
await waitForNextUpdate();
});
expect(result.current).toStrictEqual([{ ...hostLinkItem, unauthorized: true }]);
await waitFor(() =>
expect(result.current).toStrictEqual([{ ...hostLinkItem, unauthorized: true }])
);
// cleanup
mockUpselling.setPages({});
@ -289,7 +290,7 @@ describe('Security links', () => {
it('should filter out experimental page even if it has upselling', async () => {
const upselling = new UpsellingService();
upselling.setPages({ [SecurityPageName.network]: () => <span /> });
const { result, waitForNextUpdate } = renderUseAppLinks();
const { result } = renderUseAppLinks();
const hostLinkItem = {
id: SecurityPageName.hosts,
title: 'Hosts',
@ -310,9 +311,9 @@ describe('Security links', () => {
upselling: mockUpselling,
uiSettingsClient: mockUiSettingsClient,
});
await waitForNextUpdate();
});
expect(result.current).toStrictEqual([]);
await waitFor(() => expect(result.current).toStrictEqual([]));
// cleanup
mockUpselling.setPages({});
@ -331,7 +332,7 @@ describe('Security links', () => {
});
it('should update if the links are removed', async () => {
const { result, waitForNextUpdate } = renderUseLinkExists(SecurityPageName.hostsEvents);
const { result } = renderUseLinkExists(SecurityPageName.hostsEvents);
expect(result.current).toBe(true);
await act(async () => {
updateAppLinks(
@ -350,13 +351,13 @@ describe('Security links', () => {
uiSettingsClient: mockUiSettingsClient,
}
);
await waitForNextUpdate();
});
expect(result.current).toBe(false);
await waitFor(() => expect(result.current).toBe(false));
});
it('should update if the links are added', async () => {
const { result, waitForNextUpdate } = renderUseLinkExists(SecurityPageName.rules);
const { result } = renderUseLinkExists(SecurityPageName.rules);
expect(result.current).toBe(false);
await act(async () => {
updateAppLinks(
@ -382,9 +383,9 @@ describe('Security links', () => {
uiSettingsClient: mockUiSettingsClient,
}
);
await waitForNextUpdate();
});
expect(result.current).toBe(true);
await waitFor(() => expect(result.current).toBe(true));
});
});

View file

@ -6,7 +6,7 @@
*/
import { ExternalPageName } from '@kbn/security-solution-navigation';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { APP_PATH, SecurityPageName } from '../../../common';
import { useFindAppLinksByPath } from './use_find_app_links_by_path';

View file

@ -38,6 +38,10 @@ export const MockAssistantProviderComponent: React.FC<Props> = ({
isAssistantEnabled: true,
};
const mockUserProfileService = {
getCurrent: jest.fn(() => Promise.resolve({ avatar: 'avatar' })),
} as unknown as UserProfileService;
return (
<AssistantProvider
actionTypeRegistry={actionTypeRegistry}
@ -53,7 +57,7 @@ export const MockAssistantProviderComponent: React.FC<Props> = ({
navigateToApp={mockNavigateToApp}
baseConversations={BASE_SECURITY_CONVERSATIONS}
currentAppId={'test'}
userProfileService={jest.fn() as unknown as UserProfileService}
userProfileService={mockUserProfileService}
>
{children}
</AssistantProvider>

View file

@ -53,13 +53,13 @@ window.scrollTo = jest.fn();
const MockKibanaContextProvider = createKibanaContextProviderMock();
/** A utility for wrapping children in the providers required to run most tests */
export const TestProvidersComponent: React.FC<Props> = ({
export const TestProvidersComponent = ({
children,
store = createMockStore(),
startServices,
onDragEnd = jest.fn(),
cellActions = [],
}) => {
}: React.PropsWithChildren<Props>) => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {

View file

@ -10,7 +10,7 @@ import type { SecuritySubPlugins } from '../../app/types';
import { createInitialState } from './reducer';
import { mockIndexPattern, mockSourcererState, TestProviders, createMockStore } from '../mock';
import { useSourcererDataView } from '../../sourcerer/containers';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { initialGroupingState } from './grouping/reducer';
import { initialAnalyzerState } from '../../resolver/store/helpers';
import { initialNotesState } from '../../notes/store/notes.slice';

View file

@ -7,7 +7,7 @@
import type { TimelineNonEcsData } from '@kbn/timelines-plugin/common';
import { getMappedNonEcsValue, useGetMappedNonEcsValue } from './get_mapped_non_ecs_value';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
describe('getMappedNonEcsValue', () => {
it('should return the correct value', () => {

View file

@ -14,7 +14,7 @@ import {
useReplaceUrlParams,
createHistoryEntry,
} from './helpers';
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { createMemoryHistory } from 'history';
// eslint-disable-next-line no-restricted-imports
import { Router } from 'react-router-dom';

View file

@ -6,7 +6,7 @@
*/
import React from 'react';
import { act, renderHook } from '@testing-library/react-hooks';
import { act, waitFor, renderHook } from '@testing-library/react';
import {
useInitializeUrlParam,
useGlobalQueryString,
@ -56,7 +56,7 @@ describe('global query string', () => {
});
const makeWrapper = (globalUrlParam?: GlobalUrlParam) => {
const wrapper = ({ children }: { children: React.ReactElement }) => (
const wrapper = ({ children }: React.PropsWithChildren) => (
<TestProviders store={makeStore(globalUrlParam ?? {})}>{children}</TestProviders>
);
return wrapper;
@ -196,7 +196,7 @@ describe('global query string', () => {
testEmptyString: '',
},
});
const wrapper = ({ children }: { children: React.ReactElement }) => (
const wrapper = ({ children }: React.PropsWithChildren) => (
<TestProviders store={store}>{children}</TestProviders>
);
@ -306,8 +306,8 @@ describe('global query string', () => {
};
const store = makeStore(globalUrlParam);
const { waitForNextUpdate } = renderHook(() => useSyncGlobalQueryString(), {
wrapper: ({ children }: { children: React.ReactElement }) => (
renderHook(() => useSyncGlobalQueryString(), {
wrapper: ({ children }: React.PropsWithChildren) => (
<TestProviders store={store}>{children}</TestProviders>
),
});
@ -318,11 +318,11 @@ describe('global query string', () => {
store.dispatch(globalUrlParamActions.deregisterUrlParam({ key: urlParamKey }));
});
waitForNextUpdate();
expect(mockHistory.replace).toHaveBeenCalledWith({
search: ``,
});
await waitFor(() =>
expect(mockHistory.replace).toHaveBeenCalledWith({
search: ``,
})
);
});
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { allowedExperimentalValues } from '../../../../common/experimental_features';
import { UpsellingService } from '@kbn/security-solution-upselling/service';
import { updateAppLinks } from '../../links';
@ -77,40 +77,26 @@ describe('use show timeline', () => {
});
it('shows timeline for routes on default', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook(() => useShowTimeline());
await waitForNextUpdate();
const showTimeline = result.current;
expect(showTimeline).toEqual([true]);
});
const { result } = renderHook(() => useShowTimeline());
await waitFor(() => expect(result.current).toEqual([true]));
});
it('hides timeline for blacklist routes', async () => {
mockUseLocation.mockReturnValueOnce({ pathname: '/rules/add_rules' });
await act(async () => {
const { result, waitForNextUpdate } = renderHook(() => useShowTimeline());
await waitForNextUpdate();
const showTimeline = result.current;
expect(showTimeline).toEqual([false]);
});
const { result } = renderHook(() => useShowTimeline());
await waitFor(() => expect(result.current).toEqual([false]));
});
it('shows timeline for partial blacklist routes', async () => {
mockUseLocation.mockReturnValueOnce({ pathname: '/rules' });
await act(async () => {
const { result, waitForNextUpdate } = renderHook(() => useShowTimeline());
await waitForNextUpdate();
const showTimeline = result.current;
expect(showTimeline).toEqual([true]);
});
const { result } = renderHook(() => useShowTimeline());
await waitFor(() => expect(result.current).toEqual([true]));
});
it('hides timeline for sub blacklist routes', async () => {
mockUseLocation.mockReturnValueOnce({ pathname: '/administration/policy' });
await act(async () => {
const { result, waitForNextUpdate } = renderHook(() => useShowTimeline());
await waitForNextUpdate();
const showTimeline = result.current;
expect(showTimeline).toEqual([false]);
});
const { result } = renderHook(() => useShowTimeline());
await waitFor(() => expect(result.current).toEqual([false]));
});
});

View file

@ -6,7 +6,7 @@
*/
import React from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { useUserInfo, ManageUserInfo } from '.';
import type { Capabilities } from '@kbn/core/public';
@ -38,29 +38,24 @@ describe('useUserInfo', () => {
jest.spyOn(sourcererSelectors, 'signalIndexMappingOutdated').mockReturnValue(null);
});
it('returns default state', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook(() => useUserInfo(), {
wrapper: TestProviders,
});
await waitForNextUpdate();
const { result } = renderHook(() => useUserInfo(), {
wrapper: TestProviders,
});
expect(result.all).toHaveLength(1);
expect(result.current).toEqual({
canUserCRUD: null,
canUserREAD: null,
hasEncryptionKey: null,
hasIndexManage: null,
hasIndexMaintenance: null,
hasIndexWrite: null,
hasIndexRead: null,
hasIndexUpdateDelete: null,
isAuthenticated: null,
isSignalIndexExists: null,
loading: true,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
expect(result.error).toBeUndefined();
expect(result.current).toEqual({
canUserCRUD: null,
canUserREAD: null,
hasEncryptionKey: null,
hasIndexManage: null,
hasIndexMaintenance: null,
hasIndexWrite: null,
hasIndexRead: null,
hasIndexUpdateDelete: null,
isAuthenticated: null,
isSignalIndexExists: null,
loading: true,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
});
@ -70,7 +65,7 @@ describe('useUserInfo', () => {
name: 'mock-signal-index',
index_mapping_outdated: true,
});
const wrapper = ({ children }: { children: JSX.Element }) => (
const wrapper = ({ children }: React.PropsWithChildren) => (
<TestProviders>
<UserPrivilegesProvider
kibanaCapabilities={{ siem: { show: true, crud: true } } as unknown as Capabilities}
@ -79,12 +74,11 @@ describe('useUserInfo', () => {
</UserPrivilegesProvider>
</TestProviders>
);
await act(async () => {
const { waitForNextUpdate } = renderHook(() => useUserInfo(), { wrapper });
await waitForNextUpdate();
await waitForNextUpdate();
renderHook(() => useUserInfo(), { wrapper });
await waitFor(() => {
expect(spyOnGetSignalIndex).toHaveBeenCalledTimes(2);
expect(spyOnCreateSignalIndex).toHaveBeenCalledTimes(1);
});
expect(spyOnGetSignalIndex).toHaveBeenCalledTimes(2);
expect(spyOnCreateSignalIndex).toHaveBeenCalledTimes(1);
});
});

View file

@ -5,13 +5,12 @@
* 2.0.
*/
import { act, renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import produce from 'immer';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock';
import { useUserPrivileges } from '../../../../common/components/user_privileges';
import type { Privilege } from './types';
import type { UseAlertsPrivelegesReturn } from './use_alerts_privileges';
import { useAlertsPrivileges } from './use_alerts_privileges';
import { getEndpointPrivilegesInitialStateMock } from '../../../../common/components/user_privileges/endpoint/mocks';
@ -90,11 +89,8 @@ describe('useAlertsPrivileges', () => {
});
test('init', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: null,
hasIndexManage: null,
@ -106,8 +102,8 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: false,
isAuthenticated: null,
loading: false,
});
});
})
);
});
test('if there is an error when fetching user privilege, we should get back false for all index related properties', async () => {
@ -115,12 +111,8 @@ describe('useAlertsPrivileges', () => {
draft.detectionEnginePrivileges.error = new Error('Something went wrong');
});
useUserPrivilegesMock.mockReturnValue(userPrivileges);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: false,
hasIndexManage: false,
@ -132,8 +124,8 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: true,
isAuthenticated: false,
loading: false,
});
});
})
);
});
test('returns "hasIndexManage" is false if the privilege does not have cluster manage', async () => {
@ -145,12 +137,8 @@ describe('useAlertsPrivileges', () => {
});
useUserPrivilegesMock.mockReturnValue(userPrivileges);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: false,
@ -162,8 +150,8 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: true,
isAuthenticated: true,
loading: false,
});
});
})
);
});
test('returns "hasIndexManage" is true if the privilege has cluster manage', async () => {
@ -172,12 +160,8 @@ describe('useAlertsPrivileges', () => {
});
useUserPrivilegesMock.mockReturnValue(userPrivileges);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: true,
@ -189,8 +173,8 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: true,
isAuthenticated: true,
loading: false,
});
});
})
);
});
test('returns "hasKibanaCRUD" as false if user does not have SIEM Kibana "all" privileges', async () => {
@ -200,12 +184,8 @@ describe('useAlertsPrivileges', () => {
});
useUserPrivilegesMock.mockReturnValue(userPrivileges);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: true,
@ -217,8 +197,8 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: true,
isAuthenticated: true,
loading: false,
});
});
})
);
});
test('returns "hasKibanaREAD" as false if user does not have at least SIEM Kibana "read" privileges', async () => {
@ -228,12 +208,8 @@ describe('useAlertsPrivileges', () => {
});
useUserPrivilegesMock.mockReturnValue(userPrivileges);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, UseAlertsPrivelegesReturn>(() =>
useAlertsPrivileges()
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useAlertsPrivileges());
await waitFor(() =>
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: true,
@ -245,7 +221,7 @@ describe('useAlertsPrivileges', () => {
hasKibanaREAD: false,
isAuthenticated: true,
loading: false,
});
});
})
);
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { waitFor, renderHook } from '@testing-library/react';
import { useCasesFromAlerts } from './use_cases_from_alerts';
import * as api from './api';
import { useAppToasts } from '../../../../common/hooks/use_app_toasts';
@ -25,14 +25,13 @@ describe('useCasesFromAlerts hook', () => {
it('returns an array of caseIds', async () => {
const spyOnCases = jest.spyOn(api, 'getCaseIdsFromAlertId');
const { result, waitForNextUpdate } = renderHook(() =>
useCasesFromAlerts({ alertId: 'anAlertId' })
);
await waitForNextUpdate();
expect(spyOnCases).toHaveBeenCalledTimes(1);
expect(result.current).toEqual({
loading: false,
casesInfo: mockCaseIdsFromAlertId,
const { result } = renderHook(() => useCasesFromAlerts({ alertId: 'anAlertId' }));
await waitFor(() => {
expect(spyOnCases).toHaveBeenCalledTimes(1);
expect(result.current).toEqual({
loading: false,
casesInfo: mockCaseIdsFromAlertId,
});
});
});
});

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor, act, renderHook } from '@testing-library/react';
import type { ReturnQueryAlerts } from './use_query';
import { useQueryAlerts } from './use_query';
import { ALERTS_QUERY_NAMES } from './constants';
@ -28,31 +28,20 @@ describe('useQueryAlerts', () => {
});
test('init', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitForNextUpdate();
expect(result.current).toEqual({
loading: false,
data: null,
response: '',
request: '',
setQuery: result.current.setQuery,
refetch: null,
});
const { result } = renderHook(() => useQueryAlerts<unknown, unknown>(defaultProps));
expect(result.current).toEqual({
loading: true,
data: null,
response: '',
request: '',
setQuery: result.current.setQuery,
refetch: null,
});
});
test('fetch alerts data', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitFor(() =>
expect(result.current).toEqual({
loading: false,
data: alertsMock,
@ -60,61 +49,48 @@ describe('useQueryAlerts', () => {
request: JSON.stringify({ index: [indexName] ?? [''], body: mockAlertsQuery }, null, 2),
setQuery: result.current.setQuery,
refetch: result.current.refetch,
});
});
})
);
});
test('re-fetch alerts data', async () => {
const spyOnfetchQueryAlerts = jest.spyOn(api, 'fetchQueryAlerts');
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitForNextUpdate();
await waitForNextUpdate();
if (result.current.refetch) {
result.current.refetch();
}
await waitForNextUpdate();
expect(spyOnfetchQueryAlerts).toHaveBeenCalledTimes(2);
const { result } = renderHook(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitFor(() => expect(result.current.refetch).toBeDefined());
act(() => {
result.current.refetch!();
});
await waitFor(() => expect(spyOnfetchQueryAlerts).toHaveBeenCalledTimes(2));
});
test('fetch alert when index name changed', async () => {
const spyOnfetchRules = jest.spyOn(api, 'fetchQueryAlerts');
await act(async () => {
const { rerender, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>((args) => useQueryAlerts({ ...defaultProps, query: args[0], indexName: args[1] }), {
const { rerender } = renderHook<ReturnQueryAlerts<unknown, unknown>, [object, string]>(
(args) => useQueryAlerts({ ...defaultProps, query: args[0], indexName: args[1] }),
{
initialProps: [mockAlertsQuery, indexName],
});
await waitForNextUpdate();
await waitForNextUpdate();
rerender([mockAlertsQuery, 'new-mock-index-name']);
await waitForNextUpdate();
expect(spyOnfetchRules).toHaveBeenCalledTimes(2);
});
}
);
rerender([mockAlertsQuery, 'new-mock-index-name']);
await waitFor(() => expect(spyOnfetchRules).toHaveBeenCalledTimes(2));
});
test('fetch alert when query object changed', async () => {
const spyOnfetchRules = jest.spyOn(api, 'fetchQueryAlerts');
await act(async () => {
const { result, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>((args) => useQueryAlerts({ ...defaultProps, query: args[0], indexName: args[1] }), {
const { result } = renderHook<ReturnQueryAlerts<unknown, unknown>, [object, string]>(
(args) => useQueryAlerts({ ...defaultProps, query: args[0], indexName: args[1] }),
{
initialProps: [mockAlertsQuery, indexName],
});
await waitForNextUpdate();
await waitForNextUpdate();
if (result.current.setQuery) {
result.current.setQuery({ ...mockAlertsQuery });
}
await waitForNextUpdate();
expect(spyOnfetchRules).toHaveBeenCalledTimes(2);
});
);
await waitFor(() => expect(result.current.setQuery).toBeDefined());
result.current.setQuery({ ...mockAlertsQuery });
await waitFor(() => expect(spyOnfetchRules).toHaveBeenCalledTimes(2));
});
test('if there is an error when fetching data, we should get back the init value for every properties', async () => {
@ -122,12 +98,8 @@ describe('useQueryAlerts', () => {
spyOnGetUserPrivilege.mockImplementation(() => {
throw new Error('Something went wrong, let see what happen');
});
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, ReturnQueryAlerts<unknown, unknown>>(
() => useQueryAlerts<unknown, unknown>(defaultProps)
);
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useQueryAlerts<unknown, unknown>(defaultProps));
await waitFor(() =>
expect(result.current).toEqual({
loading: false,
data: null,
@ -135,25 +107,18 @@ describe('useQueryAlerts', () => {
request: '',
setQuery: result.current.setQuery,
refetch: result.current.refetch,
});
});
})
);
});
test('skip', async () => {
const abortSpy = jest.spyOn(AbortController.prototype, 'abort');
await act(async () => {
const localProps = { ...defaultProps, skip: false };
const { rerender, waitForNextUpdate } = renderHook<
[object, string],
ReturnQueryAlerts<unknown, unknown>
>(() => useQueryAlerts<unknown, unknown>(localProps));
await waitForNextUpdate();
await waitForNextUpdate();
const localProps = { ...defaultProps, skip: false };
const { rerender } = renderHook(() => useQueryAlerts<unknown, unknown>(localProps));
localProps.skip = true;
act(() => rerender());
act(() => rerender());
expect(abortSpy).toHaveBeenCalledTimes(2);
});
localProps.skip = true;
rerender();
rerender();
expect(abortSpy).toHaveBeenCalledTimes(2);
});
});

View file

@ -4,10 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import type { PropsWithChildren } from 'react';
import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor, act, renderHook } from '@testing-library/react';
import { TestProvidersWithPrivileges } from '../../../../common/mock';
import type { ReturnSignalIndex } from './use_signal_index';
import { useSignalIndex } from './use_signal_index';
import * as api from './api';
import { useAppToastsMock } from '../../../../common/hooks/use_app_toasts.mock';
@ -31,35 +29,26 @@ describe('useSignalIndex', () => {
});
test('init', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
expect(result.current).toEqual({
createDeSignalIndex: null,
loading: true,
signalIndexExists: null,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
expect(result.current).toEqual({
createDeSignalIndex: null,
loading: false,
signalIndexExists: null,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
});
test('fetch alerts info', async () => {
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => {
expect(result.current.loading).toBe(false);
expect(result.current).toEqual({
createDeSignalIndex: result.current.createDeSignalIndex,
loading: false,
@ -71,48 +60,39 @@ describe('useSignalIndex', () => {
});
test('make sure that createSignalIndex is giving back the signal info', async () => {
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => expect(result.current.createDeSignalIndex).toBeDefined());
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
if (result.current.createDeSignalIndex != null) {
await result.current.createDeSignalIndex();
}
await waitForNextUpdate();
await result.current.createDeSignalIndex!();
});
await waitFor(() =>
expect(result.current).toEqual({
createDeSignalIndex: result.current.createDeSignalIndex,
loading: false,
signalIndexExists: true,
signalIndexName: 'mock-signal-index',
signalIndexMappingOutdated: false,
});
});
})
);
});
test('make sure that createSignalIndex have been called when trying to create signal index', async () => {
const spyOnCreateSignalIndex = jest.spyOn(api, 'createSignalIndex');
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
if (result.current.createDeSignalIndex != null) {
await result.current.createDeSignalIndex();
}
await waitForNextUpdate();
expect(spyOnCreateSignalIndex).toHaveBeenCalledTimes(1);
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => expect(result.current.createDeSignalIndex).toBeDefined());
await act(async () => {
await result.current.createDeSignalIndex!();
});
await waitFor(() => expect(spyOnCreateSignalIndex).toHaveBeenCalledTimes(1));
});
test('if there is an error during createSignalIndex, we should get back signalIndexExists === false && signalIndexName == null', async () => {
@ -120,27 +100,25 @@ describe('useSignalIndex', () => {
spyOnCreateSignalIndex.mockImplementation(() => {
throw new Error('Something went wrong, let see what happen');
});
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => expect(result.current.createDeSignalIndex).toBeDefined());
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
if (result.current.createDeSignalIndex != null) {
await result.current.createDeSignalIndex();
}
await result.current.createDeSignalIndex!();
});
await waitFor(() =>
expect(result.current).toEqual({
createDeSignalIndex: result.current.createDeSignalIndex,
loading: false,
signalIndexExists: false,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
});
})
);
});
test('if there is an error when fetching alerts info, signalIndexExists === false && signalIndexName == null', async () => {
@ -148,24 +126,25 @@ describe('useSignalIndex', () => {
spyOnGetSignalIndex.mockImplementation(() => {
throw new Error('Something went wrong, let see what happen');
});
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => expect(result.current.createDeSignalIndex).toBeDefined());
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
await result.current.createDeSignalIndex!();
});
await waitFor(() =>
expect(result.current).toEqual({
createDeSignalIndex: result.current.createDeSignalIndex,
loading: false,
signalIndexExists: false,
signalIndexName: null,
signalIndexMappingOutdated: null,
});
});
})
);
});
test('should not make API calls when signal index already stored in sourcerer', async () => {
@ -175,16 +154,11 @@ describe('useSignalIndex', () => {
.mockReturnValue('mock-signal-index-from-sourcerer');
jest.spyOn(sourcererSelectors, 'signalIndexMappingOutdated').mockReturnValue(false);
await act(async () => {
const { result, waitForNextUpdate } = renderHook<PropsWithChildren<{}>, ReturnSignalIndex>(
() => useSignalIndex(),
{
wrapper: TestProvidersWithPrivileges,
}
);
await waitForNextUpdate();
await waitForNextUpdate();
await waitForNextUpdate();
const { result } = renderHook(() => useSignalIndex(), {
wrapper: TestProvidersWithPrivileges,
});
await waitFor(() => {
expect(spyOnGetSignalIndex).not.toHaveBeenCalled();
expect(result.current).toEqual({
createDeSignalIndex: result.current.createDeSignalIndex,

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react';
import { TestProviders } from '../../../common/mock';
import { useAlertHistogramCount } from './use_alert_histogram_count';

View file

@ -7,7 +7,6 @@
import { createMockStore, mockGlobalState, TestProviders } from '../../../common/mock';
import { TableId } from '@kbn/securitysolution-data-table';
import { renderHook } from '@testing-library/react-hooks';
import { getUseCellActionsHook } from './use_cell_actions';
import { columns as mockColumns, data as mockData } from './mock/data';
import type {
@ -17,7 +16,7 @@ import type {
EuiDataGridRefProps,
} from '@elastic/eui';
import { EuiButtonEmpty } from '@elastic/eui';
import { render, screen } from '@testing-library/react';
import { render, screen, waitFor, renderHook } from '@testing-library/react';
import type { ComponentProps, JSXElementConstructor, PropsWithChildren } from 'react';
import React from 'react';
import { makeAction } from '../../../common/components/cell_actions/mocks';
@ -86,7 +85,7 @@ const TestProviderWithCustomStateAndActions = withCustomPropsAndCellActions({
describe('getUseCellActionsHook', () => {
it('should render cell actions correctly for gridView view', async () => {
const { result, waitForNextUpdate } = renderHook(
const { result } = renderHook(
() =>
useCellActions({
columns: mockColumns as unknown as EuiDataGridColumn[],
@ -101,17 +100,17 @@ describe('getUseCellActionsHook', () => {
}
);
await waitForNextUpdate();
await waitFor(() => {
const cellAction = result.current.getCellActions('host.name', 0)[0];
const cellAction = result.current.getCellActions('host.name', 0)[0];
renderCellAction(cellAction);
renderCellAction(cellAction);
expect(screen.getByTestId('dataGridColumnCellAction-action1')).toBeInTheDocument();
expect(screen.getByTestId('dataGridColumnCellAction-action1')).toBeInTheDocument();
});
});
it('should not render cell actions correctly for eventRendered view', async () => {
const { result, waitForNextUpdate } = renderHook(
const { result } = renderHook(
() =>
useCellActions({
columns: mockColumns as unknown as EuiDataGridColumn[],
@ -128,8 +127,6 @@ describe('getUseCellActionsHook', () => {
const cellAction = result.current.getCellActions('host.name', 0);
await waitForNextUpdate();
expect(cellAction).toHaveLength(0);
await waitFor(() => expect(cellAction).toHaveLength(0));
});
});

View file

@ -8,8 +8,7 @@
import React from 'react';
import { getPersistentControlsHook } from './use_persistent_controls';
import { TableId } from '@kbn/securitysolution-data-table';
import { renderHook } from '@testing-library/react-hooks';
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, renderHook } from '@testing-library/react';
import { createMockStore, mockGlobalState, TestProviders } from '../../../common/mock';
import { useSourcererDataView } from '../../../sourcerer/containers';
import { useDeepEqualSelector, useShallowEqualSelector } from '../../../common/hooks/use_selector';

View file

@ -5,8 +5,8 @@
* 2.0.
*/
import type { RenderHookResult } from '@testing-library/react-hooks';
import { renderHook } from '@testing-library/react-hooks';
import type { RenderHookResult } from '@testing-library/react';
import { renderHook } from '@testing-library/react';
import type { UseRuleDetailsParams, UseRuleDetailsResult } from './use_rule_details';
import { useRuleDetails } from './use_rule_details';
import { useRuleWithFallback } from '../../../detection_engine/rule_management/logic/use_rule_with_fallback';
@ -19,7 +19,7 @@ const initialProps: UseRuleDetailsParams = {
};
describe('useRuleDetails', () => {
let hookResult: RenderHookResult<UseRuleDetailsParams, UseRuleDetailsResult>;
let hookResult: RenderHookResult<UseRuleDetailsResult, UseRuleDetailsParams>;
it('should return loading as true when the rule is loading', () => {
mockUseRuleWithFallback.mockReturnValue({

View file

@ -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 { useIntegrationCardList } from './use_integration_card_list';
import { trackOnboardingLinkClick } from '../../../lib/telemetry';

View file

@ -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 { useBodyConfig } from './use_body_config';
import { mockOnboardingContext, onboardingContext } from '../../__mocks__/mocks';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { renderHook, act, type RenderHookResult } from '@testing-library/react-hooks';
import { renderHook, act, type RenderHookResult } from '@testing-library/react';
import { useCompletedCards } from './use_completed_cards';
import type { OnboardingGroupConfig } from '../../../types';
import type { OnboardingCardId } from '../../../constants';
@ -107,8 +107,8 @@ describe('useCompletedCards Hook', () => {
describe('when checkComplete functions are rejected', () => {
let renderResult: RenderHookResult<
OnboardingGroupConfig[],
ReturnType<typeof useCompletedCards>
ReturnType<typeof useCompletedCards>,
OnboardingGroupConfig[]
>;
beforeEach(async () => {
mockUseKibana.mockReturnValue({
@ -150,8 +150,8 @@ describe('useCompletedCards Hook', () => {
describe('when checkComplete functions are resolved', () => {
let renderResult: RenderHookResult<
OnboardingGroupConfig[],
ReturnType<typeof useCompletedCards>
ReturnType<typeof useCompletedCards>,
OnboardingGroupConfig[]
>;
beforeEach(async () => {
renderResult = renderHook(useCompletedCards, { initialProps: mockCardsGroupConfig });

View file

@ -5,10 +5,9 @@
* 2.0.
*/
import { renderHook, act } from '@testing-library/react-hooks';
import { waitFor } from '@testing-library/react';
import type { OnboardingCardId } from '../../../constants';
import { useExpandedCard } from './use_expanded_card';
import type { OnboardingCardId } from '../../../constants';
import { waitFor, renderHook, act } from '@testing-library/react';
const mockSetCardDetail = jest.fn();
jest.mock('../../hooks/use_url_detail', () => ({