10973 migrate flaky e2e tests to jest 2 (#211363)

## Summary

This PR tries to fix the following issues - which are flaky FTR tests:

- https://github.com/elastic/kibana/issues/209529
- https://github.com/elastic/kibana/issues/201686
- https://github.com/elastic/kibana/issues/203680
- https://github.com/elastic/kibana/issues/178413 - test is still
skipped, added unit tests for rules table, header and counter
components.
- https://github.com/elastic/kibana/issues/193073
- https://github.com/elastic/kibana/issues/193616
- https://github.com/elastic/kibana/issues/191604
- https://github.com/elastic/kibana/issues/191593
- https://github.com/elastic/kibana/issues/191511
- https://github.com/elastic/kibana/issues/191474
- https://github.com/elastic/kibana/issues/191322
- https://github.com/elastic/kibana/issues/191128
- https://github.com/elastic/kibana/issues/191144
- https://github.com/elastic/kibana/issues/191027
- https://github.com/elastic/kibana/issues/190831
- https://github.com/elastic/kibana/issues/190779



There will be an RFC document which is going to be released to help us
better understand and decide which tests are more suitable to make as
E2E tests and which as unit tests.

### Checklist
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [x] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed

### Closes
this PR closes the above mentioned issues in relation for this ticket -
https://github.com/elastic/security-team/issues/10973
This commit is contained in:
Alex Prozorov 2025-02-18 15:14:24 +02:00 committed by GitHub
parent 2673b9b93b
commit dac36902f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 1110 additions and 314 deletions

View file

@ -65,7 +65,7 @@ describe('NoVulnerabilitiesStates', () => {
expect(button).toHaveAttribute('href', expect.stringContaining(cnvmintegrationLink));
});
it('Vulnerabilities - `Add Wiz integration`: should have link element to CNVM integration installation page', async () => {
it('Vulnerabilities - `Add Wiz integration`: should have link element to wiz integration installation page', async () => {
await waitFor(() =>
expect(screen.getByText(/Already using a\s+cloud security product?/i)).toBeInTheDocument()
);

View file

@ -53,6 +53,24 @@ describe('<Findings />', () => {
expect(screen.getByText(/add kspm integration/i)).toBeInTheDocument();
});
it('verifies CSPM and KSPM integration buttons have link and are clickable', async () => {
server.use(statusHandlers.notInstalledHandler);
renderFindingsPage();
expect(screen.getByText(/loading/i)).toBeInTheDocument();
const cspmButton = await waitFor(() =>
screen.getByRole('link', { name: /add cspm integration/i })
);
const kspmButton = await waitFor(() =>
screen.getByRole('link', { name: /add kspm integration/i })
);
expect(cspmButton).toHaveAttribute('href', expect.stringContaining('add-integration/cspm'));
expect(cspmButton).toBeEnabled();
expect(kspmButton).toHaveAttribute('href', expect.stringContaining('add-integration/kspm'));
expect(kspmButton).toBeEnabled();
});
it("renders the 'latest misconfigurations findings' DataTable component when the CSPM/KSPM integration status is not installed but there are findings", async () => {
const finding1 = generateCspFinding('0003', 'failed');
const finding2 = generateCspFinding('0004', 'passed');

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export * from './rules_counters.mock';
export * from './rules_table_headers.mock';

View file

@ -0,0 +1,86 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const benchmarkValuesMock = {
integrationType: 'KSPM',
integrationName: 'EKS',
resourceName: 'Clusters',
resourceCountLabel: 'clusters',
integrationLink: '/kbn/app/fleet/integrations/cloud_security_posture-1.12.0/add-integration/kspm',
learnMoreLink: 'https://ela.st/kspm-get-started',
};
export const itemsDataMock = [
{
id: 'cis_k8s',
name: 'CIS Kubernetes V1.23',
version: '1.0.1',
score: {
totalFailed: 47,
totalPassed: 321,
totalFindings: 368,
postureScore: 87.2,
resourcesEvaluated: 180,
},
evaluation: 1,
},
{
id: 'cis_azure',
name: 'CIS Microsoft Azure Foundations',
version: '2.0.0',
score: {
totalFailed: 0,
totalPassed: 0,
totalFindings: 0,
postureScore: 0,
},
evaluation: 0,
},
{
id: 'cis_gcp',
name: 'CIS Google Cloud Platform Foundation',
version: '2.0.0',
score: {
totalFailed: 366,
totalPassed: 62,
totalFindings: 428,
postureScore: 14.5,
resourcesEvaluated: 376,
},
evaluation: 1,
},
{
id: 'cis_aws',
name: 'CIS Amazon Web Services Foundations',
version: '1.5.0',
score: {
totalFailed: 0,
totalPassed: 0,
totalFindings: 0,
postureScore: 0,
},
evaluation: 0,
},
{
id: 'cis_eks',
name: 'CIS Amazon Elastic Kubernetes Service (EKS)',
version: '1.0.1',
score: {
totalFailed: 20,
totalPassed: 62,
totalFindings: 82,
postureScore: 75.6,
resourcesEvaluated: 14,
},
evaluation: 1,
},
];
export const paramsMock = {
benchmarkId: 'cis_eks',
benchmarkVersion: '1.0.1',
};

View file

@ -0,0 +1,72 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const selectRulesMock = [
{
metadata: {
impact:
'Audit logs will be created on the master nodes, which will consume disk space. Care should be taken to avoid generating too large volumes of log information as this could impact the available of the cluster nodes.\nS3 lifecycle features can be used to manage the accumulation and management of logs over time. \n\nSee the following AWS resource for more information on these features:\nhttp://docs.aws.amazon.com/AmazonS3/latest/dev/object-lifecycle-mgmt.html',
default_value:
"By default, cluster control plane logs aren't sent to CloudWatch Logs. ... When you enable a log type, the logs are sent with a log verbosity level of 2 . To enable or disable control plane logs with the console. Open the Amazon EKS console at https://console.aws.amazon.com/eks/home#/clusters . Amazon EKS Information in CloudTrail CloudTrail is enabled on your AWS account when you create the account. When activity occurs in Amazon EKS, that activity is recorded in a CloudTrail event along with other AWS service events in Event history.\n",
references:
'1. https://kubernetes.io/docs/tasks/debug-application-cluster/audit/\n2. https://aws.github.io/aws-eks-best-practices/detective/\n3. https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html\n4. https://docs.aws.amazon.com/eks/latest/userguide/logging-using-cloudtrail.html',
id: '66cd0518-cfa3-5917-a399-a7dfde4e19db',
name: 'Enable audit Logs',
profile_applicability: '* Level 1',
description:
'The audit logs are part of the EKS managed Kubernetes control plane logs that are managed by Amazon EKS.\nAmazon EKS is integrated with AWS CloudTrail, a service that provides a record of actions taken by a user, role, or an AWS service in Amazon EKS.\nCloudTrail captures all API calls for Amazon EKS as events.\nThe calls captured include calls from the Amazon EKS console and code calls to the Amazon EKS API operations.',
rationale:
'Exporting logs and metrics to a dedicated, persistent datastore such as CloudTrail ensures availability of audit data following a cluster security event, and provides a central location for analysis of log and metric data collated from multiple sources.',
audit:
'Perform the following to determine if CloudTrail is enabled for all regions:\n\n**Via the Management Console**\n\n1. Sign in to the AWS Management Console and open the EKS console at https://console.aws.amazon.com/eks\n2. Click on Cluster Name of the cluster you are auditing\n3. Click Logging\n You will see Control Plane Logging info\n\n ```\n API Server Audit Authenticator\n Enabled/Disabled Enabled/Disabled Enabled/Disabled\n\n Controller Manager Scheduler\n Enabled/Disabled Enabled/Disabled\n```\n4. Ensure all 5 choices are set to Enabled',
remediation:
'Perform the following to determine if CloudTrail is enabled for all regions:\n\n**Via The Management Console**\n\n1. Sign in to the AWS Management Console and open the EKS console at https://console.aws.amazon.com/eks\n2. Click on Cluster Name of the cluster you are auditing\n3. Click Logging\n4. Select Manage Logging from the button on the right hand side\n5. Toggle each selection to the Enabled position.\n6. Click Save Changes\n\n**Via CLI**\n\n`aws --region "${REGION_CODE}" eks describe-cluster --name "${CLUSTER_NAME}" --query \'cluster.logging.clusterLogging[?enabled==true].types`',
section: 'Logging',
version: '1.0',
tags: ['CIS', 'EKS', 'CIS 2.1.1', 'Logging'],
benchmark: {
name: 'CIS Amazon Elastic Kubernetes Service (EKS)',
version: 'v1.0.1',
id: 'cis_eks',
rule_number: '2.1.1',
posture_type: 'kspm',
},
rego_rule_id: 'cis_2_1_1',
},
state: 'unmuted',
},
{
metadata: {
impact: 'None.',
default_value: 'See the AWS EKS documentation for the default value.\n',
references: '1. https://kubernetes.io/docs/admin/kube-proxy/',
id: '90b8ae5e-df30-5ba6-9fe9-03aab2b7a1c3',
name: 'Ensure that the kubeconfig file permissions are set to 644 or more restrictive',
profile_applicability: '* Level 1',
description:
'If `kubelet` is running, and if it is using a file-based kubeconfig file, ensure that the proxy kubeconfig file has permissions of `644` or more restrictive.',
rationale:
'The `kubelet` kubeconfig file controls various parameters of the `kubelet` service in the worker node.\nYou should restrict its file permissions to maintain the integrity of the file.\nThe file should be writable by only the administrators on the system.\n\nIt is possible to run `kubelet` with the kubeconfig parameters configured as a Kubernetes ConfigMap instead of a file.\nIn this case, there is no proxy kubeconfig file.',
audit:
"SSH to the worker nodes\n\nTo check to see if the Kubelet Service is running:\n```\nsudo systemctl status kubelet\n```\nThe output should return `Active: active (running) since..`\n\nRun the following command on each node to find the appropriate kubeconfig file:\n\n```\nps -ef | grep kubelet\n```\nThe output of the above command should return something similar to `--kubeconfig /var/lib/kubelet/kubeconfig` which is the location of the kubeconfig file.\n\nRun this command to obtain the kubeconfig file permissions:\n\n```\nstat -c %a /var/lib/kubelet/kubeconfig\n```\nThe output of the above command gives you the kubeconfig file's permissions.\n\nVerify that if a file is specified and it exists, the permissions are `644` or more restrictive.",
remediation:
'Run the below command (based on the file location on your system) on the each worker\nnode.\nFor example,\n```\nchmod 644 <kubeconfig file>\n```',
section: 'Worker Node Configuration Files',
version: '1.0',
tags: ['CIS', 'EKS', 'CIS 3.1.1', 'Worker Node Configuration Files'],
benchmark: {
name: 'CIS Amazon Elastic Kubernetes Service (EKS)',
version: 'v1.0.1',
id: 'cis_eks',
rule_number: '3.1.1',
posture_type: 'kspm',
},
rego_rule_id: 'cis_3_1_1',
},
state: 'unmuted',
},
];

View file

@ -0,0 +1,137 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import { render, screen } from '@testing-library/react';
import { RulesCounters } from './rules_counters';
import { useBenchmarkDynamicValues } from '../../common/hooks/use_benchmark_dynamic_values';
import { useParams } from 'react-router-dom';
import { RULE_COUNTERS_TEST_SUBJ } from './test_subjects';
import { useNavigateFindings } from '@kbn/cloud-security-posture/src/hooks/use_navigate_findings';
import { useCspBenchmarkIntegrationsV2 } from '../benchmarks/use_csp_benchmark_integrations';
import { useKibana } from '../../common/hooks/use_kibana';
import { within } from '@testing-library/dom';
import { cloudPosturePages } from '../../common/navigation/constants';
import { RULE_FAILED } from '../../../common/constants';
import userEvent from '@testing-library/user-event';
import { benchmarkValuesMock, itemsDataMock, paramsMock } from './__mocks__';
jest.mock('../../common/hooks/use_benchmark_dynamic_values');
jest.mock('react-router-dom', () => ({
useParams: jest.fn(),
}));
jest.mock('@kbn/cloud-security-posture/src/hooks/use_navigate_findings');
jest.mock('../benchmarks/use_csp_benchmark_integrations');
jest.mock('../../common/hooks/use_kibana');
describe('RulesCounters', () => {
const mockNavigate = jest.fn();
beforeEach(() => {
(useKibana as jest.Mock).mockReturnValue({
services: {
http: {
basePath: {
basePath: '/kbn',
serverBasePath: '/kbn',
assetsHrefBase: '/kbn/XXXXXXXXXXXX',
prepend: (path: string) => path,
},
},
charts: {
theme: {
useChartsBaseTheme: () => ({}),
},
},
},
});
(useCspBenchmarkIntegrationsV2 as jest.Mock).mockReturnValue({
status: 'success',
data: {
items: itemsDataMock,
},
});
(useBenchmarkDynamicValues as jest.Mock).mockReturnValue({
getBenchmarkDynamicValues: () => benchmarkValuesMock,
});
(useParams as jest.Mock).mockReturnValue(paramsMock);
(useNavigateFindings as jest.Mock).mockReturnValue(mockNavigate); // Store the mock function
});
it('should not show empty state and show correct posture score', () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
expect(
screen.queryByTestId(RULE_COUNTERS_TEST_SUBJ.RULE_COUNTERS_EMPTY_STATE)
).not.toBeInTheDocument();
const postureScoreContainer = screen.getByTestId(RULE_COUNTERS_TEST_SUBJ.POSTURE_SCORE_COUNTER);
expect(within(postureScoreContainer).getByText('76%')).toBeInTheDocument();
});
it('have correct href on posture score button', () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
const postureScoreButton = screen.getByTestId(RULE_COUNTERS_TEST_SUBJ.POSTURE_SCORE_BUTTON);
expect(postureScoreButton).toHaveAttribute(
'href',
expect.stringContaining(`/app/security${cloudPosturePages.dashboard.path}`)
);
});
it('shows integrations count when there are findings', () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
screen.debug();
const integrationsCounter = screen.getByTestId(
RULE_COUNTERS_TEST_SUBJ.INTEGRATIONS_EVALUATED_COUNTER
);
expect(within(integrationsCounter).getByText('1')).toBeInTheDocument();
});
it('have correct href on integrations counter button', () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
const postureScoreButton = screen.getByTestId(
RULE_COUNTERS_TEST_SUBJ.INTEGRATIONS_EVALUATED_BUTTON
);
expect(postureScoreButton).toHaveAttribute(
'href',
expect.stringContaining(benchmarkValuesMock.integrationLink)
);
});
it('shows the failed findings counter when there are findings', () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
const failedFindingsCounter = screen.getByTestId(
RULE_COUNTERS_TEST_SUBJ.FAILED_FINDINGS_COUNTER
);
expect(within(failedFindingsCounter).getByText('20')).toBeInTheDocument();
});
it('call useNavigateFindings with correct params when clicking on failed findings button', async () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
const failedFindingsButton = screen.getByTestId(RULE_COUNTERS_TEST_SUBJ.FAILED_FINDINGS_BUTTON);
await userEvent.click(failedFindingsButton);
expect(mockNavigate).toHaveBeenCalledWith({
'result.evaluation': RULE_FAILED,
'rule.benchmark.id': paramsMock.benchmarkId,
'rule.benchmark.version': `v${paramsMock.benchmarkVersion}`,
});
});
it('shows the disabled rules count', async () => {
render(<RulesCounters mutedRulesCount={0} setEnabledDisabledItemsFilter={() => {}} />);
const dislabedRulesCounter = screen.getByTestId(RULE_COUNTERS_TEST_SUBJ.DISABLED_RULES_COUNTER);
expect(within(dislabedRulesCounter).getByText('0')).toBeInTheDocument();
});
});

View file

@ -0,0 +1,143 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { FC, PropsWithChildren } from 'react';
import { render, screen } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { coreMock } from '@kbn/core/public/mocks';
import { TestProvider } from '../../test/test_provider';
import { RulesTable } from './rules_table';
import * as TEST_SUBJECTS from './test_subjects';
import { selectRulesMock } from './__mocks__/rules_table_headers.mock';
import { CspBenchmarkRulesWithStates } from './rules_container';
import { METRIC_TYPE } from '@kbn/analytics';
import {
CHANGE_RULE_STATE,
uiMetricService,
} from '@kbn/cloud-security-posture-common/utils/ui_metrics';
import { useChangeCspRuleState } from './use_change_csp_rule_state';
import userEvent from '@testing-library/user-event';
import { RULES_TABLE } from './test_subjects';
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
});
const getWrapper =
(
{ canUpdate = true }: { canUpdate: boolean } = { canUpdate: true }
): FC<PropsWithChildren<unknown>> =>
({ children }) => {
const coreStart = coreMock.createStart();
const core = {
...coreStart,
application: {
...coreStart.application,
capabilities: {
...coreStart.application.capabilities,
siemV2: { crud: canUpdate },
},
},
};
return (
<QueryClientProvider client={queryClient}>
<TestProvider core={core}>{children}</TestProvider>
</QueryClientProvider>
);
};
jest.mock('@kbn/cloud-security-posture-common/utils/ui_metrics', () => ({
uiMetricService: {
trackUiMetric: jest.fn(),
},
CHANGE_RULE_STATE: 'cloud_security_posture.rule.change_state',
}));
jest.mock('./use_change_csp_rule_state');
describe('RulesTable', () => {
const Wrapper = getWrapper();
const mockProps = {
setPagination: jest.fn(),
perPage: 25,
rules_page: selectRulesMock as CspBenchmarkRulesWithStates[],
page: 0,
total: selectRulesMock.length,
loading: false,
error: undefined,
selectedRuleId: undefined,
selectedRules: [],
setSelectedRules: jest.fn(),
onRuleClick: jest.fn(),
onSortChange: jest.fn(),
};
beforeEach(() => {
(useChangeCspRuleState as jest.Mock).mockReturnValue({
mutate: jest.fn(),
isLoading: false,
});
jest.clearAllMocks();
});
it('renders table with correct test id', () => {
render(
<Wrapper>
<RulesTable {...mockProps} />
</Wrapper>
);
expect(screen.getByTestId(TEST_SUBJECTS.CSP_RULES_TABLE)).toBeInTheDocument();
});
it('tracks metric when toggling rule state', async () => {
render(
<Wrapper>
<RulesTable {...mockProps} />
</Wrapper>
);
const switchButtons = screen.getAllByTestId(RULES_TABLE.RULES_ROWS_ENABLE_SWITCH_BUTTON);
await userEvent.click(switchButtons[0]);
expect(uiMetricService.trackUiMetric).toHaveBeenCalledWith(
METRIC_TYPE.COUNT,
CHANGE_RULE_STATE
);
});
it('calls mutateRulesStates with correct params when toggling rule state', async () => {
const mutateMock = jest.fn();
(useChangeCspRuleState as jest.Mock).mockReturnValue({
mutate: mutateMock,
isLoading: false,
});
render(
<Wrapper>
<RulesTable {...mockProps} />
</Wrapper>
);
const switchButtons = screen.getAllByTestId(RULES_TABLE.RULES_ROWS_ENABLE_SWITCH_BUTTON);
await userEvent.click(switchButtons[0]);
expect(mutateMock).toHaveBeenCalledWith({
newState: 'mute',
ruleIds: [
{
benchmark_id: selectRulesMock[0].metadata.benchmark.id,
benchmark_version: selectRulesMock[0].metadata.benchmark.version,
rule_number: selectRulesMock[0].metadata.benchmark.rule_number,
rule_id: selectRulesMock[0].metadata.id,
},
],
});
});
});

