Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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({}),
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -178,15 +175,15 @@ 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();
expect(appState).toMatchObject(result.current.defaultDiscoverAppState);
});
});
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();
Expand All @@ -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);
});
Expand All @@ -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,
Expand All @@ -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);
});
Expand Down Expand Up @@ -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);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -70,37 +71,27 @@ 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();
});

expect(useSecurityJobsRefetch).toHaveBeenCalled();
});

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([
{
Expand All @@ -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,
},
};

mockAnomaliesSearch.mockResolvedValue({
aggregations: { number_of_anomalies: { buckets: [fistJobCount, secondJobCount] } },
});
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] } },
});

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);
Expand All @@ -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());
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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([
{
Expand Down Expand Up @@ -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',
})
);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
Loading