]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22323 Fix a11y issues on PR overview page
authorIsmail Cherri <ismail.cherri@sonarsource.com>
Mon, 9 Sep 2024 12:07:50 +0000 (14:07 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 10 Sep 2024 20:03:12 +0000 (20:03 +0000)
16 files changed:
server/sonar-web/design-system/src/components/CoverageIndicator.tsx
server/sonar-web/design-system/src/components/DonutChart.tsx
server/sonar-web/design-system/src/components/DuplicationsIndicator.tsx
server/sonar-web/design-system/src/components/__tests__/CoverageIndicator-test.tsx
server/sonar-web/design-system/src/components/__tests__/DuplicationsIndicator-test.tsx
server/sonar-web/design-system/src/components/__tests__/__snapshots__/CoverageIndicator-test.tsx.snap
server/sonar-web/design-system/src/components/__tests__/__snapshots__/DuplicationsIndicator-test.tsx.snap
server/sonar-web/src/main/js/apps/overview/branches/QualityGateStatus.tsx
server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx
server/sonar-web/src/main/js/apps/overview/components/AnalysisStatus.tsx
server/sonar-web/src/main/js/apps/overview/components/IssueMeasuresCardInner.tsx
server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx
server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx
server/sonar-web/src/main/js/components/measure/__tests__/MeasureIndicator-test.tsx
server/sonar-web/src/main/js/components/measure/__tests__/__snapshots__/MeasureIndicator-test.tsx.snap
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 9eeb58479b7d98b856163f5373b7d14a1106ee8a..a6eb05c100933b6aed994f6e117cd6e9a5952a25 100644 (file)
@@ -28,17 +28,23 @@ const FULL_PERCENT = 100;
 const PAD_ANGLE = 0.1;
 
 export interface CoverageIndicatorProps {
+  'aria-hidden'?: boolean | 'true' | 'false';
+  'aria-label'?: string;
   size?: 'xs' | 'sm' | 'md';
   value?: number | string;
 }
 
-export function CoverageIndicator({ size = 'sm', value }: CoverageIndicatorProps) {
+export function CoverageIndicator({
+  size = 'sm',
+  value,
+  ...rest
+}: Readonly<CoverageIndicatorProps>) {
   const theme = useTheme();
   const width = SIZE_TO_WIDTH_MAPPING[size];
   const thickness = SIZE_TO_THICKNESS_MAPPING[size];
 
   if (value === undefined) {
-    return <NoDataIcon size={size} />;
+    return <NoDataIcon size={size} {...rest} />;
   }
 
   const themeRed = themeColor('coverageRed')({ theme });
@@ -64,6 +70,7 @@ export function CoverageIndicator({ size = 'sm', value }: CoverageIndicatorProps
       padAngle={padAngle}
       thickness={thickness}
       width={width}
+      {...rest}
     />
   );
 }
index 14c4ec3782b8bb32536b36b41ab7557f62d39b08..4fc1e63844513e363f6ee0a350e0dc4925402236 100644 (file)
@@ -25,6 +25,8 @@ export interface DataPoint {
 }
 
 export interface DonutChartProps {
+  'aria-hidden'?: boolean | 'true' | 'false';
+  'aria-label'?: string;
   cornerRadius?: number;
   data: DataPoint[];
   height: number;
@@ -35,8 +37,18 @@ export interface DonutChartProps {
   width: number;
 }
 
-export function DonutChart(props: DonutChartProps) {
-  const { height, cornerRadius, minPercent = 0, padding = [0, 0, 0, 0], width } = props;
+export function DonutChart(props: Readonly<DonutChartProps>) {
+  const {
+    height,
+    cornerRadius,
+    minPercent = 0,
+    padding = [0, 0, 0, 0],
+    width,
+    padAngle,
+    data,
+    thickness,
+    ...rest
+  } = props;
 
   const availableWidth = width - padding[1] - padding[3];
   const availableHeight = height - padding[0] - padding[2];
@@ -44,31 +56,31 @@ export function DonutChart(props: DonutChartProps) {
   const size = Math.min(availableWidth, availableHeight);
   const radius = Math.floor(size / 2);
 
-  const total = props.data.reduce((acc, d) => acc + d.value, 0);
+  const total = data.reduce((acc, d) => acc + d.value, 0);
 
   const pie = d3Pie<any, DataPoint>()
     .sort(null)
     .value((d) => Math.max(d.value, (total / 100) * minPercent));
 
-  if (props.padAngle !== undefined) {
-    pie.padAngle(props.padAngle);
+  if (padAngle !== undefined) {
+    pie.padAngle(padAngle);
   }
 
-  const sectors = pie(props.data).map((d, i) => {
+  const sectors = pie(data).map((d, i) => {
     return (
       <Sector
         cornerRadius={cornerRadius}
         data={d}
-        fill={props.data[i].fill}
+        fill={data[i].fill}
         key={i}
         radius={radius}
-        thickness={props.thickness}
+        thickness={thickness}
       />
     );
   });
 
   return (
-    <svg className="donut-chart" height={height} role="img" width={width}>
+    <svg className="donut-chart" height={height} width={width} {...rest}>
       <g transform={`translate(${padding[3]}, ${padding[0]})`}>
         <g transform={`translate(${radius}, ${radius})`}>{sectors}</g>
       </g>
@@ -84,7 +96,7 @@ interface SectorProps {
   thickness: number;
 }
 
-function Sector(props: SectorProps) {
+function Sector(props: Readonly<SectorProps>) {
   const arc = d3Arc<any, PieArcDatum<DataPoint>>()
     .outerRadius(props.radius)
     .innerRadius(props.radius - props.thickness);
index f43cb8a7206cc5fd6466006384cb9e7079d6470b..9a00372a8923bbf5b419102392ae7824bd8265fe 100644 (file)
@@ -24,13 +24,15 @@ import { DuplicationEnum, DuplicationLabel } from '../types/measures';
 import { NoDataIcon } from './icons';
 
 interface Props {
+  'aria-hidden'?: boolean | 'true' | 'false';
+  'aria-label'?: string;
   rating?: DuplicationLabel;
   size?: 'xs' | 'sm' | 'md';
 }
 
 const SIZE_TO_PX_MAPPING = { xs: 16, sm: 24, md: 36 };
 
-export function DuplicationsIndicator({ size = 'sm', rating }: Props) {
+export function DuplicationsIndicator({ size = 'sm', rating, ...rest }: Readonly<Props>) {
   const theme = useTheme();
   const sizePX = SIZE_TO_PX_MAPPING[size];
 
@@ -47,20 +49,23 @@ export function DuplicationsIndicator({ size = 'sm', rating }: Props) {
       rating={rating}
       secondaryColor={secondaryColor}
       size={sizePX}
+      {...rest}
     />
   );
 }
 
 interface SVGProps {
+  'aria-hidden'?: boolean | 'true' | 'false';
+  'aria-label'?: string;
   primaryColor: string;
   rating: DuplicationLabel;
   secondaryColor: string;
   size: number;
 }
 
-function RatingSVG({ primaryColor, rating, secondaryColor, size }: SVGProps) {
+function RatingSVG({ primaryColor, rating, secondaryColor, size, ...rest }: Readonly<SVGProps>) {
   return (
-    <svg height={size} role="img" viewBox="0 0 16 16" width={size}>
+    <svg height={size} viewBox="0 0 16 16" width={size} {...rest}>
       <circle cx="8" cy="8" fill={primaryColor} r="2" />
       {isDefined(rating) &&
         {
index df178e6336f5fdbd8ac8dc666e7d961ade35708c..648869f9ac928029a37b7482c219cef168cd366d 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { screen } from '@testing-library/react';
 import { render } from '../../helpers/testUtils';
 import { FCProps } from '../../types/misc';
 
 import { CoverageIndicator } from '../CoverageIndicator';
 
 it('should display CoverageIndicator', () => {
-  setupWithProps({ value: 10 });
-  expect(screen.getByRole('img', { hidden: true })).toMatchSnapshot();
+  const wrapper = setupWithProps({ value: 10 });
+  expect(wrapper.baseElement).toMatchSnapshot();
 });
 
 it('should display CoverageIndicator without value', () => {
-  setupWithProps();
-  expect(screen.getByRole('img', { hidden: true })).toMatchSnapshot();
+  const wrapper = setupWithProps();
+  expect(wrapper.baseElement).toMatchSnapshot();
+});
+
+it('should display CoverageIndicator with correct aria properties', () => {
+  const wrapper = setupWithProps({ 'aria-label': 'label', 'aria-hidden': true });
+  expect(wrapper.baseElement).toMatchSnapshot();
 });
 
 function setupWithProps(props: Partial<FCProps<typeof CoverageIndicator>> = {}) {
index 65f59934ad94aaab8e472a91f74e5ca41eb35bbc..f0c9fbc1405a11132625a051a0c39439fe6a2f2e 100644 (file)
@@ -17,7 +17,6 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { screen } from '@testing-library/react';
 import { render } from '../../helpers/testUtils';
 import { FCProps } from '../../types/misc';
 
@@ -25,15 +24,15 @@ import { DuplicationLabel } from '../../types/measures';
 import { DuplicationsIndicator } from '../DuplicationsIndicator';
 
 it('should display DuplicationsIndicator without rating', () => {
-  setupWithProps();
-  expect(screen.getByRole('img', { hidden: true })).toMatchSnapshot();
+  const wrapper = setupWithProps();
+  expect(wrapper.baseElement).toMatchSnapshot();
 });
 
 it.each(['A', 'B', 'C', 'D', 'E', 'F'])(
   'should display DuplicationsIndicator with rating',
   (variant: DuplicationLabel) => {
-    setupWithProps({ rating: variant });
-    expect(screen.getByRole('img', { hidden: true })).toMatchSnapshot();
+    const wrapper = setupWithProps({ rating: variant });
+    expect(wrapper.baseElement).toMatchSnapshot();
   },
 );
 
index 8a49b54ab50814b42a4fbba3ca8a5a9437161c03..f04fb70a190debc6067f06a521170de9750bd19d 100644 (file)
@@ -1,49 +1,83 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should display CoverageIndicator 1`] = `
-<svg
-  class="donut-chart"
-  height="24"
-  role="img"
-  width="24"
->
-  <g
-    transform="translate(0, 0)"
-  >
-    <g
-      transform="translate(12, 12)"
+<body>
+  <div>
+    <svg
+      class="donut-chart"
+      height="24"
+      width="24"
+    >
+      <g
+        transform="translate(0, 0)"
+      >
+        <g
+          transform="translate(12, 12)"
+        >
+          <path
+            d="M0.75,-11.977A12,12,0,0,1,7.222,-9.583L5.265,-7.299A9,9,0,0,0,0.75,-8.969Z"
+            style="fill: rgb(18,183,106);"
+          />
+          <path
+            d="M8.361,-8.608A12,12,0,1,1,-0.75,-11.977L-0.75,-8.969A9,9,0,1,0,6.404,-6.324Z"
+            style="fill: rgb(180,35,24);"
+          />
+        </g>
+      </g>
+    </svg>
+  </div>
+</body>
+`;
+
+exports[`should display CoverageIndicator with correct aria properties 1`] = `
+<body>
+  <div>
+    <svg
+      aria-hidden="true"
+      aria-label="label"
+      fill="none"
+      height="24"
+      role="img"
+      style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
+      version="1.1"
+      viewBox="0 0 16 16"
+      width="24"
+      xml:space="preserve"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
     >
       <path
-        d="M0.75,-11.977A12,12,0,0,1,7.222,-9.583L5.265,-7.299A9,9,0,0,0,0.75,-8.969Z"
-        style="fill: rgb(18,183,106);"
-      />
-      <path
-        d="M8.361,-8.608A12,12,0,1,1,-0.75,-11.977L-0.75,-8.969A9,9,0,1,0,6.404,-6.324Z"
-        style="fill: rgb(180,35,24);"
+        clip-rule="evenodd"
+        d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
+        fill="#E1E6F3"
+        fill-rule="evenodd"
       />
-    </g>
-  </g>
-</svg>
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display CoverageIndicator without value 1`] = `
-<svg
-  aria-hidden="true"
-  fill="none"
-  height="24"
-  role="img"
-  style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
-  version="1.1"
-  viewBox="0 0 16 16"
-  width="24"
-  xml:space="preserve"
-  xmlns:xlink="http://www.w3.org/1999/xlink"
->
-  <path
-    clip-rule="evenodd"
-    d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
-    fill="#E1E6F3"
-    fill-rule="evenodd"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      aria-hidden="true"
+      fill="none"
+      height="24"
+      role="img"
+      style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
+      version="1.1"
+      viewBox="0 0 16 16"
+      width="24"
+      xml:space="preserve"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
+    >
+      <path
+        clip-rule="evenodd"
+        d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
+        fill="#E1E6F3"
+        fill-rule="evenodd"
+      />
+    </svg>
+  </div>
+</body>
 `;
index 21ac97b1eeac8eafad906b8fd182417153eda461..677207098fee00478109c1afa85d39e4decb5af7 100644 (file)
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`should display DuplicationsIndicator with rating 1`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(18,183,106)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(18,183,106)"
-    r="2"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(18,183,106)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(18,183,106)"
+        r="2"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator with rating 2`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(18,183,106)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <path
-    d="M8 0c.81879 0 1.63272.125698 2.4134.372702L9.81002 2.27953A5.99976 5.99976 0 0 0 8 2V0Z"
-    fill="rgb(18,183,106)"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(18,183,106)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <path
+        d="M8 0c.81879 0 1.63272.125698 2.4134.372702L9.81002 2.27953A5.99976 5.99976 0 0 0 8 2V0Z"
+        fill="rgb(18,183,106)"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator with rating 3`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(110,183,18)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <path
-    d="M8 0c1.89071 2e-8 3.7203.669649 5.1643 1.89017l-1.2911 1.52746C10.7902 2.50224 9.41803 2 8 2V0Z"
-    fill="rgb(110,183,18)"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(110,183,18)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14c3.3137 0 6-2.6863 6-6 0-3.31371-2.6863-6-6-6-3.31371 0-6 2.68629-6 6 0 3.3137 2.68629 6 6 6Zm0 2c4.4183 0 8-3.5817 8-8 0-4.41828-3.5817-8-8-8-4.41828 0-8 3.58172-8 8 0 4.4183 3.58172 8 8 8Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <path
+        d="M8 0c1.89071 2e-8 3.7203.669649 5.1643 1.89017l-1.2911 1.52746C10.7902 2.50224 9.41803 2 8 2V0Z"
+        fill="rgb(110,183,18)"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator with rating 4`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(245,184,64)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <path
-    d="M8 0a7.9999 7.9999 0 0 1 4.5815 1.44181 7.99949 7.99949 0 0 1 2.9301 3.80574l-1.8779.68811A6.00009 6.00009 0 0 0 8 2V0Z"
-    fill="rgb(245,184,64)"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(245,184,64)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <path
+        d="M8 0a7.9999 7.9999 0 0 1 4.5815 1.44181 7.99949 7.99949 0 0 1 2.9301 3.80574l-1.8779.68811A6.00009 6.00009 0 0 0 8 2V0Z"
+        fill="rgb(245,184,64)"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator with rating 5`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(247,95,9)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <path
-    d="M8 0a8 8 0 0 1 5.0686 1.81054 8.00033 8.00033 0 0 1 2.7744 4.61211l-1.9608.39434a5.99958 5.99958 0 0 0-2.0808-3.45908A5.99972 5.99972 0 0 0 8 2V0Z"
-    fill="rgb(247,95,9)"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(247,95,9)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <path
+        d="M8 0a8 8 0 0 1 5.0686 1.81054 8.00033 8.00033 0 0 1 2.7744 4.61211l-1.9608.39434a5.99958 5.99958 0 0 0-2.0808-3.45908A5.99972 5.99972 0 0 0 8 2V0Z"
+        fill="rgb(247,95,9)"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator with rating 6`] = `
-<svg
-  height="24"
-  role="img"
-  viewBox="0 0 16 16"
-  width="24"
->
-  <circle
-    cx="8"
-    cy="8"
-    fill="rgb(240,68,56)"
-    r="2"
-  />
-  <path
-    clip-rule="evenodd"
-    d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
-    fill="rgb(239,242,249)"
-    fill-rule="evenodd"
-  />
-  <path
-    d="M8 0a8.0002 8.0002 0 0 1 5.6569 13.6569l-1.4143-1.4143a5.9993 5.9993 0 0 0 1.3007-6.5387A5.9999 5.9999 0 0 0 8 2V0Z"
-    fill="rgb(240,68,56)"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      height="24"
+      viewBox="0 0 16 16"
+      width="24"
+    >
+      <circle
+        cx="8"
+        cy="8"
+        fill="rgb(240,68,56)"
+        r="2"
+      />
+      <path
+        clip-rule="evenodd"
+        d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14ZM8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16Z"
+        fill="rgb(239,242,249)"
+        fill-rule="evenodd"
+      />
+      <path
+        d="M8 0a8.0002 8.0002 0 0 1 5.6569 13.6569l-1.4143-1.4143a5.9993 5.9993 0 0 0 1.3007-6.5387A5.9999 5.9999 0 0 0 8 2V0Z"
+        fill="rgb(240,68,56)"
+      />
+    </svg>
+  </div>
+</body>
 `;
 
 exports[`should display DuplicationsIndicator without rating 1`] = `
-<svg
-  aria-hidden="true"
-  fill="none"
-  height="24"
-  role="img"
-  style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
-  version="1.1"
-  viewBox="0 0 16 16"
-  width="24"
-  xml:space="preserve"
-  xmlns:xlink="http://www.w3.org/1999/xlink"
->
-  <path
-    clip-rule="evenodd"
-    d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
-    fill="#E1E6F3"
-    fill-rule="evenodd"
-  />
-</svg>
+<body>
+  <div>
+    <svg
+      aria-hidden="true"
+      fill="none"
+      height="24"
+      role="img"
+      style="clip-rule: evenodd; display: inline-block; fill-rule: evenodd; user-select: none; vertical-align: middle; stroke-linejoin: round; stroke-miterlimit: 1.414;"
+      version="1.1"
+      viewBox="0 0 16 16"
+      width="24"
+      xml:space="preserve"
+      xmlns:xlink="http://www.w3.org/1999/xlink"
+    >
+      <path
+        clip-rule="evenodd"
+        d="M16 8C16 12.4183 12.4183 16 8 16C5.5106 16 3.28676 14.863 1.81951 13.0799L15.4913 5.1865C15.8201 6.06172 16 7.00986 16 8ZM14.5574 3.41624L0.750565 11.3876C0.269025 10.3589 0 9.21089 0 8C0 3.58172 3.58172 0 8 0C10.7132 0 13.1109 1.35064 14.5574 3.41624Z"
+        fill="#E1E6F3"
+        fill-rule="evenodd"
+      />
+    </svg>
+  </div>
+</body>
 `;
index 04715c9965f0cbe0744c89007ac95f7e6ec1ccde..60cb87a9c27d9f879b03771c2b6b6cf3ef4b3dba 100644 (file)
@@ -37,7 +37,7 @@ export default function QualityGateStatus(props: Readonly<Props>) {
       <QualityGateIndicator size="xl" status={status} />
       <div className="sw-flex sw-flex-col sw-ml-2 sw-justify-around">
         <div className="sw-flex sw-items-center">
-          <Note>{translate('overview.quality_gate')}</Note>
+          <Note as="h1">{translate('overview.quality_gate')}</Note>
           <HelpTooltip
             className="sw-ml-2"
             overlay={<div>{translate('overview.quality_gate.help')}</div>}
index ad0af592950309040147af36a76368753d981cb2..37c5e3248a807e1188eddbb80adaac9887da57f6 100644 (file)
@@ -19,7 +19,7 @@
  */
 import styled from '@emotion/styled';
 import { LinkHighlight, LinkStandalone, Tooltip } from '@sonarsource/echoes-react';
-import { Badge, TextBold, TextSubdued } from 'design-system';
+import { Badge, TextBold, TextSubdued, themeColor } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import { formatMeasure } from '~sonar-aligned/helpers/measures';
@@ -98,7 +98,9 @@ export function SoftwareImpactMeasureCard(props: Readonly<SoftwareImpactBreakdow
       className="sw-overflow-hidden sw-rounded-2 sw-flex-col"
     >
       <div className="sw-flex sw-items-center">
-        <TextBold name={intl.formatMessage({ id: `software_quality.${softwareQuality}` })} />
+        <ColorBold className="sw-body-sm-highlight">
+          {intl.formatMessage({ id: `software_quality.${softwareQuality}` })}
+        </ColorBold>
         {failed && (
           <Badge className="sw-h-fit sw-ml-2" variant="deleted">
             <FormattedMessage id="overview.measures.failed_badge" />
@@ -174,5 +176,8 @@ export function SoftwareImpactMeasureCard(props: Readonly<SoftwareImpactBreakdow
 const StyledDash = styled(TextBold)`
   font-size: 36px;
 `;
+const ColorBold = styled.h2`
+  color: ${themeColor('pageTitle')};
+`;
 
 export default SoftwareImpactMeasureCard;
index ce9504100f4a2732a27d441e7161a9f07ca9c178..fa1a30d7b9e993379bb1945ccaa970140e6fe014 100644 (file)
@@ -73,6 +73,7 @@ export function AnalysisStatus(props: Readonly<HeaderMetaProps>) {
           {/* TODO: replace the Link below with a lighweight/discreet button component */}
           {/* when it is available in Echoes */}
           <Link
+            aria-label={translate('project_navigation.analysis_status.details_link.label')}
             className="sw-ml-1"
             onClick={openModal}
             shouldBlurAfterClick
@@ -103,6 +104,7 @@ export function AnalysisStatus(props: Readonly<HeaderMetaProps>) {
           {/* TODO: replace the Link below with a lighweight/discreet button component */}
           {/* when it is available in Echoes */}
           <Link
+            aria-label={translate('project_navigation.analysis_status.details_link.label')}
             className="sw-ml-1"
             onClick={openModal}
             shouldBlurAfterClick
index 240b1ff975ff3b01a910415c61265350b1a0d3e6..ce1c5a38b4fc2c161aaf3755644aa72936a08412 100644 (file)
@@ -84,6 +84,6 @@ export function IssueMeasuresCardInner(props: Readonly<IssueMeasuresCardInnerPro
   );
 }
 
-const ColorBold = styled.div`
+const ColorBold = styled.h2`
   color: ${themeColor('pageTitle')};
 `;
index d4cad7eba00b028237317993912e745a0b6832d8..7b21eb3a755a72c26246caaed21c9c96b8963f1f 100644 (file)
@@ -73,6 +73,6 @@ export default function MeasuresCard(
   );
 }
 
-const ColorBold = styled.span`
+const ColorBold = styled.h2`
   color: ${themeColor('pageTitle')};
 `;
index e33c391ec37fce4a8fe20775aff60083dd159b6a..2102107d12fe265c692bd48ccac378461b3a7853 100644 (file)
@@ -160,9 +160,9 @@ export default function MeasuresCardPercent(
 
 function renderIcon(type: MeasurementType, value?: string) {
   if (type === MeasurementType.Coverage) {
-    return <CoverageIndicator value={value} size="md" />;
+    return <CoverageIndicator aria-hidden="true" value={value} size="md" />;
   }
 
   const rating = duplicationRatingConverter(Number(value));
-  return <DuplicationsIndicator rating={rating} size="md" />;
+  return <DuplicationsIndicator aria-hidden="true" rating={rating} size="md" />;
 }
index 3b42b47f1342a60a6f6536bd33871759e215c055..8cc7f9e5e22b145908e001dd9e5fb0c2905430cc 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { render, screen } from '@testing-library/react';
+import { render } from '@testing-library/react';
 import * as React from 'react';
 import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
 import { Status } from '../../../apps/overview/utils';
 import MeasureIndicator from '../MeasureIndicator';
 
 it('renders correctly for coverage', () => {
-  render(
+  const wrapper = render(
     <MeasureIndicator
       componentKey="test"
       metricKey={MetricKey.coverage}
@@ -32,7 +32,7 @@ it('renders correctly for coverage', () => {
       value="73.0"
     />,
   );
-  expect(screen.getByRole('img')).toMatchSnapshot();
+  expect(wrapper.baseElement).toMatchSnapshot();
 });
 
 it('renders correctly for failed quality gate', () => {
index b088c02d4c2a1755d8e38470b4f0fff5e40e84bc..b223dc714b53d5ee0dad67ea52630fe513f2d466 100644 (file)
@@ -1,29 +1,34 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`renders correctly for coverage 1`] = `
-<svg
-  class="donut-chart"
-  height="24"
-  role="img"
-  width="24"
->
-  <g
-    transform="translate(0, 0)"
-  >
-    <g
-      transform="translate(12, 12)"
-    >
-      <path
-        d="M0.75,-11.977A12,12,0,1,1,-11.672,2.785L-8.709,2.271A9,9,0,1,0,0.75,-8.969Z"
-        style="fill: rgb(18,183,106);"
-      />
-      <path
-        d="M-11.929,1.307A12,12,0,0,1,-0.75,-11.977L-0.75,-8.969A9,9,0,0,0,-8.965,0.793Z"
-        style="fill: rgb(180,35,24);"
-      />
-    </g>
-  </g>
-</svg>
+<body>
+  <div>
+    <div>
+      <svg
+        class="donut-chart"
+        height="24"
+        width="24"
+      >
+        <g
+          transform="translate(0, 0)"
+        >
+          <g
+            transform="translate(12, 12)"
+          >
+            <path
+              d="M0.75,-11.977A12,12,0,1,1,-11.672,2.785L-8.709,2.271A9,9,0,1,0,0.75,-8.969Z"
+              style="fill: rgb(18,183,106);"
+            />
+            <path
+              d="M-11.929,1.307A12,12,0,0,1,-0.75,-11.977L-0.75,-8.969A9,9,0,0,0,-8.965,0.793Z"
+              style="fill: rgb(180,35,24);"
+            />
+          </g>
+        </g>
+      </svg>
+    </div>
+  </div>
+</body>
 `;
 
 exports[`renders correctly for failed quality gate 1`] = `
index 2701872489e26258662ba6761a348505301c93c9..13095e0a3937e6c538e8818ef50be86582fb66fe 100644 (file)
@@ -1992,6 +1992,7 @@ project_navigation.analysis_status.warnings=The last analysis has warnings.
 project_navigation.analysis_status.pending=New analysis pending
 project_navigation.analysis_status.in_progress=New analysis in progress
 project_navigation.analysis_status.details_link=See details
+project_navigation.analysis_status.details_link.label=See details about the last analysis
 
 #------------------------------------------------------------------------------
 #