View file

@ -28,10 +28,9 @@ import { uniqBy } from 'lodash';
import { ColumnNameWithTooltip } from '../../components/column_name_with_tooltip';
import type { CspBenchmarkRulesWithStates, RulesState } from './rules_container';
import * as TEST_SUBJECTS from './test_subjects';
import { useChangeCspRuleState } from './use_change_csp_rule_state';
import { RULES_TABLE } from './test_subjects';
export const RULES_ROWS_ENABLE_SWITCH_BUTTON = 'rules-row-enable-switch-button';
export const RULES_ROW_SELECT_ALL_CURRENT_PAGE = 'cloud-security-fields-selector-item-all';
import { useChangeCspRuleState } from './use_change_csp_rule_state';
type RulesTableProps = Pick<
RulesState,
@ -168,7 +167,7 @@ const getColumns = ({
field: 'action',
name: (
<EuiCheckbox
id={RULES_ROW_SELECT_ALL_CURRENT_PAGE}
id={RULES_TABLE.RULES_ROW_SELECT_ALL_CURRENT_PAGE}
checked={isCurrentPageRulesASubset(items, selectedRules) && isAllRulesSelectedThisPage}
onChange={() => {
const uniqueSelectedRules = uniqBy([...selectedRules, ...items], 'metadata.id');
@ -300,7 +299,7 @@ const RuleStateSwitch = ({ rule }: { rule: CspBenchmarkRulesWithStates }) => {
className="eui-textTruncate"
checked={!isRuleMuted}
onChange={changeCspRuleStateFn}
data-test-subj={RULES_ROWS_ENABLE_SWITCH_BUTTON}
data-test-subj={RULES_TABLE.RULES_ROWS_ENABLE_SWITCH_BUTTON}
label=""
compressed={true}
/>

View file

@ -0,0 +1,163 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { FC, PropsWithChildren } from 'react';
import { render, screen } from '@testing-library/react';
import { RulesTableHeader } from './rules_table_header';
import { CspBenchmarkRulesWithStates } from './rules_container';
import { TestProvider } from '../../test/test_provider';
import { coreMock } from '@kbn/core/public/mocks';
import { RULES_TABLE_HEADER_TEST_SUBJ } from './test_subjects';
import userEvent from '@testing-library/user-event';
import { useChangeCspRuleState } from './use_change_csp_rule_state';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { selectRulesMock } from './__mocks__';
jest.mock('./use_change_csp_rule_state');
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
});
const getWrapper =
(
{ canUpdate = true }: { canUpdate: boolean } = { canUpdate: true }
): FC<PropsWithChildren<unknown>> =>
({ children }) => {
const coreStart = coreMock.createStart();
const core = {
...coreStart,
application: {
...coreStart.application,
capabilities: {
...coreStart.application.capabilities,
siemV2: { crud: canUpdate },
},
},
};
return (
<QueryClientProvider client={queryClient}>
<TestProvider core={core}>{children}</TestProvider>
</QueryClientProvider>
);
};
describe('RulesTableHeader', () => {
const Wrapper = getWrapper();
const mockProps = {
search: jest.fn(),
searchValue: '',
isSearching: false,
totalRulesCount: 2,
pageSize: 25,
onSectionChange: jest.fn(),
onRuleNumberChange: jest.fn(),
sectionSelectOptions: ['Logging', 'Worker Node Configuration Files'],
ruleNumberSelectOptions: ['2.1.1', '3.1.1'],
selectedRules: selectRulesMock as CspBenchmarkRulesWithStates[],
setEnabledDisabledItemsFilter: jest.fn(),
enabledDisabledItemsFilterState: 'no-filter',
setSelectAllRules: jest.fn(),
setSelectedRules: jest.fn(),
};
beforeEach(() => {
(useChangeCspRuleState as jest.Mock).mockReturnValue({
mutate: jest.fn(),
isLoading: false,
});
});
it('renders header with correct initial state', () => {
render(
<Wrapper>
<RulesTableHeader {...mockProps} />
</Wrapper>
);
expect(
screen.getByTestId(RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_SEARCH_INPUT)
).toBeInTheDocument();
expect(
screen.getByTestId(RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_MULTI_SELECT)
).toBeInTheDocument();
expect(
screen.getByTestId(RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_RULE_NUMBER_SELECT)
).toBeInTheDocument();
expect(
screen.getByTestId(RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_RULE_SHOWING_LABEL)
).toBeInTheDocument();
});
it('update multi-select filter when selecting an option', async () => {
render(
<Wrapper>
<RulesTableHeader {...mockProps} />
</Wrapper>
);
const multiSelectFilterId = 'cis-section-multi-select-filter';
const multiSelectFilter = await screen.findByTestId(
`options-filter-popover-button-${multiSelectFilterId}`
);
await userEvent.click(multiSelectFilter);
const firstOption = screen.getByText('Logging');
await userEvent.click(firstOption);
const updatedMultiSelect = screen.getByTestId(
RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_MULTI_SELECT
);
expect(updatedMultiSelect).toHaveTextContent('1');
});
it('calls onRuleNumberChange with correct params on rule selection change', async () => {
render(
<Wrapper>
<RulesTableHeader {...mockProps} />
</Wrapper>
);
const multiSelectFilterId = 'rule-number-multi-select-filter';
const ruleNumberSelectFilter = await screen.findByTestId(
`options-filter-popover-button-${multiSelectFilterId}`
);
await userEvent.click(ruleNumberSelectFilter);
const firstOption = await screen.findByText('2.1.1');
await userEvent.click(firstOption);
expect(mockProps.onRuleNumberChange).toHaveBeenCalledWith(['2.1.1']);
});
it('calls setEnabledDisabledItemsFilter with correct params on click', async () => {
render(
<Wrapper>
<RulesTableHeader {...mockProps} />
</Wrapper>
);
const enableFilterButton = await screen.findByTestId(
RULES_TABLE_HEADER_TEST_SUBJ.RULES_ENABLED_FILTER
);
const disableFilterButton = await screen.findByTestId(
RULES_TABLE_HEADER_TEST_SUBJ.RULES_DISABLED_FILTER
);
await userEvent.click(enableFilterButton);
expect(mockProps.setEnabledDisabledItemsFilter).toHaveBeenCalledWith('enabled');
await userEvent.click(disableFilterButton);
expect(mockProps.setEnabledDisabledItemsFilter).toHaveBeenCalledWith('disabled');
});
});

View file

@ -29,14 +29,7 @@ import {
} from './use_change_csp_rule_state';
import { CspBenchmarkRulesWithStates } from './rules_container';
import { MultiSelectFilter } from '../../common/component/multi_select_filter';
export const RULES_BULK_ACTION_BUTTON = 'bulk-action-button';
export const RULES_BULK_ACTION_OPTION_ENABLE = 'bulk-action-option-enable';
export const RULES_BULK_ACTION_OPTION_DISABLE = 'bulk-action-option-disable';
export const RULES_SELECT_ALL_RULES = 'select-all-rules-button';
export const RULES_CLEAR_ALL_RULES_SELECTION = 'clear-rules-selection-button';
export const RULES_DISABLED_FILTER = 'rules-disabled-filter';
export const RULES_ENABLED_FILTER = 'rules-enabled-filter';
import { RULES_TABLE_HEADER_TEST_SUBJ } from './test_subjects';
interface RulesTableToolbarProps {
search: (value: string) => void;
@ -109,6 +102,7 @@ export const RulesTableHeader = ({
<EuiFlexItem grow={0}>
<EuiFlexGroup gutterSize="s" direction="row">
<EuiFlexItem
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_MULTI_SELECT}
css={css`
min-width: 160px;
`}
@ -135,6 +129,7 @@ export const RulesTableHeader = ({
css={css`
min-width: 160px;
`}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_RULE_NUMBER_SELECT}
>
<MultiSelectFilter
buttonLabel={i18n.translate(
@ -164,7 +159,7 @@ export const RulesTableHeader = ({
withNext
hasActiveFilters={enabledDisabledItemsFilterState === 'enabled'}
onClick={toggleEnabledRulesFilter}
data-test-subj={RULES_ENABLED_FILTER}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_ENABLED_FILTER}
>
<FormattedMessage
id="xpack.csp.rules.rulesTable.enabledRuleFilterButton"
@ -174,7 +169,7 @@ export const RulesTableHeader = ({
<EuiFilterButton
hasActiveFilters={enabledDisabledItemsFilterState === 'disabled'}
onClick={toggleDisabledRulesFilter}
data-test-subj={RULES_DISABLED_FILTER}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_DISABLED_FILTER}
>
<FormattedMessage
id="xpack.csp.rules.rulesTable.disabledRuleFilterButton"
@ -214,6 +209,7 @@ const SearchField = ({
<div>
<EuiFlexItem grow={true} style={{ alignItems: 'flex-end' }}>
<EuiFieldSearch
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_SEARCH_INPUT}
isLoading={isSearching}
placeholder={i18n.translate('xpack.csp.rules.rulesTable.searchPlaceholder', {
defaultMessage: 'Search by Rule Name',
@ -278,7 +274,7 @@ const CurrentPageOfTotal = ({
size="xs"
iconType="arrowDown"
iconSide="right"
data-test-subj={RULES_BULK_ACTION_BUTTON}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.BULK_ACTION_BUTTON}
>
Bulk actions
</EuiButtonEmpty>
@ -287,7 +283,7 @@ const CurrentPageOfTotal = ({
<EuiContextMenuItem
disabled={selectedRules.length === 0 || areAllSelectedRulesUnmuted}
onClick={changeCspRuleStateUnmute}
data-test-subj={RULES_BULK_ACTION_OPTION_ENABLE}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.BULK_ACTION_OPTION_ENABLE}
>
<EuiText key="disabled">
<FormattedMessage id="xpack.csp.rules.rulesTable.optionEnable" defaultMessage="Enable" />
@ -296,7 +292,7 @@ const CurrentPageOfTotal = ({
<EuiContextMenuItem
disabled={selectedRules.length === 0 || areAllSelectedRulesMuted}
onClick={changeCspRuleStateMute}
data-test-subj={RULES_BULK_ACTION_OPTION_DISABLE}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.BULK_ACTION_OPTION_DISABLE}
>
<EuiText>
<FormattedMessage id="xpack.csp.rules.rulesTable.optionDisable" defaultMessage="Disable" />
@ -308,7 +304,10 @@ const CurrentPageOfTotal = ({
<EuiFlexItem grow={false}>
<EuiSpacer size="s" />
<EuiFlexGroup gutterSize="s" alignItems={'center'}>
<EuiFlexItem grow={false}>
<EuiFlexItem
grow={false}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.RULES_TABLE_HEADER_RULE_SHOWING_LABEL}
>
<EuiText size="xs" textAlign="left" color="subdued" style={{ marginLeft: '8px' }}>
<FormattedMessage
id="xpack.csp.rules.rulesTable.showingPageOfTotalLabel"
@ -328,7 +327,7 @@ const CurrentPageOfTotal = ({
onClick={setSelectAllRules}
size="xs"
iconType="pagesSelect"
data-test-subj={RULES_SELECT_ALL_RULES}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.SELECT_ALL_RULES}
>
<FormattedMessage
id="xpack.csp.rules.rulesTable.selectAllRulesOption"
@ -341,7 +340,7 @@ const CurrentPageOfTotal = ({
onClick={() => setSelectedRules([])}
size="xs"
iconType="cross"
data-test-subj={RULES_CLEAR_ALL_RULES_SELECTION}
data-test-subj={RULES_TABLE_HEADER_TEST_SUBJ.CLEAR_ALL_RULES_SELECTION}
>
<FormattedMessage
id="xpack.csp.rules.rulesTable.clearSelectionOption"

View file

@ -23,5 +23,25 @@ export const RULE_COUNTERS_TEST_SUBJ = {
DISABLED_RULES_BUTTON: 'rules-counters-disabled-rules-button',
};
export const RULES_TABLE_HEADER_TEST_SUBJ = {
RULES_TABLE_HEADER_SEARCH_INPUT: 'rules-table-header-search-input',
RULES_TABLE_HEADER_MULTI_SELECT: 'rules-table-header-multi-select',
RULES_TABLE_HEADER_RULE_NUMBER_SELECT: 'rules-table-header-rule-number-select',
RULES_TABLE_HEADER_RULE_SHOWING_LABEL: 'rules-table-header-rule-showing-label',
BULK_ACTION_BUTTON: 'bulk-action-button',
BULK_ACTION_OPTION_ENABLE: 'bulk-action-option-enable',
BULK_ACTION_OPTION_DISABLE: 'bulk-action-option-disable',
SELECT_ALL_RULES: 'select-all-rules-button',
CLEAR_ALL_RULES_SELECTION: 'clear-rules-selection-button',
RULES_DISABLED_FILTER: 'rules-disabled-filter',
RULES_ENABLED_FILTER: 'rules-enabled-filter',
RULES_TABLE_HEADER_RULE_NUMBER_SELECT_BUTTON: 'rules-table-header-rule-number-select-button',
};
export const RULES_TABLE = {
RULES_ROWS_ENABLE_SWITCH_BUTTON: 'rules-row-enable-switch-button',
RULES_ROW_SELECT_ALL_CURRENT_PAGE: 'cloud-security-fields-selector-item-all',
};
export const getCspBenchmarkRuleTableRowItemTestId = (id: string) =>
`${CSP_RULES_TABLE_ROW_ITEM_NAME}_${id}`;

View file

@ -135,9 +135,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
await pageObjects.header.waitUntilLoadingHasFinished();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(true);
// add timeout to give extra time for the modal to show up
await retry.tryForTime(agentCreationTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const resStatus = await cisIntegrationAws.showPostInstallCloudFormationModal();
expect(resStatus).to.be(true);
});
await cisIntegration.navigateToIntegrationCspList();
await pageObjects.header.waitUntilLoadingHasFinished();

View file

@ -40,6 +40,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
const kibanaServer = getService('kibanaServer');
const spacesService = getService('spaces');
const retry = getService('retry');
const fetchingOfDataViewsTimeout = 1000 * 20; // 20 seconds
const pageObjects = getPageObjects([
'common',
@ -56,6 +57,16 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
let cspSecurity = pageObjects.cspSecurity;
let findings: typeof pageObjects.findings;
const waitForDataViews = async ({
timeout,
action,
}: {
timeout: number;
action: () => Promise<void>;
}) => {
await retry.tryForTime(timeout, action);
};
before(async () => {
await spacesService.delete(TEST_SPACE);
@ -98,14 +109,21 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
}
await findings.navigateToLatestVulnerabilitiesPage();
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
// give more time for the data view to be fetched before checking loading status
await waitForDataViews({
timeout: fetchingOfDataViewsTimeout,
action: async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
},
});
});
});
@ -129,14 +147,19 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
const cspDashboard = pageObjects.cloudPostureDashboard;
await cspDashboard.navigateToComplianceDashboardPage();
await pageObjects.header.waitUntilLoadingHasFinished();
await waitForDataViews({
timeout: fetchingOfDataViewsTimeout,
action: async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
},
});
});
});
@ -164,14 +187,18 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
}
await findings.navigateToLatestFindingsPage(TEST_SPACE);
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
TEST_SPACE
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
await waitForDataViews({
timeout: fetchingOfDataViewsTimeout,
action: async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
TEST_SPACE
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
},
});
});
});
@ -200,14 +227,18 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
const cspDashboard = pageObjects.cloudPostureDashboard;
await cspDashboard.navigateToComplianceDashboardPage(TEST_SPACE);
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
TEST_SPACE
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
await waitForDataViews({
timeout: fetchingOfDataViewsTimeout,
action: async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
TEST_SPACE
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
},
});
});
});
@ -234,14 +265,18 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => {
const cspDashboard = pageObjects.cloudPostureDashboard;
await cspDashboard.navigateToComplianceDashboardPage();
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
await waitForDataViews({
timeout: fetchingOfDataViewsTimeout,
action: async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
const idDataViewExistsPostFindingsNavigation = await getDataViewSafe(
kibanaServer.savedObjects,
expectedDataViewId,
'default'
);
expect(idDataViewExistsPostFindingsNavigation).to.be(true);
},
});
});
});
});

View file

@ -30,6 +30,7 @@ export default function (providerContext: FtrProviderContext) {
const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']);
const retry = getService('retry');
const logger = getService('log');
const saveIntegrationPolicyTimeout = 1000 * 30; // 30 seconds
describe('Test adding Cloud Security Posture Integrations CSPM AWS', function () {
this.tags(['cloud_security_posture_cis_integration_cspm_aws']);
@ -51,6 +52,7 @@ export default function (providerContext: FtrProviderContext) {
});
it('Hyperlink on PostInstallation Modal should have the correct URL', async () => {
await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationAws.getPostInstallCloudFormationModal()) !== undefined).to.be(
@ -83,6 +85,7 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(AWS_MANUAL_TEST_ID);
await cisIntegration.fillInTextField(ROLE_ARN_TEST_ID, roleArn);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
@ -119,15 +122,18 @@ export default function (providerContext: FtrProviderContext) {
DIRECT_ACCESS_SECRET_KEY_TEST_ID,
directAccessSecretKey
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(DIRECT_ACCESS_KEY_ID_TEST_ID)) ===
directAccessKeyId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(DIRECT_ACCESS_KEY_ID_TEST_ID)) ===
directAccessKeyId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
});
});
});
@ -151,19 +157,22 @@ export default function (providerContext: FtrProviderContext) {
TEMP_ACCESS_SESSION_TOKEN_TEST_ID,
tempAccessSessionToken
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_KEY_ID_TEST_ID)) === accessKeyId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_SESSION_TOKEN_TEST_ID)) ===
tempAccessSessionToken
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_KEY_ID_TEST_ID)) === accessKeyId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_SESSION_TOKEN_TEST_ID)) ===
tempAccessSessionToken
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
});
});
});
@ -182,19 +191,22 @@ export default function (providerContext: FtrProviderContext) {
SHARED_CREDETIALS_PROFILE_NAME_TEST_ID,
sharedCredentialProfileName
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDENTIALS_FILE_TEST_ID)) ===
sharedCredentialFile
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDETIALS_PROFILE_NAME_TEST_ID)) ===
sharedCredentialProfileName
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDENTIALS_FILE_TEST_ID)) ===
sharedCredentialFile
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDETIALS_PROFILE_NAME_TEST_ID)) ===
sharedCredentialProfileName
).to.be(true);
});
});
});
@ -202,12 +214,15 @@ export default function (providerContext: FtrProviderContext) {
it('CIS_AWS Single Cloud Formation workflow', async () => {
await cisIntegration.clickOptionButton(CIS_AWS_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html'
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html'
);
});
});
});
@ -218,13 +233,16 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(AWS_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.clickOptionButton(AWS_MANUAL_TEST_ID);
await cisIntegration.fillInTextField(ROLE_ARN_TEST_ID, roleArn);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect((await cisIntegration.getFieldValueInEditPage(ROLE_ARN_TEST_ID)) === roleArn).to.be(
true
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(ROLE_ARN_TEST_ID)) === roleArn
).to.be(true);
});
});
});
@ -244,15 +262,18 @@ export default function (providerContext: FtrProviderContext) {
DIRECT_ACCESS_SECRET_KEY_TEST_ID,
directAccessSecretKey
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(DIRECT_ACCESS_KEY_ID_TEST_ID)) ===
directAccessKeyId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(DIRECT_ACCESS_KEY_ID_TEST_ID)) ===
directAccessKeyId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
});
});
});
@ -277,19 +298,22 @@ export default function (providerContext: FtrProviderContext) {
TEMP_ACCESS_SESSION_TOKEN_TEST_ID,
tempAccessSessionToken
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_KEY_ID_TEST_ID)) === accessKeyId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_SESSION_TOKEN_TEST_ID)) ===
tempAccessSessionToken
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_KEY_ID_TEST_ID)) === accessKeyId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(TEMP_ACCESS_SESSION_TOKEN_TEST_ID)) ===
tempAccessSessionToken
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('secret-access-key')).to.not.be(null);
});
});
});
@ -309,19 +333,22 @@ export default function (providerContext: FtrProviderContext) {
SHARED_CREDETIALS_PROFILE_NAME_TEST_ID,
sharedCredentialProfileName
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDENTIALS_FILE_TEST_ID)) ===
sharedCredentialFile
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDETIALS_PROFILE_NAME_TEST_ID)) ===
sharedCredentialProfileName
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDENTIALS_FILE_TEST_ID)) ===
sharedCredentialFile
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(SHARED_CREDETIALS_PROFILE_NAME_TEST_ID)) ===
sharedCredentialProfileName
).to.be(true);
});
});
});
});

