diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts
index 04a47f0fc12a1..d4d436e981cc4 100644
--- a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts
+++ b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts
@@ -9,4 +9,5 @@ import { euiThemeVars } from '@kbn/ui-theme';
export const statusColors = {
passed: euiThemeVars.euiColorSuccess,
failed: euiThemeVars.euiColorVis9,
+ unknown: euiThemeVars.euiColorLightShade,
};
diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx
new file mode 100644
index 0000000000000..166fb1184e0b9
--- /dev/null
+++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.test.tsx
@@ -0,0 +1,49 @@
+/*
+ * 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 { ComplianceScoreBar } from './compliance_score_bar';
+import {
+ COMPLIANCE_SCORE_BAR_UNKNOWN,
+ COMPLIANCE_SCORE_BAR_PASSED,
+ COMPLIANCE_SCORE_BAR_FAILED,
+} from './test_subjects';
+
+describe('', () => {
+ it('should display 0% compliance score with status unknown when both passed and failed are 0', () => {
+ render();
+ expect(screen.getByText('0%')).toBeInTheDocument();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).not.toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
+ });
+
+ it('should display 100% compliance score when passed is greater than 0 and failed is 0', () => {
+ render();
+ expect(screen.getByText('100%')).toBeInTheDocument();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
+ });
+
+ it('should display 0% compliance score when passed is 0 and failed is greater than 0', () => {
+ render();
+ expect(screen.getByText('0%')).toBeInTheDocument();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
+ });
+
+ it('should display 50% compliance score when passed is equal to failed', () => {
+ render();
+ expect(screen.getByText('50%')).toBeInTheDocument();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_FAILED)).not.toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_PASSED)).not.toBeNull();
+ expect(screen.queryByTestId(COMPLIANCE_SCORE_BAR_UNKNOWN)).toBeNull();
+ });
+});
diff --git a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
index d4acbc97ab10c..3829542829909 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/components/compliance_score_bar.tsx
@@ -11,7 +11,12 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import { statusColors } from '@kbn/cloud-security-posture';
import { calculatePostureScore } from '../../common/utils/helpers';
-import { CSP_FINDINGS_COMPLIANCE_SCORE } from './test_subjects';
+import {
+ CSP_FINDINGS_COMPLIANCE_SCORE,
+ COMPLIANCE_SCORE_BAR_UNKNOWN,
+ COMPLIANCE_SCORE_BAR_FAILED,
+ COMPLIANCE_SCORE_BAR_PASSED,
+} from './test_subjects';
/**
* This component will take 100% of the width set by the parent
@@ -59,12 +64,22 @@ export const ComplianceScoreBar = ({
gap: 1px;
`}
>
+ {!totalPassed && !totalFailed && (
+
+ )}
{!!totalPassed && (
)}
{!!totalFailed && (
@@ -73,6 +88,7 @@ export const ComplianceScoreBar = ({
flex: ${totalFailed};
background: ${statusColors.failed};
`}
+ data-test-subj={COMPLIANCE_SCORE_BAR_FAILED}
/>
)}
diff --git a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts
index d29971d3352e3..b609950720ecd 100644
--- a/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts
+++ b/x-pack/plugins/cloud_security_posture/public/components/test_subjects.ts
@@ -92,3 +92,7 @@ export const CIS_GCP_INPUT_FIELDS_TEST_SUBJECTS = {
};
export const SUBSCRIPTION_NOT_ALLOWED_TEST_SUBJECT = 'cloud_posture_page_subscription_not_allowed';
+
+export const COMPLIANCE_SCORE_BAR_UNKNOWN = 'complianceScoreBarUnknown';
+export const COMPLIANCE_SCORE_BAR_FAILED = 'complianceScoreBarFailed';
+export const COMPLIANCE_SCORE_BAR_PASSED = 'complianceScoreBarPassed';
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx
new file mode 100644
index 0000000000000..60aa64aa88141
--- /dev/null
+++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.test.tsx
@@ -0,0 +1,101 @@
+/*
+ * 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 } from '@testing-library/react';
+import { useEuiTheme } from '@elastic/eui';
+import { ComplianceBarComponent } from './latest_findings_group_renderer';
+import { RawBucket } from '@kbn/grouping/src';
+import { FindingsGroupingAggregation } from './use_grouped_findings';
+import { ComplianceScoreBar } from '../../../components/compliance_score_bar';
+
+jest.mock('@elastic/eui', () => {
+ const actual = jest.requireActual('@elastic/eui');
+ return {
+ ...actual,
+ useEuiTheme: jest.fn(),
+ };
+});
+
+jest.mock('../../../components/compliance_score_bar', () => ({
+ ComplianceScoreBar: jest.fn(() => null),
+}));
+
+jest.mock('../../../components/cloud_security_grouping');
+
+describe('', () => {
+ beforeEach(() => {
+ (useEuiTheme as jest.Mock).mockReturnValue({ euiTheme: { size: { s: 's' } } });
+ (ComplianceScoreBar as jest.Mock).mockClear();
+ });
+
+ it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when total = failed+passed', () => {
+ const bucket = {
+ doc_count: 10,
+ failedFindings: {
+ doc_count: 4,
+ },
+ passedFindings: {
+ doc_count: 6,
+ },
+ } as RawBucket;
+
+ render();
+
+ expect(ComplianceScoreBar).toHaveBeenCalledWith(
+ expect.objectContaining({
+ totalFailed: 4,
+ totalPassed: 6,
+ }),
+ {}
+ );
+ });
+
+ it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are unknown findings', () => {
+ const bucket = {
+ doc_count: 10,
+ failedFindings: {
+ doc_count: 3,
+ },
+ passedFindings: {
+ doc_count: 6,
+ },
+ } as RawBucket;
+
+ render();
+
+ expect(ComplianceScoreBar).toHaveBeenCalledWith(
+ expect.objectContaining({
+ totalFailed: 3,
+ totalPassed: 6,
+ }),
+ {}
+ );
+ });
+
+ it('renders ComplianceScoreBar with correct totalFailed and totalPassed, when there are no findings', () => {
+ const bucket = {
+ doc_count: 10,
+ failedFindings: {
+ doc_count: 0,
+ },
+ passedFindings: {
+ doc_count: 0,
+ },
+ } as RawBucket;
+
+ render();
+
+ expect(ComplianceScoreBar).toHaveBeenCalledWith(
+ expect.objectContaining({
+ totalFailed: 0,
+ totalPassed: 0,
+ }),
+ {}
+ );
+ });
+});
diff --git a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx
index b4ad5d15ec8e9..b41c5e4996db1 100644
--- a/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx
+++ b/x-pack/plugins/cloud_security_posture/public/pages/configurations/latest_findings/latest_findings_group_renderer.tsx
@@ -198,11 +198,15 @@ const FindingsCountComponent = ({ bucket }: { bucket: RawBucket }) => {
+export const ComplianceBarComponent = ({
+ bucket,
+}: {
+ bucket: RawBucket;
+}) => {
const { euiTheme } = useEuiTheme();
const totalFailed = bucket.failedFindings?.doc_count || 0;
- const totalPassed = bucket.doc_count - totalFailed;
+ const totalPassed = bucket.passedFindings?.doc_count || 0;
return (
;
- numberOfPassedFindings?: number;
- numberOfFailedFindings?: number;
}) => {
return (