Browse Source

[Issue 1508] Improve test coverage (#1527)

* component Utils test covered

* component Topic test covered

* Improved test coverage

* edited ConfigListItem component

* Resolve feedback's comment

* made correct description in test case title
Zorii4 3 years ago
parent
commit
8a7399b093

+ 0 - 1
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/utils.ts

@@ -31,7 +31,6 @@ export const getTimestampFromSeekToParam = (params: URLSearchParams) => {
       .get('seekTo')
       .get('seekTo')
       ?.split(',')
       ?.split(',')
       .map((item) => Number(item.split('::')[1]));
       .map((item) => Number(item.split('::')[1]));
-
     return new Date(Math.max(...(offsets || []), 0));
     return new Date(Math.max(...(offsets || []), 0));
   }
   }
 
 

+ 88 - 1
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/utils.spec.ts

@@ -1,5 +1,11 @@
 import { Option } from 'react-multi-select-component/dist/lib/interfaces';
 import { Option } from 'react-multi-select-component/dist/lib/interfaces';
-import { filterOptions } from 'components/Topics/Topic/Details/Messages/Filters/utils';
+import {
+  filterOptions,
+  getOffsetFromSeekToParam,
+  getTimestampFromSeekToParam,
+  getSelectedPartitionsFromSeekToParam,
+} from 'components/Topics/Topic/Details/Messages/Filters/utils';
+import { SeekType, Partition } from 'generated-sources';
 
 
 const options: Option[] = [
 const options: Option[] = [
   {
   {
@@ -20,6 +26,9 @@ const options: Option[] = [
   },
   },
 ];
 ];
 
 
+let paramsString;
+let searchParams = new URLSearchParams(paramsString);
+
 describe('utils', () => {
 describe('utils', () => {
   describe('filterOptions', () => {
   describe('filterOptions', () => {
     it('returns options if no filter is defined', () => {
     it('returns options if no filter is defined', () => {
@@ -30,4 +39,82 @@ describe('utils', () => {
       expect(filterOptions(options, '11')).toEqual([options[2]]);
       expect(filterOptions(options, '11')).toEqual([options[2]]);
     });
     });
   });
   });
+
+  describe('getOffsetFromSeekToParam', () => {
+    beforeEach(() => {
+      paramsString = 'seekTo=0::123,1::123,2::0';
+      searchParams = new URLSearchParams(paramsString);
+    });
+
+    it('returns nothing when param "seekType" is equal BEGGINING', () => {
+      searchParams.set('seekType', SeekType.BEGINNING);
+      expect(getOffsetFromSeekToParam(searchParams)).toEqual('');
+    });
+
+    it('returns nothing when param "seekType" is equal TIMESTAMP', () => {
+      searchParams.set('seekType', SeekType.TIMESTAMP);
+      expect(getOffsetFromSeekToParam(searchParams)).toEqual('');
+    });
+
+    it('returns correct messages list when param "seekType" is equal OFFSET', () => {
+      searchParams.set('seekType', SeekType.OFFSET);
+      expect(getOffsetFromSeekToParam(searchParams)).toEqual('123');
+    });
+
+    it('returns 0 when param "seekTo" is not defined and param "seekType" is equal OFFSET', () => {
+      searchParams.set('seekType', SeekType.OFFSET);
+      searchParams.delete('seekTo');
+      expect(getOffsetFromSeekToParam(searchParams)).toEqual('0');
+    });
+  });
+
+  describe('getTimestampFromSeekToParam', () => {
+    beforeEach(() => {
+      paramsString = `seekTo=0::1627333200000,1::1627333200000`;
+      searchParams = new URLSearchParams(paramsString);
+    });
+
+    it('returns null when param "seekType" is equal BEGGINING', () => {
+      searchParams.set('seekType', SeekType.BEGINNING);
+      expect(getTimestampFromSeekToParam(searchParams)).toEqual(null);
+    });
+    it('returns null when param "seekType" is equal OFFSET', () => {
+      searchParams.set('seekType', SeekType.OFFSET);
+      expect(getTimestampFromSeekToParam(searchParams)).toEqual(null);
+    });
+    it('returns correct messages list when param "seekType" is equal TIMESTAMP', () => {
+      searchParams.set('seekType', SeekType.TIMESTAMP);
+      expect(getTimestampFromSeekToParam(searchParams)).toEqual(
+        new Date(1627333200000)
+      );
+    });
+    it('returns default timestamp when param "seekTo" is empty and param "seekType" is equal TIMESTAMP', () => {
+      searchParams.set('seekType', SeekType.TIMESTAMP);
+      searchParams.delete('seekTo');
+      expect(getTimestampFromSeekToParam(searchParams)).toEqual(new Date(0));
+    });
+  });
+
+  describe('getSelectedPartitionsFromSeekToParam', () => {
+    const part: Partition[] = [{ partition: 42, offsetMin: 0, offsetMax: 100 }];
+
+    it('returns parsed partition from params when partition list includes selected partition', () => {
+      searchParams.set('seekTo', '42::0');
+      expect(getSelectedPartitionsFromSeekToParam(searchParams, part)).toEqual([
+        { label: '42', value: 42 },
+      ]);
+    });
+    it('returns parsed partition from params when partition list NOT includes selected partition', () => {
+      searchParams.set('seekTo', '24::0');
+      expect(getSelectedPartitionsFromSeekToParam(searchParams, part)).toEqual(
+        []
+      );
+    });
+    it('returns partitions when param "seekTo" is not defined', () => {
+      searchParams.delete('seekTo');
+      expect(getSelectedPartitionsFromSeekToParam(searchParams, part)).toEqual([
+        { label: '42', value: 42 },
+      ]);
+    });
+  });
 });
 });

+ 8 - 4
kafka-ui-react-app/src/components/Topics/Topic/Details/Settings/ConfigListItem.tsx

@@ -3,19 +3,23 @@ import React from 'react';
 
 
 import * as S from './Settings.styled';
 import * as S from './Settings.styled';
 
 
-interface ListItemProps {
+export interface ListItemProps {
   config: TopicConfig;
   config: TopicConfig;
 }
 }
 
 
 const ConfigListItem: React.FC<ListItemProps> = ({
 const ConfigListItem: React.FC<ListItemProps> = ({
   config: { name, value, defaultValue },
   config: { name, value, defaultValue },
 }) => {
 }) => {
-  const hasCustomValue = value !== defaultValue;
+  const hasCustomValue = !!defaultValue && value !== defaultValue;
 
 
   return (
   return (
     <S.ConfigList>
     <S.ConfigList>
-      <S.ConfigItemCell $hasCustomValue>{name}</S.ConfigItemCell>
-      <S.ConfigItemCell $hasCustomValue>{value}</S.ConfigItemCell>
+      <S.ConfigItemCell $hasCustomValue={hasCustomValue}>
+        {name}
+      </S.ConfigItemCell>
+      <S.ConfigItemCell $hasCustomValue={hasCustomValue}>
+        {value}
+      </S.ConfigItemCell>
       <td className="has-text-grey" title="Default Value">
       <td className="has-text-grey" title="Default Value">
         {hasCustomValue && defaultValue}
         {hasCustomValue && defaultValue}
       </td>
       </td>

+ 1 - 1
kafka-ui-react-app/src/components/Topics/Topic/Details/Settings/Settings.styled.ts

@@ -6,5 +6,5 @@ export const ConfigList = styled.tr`
   }
   }
 `;
 `;
 export const ConfigItemCell = styled.td<{ $hasCustomValue: boolean }>`
 export const ConfigItemCell = styled.td<{ $hasCustomValue: boolean }>`
-  font-weight: ${(props) => (props.$hasCustomValue ? 500 : 400)};
+  font-weight: ${(props) => (props.$hasCustomValue ? 500 : 400)} !important;
 `;
 `;

+ 42 - 0
kafka-ui-react-app/src/components/Topics/Topic/Details/Settings/__test__/ConfigListItem.spec.tsx

@@ -0,0 +1,42 @@
+import React from 'react';
+import { render } from 'lib/testHelpers';
+import { screen } from '@testing-library/react';
+import ConfigListItem, {
+  ListItemProps,
+} from 'components/Topics/Topic/Details/Settings/ConfigListItem';
+
+const setupComponent = (props: ListItemProps) => {
+  render(
+    <table>
+      <tbody>
+        <ConfigListItem {...props} />
+      </tbody>
+    </table>
+  );
+};
+
+it('renders with CustomValue', () => {
+  setupComponent({
+    config: {
+      name: 'someName',
+      value: 'someValue',
+      defaultValue: 'someDefaultValue',
+    },
+  });
+  expect(screen.getByText('someName')).toBeInTheDocument();
+  expect(screen.getByText('someName')).toHaveStyle('font-weight: 500');
+  expect(screen.getByText('someValue')).toBeInTheDocument();
+  expect(screen.getByText('someValue')).toHaveStyle('font-weight: 500');
+  expect(screen.getByText('someDefaultValue')).toBeInTheDocument();
+});
+
+it('renders without CustomValue', () => {
+  setupComponent({
+    config: { name: 'someName', value: 'someValue', defaultValue: 'someValue' },
+  });
+  expect(screen.getByText('someName')).toBeInTheDocument();
+  expect(screen.getByText('someName')).toHaveStyle('font-weight: 400');
+  expect(screen.getByText('someValue')).toBeInTheDocument();
+  expect(screen.getByText('someValue')).toHaveStyle('font-weight: 400');
+  expect(screen.getByTitle('Default Value')).toHaveTextContent('');
+});

+ 61 - 0
kafka-ui-react-app/src/components/Topics/Topic/__tests__/Topic.spec.tsx

@@ -0,0 +1,61 @@
+import React from 'react';
+import { Route } from 'react-router-dom';
+import { render } from 'lib/testHelpers';
+import { screen } from '@testing-library/react';
+import Topic from 'components/Topics/Topic/Topic';
+import {
+  clusterTopicPath,
+  clusterTopicEditPath,
+  clusterTopicSendMessagePath,
+} from 'lib/paths';
+
+jest.mock('components/Topics/Topic/Edit/EditContainer', () => () => (
+  <div>Edit Container</div>
+));
+jest.mock('components/Topics/Topic/SendMessage/SendMessage', () => () => (
+  <div>Send Message</div>
+));
+jest.mock('components/Topics/Topic/Details/DetailsContainer', () => () => (
+  <div>Details Container</div>
+));
+jest.mock('components/common/PageLoader/PageLoader', () => () => (
+  <div>Loading</div>
+));
+
+const fetchTopicDetailsMock = jest.fn();
+
+const renderComponent = (pathname: string, topicFetching: boolean) =>
+  render(
+    <Route path={clusterTopicPath(':clusterName', ':topicName')}>
+      <Topic
+        isTopicFetching={topicFetching}
+        fetchTopicDetails={fetchTopicDetailsMock}
+      />
+    </Route>,
+    { pathname }
+  );
+
+it('renders Edit page', () => {
+  renderComponent(clusterTopicEditPath('local', 'myTopicName'), false);
+  expect(screen.getByText('Edit Container')).toBeInTheDocument();
+});
+
+it('renders Send Message page', () => {
+  renderComponent(clusterTopicSendMessagePath('local', 'myTopicName'), false);
+  expect(screen.getByText('Send Message')).toBeInTheDocument();
+});
+
+it('renders Details Container page', () => {
+  renderComponent(clusterTopicPath('local', 'myTopicName'), false);
+  expect(screen.getByText('Details Container')).toBeInTheDocument();
+});
+
+it('renders Page loader', () => {
+  renderComponent(clusterTopicPath('local', 'myTopicName'), true);
+  expect(screen.getByText('Loading')).toBeInTheDocument();
+});
+
+it('fetches topicDetails', () => {
+  renderComponent(clusterTopicPath('local', 'myTopicName'), false);
+  expect(fetchTopicDetailsMock).toHaveBeenCalledTimes(1);
+});