View file

@ -25,8 +25,10 @@ const clientCertificatePassword = 'clientCertificatePasswordTest';
// eslint-disable-next-line import/no-default-export
export default function (providerContext: FtrProviderContext) {
const { getPageObjects } = providerContext;
const { getPageObjects, getService } = providerContext;
const retry = getService('retry');
const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']);
const saveIntegrationPolicyTimeout = 1000 * 30; // 30 seconds
describe('Test adding Cloud Security Posture Integrations CSPM AZURE', function () {
this.tags(['cloud_security_posture_cis_integration_cspm_azure']);
@ -44,15 +46,18 @@ export default function (providerContext: FtrProviderContext) {
it('Azure Organization ARM Template Workflow', async () => {
await cisIntegration.clickOptionButton(CIS_AZURE_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(CIS_AZURE_SETUP_FORMAT_TEST_SUBJECTS.ARM_TEMPLATE);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationAzure.getPostInstallArmTemplateModal()) !== undefined).to.be(
true
);
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager'
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationAzure.getPostInstallArmTemplateModal()) !== undefined).to.be(
true
);
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager'
);
});
});
});
@ -61,9 +66,13 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(CIS_AZURE_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(CIS_AZURE_SETUP_FORMAT_TEST_SUBJECTS.MANUAL);
await cisIntegration.selectValue(AZURE_CREDENTIAL_SELECTOR, 'managed_identity');
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
});
});
});
@ -88,22 +97,26 @@ export default function (providerContext: FtrProviderContext) {
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_SECRET,
clientSecret
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('client-secret')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('client-secret')).to.not.be(null);
});
});
});
@ -133,27 +146,30 @@ export default function (providerContext: FtrProviderContext) {
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PASSWORD,
clientCertificatePassword
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PATH
)) === clientCertificatePath
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PATH
)) === clientCertificatePath
).to.be(true);
});
});
});
@ -161,15 +177,18 @@ export default function (providerContext: FtrProviderContext) {
it('Azure Single ARM Template Workflow', async () => {
await cisIntegration.clickOptionButton(CIS_AZURE_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(CIS_AZURE_SINGLE_SUB_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationAzure.getPostInstallArmTemplateModal()) !== undefined).to.be(
true
);
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager'
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationAzure.getPostInstallArmTemplateModal()) !== undefined).to.be(
true
);
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager'
);
});
});
});
@ -179,9 +198,12 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(CIS_AZURE_SINGLE_SUB_TEST_ID);
await cisIntegration.clickOptionButton(CIS_AZURE_SETUP_FORMAT_TEST_SUBJECTS.MANUAL);
await cisIntegration.selectValue(AZURE_CREDENTIAL_SELECTOR, 'managed_identity');
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
});
});
});
@ -206,22 +228,25 @@ export default function (providerContext: FtrProviderContext) {
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_SECRET,
clientSecret
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('client-secret')).to.not.be(null);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(await cisIntegration.getReplaceSecretButton('client-secret')).to.not.be(null);
});
});
});
@ -251,27 +276,29 @@ export default function (providerContext: FtrProviderContext) {
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PASSWORD,
clientCertificatePassword
);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PATH
)) === clientCertificatePath
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_ID
)) === clientId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.TENANT_ID
)) === tenantId
).to.be(true);
expect(
(await cisIntegration.getValueInEditPage(
CIS_AZURE_INPUT_FIELDS_TEST_SUBJECTS.CLIENT_CERTIFICATE_PATH
)) === clientCertificatePath
).to.be(true);
});
});
});
});

