Repository: provectus/kafka-ui
Issue: Topic stats look strange
Labels: type/bug
scope/frontend
status/accepted

<img width="307" alt="Screenshot 2021-12-17 at 13 39 40" src="https://user-images.githubusercontent.com/1096273/146532288-a54d7e14-8616-4063-9388-4339ec09fae2.png">

1.  URP = 0 is good, so it should green/black if 0 and red if greater than 0 
2.  In sync replicas marked with dot, what does it mean? 1 of 1 looks correct for me.

Issue comments:

Pull request review comments:
@NelyDavtyan this change should not occur. Please regen your types locally first `npm run gen:sources`
ping: @Haarolean
@workshur, thanks.
pls cover your code with tests
there is no snapshot as I see
Actually we need to add specs for this particular line of [code](https://sonarcloud.io/component_measures?id=provectus_kafka-ui_frontend&metric=new_coverage&pullRequest=1336&selected=provectus_kafka-ui_frontend%3Asrc%2Fcomponents%2FTopics%2FTopic%2FDetails%2FOverview%2FOverview.tsx&view=list) 
To my mind 82-83 rows are unnecessary, because on row 84, you check the same thing
Maybe we should move this constants to fixtures. And also create an object rather then many strings, type this object with some interface(or use one from Overview component props) and pass as props into renderComponent
As Oleg mentioned in my PR, that we should not use explicitly 'Colors', but import them as theme, I think that here we should also use theme like this:
https://github.com/provectus/kafka-ui/blob/master/kafka-ui-react-app/src/components/common/Pagination/__tests__/Pagination.spec.tsx#L83
Oops, you're right, thanks. 😊
Yes, you are right. I will delete.
I've fixed it.
 Do we really need shallow from enzyme here? Or we can rewrite this test with renderComponent from testing library
Yeah It looks like easy win
Decided to rewrite it in another issue

Patch that resolved the issue:
diff --git a/kafka-ui-react-app/src/components/Connect/Details/Overview/__tests__/__snapshots__/Overview.spec.tsx.snap b/kafka-ui-react-app/src/components/Connect/Details/Overview/__tests__/__snapshots__/Overview.spec.tsx.snap
index ebe3e8573a9..d704ed4b835 100644
--- a/kafka-ui-react-app/src/components/Connect/Details/Overview/__tests__/__snapshots__/Overview.spec.tsx.snap
+++ b/kafka-ui-react-app/src/components/Connect/Details/Overview/__tests__/__snapshots__/Overview.spec.tsx.snap
@@ -211,6 +211,7 @@ exports[`Overview view matches snapshot 1`] = `
              
             <svg
               className="c6"
+              role="svg"
               viewBox="0 0 4 4"
               xmlns="http://www.w3.org/2000/svg"
             >
@@ -219,6 +220,7 @@ exports[`Overview view matches snapshot 1`] = `
                 cx={2}
                 cy={2}
                 r={2}
+                role="circle"
               />
             </svg>
           </div>
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
index abce1702b59..81bcc3456eb 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/Overview.tsx
@@ -11,7 +11,7 @@ import VerticalElipsisIcon from 'components/common/Icons/VerticalElipsisIcon';
 import * as Metrics from 'components/common/Metrics';
 import TagStyled from 'components/common/Tag/Tag.styled';
 
-interface Props extends Topic, TopicDetails {
+export interface Props extends Topic, TopicDetails {
   clusterName: ClusterName;
   topicName: TopicName;
   clearTopicMessages(
@@ -52,6 +52,7 @@ const Overview: React.FC<Props> = ({
             label="URP"
             title="Under replicated partitions"
             isAlert
+            alertType={underReplicatedPartitions === 0 ? 'error' : 'success'}
           >
             <Metrics.RedText>{underReplicatedPartitions}</Metrics.RedText>
           </Metrics.Indicator>
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx
index 3bd9fd920a2..f0b8f58303b 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Overview/__test__/Overview.spec.tsx
@@ -1,9 +1,11 @@
 import React from 'react';
 import { shallow } from 'enzyme';
+import { screen } from '@testing-library/react';
+import { render } from 'lib/testHelpers';
 import Overview from 'components/Topics/Topic/Details/Overview/Overview';
+import theme from 'theme/theme';
 
 describe('Overview', () => {
-  const mockInternal = false;
   const mockClusterName = 'local';
   const mockTopicName = 'topic';
   const mockClearTopicMessages = jest.fn();
@@ -23,13 +25,32 @@ describe('Overview', () => {
     },
   ];
 
+  const renderComponent = ({
+    underReplicatedPartitions = 1,
+    inSyncReplicas = 1,
+    replicas = 1,
+  } = {}) =>
+    render(
+      <Overview
+        name={mockTopicName}
+        partitions={mockPartitions}
+        internal={undefined}
+        clusterName={mockClusterName}
+        topicName={mockTopicName}
+        clearTopicMessages={mockClearTopicMessages}
+        underReplicatedPartitions={underReplicatedPartitions}
+        inSyncReplicas={inSyncReplicas}
+        replicas={replicas}
+      />
+    );
+
   describe('when it has internal flag', () => {
     it('does not render the Action button a Topic', () => {
       const component = shallow(
         <Overview
           name={mockTopicName}
           partitions={mockPartitions}
-          internal={mockInternal}
+          internal={false}
           clusterName={mockClusterName}
           topicName={mockTopicName}
           clearTopicMessages={mockClearTopicMessages}
@@ -44,7 +65,7 @@ describe('Overview', () => {
         <Overview
           name={mockTopicName}
           partitions={[]}
-          internal={mockInternal}
+          internal
           clusterName={mockClusterName}
           topicName={mockTopicName}
           clearTopicMessages={mockClearTopicMessages}
@@ -54,4 +75,27 @@ describe('Overview', () => {
       expect(componentEmpty.find('td').text()).toEqual('No Partitions found');
     });
   });
+
+  describe('should render circular alert', () => {
+    it('should be in document', () => {
+      renderComponent();
+      const circles = screen.getAllByRole('circle');
+      expect(circles.length).toEqual(2);
+    });
+
+    it('should be the appropriate color', () => {
+      renderComponent({
+        underReplicatedPartitions: 0,
+        inSyncReplicas: 1,
+        replicas: 2,
+      });
+      const circles = screen.getAllByRole('circle');
+      expect(circles[0]).toHaveStyle(
+        `fill: ${theme.circularAlert.color.error}`
+      );
+      expect(circles[1]).toHaveStyle(
+        `fill: ${theme.circularAlert.color.error}`
+      );
+    });
+  });
 });
diff --git a/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx b/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx
index 5b98b645287..3431b67394a 100644
--- a/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx
+++ b/kafka-ui-react-app/src/components/common/Metrics/Indicator.tsx
@@ -3,7 +3,7 @@ import { AlertType } from 'redux/interfaces';
 
 import * as S from './Metrics.styled';
 
-interface Props {
+export interface Props {
   fetching?: boolean;
   isAlert?: boolean;
   label: React.ReactNode;
diff --git a/kafka-ui-react-app/src/components/common/Metrics/Metrics.styled.tsx b/kafka-ui-react-app/src/components/common/Metrics/Metrics.styled.tsx
index 8384e12aa3f..6feb0a3da93 100644
--- a/kafka-ui-react-app/src/components/common/Metrics/Metrics.styled.tsx
+++ b/kafka-ui-react-app/src/components/common/Metrics/Metrics.styled.tsx
@@ -78,6 +78,7 @@ export const RedText = styled.span`
 `;
 
 export const CircularAlertWrapper = styled.svg.attrs({
+  role: 'svg',
   viewBox: '0 0 4 4',
   xmlns: 'http://www.w3.org/2000/svg',
 })`
@@ -87,7 +88,12 @@ export const CircularAlertWrapper = styled.svg.attrs({
   height: 4px;
 `;
 
-export const CircularAlert = styled.circle.attrs({ cx: 2, cy: 2, r: 2 })<{
+export const CircularAlert = styled.circle.attrs({
+  role: 'circle',
+  cx: 2,
+  cy: 2,
+  r: 2,
+})<{
   $type: AlertType;
 }>(
   ({ theme, $type }) => css`
diff --git a/kafka-ui-react-app/src/components/common/Metrics/__tests__/Indicator.spec.tsx b/kafka-ui-react-app/src/components/common/Metrics/__tests__/Indicator.spec.tsx
index 10fcaa85675..07bb6f6853d 100644
--- a/kafka-ui-react-app/src/components/common/Metrics/__tests__/Indicator.spec.tsx
+++ b/kafka-ui-react-app/src/components/common/Metrics/__tests__/Indicator.spec.tsx
@@ -2,20 +2,61 @@ import React from 'react';
 import { Indicator } from 'components/common/Metrics';
 import { screen } from '@testing-library/react';
 import { render } from 'lib/testHelpers';
+import { Props } from 'components/common/Metrics/Indicator';
+import theme from 'theme/theme';
 
 const title = 'Test Title';
 const label = 'Test Label';
 const child = 'Child';
 
 describe('Indicator', () => {
-  it('matches the snapshot', () => {
+  const setupComponent = (props: Partial<Props> = {}) =>
     render(
-      <Indicator title={title} label="Test Label">
+      <Indicator title={props.title} label={props.label} {...props}>
         {child}
       </Indicator>
     );
+
+  it('renders indicator', () => {
+    setupComponent({ title, label });
     expect(screen.getByTitle(title)).toBeInTheDocument();
     expect(screen.getByText(label)).toBeInTheDocument();
     expect(screen.getByText(child)).toBeInTheDocument();
   });
+
+  describe('should render circular alert', () => {
+    it('should be in document', () => {
+      setupComponent({ title, label, isAlert: true });
+      expect(screen.getByRole('svg')).toBeInTheDocument();
+      expect(screen.getByRole('circle')).toBeInTheDocument();
+    });
+
+    it('success alert', () => {
+      setupComponent({ title, label, isAlert: true, alertType: 'success' });
+      expect(screen.getByRole('circle')).toHaveStyle(
+        `fill: ${theme.circularAlert.color.success}`
+      );
+    });
+
+    it('error alert', () => {
+      setupComponent({ title, label, isAlert: true, alertType: 'error' });
+      expect(screen.getByRole('circle')).toHaveStyle(
+        `fill: ${theme.circularAlert.color.error}`
+      );
+    });
+
+    it('warning alert', () => {
+      setupComponent({ title, label, isAlert: true, alertType: 'warning' });
+      expect(screen.getByRole('circle')).toHaveStyle(
+        `fill: ${theme.circularAlert.color.warning}`
+      );
+    });
+
+    it('info alert', () => {
+      setupComponent({ title, label, isAlert: true, alertType: 'info' });
+      expect(screen.getByRole('circle')).toHaveStyle(
+        `fill: ${theme.circularAlert.color.info}`
+      );
+    });
+  });
 });


Test patch: