From 87f7939d2a4dfc0b45eaeb9f6b4c359eeeca2001 Mon Sep 17 00:00:00 2001 From: Revanshu Paliwal Date: Mon, 24 Apr 2023 15:48:29 +0200 Subject: [PATCH] SONAR-19018 Updating CaYC boxes in projects pages to MIUI --- .../src/components/QualityGateIndicator.tsx | 17 +---- .../design-system/src/components/Text.tsx | 4 + .../__tests__/QualityGateIndicator-test.tsx | 5 +- .../js/app/components/GlobalContainer.tsx | 16 +++- .../src/main/js/app/styles/init/type.css | 4 + .../ApplicationNonCaycProjectWarning.tsx | 67 +++++++++-------- .../branches/BranchOverviewRenderer.tsx | 74 ++++++++++--------- .../branches/CleanAsYouCodeWarning.tsx | 35 +++++---- .../CleanAsYouCodeWarningOverCompliant.tsx | 31 +++++--- .../apps/overview/branches/NoCodeWarning.tsx | 6 +- .../overview/branches/QualityGatePanel.tsx | 19 +++++ .../branches/QualityGatePanelSection.tsx | 18 +---- .../branches/__tests__/BranchOverview-it.tsx | 15 ++++ .../components/QualityGateCondition.tsx | 26 +++---- .../components/SonarLintPromotion.tsx | 5 +- .../measure/__tests__/utils-test.tsx | 18 +++-- 16 files changed, 206 insertions(+), 154 deletions(-) diff --git a/server/sonar-web/design-system/src/components/QualityGateIndicator.tsx b/server/sonar-web/design-system/src/components/QualityGateIndicator.tsx index 0f0abf6a012..810269c357a 100644 --- a/server/sonar-web/design-system/src/components/QualityGateIndicator.tsx +++ b/server/sonar-web/design-system/src/components/QualityGateIndicator.tsx @@ -37,7 +37,6 @@ interface Props { size?: keyof typeof SIZE; status: QGStatus; tooltipPlacement?: BasePlacement; - withTooltip?: boolean; } const RX_4 = 4; @@ -49,7 +48,6 @@ export function QualityGateIndicator(props: Props) { size = 'md', status, tooltipPlacement = PopupPlacement.Right, - withTooltip, ariaLabel, } = props; const iconProps = { @@ -59,7 +57,6 @@ export function QualityGateIndicator(props: Props) { size, tooltipPlacement, width: SIZE[size], - withTooltip, }; let StatusComponent: React.ReactNode; switch (status) { @@ -94,17 +91,9 @@ interface IconProps { size: keyof typeof SIZE; tooltipPlacement?: BasePlacement; width: string; - withTooltip?: boolean; } -function QGNotComputed({ - className, - rx, - size, - tooltipPlacement, - withTooltip, - ...sizeProps -}: IconProps) { +function QGNotComputed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) { const theme = useTheme(); const contrastColor = themeContrast('qgIndicatorNotComputed')({ theme }); return ( @@ -121,7 +110,7 @@ function QGNotComputed({ ); } -function QGPassed({ className, rx, size, tooltipPlacement, withTooltip, ...sizeProps }: IconProps) { +function QGPassed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) { const theme = useTheme(); const contrastColor = themeContrast('qgIndicatorPassed')({ theme }); return ( @@ -153,7 +142,7 @@ function QGPassed({ className, rx, size, tooltipPlacement, withTooltip, ...sizeP ); } -function QGFailed({ className, rx, size, tooltipPlacement, withTooltip, ...sizeProps }: IconProps) { +function QGFailed({ className, rx, size, tooltipPlacement, ...sizeProps }: IconProps) { const theme = useTheme(); const contrastColor = themeContrast('qgIndicatorFailed')({ theme }); return ( diff --git a/server/sonar-web/design-system/src/components/Text.tsx b/server/sonar-web/design-system/src/components/Text.tsx index 775091713c5..14da5264f36 100644 --- a/server/sonar-web/design-system/src/components/Text.tsx +++ b/server/sonar-web/design-system/src/components/Text.tsx @@ -101,3 +101,7 @@ export const LightLabel = styled.span` export const LightPrimary = styled.span` color: ${themeContrast('primaryLight')}; `; + +export const PageContentFontWrapper = styled.div` + color: ${themeColor('pageContent')}; +`; diff --git a/server/sonar-web/design-system/src/components/__tests__/QualityGateIndicator-test.tsx b/server/sonar-web/design-system/src/components/__tests__/QualityGateIndicator-test.tsx index 20c0ef8bc2f..4dfa80ac5af 100644 --- a/server/sonar-web/design-system/src/components/__tests__/QualityGateIndicator-test.tsx +++ b/server/sonar-web/design-system/src/components/__tests__/QualityGateIndicator-test.tsx @@ -50,15 +50,14 @@ it.each([ it('should display tooltip', () => { const { rerender } = setupWithProps({ status: 'NONE', - withTooltip: true, ariaLabel: 'label-none', }); expect(screen.getByLabelText('label-none')).toBeInTheDocument(); - rerender(); + rerender(); expect(screen.getByLabelText('label-ok')).toBeInTheDocument(); - rerender(); + rerender(); expect(screen.getByLabelText('label-error')).toBeInTheDocument(); }); diff --git a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx index ce3f0c22d95..e9bf7fb4761 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalContainer.tsx @@ -18,6 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import { ThemeProvider } from '@emotion/react'; +import classNames from 'classnames'; import { lightTheme } from 'design-system'; import * as React from 'react'; import { Outlet, useLocation } from 'react-router-dom'; @@ -25,18 +26,20 @@ import A11yProvider from '../../components/a11y/A11yProvider'; import A11ySkipLinks from '../../components/a11y/A11ySkipLinks'; import SuggestionsProvider from '../../components/embed-docs-modal/SuggestionsProvider'; import Workspace from '../../components/workspace/Workspace'; -import BranchStatusContextProvider from './branch-status/BranchStatusContextProvider'; import GlobalFooter from './GlobalFooter'; +import StartupModal from './StartupModal'; +import SystemAnnouncement from './SystemAnnouncement'; +import BranchStatusContextProvider from './branch-status/BranchStatusContextProvider'; import IndexationContextProvider from './indexation/IndexationContextProvider'; import IndexationNotification from './indexation/IndexationNotification'; import LanguagesContextProvider from './languages/LanguagesContextProvider'; import MetricsContextProvider from './metrics/MetricsContextProvider'; import GlobalNav from './nav/global/GlobalNav'; import PromotionNotification from './promotion-notification/PromotionNotification'; -import StartupModal from './StartupModal'; -import SystemAnnouncement from './SystemAnnouncement'; import UpdateNotification from './update-notification/UpdateNotification'; +const TEMP_PAGELIST_WITH_NEW_BACKGROUND = ['/dashboard']; + export default function GlobalContainer() { // it is important to pass `location` down to `GlobalNav` to trigger render on url change const location = useLocation(); @@ -48,7 +51,12 @@ export default function GlobalContainer() {
-
+
diff --git a/server/sonar-web/src/main/js/app/styles/init/type.css b/server/sonar-web/src/main/js/app/styles/init/type.css index 874e032e73d..03f5f3b27ea 100644 --- a/server/sonar-web/src/main/js/app/styles/init/type.css +++ b/server/sonar-web/src/main/js/app/styles/init/type.css @@ -302,3 +302,7 @@ small, font-family: var(--sourceCodeFontFamily); font-size: var(--smallFontSize); } + +.new-background { + background-color: #fcfcfd; +} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx b/server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx index e1fc30b255b..e8f6fc3c1bc 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx @@ -17,15 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Card, FlagMessage, Link } from 'design-system'; import * as React from 'react'; -import DocLink from '../../../components/common/DocLink'; -import Link from '../../../components/common/Link'; -import QualifierIcon from '../../../components/icons/QualifierIcon'; -import { Alert } from '../../../components/ui/Alert'; +import withAppStateContext, { + WithAppStateContextProps, +} from '../../../app/components/app-state/withAppStateContext'; import { getBranchLikeQuery } from '../../../helpers/branch-like'; +import { getUrlForDoc } from '../../../helpers/docs'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { getProjectQueryUrl } from '../../../helpers/urls'; -import { ComponentQualifier } from '../../../types/component'; import { QualityGateStatus } from '../../../types/quality-gates'; import { CaycStatus } from '../../../types/types'; @@ -34,18 +34,34 @@ interface Props { caycStatus: CaycStatus; } -export default function ApplicationNonCaycProjectWarning({ projects, caycStatus }: Props) { +function ApplicationNonCaycProjectWarning({ + projects, + caycStatus, + appState, +}: Props & WithAppStateContextProps) { + const caycUrl = getUrlForDoc(appState.version, '/user-guide/clean-as-you-code/'); + const caycDrawbacksUrl = getUrlForDoc( + appState.version, + '/user-guide/clean-as-you-code/#potential-drawbacks' + ); + return ( -
+ {caycStatus === CaycStatus.NonCompliant ? ( - + {translateWithParameters( 'overview.quality_gate.application.non_cayc.projects_x', projects.length )} - + ) : ( -

+

{translateWithParameters( 'overview.quality_gate.application.cayc_over_compliant.projects_x', projects.length @@ -53,34 +69,25 @@ export default function ApplicationNonCaycProjectWarning({ projects, caycStatus

)} -
    +
      {projects.map(({ key, name, branchLike }) => ( -
    • - - - {name} - +
    • + {name}
    • ))}
    -
    -
    +
    +
    {caycStatus === CaycStatus.NonCompliant ? ( - - {translate('overview.quality_gate.conditions.cayc.link')} - + {translate('overview.quality_gate.conditions.cayc.link')} ) : ( - + {translate('overview.quality_gate.conditions.cayc_over_compliant.link')} - + )}
    -
    + ); } + +export default withAppStateContext(ApplicationNonCaycProjectWarning); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx index 7593b4ae651..ddcb860be48 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverviewRenderer.tsx @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { LargeCenteredLayout } from 'design-system'; +import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system'; import * as React from 'react'; import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget'; import { parseDate } from '../../../helpers/dates'; @@ -86,49 +86,51 @@ export default function BranchOverviewRenderer(props: BranchOverviewRendererProp projectBinding={projectBinding} /> -
    - + +
    + - {projectIsEmpty ? ( - - ) : ( -
    -
    - -
    - -
    -
    - + ) : ( +
    +
    + +
    - +
    +
    + + + +
    -
    - )} -
    + )} +
    + ); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx b/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx index 19a876a7889..746f5fa5a7f 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx @@ -17,11 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { DiscreetLink, FlagMessage, Link } from 'design-system'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import DocLink from '../../../components/common/DocLink'; -import Link from '../../../components/common/Link'; -import { Alert } from '../../../components/ui/Alert'; +import withAppStateContext, { + WithAppStateContextProps, +} from '../../../app/components/app-state/withAppStateContext'; +import { getUrlForDoc } from '../../../helpers/docs'; import { translate } from '../../../helpers/l10n'; import { getQualityGateUrl } from '../../../helpers/urls'; import { Component } from '../../../types/types'; @@ -30,33 +32,38 @@ interface Props { component: Pick; } -export default function CleanAsYouCodeWarning({ component }: Props) { +function CleanAsYouCodeWarning({ component, appState }: Props & WithAppStateContextProps) { + const caycUrl = getUrlForDoc(appState.version, '/user-guide/clean-as-you-code/'); + return ( <> - {translate('overview.quality_gate.conditions.cayc.warning')} + + {translate('overview.quality_gate.conditions.cayc.warning')} + {component.qualityGate ? ( -

    +

    + {translate('overview.quality_gate.conditions.non_cayc.warning.link')} - + ), }} />

    ) : ( -

    - {translate('overview.quality_gate.conditions.cayc.details')} -

    +

    {translate('overview.quality_gate.conditions.cayc.details')}

    )} - - {translate('overview.quality_gate.conditions.cayc.link')} - + {translate('overview.quality_gate.conditions.cayc.link')} ); } + +export default withAppStateContext(CleanAsYouCodeWarning); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarningOverCompliant.tsx b/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarningOverCompliant.tsx index f055badf67c..c2a5e08982e 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarningOverCompliant.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarningOverCompliant.tsx @@ -17,10 +17,13 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { DiscreetLink, Link } from 'design-system'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; -import DocLink from '../../../components/common/DocLink'; -import Link from '../../../components/common/Link'; +import withAppStateContext, { + WithAppStateContextProps, +} from '../../../app/components/app-state/withAppStateContext'; +import { getUrlForDoc } from '../../../helpers/docs'; import { translate } from '../../../helpers/l10n'; import { getQualityGateUrl } from '../../../helpers/urls'; import { Component } from '../../../types/types'; @@ -29,11 +32,19 @@ interface Props { component: Pick; } -export default function CleanAsYouCodeWarningOverCompliant({ component }: Props) { +function CleanAsYouCodeWarningOverCompliant({ + component, + appState, +}: Props & WithAppStateContextProps) { + const caycDrawbackUrl = getUrlForDoc( + appState.version, + '/user-guide/clean-as-you-code/#potential-drawbacks' + ); + return ( <> {component.qualityGate ? ( -

    +

    + {translate('overview.quality_gate.conditions.cayc_over_compliant.warning.link')} - + ), }} />

    ) : ( -

    +

    {translate('overview.quality_gate.conditions.cayc_over_compliant.details')}

    )} - + {translate('overview.quality_gate.conditions.cayc_over_compliant.link')} - + ); } + +export default withAppStateContext(CleanAsYouCodeWarningOverCompliant); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx b/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx index 8810fbb8e06..19a939a74c4 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/NoCodeWarning.tsx @@ -17,8 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { FlagMessage } from 'design-system'; import * as React from 'react'; -import { Alert } from '../../../components/ui/Alert'; import { getBranchLikeDisplayName, isMainBranch } from '../../../helpers/branch-like'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { BranchLike } from '../../../types/branch-like'; @@ -84,9 +84,9 @@ export function NoCodeWarning({ branchLike, component, measures }: Props) { /* eslint-enable no-lonely-if */ return ( - + {title} - + ); } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx index 063142c02b5..bdea28e3c36 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx @@ -29,6 +29,8 @@ import QualityGateStatusPassedView from '../components/QualityGateStatusPassedVi import { QualityGateStatusTitle } from '../components/QualityGateStatusTitle'; import SonarLintPromotion from '../components/SonarLintPromotion'; import ApplicationNonCaycProjectWarning from './ApplicationNonCaycProjectWarning'; +import CleanAsYouCodeWarning from './CleanAsYouCodeWarning'; +import CleanAsYouCodeWarningOverCompliant from './CleanAsYouCodeWarningOverCompliant'; import QualityGatePanelSection from './QualityGatePanelSection'; export interface QualityGatePanelProps { @@ -119,6 +121,23 @@ export function QualityGatePanel(props: QualityGatePanelProps) { caycStatus={CaycStatus.OverCompliant} /> )} + + {qgStatuses.length === 1 && + qgStatuses[0].caycStatus === CaycStatus.NonCompliant && + !isApplication(component.qualifier) && ( + + + + )} + + {qgStatuses.length === 1 && + qgStatuses[0].caycStatus === CaycStatus.OverCompliant && + !isApplication(component.qualifier) && ( + + + + )} + qgStatus.failedConditions)} /> diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx index d4ceaf05679..e557ea0f526 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx @@ -29,8 +29,6 @@ import { } from '../../../types/quality-gates'; import { CaycStatus, Component } from '../../../types/types'; import QualityGateConditions from '../components/QualityGateConditions'; -import CleanAsYouCodeWarning from './CleanAsYouCodeWarning'; -import CleanAsYouCodeWarningOverCompliant from './CleanAsYouCodeWarningOverCompliant'; export interface QualityGatePanelSectionProps { branchLike?: BranchLike; @@ -176,21 +174,7 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) { ) : ( - <> - {renderFailedConditions()} - {qgStatus.caycStatus === CaycStatus.NonCompliant && - !isApplication(component.qualifier) && ( -
    - -
    - )} - {qgStatus.caycStatus === CaycStatus.OverCompliant && - !isApplication(component.qualifier) && ( -
    - -
    - )} - + renderFailedConditions() )} ); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx index 93f8b78d687..203aeb5a512 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx @@ -232,6 +232,21 @@ describe('project overview', () => { expect(screen.getByText('overview.quality_gate.conditions.cayc.warning')).toBeInTheDocument(); }); + it('should show Cayc message when QG is over-compliant', async () => { + jest + .mocked(getQualityGateProjectStatus) + .mockResolvedValueOnce( + mockQualityGateProjectStatus({ status: 'OK', caycStatus: CaycStatus.OverCompliant }) + ); + + renderBranchOverview(); + + expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); + expect( + screen.getByText('overview.quality_gate.conditions.cayc_over_compliant.link') + ).toBeInTheDocument(); + }); + it('should show a failed QG', async () => { renderBranchOverview(); diff --git a/server/sonar-web/src/main/js/apps/overview/components/QualityGateCondition.tsx b/server/sonar-web/src/main/js/apps/overview/components/QualityGateCondition.tsx index 73476f95598..78409d0e74e 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/QualityGateCondition.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/QualityGateCondition.tsx @@ -111,21 +111,17 @@ export default class QualityGateCondition extends React.PureComponent { return {children}; } - if (isIssueMeasure(condition.measure.metric.key)) { - const url = getComponentIssuesUrl(component.key, { - ...propsToIssueParams(condition.measure.metric.key, condition.period != null), - ...getBranchLikeQuery(branchLike), - }); - - return {children}; - } - - const url = getComponentDrilldownUrl({ - componentKey: component.key, - metric: condition.measure.metric.key, - branchLike, - listView: true, - }); + const url = isIssueMeasure(condition.measure.metric.key) + ? getComponentIssuesUrl(component.key, { + ...propsToIssueParams(condition.measure.metric.key, condition.period != null), + ...getBranchLikeQuery(branchLike), + }) + : getComponentDrilldownUrl({ + componentKey: component.key, + metric: condition.measure.metric.key, + branchLike, + listView: true, + }); return {children}; } diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx index 67a41dc2c34..625dc9c6282 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/SonarLintPromotion.tsx @@ -68,10 +68,13 @@ export function SonarLintPromotion({ currentUser, qgConditions }: SonarLintPromo rel="noopener noreferrer" target="_blank" showExternalIcon={false} + className="sw-mr-1" > SonarLint - + + + ), }} diff --git a/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx b/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx index 0428864b305..83084356fec 100644 --- a/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx +++ b/server/sonar-web/src/main/js/components/measure/__tests__/utils-test.tsx @@ -21,13 +21,15 @@ import { duplicationRatingConverter } from '../utils'; describe('duplicationRatingConverter', () => { - it('should work correctly for different use cases', () => { - expect(duplicationRatingConverter(-10)).toEqual('A'); - expect(duplicationRatingConverter(2)).toEqual('A'); - expect(duplicationRatingConverter(4)).toEqual('B'); - expect(duplicationRatingConverter(8)).toEqual('C'); - expect(duplicationRatingConverter(18)).toEqual('D'); - expect(duplicationRatingConverter(20)).toEqual('E'); - expect(duplicationRatingConverter(25)).toEqual('E'); + it.each([ + [-10, 'A'], + [2, 'A'], + [4, 'B'], + [8, 'C'], + [18, 'D'], + [20, 'E'], + [25, 'E'], + ])('should work correctly when value is %s', (value: number, result: string) => { + expect(duplicationRatingConverter(value)).toEqual(result); }); }); -- 2.39.5