View file

@ -24,8 +24,10 @@ const {
// eslint-disable-next-line import/no-default-export
export default function (providerContext: FtrProviderContext) {
const { getPageObjects } = providerContext;
const { getPageObjects, getService } = providerContext;
const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']);
const retry = getService('retry');
const saveIntegrationPolicyTimeout = 1000 * 30; // 30 seconds
describe('Test adding Cloud Security Posture Integrations CSPM GCP', function () {
this.tags(['cloud_security_posture_cis_integration_cspm_gcp']);
@ -65,11 +67,15 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(GCP_ORGANIZATION_TEST_ID);
await cisIntegration.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(true)) === true).to.be(
true
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(true)) === true).to.be(
true
);
});
});
it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are Project ID or Organization ID provided, it should use that value', async () => {
@ -80,16 +86,19 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID);
await cisIntegration.fillInTextField('project_id_test_id', projectName);
await cisIntegration.fillInTextField('organization_id_test_id', organizationName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(
true,
organizationName,
projectName
)) === true
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(
true,
organizationName,
projectName
)) === true
).to.be(true);
});
});
it('Add Agent FLyout - Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are Project ID or Organization ID provided, it should use that value', async () => {
@ -103,40 +112,51 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(GCP_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false)) === true).to.be(
true
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false)) === true
).to.be(true);
});
});
it('Hyperlink on PostInstallation Modal should have the correct URL', async () => {
await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://cloud.google.com/shell/docs'
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegration.getUrlOnPostInstallModal()) ===
'https://cloud.google.com/shell/docs'
);
});
});
it('Clicking on Launch CloudShell on post intall modal should lead user to CloudShell page', async () => {
await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(
await cisIntegration.clickLaunchAndGetCurrentUrl(
'confirmGoogleCloudShellModalConfirmButton'
)
).includes('shell.cloud.google.com%2Fcloudshell')
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(
await cisIntegration.clickLaunchAndGetCurrentUrl(
'confirmGoogleCloudShellModalConfirmButton'
)
).includes('shell.cloud.google.com%2Fcloudshell')
).to.be(true);
});
});
});
// FLAKY: https://github.com/elastic/kibana/issues/190779
describe.skip('CIS_GCP Organization Credentials File', () => {
describe('CIS_GCP Organization Credentials File', () => {
it('CIS_GCP Organization Credentials File workflow', async () => {
const projectName = 'PRJ_NAME_TEST';
const credentialFileName = 'CRED_FILE_TEST_NAME';
@ -145,14 +165,18 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(GCP_MANUAL_TEST_ID);
await cisIntegration.fillInTextField(PRJ_ID_TEST_ID, projectName);
await cisIntegration.fillInTextField(CREDENTIALS_FILE_TEST_ID, credentialFileName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(CREDENTIALS_FILE_TEST_ID)) ===
credentialFileName
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(CREDENTIALS_FILE_TEST_ID)) ===
credentialFileName
).to.be(true);
});
});
});
@ -169,30 +193,38 @@ export default function (providerContext: FtrProviderContext) {
'credentials_json_option_test_id'
);
await cisIntegration.fillInTextField(CREDENTIALS_JSON_TEST_ID, credentialJsonName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getSecretComponentReplaceButton(
'button-replace-credentials-json'
)) !== undefined
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getSecretComponentReplaceButton(
'button-replace-credentials-json'
)) !== undefined
).to.be(true);
});
});
});
// FLAKY: https://github.com/elastic/kibana/issues/191144
describe.skip('CIS_GCP Single', () => {
describe('CIS_GCP Single', () => {
it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are no Project ID, it should use default value', async () => {
await cisIntegration.clickOptionButton(CIS_GCP_OPTION_TEST_ID);
await cisIntegration.clickOptionButton(GCP_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false)) === true).to.be(
true
);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false)) === true
).to.be(true);
});
});
it('Post Installation Google Cloud Shell modal pops up after user clicks on Save button when adding integration, when there are Project ID, it should use that value', async () => {
const projectName = 'PRJ_NAME_TEST';
@ -200,12 +232,16 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(GCP_SINGLE_ACCOUNT_TEST_ID);
await cisIntegration.clickOptionButton(GCP_CLOUD_SHELL_TEST_ID);
await cisIntegration.fillInTextField('project_id_test_id', projectName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false, '', projectName)) ===
true
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect(
(await cisIntegrationGcp.isPostInstallGoogleCloudShellModal(false, '', projectName)) ===
true
).to.be(true);
});
});
it('Add Agent FLyout - Organization ID field on cloud shell command should only be shown if user chose Google Cloud Shell, if user chose Single Account it shouldn not show up', async () => {
await cisIntegration.navigateToIntegrationCspList();
@ -235,14 +271,19 @@ export default function (providerContext: FtrProviderContext) {
await cisIntegration.clickOptionButton(GCP_MANUAL_TEST_ID);
await cisIntegration.fillInTextField(PRJ_ID_TEST_ID, projectName);
await cisIntegration.fillInTextField(CREDENTIALS_FILE_TEST_ID, credentialFileName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(CREDENTIALS_FILE_TEST_ID)) ===
credentialFileName
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
expect(
(await cisIntegration.getFieldValueInEditPage(CREDENTIALS_FILE_TEST_ID)) ===
credentialFileName
).to.be(true);
});
});
it('Users are able to switch credentials_type from/to Credential JSON fields ', async () => {
const credentialJsonName = 'CRED_JSON_TEST_NAME';
@ -274,16 +315,20 @@ export default function (providerContext: FtrProviderContext) {
'credentials_json_option_test_id'
);
await cisIntegration.fillInTextField(CREDENTIALS_JSON_TEST_ID, credentialJsonName);
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getSecretComponentReplaceButton(
'button-replace-credentials-json'
)) !== undefined
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.getSecretComponentReplaceButton(
'button-replace-credentials-json'
)) !== undefined
).to.be(true);
});
});
it('Users are able to switch credentials_type from/to Credential File fields ', async () => {
const credentialFileName = 'CRED_FILE_TEST_NAME';

View file

@ -10,8 +10,10 @@ import type { FtrProviderContext } from '../../../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default function (providerContext: FtrProviderContext) {
const { getPageObjects } = providerContext;
const { getPageObjects, getService } = providerContext;
const pageObjects = getPageObjects(['cloudPostureDashboard', 'cisAddIntegration', 'header']);
const retry = getService('retry');
const saveIntegrationPolicyTimeout = 1000 * 30; // 30 seconds
describe('Test adding Cloud Security Posture Integrations KSPM K8S', function () {
this.tags(['cloud_security_posture_cis_integration_kspm_k8s']);
@ -24,14 +26,17 @@ export default function (providerContext: FtrProviderContext) {
describe('KSPM K8S', () => {
it('KSPM K8S Workflow', async () => {
await cisIntegration.inputUniqueIntegrationName();
await cisIntegration.clickSaveButton();
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.isOptionChecked('cisK8sTestId', 'cloudbeat/cis_k8s')) === 'true'
).to.be(true);
await retry.tryForTime(saveIntegrationPolicyTimeout, async () => {
await pageObjects.header.waitUntilLoadingHasFinished();
expect((await cisIntegration.getPostInstallModal()) !== undefined).to.be(true);
await cisIntegration.navigateToIntegrationCspList();
await cisIntegration.clickFirstElementOnIntegrationTable();
expect(
(await cisIntegration.isOptionChecked('cisK8sTestId', 'cloudbeat/cis_k8s')) === 'true'
).to.be(true);
});
});
});
});

View file

@ -9,8 +9,9 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../ftr_provider_context';
// eslint-disable-next-line import/no-default-export
export default ({ getPageObjects }: FtrProviderContext) => {
export default ({ getPageObjects, getService }: FtrProviderContext) => {
const PageObjects = getPageObjects(['common', 'findings', 'header']);
const retry = getService('retry');
describe('Findings Page onboarding', function () {
this.tags(['cloud_security_posture_findings_onboarding']);
@ -18,6 +19,13 @@ export default ({ getPageObjects }: FtrProviderContext) => {
let notInstalledCSP: typeof findings.notInstalledCSP;
let thirdPartyIntegrationsNoMisconfigurationsFindingsPrompt: typeof findings.thirdPartyIntegrationsNoMisconfigurationsFindingsPrompt;
// wrapper function to waitUntilLoadingHasFinished
const navigateToMisconfigurationsWithRetry = async () => {
await retry.try(async () => {
await PageObjects.header.waitUntilLoadingHasFinished();
});
};
beforeEach(async () => {
findings = PageObjects.findings;
notInstalledCSP = findings.notInstalledCSP;
@ -29,7 +37,7 @@ export default ({ getPageObjects }: FtrProviderContext) => {
it('Misconfigurations - clicking on the `No integrations installed` prompt action button - `install cloud posture integration`: navigates to the CSPM integration installation page', async () => {
await findings.navigateToMisconfigurations();
await PageObjects.header.waitUntilLoadingHasFinished();
await navigateToMisconfigurationsWithRetry();
const element = await notInstalledCSP.getElement();
expect(element).to.not.be(null);
@ -40,7 +48,7 @@ export default ({ getPageObjects }: FtrProviderContext) => {
it('Misconfigurations - clicking on the `No integrations installed` prompt action button - `install kubernetes posture integration`: navigates to the KSPM integration installation page', async () => {
await findings.navigateToMisconfigurations();
await PageObjects.header.waitUntilLoadingHasFinished();
await navigateToMisconfigurationsWithRetry();
const element = await notInstalledCSP.getElement();
expect(element).to.not.be(null);
@ -51,7 +59,7 @@ export default ({ getPageObjects }: FtrProviderContext) => {
it('Misconfigurations - clicking on the `Third party integrations` prompt action button - `Wiz Integration`: navigates to the Wiz integration installation page', async () => {
await findings.navigateToMisconfigurations();
await PageObjects.header.waitUntilLoadingHasFinished();
await navigateToMisconfigurationsWithRetry();
const element = await thirdPartyIntegrationsNoMisconfigurationsFindingsPrompt.getElement();
expect(element).to.not.be(null);