]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-21692 Fix jest warnings related to Valid DOM in IssuesApp (#10695)
authorIsmail Cherri <ismail.cherri@sonarsource.com>
Fri, 23 Feb 2024 09:25:43 +0000 (10:25 +0100)
committersonartech <sonartech@sonarsource.com>
Fri, 23 Feb 2024 20:02:35 +0000 (20:02 +0000)
server/sonar-web/design-system/src/components/ExecutionFlowAccordion.tsx
server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx
server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocation.tsx
server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsCrossFile.tsx
server/sonar-web/src/main/js/apps/issues/issues-subnavigation/IssueLocationsNavigator.tsx
server/sonar-web/src/main/js/apps/issues/issues-subnavigation/__tests__/SubnavigationIssues-it.tsx

index 9e9ab5cf6f1c6606442b9a73ccce7d40f47be7f9..cc37544272a81d28b6ff5f6fbebe7130db54f19d 100644 (file)
@@ -35,7 +35,7 @@ interface Props {
   onClick?: () => void;
 }
 
-export function ExecutionFlowAccordion(props: Props) {
+export function ExecutionFlowAccordion(props: Readonly<Props>) {
   const { children, expanded, header, hidden, id, innerRef, onClick } = props;
 
   return (
index d1135cda01eb318f3021c317fd77e4ded2ab38b8..ddce033ae5fc8ffd528da073469dddb49aeb923b 100644 (file)
@@ -97,7 +97,7 @@ describe('issue app', () => {
     const dataFlowButton = await screen.findByRole('button', {
       name: 'issue.flow.x_steps.2 Backtracking 1',
     });
-    const exectionFlowButton = screen.getByRole('link', {
+    const exectionFlowButton = screen.getByRole('button', {
       name: 'issue.show_full_execution_flow.3',
     });
 
@@ -345,8 +345,8 @@ describe('issue app', () => {
 
     await user.click(await ui.issueItemAction4.find());
 
-    expect(screen.getByRole('link', { name: 'location 1' })).toBeInTheDocument();
-    expect(screen.getByRole('link', { name: 'location 2' })).toBeInTheDocument();
+    expect(screen.getByRole('button', { name: 'location 1' })).toBeInTheDocument();
+    expect(screen.getByRole('button', { name: 'location 2' })).toBeInTheDocument();
 
     // Select the "why is this an issue" tab
     await user.click(
@@ -359,7 +359,7 @@ describe('issue app', () => {
       }),
     ).toHaveAttribute('aria-current', 'false');
 
-    await user.click(screen.getByRole('link', { name: 'location 1' }));
+    await user.click(screen.getByRole('button', { name: 'location 1' }));
 
     expect(
       screen.queryByRole('tab', {
@@ -378,7 +378,7 @@ describe('issue app', () => {
       }),
     ).toHaveAttribute('aria-current', 'false');
 
-    await user.click(screen.getByRole('link', { name: 'location 1' }));
+    await user.click(screen.getByRole('button', { name: 'location 1' }));
 
     expect(
       screen.queryByRole('tab', {
index c2414f6579b828dd5d4b881afa2003500a10dc23..a1d910f2eb58c7a996948616e01f112ae923d6e2 100644 (file)
@@ -19,7 +19,7 @@
  */
 import styled from '@emotion/styled';
 import classNames from 'classnames';
-import { BaseLink, LocationMarker, StyledMarker, themeColor } from 'design-system';
+import { LocationMarker, StyledMarker, themeColor } from 'design-system';
 import React, { useCallback, useEffect, useMemo, useRef } from 'react';
 import { translate } from '../../../helpers/l10n';
 
@@ -31,7 +31,7 @@ interface Props {
   selected: boolean;
 }
 
-export default function IssueLocation(props: Props) {
+export default function IssueLocation(props: Readonly<Props>) {
   const { index, message, selected, concealed, onClick } = props;
   const node = useRef<HTMLElement | null>(null);
   const locationType = useMemo(() => getLocationType(message), [message]);
@@ -47,7 +47,7 @@ export default function IssueLocation(props: Props) {
   }, [selected]);
 
   const handleClick = useCallback(
-    (event: React.MouseEvent<HTMLAnchorElement>) => {
+    (event: React.MouseEvent<HTMLButtonElement>) => {
       event.preventDefault();
       onClick(index);
     },
@@ -55,12 +55,7 @@ export default function IssueLocation(props: Props) {
   );
 
   return (
-    <StyledLink
-      aria-label={normalizedMessage}
-      aria-current={selected}
-      onClick={handleClick}
-      to={{}}
-    >
+    <StyledButton aria-label={normalizedMessage} aria-current={selected} onClick={handleClick}>
       <StyledLocation
         className={classNames('sw-p-1 sw-rounded-1/2 sw-flex sw-gap-2 sw-body-sm', {
           selected,
@@ -81,7 +76,7 @@ export default function IssueLocation(props: Props) {
           </StyledLocationName>
         </span>
       </StyledLocation>
-    </StyledLink>
+    </StyledButton>
   );
 }
 
@@ -96,9 +91,10 @@ const StyledLocation = styled.div`
   }
 `;
 
-const StyledLink = styled(BaseLink)`
+const StyledButton = styled.button`
   color: ${themeColor('pageContent')};
   border: none;
+  background: none;
 `;
 
 const StyledLocationName = styled.span`
index a3e4d544a97e64eed787f5251bd98f1a80d45958..bb2f02a738c61c6bb779078e46028cceaff9944c 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import styled from '@emotion/styled';
-import { DiscreetLink, themeBorder, themeContrast } from 'design-system';
+import { BareButton, themeBorder, themeContrast } from 'design-system';
 import React, { PureComponent } from 'react';
 import { translateWithParameters } from '../../../helpers/l10n';
 import { collapsePath } from '../../../helpers/path';
@@ -171,17 +171,12 @@ export default class IssueLocationsCrossFile extends PureComponent<Props, State>
         <div className="sw-flex sw-flex-col sw-gap-4">
           {this.renderGroup(firstGroup, 0, { onlyFirst: true })}
           <div>
-            <ExpandLink
-              blurAfterClick
-              onClick={this.handleMoreLocationsClick}
-              preventDefault
-              to={{}}
-            >
+            <ExpandButton onClick={this.handleMoreLocationsClick}>
               {translateWithParameters(
                 'issues.show_x_more_locations',
                 locations.length - VISIBLE_LOCATIONS_COLLAPSE,
               )}
-            </ExpandLink>
+            </ExpandButton>
           </div>
           {this.renderGroup(lastGroup, groups.length - 1, { onlyLast: true })}
         </div>
@@ -203,6 +198,7 @@ const ComponentName = styled.div`
   color: ${themeContrast('subnavigation')};
 `;
 
-const ExpandLink = styled(DiscreetLink)`
+const ExpandButton = styled(BareButton)`
   color: ${themeContrast('subnavigationSubheading')};
+  border-bottom: ${themeBorder('default', 'currentColor')};
 `;
index f0af1b1b19bbfae7a2537fd5be7e21c258b0578d..22bc6fc1ec473cd92c941fadde42e2299d4e405e 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 { DiscreetLink, ExecutionFlowAccordion, SubnavigationFlowSeparator } from 'design-system';
+import styled from '@emotion/styled';
+import {
+  BareButton,
+  ExecutionFlowAccordion,
+  SubnavigationFlowSeparator,
+  themeBorder,
+} from 'design-system';
 import React, { Fragment, useCallback, useRef } from 'react';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { Flow, FlowType, Issue } from '../../../types/types';
@@ -36,7 +42,7 @@ interface Props {
   selectedLocationIndex: number | undefined;
 }
 
-export default function IssueLocationsNavigator(props: Props) {
+export default function IssueLocationsNavigator(props: Readonly<Props>) {
   const { issue, onFlowSelect, onLocationSelect, selectedFlowIndex, selectedLocationIndex } = props;
   const accordionElement = useRef<HTMLDivElement | null>(null);
   const hasFlows =
@@ -133,18 +139,16 @@ export default function IssueLocationsNavigator(props: Props) {
                 flow.type === FlowType.EXECUTION &&
                 hasFlowsWithType && (
                   <div>
-                    <DiscreetLink
+                    <StyledBareButton
                       onClick={() => {
                         handleAccordionClick(index);
                       }}
-                      preventDefault
-                      to="{{}}"
                     >
                       {translateWithParameters(
                         'issue.show_full_execution_flow',
                         flow.locations.length,
                       )}
-                    </DiscreetLink>
+                    </StyledBareButton>
                   </div>
                 )}
             </Fragment>
@@ -165,3 +169,7 @@ function getExecutionFlowLabel(flow: Flow, hasFlowsWithType: boolean) {
 
   return translate('issues.execution_flow');
 }
+
+const StyledBareButton = styled(BareButton)`
+  border-bottom: ${themeBorder('default', 'currentColor')};
+`;
index eb9445b407c4c513016413293eea58f7eb59f0de..60cd0a4dfb5dfb876251af87a3960f68053be5a9 100644 (file)
@@ -22,7 +22,7 @@ import userEvent from '@testing-library/user-event';
 import * as React from 'react';
 import { mockFlowLocation, mockIssue, mockPaging } from '../../../../helpers/testMocks';
 import { renderComponent } from '../../../../helpers/testReactTestingUtils';
-import { byRole, byText } from '../../../../helpers/testSelector';
+import { byRole } from '../../../../helpers/testSelector';
 import { ComponentPropsType } from '../../../../helpers/testUtils';
 import { FlowType, Issue } from '../../../../types/types';
 import { VISIBLE_LOCATIONS_COLLAPSE } from '../IssueLocationsCrossFile';
@@ -228,7 +228,7 @@ describe('interacting', () => {
 function getPageObject() {
   const selectors = {
     headerBackButton: byRole('link', { name: 'issues.return_to_list' }),
-    expandBadgesButton: byText(/issues.show_x_more_locations.\d/),
+    expandBadgesButton: byRole('button', { name: /issues.show_x_more_locations.\d/ }),
   };
   const user = userEvent.setup();
   const ui = {