From a0de718c034932c29d17921b6e835186e62d47b2 Mon Sep 17 00:00:00 2001 From: stanislavh Date: Thu, 5 Oct 2023 13:48:36 +0200 Subject: [PATCH] SONAR-20649 Fix flaky test bulk issue change --- .../js/apps/issues/__tests__/IssueApp-it.tsx | 418 ++++++++++++++++++ .../js/apps/issues/__tests__/IssuesApp-it.tsx | 369 +--------------- 2 files changed, 419 insertions(+), 368 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx new file mode 100644 index 00000000000..8ac1afbdaec --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssueApp-it.tsx @@ -0,0 +1,418 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { act, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; +import { TabKeys } from '../../../components/rules/RuleTabViewer'; +import { byRole } from '../../../helpers/testSelector'; +import { + branchHandler, + componentsHandler, + issuesHandler, + renderIssueApp, + renderProjectIssuesApp, + ui, +} from '../test-utils'; + +jest.mock('../sidebar/Sidebar', () => { + const fakeSidebar = () => { + return
; + }; + return { + __esModule: true, + default: fakeSidebar, + Sidebar: fakeSidebar, + }; +}); + +jest.mock('../../../components/common/ScreenPositionHelper', () => ({ + __esModule: true, + default: class ScreenPositionHelper extends React.Component<{ + children: (args: { top: number }) => React.ReactNode; + }> { + render() { + // eslint-disable-next-line testing-library/no-node-access + return this.props.children({ top: 10 }); + } + }, +})); + +beforeEach(() => { + issuesHandler.reset(); + componentsHandler.reset(); + branchHandler.reset(); + window.scrollTo = jest.fn(); + window.HTMLElement.prototype.scrollTo = jest.fn(); +}); + +describe('issue app', () => { + it('should navigate to Why is this an issue tab', async () => { + renderProjectIssuesApp('project/issues?issues=issue2&open=issue2&id=myproject&why=1'); + + expect( + await screen.findByRole('tab', { + name: `coding_rules.description_section.title.root_cause`, + }), + ).toHaveAttribute('aria-current', 'true'); + }); + + it('should interact with flows and locations', async () => { + const user = userEvent.setup(); + renderProjectIssuesApp('project/issues?issues=issue11&open=issue11&id=myproject'); + + expect(await screen.findByLabelText('list_of_issues')).toBeInTheDocument(); + + const dataFlowButton = await screen.findByRole('button', { + name: 'issue.flow.x_steps.2 Backtracking 1', + }); + const exectionFlowButton = screen.getByRole('button', { + name: 'issue.flow.x_steps.3 issue.full_execution_flow', + }); + + let dataLocation1Button = screen.getByRole('link', { name: '1 Data location 1' }); + let dataLocation2Button = screen.getByRole('link', { name: '2 Data location 2' }); + + expect(dataFlowButton).toBeInTheDocument(); + expect(dataLocation1Button).toBeInTheDocument(); + expect(dataLocation2Button).toBeInTheDocument(); + + await user.click(dataFlowButton); + // Colapsing flow + expect(dataLocation1Button).not.toBeInTheDocument(); + expect(dataLocation2Button).not.toBeInTheDocument(); + + await user.click(exectionFlowButton); + expect(screen.getByRole('link', { name: '1 Execution location 1' })).toBeInTheDocument(); + expect(screen.getByRole('link', { name: '2 Execution location 2' })).toBeInTheDocument(); + expect(screen.getByRole('link', { name: '3 Execution location 3' })).toBeInTheDocument(); + + // Keyboard interaction + await user.click(dataFlowButton); + dataLocation1Button = screen.getByRole('link', { name: '1 Data location 1' }); + dataLocation2Button = screen.getByRole('link', { name: '2 Data location 2' }); + + // Location navigation + await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); + + expect(dataLocation1Button).toHaveAttribute('aria-current', 'true'); + await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); + expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); + expect(dataLocation2Button).toHaveAttribute('aria-current', 'true'); + await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); + expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); + expect(dataLocation2Button).toHaveAttribute('aria-current', 'false'); + await user.keyboard('{Alt>}{ArrowUp}{/Alt}'); + expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); + + expect(dataLocation2Button).toHaveAttribute('aria-current', 'true'); + + // Flow navigation + await user.keyboard('{Alt>}{ArrowRight}{/Alt}'); + expect(screen.getByRole('link', { name: '1 Execution location 1' })).toHaveAttribute( + 'aria-current', + 'true', + ); + await user.keyboard('{Alt>}{ArrowLeft}{/Alt}'); + expect(screen.getByRole('link', { name: '1 Data location 1' })).toHaveAttribute( + 'aria-current', + 'true', + ); + }); + + it('should show education principles', async () => { + const user = userEvent.setup(); + renderProjectIssuesApp('project/issues?issues=issue2&open=issue2&id=myproject'); + await user.click( + await screen.findByRole('tab', { name: `coding_rules.description_section.title.more_info` }), + ); + expect(screen.getByRole('heading', { name: 'Defense-In-Depth', level: 3 })).toBeInTheDocument(); + }); + + it('should be able to perform action on issues', async () => { + const user = userEvent.setup(); + issuesHandler.setIsAdmin(true); + renderIssueApp(); + + // Get a specific issue list item + const listItem = within(await screen.findByRole('region', { name: 'Fix that' })); + + // Change issue status + expect(listItem.getByText('issue.status.OPEN')).toBeInTheDocument(); + + await act(async () => { + await user.click(listItem.getByText('issue.status.OPEN')); + }); + expect(listItem.getByText('issue.transition.confirm')).toBeInTheDocument(); + expect(listItem.getByText('issue.transition.resolve')).toBeInTheDocument(); + + await act(async () => { + await user.click(listItem.getByText('issue.transition.confirm')); + }); + expect( + listItem.getByLabelText('issue.transition.status_x_click_to_change.issue.status.CONFIRMED'), + ).toBeInTheDocument(); + + // As won't fix + await act(async () => { + await user.click(listItem.getByText('issue.status.CONFIRMED')); + await user.click(listItem.getByText('issue.transition.wontfix')); + }); + // Comment should open and close + expect(listItem.getByRole('button', { name: 'issue.comment.formlink' })).toBeInTheDocument(); + await act(async () => { + await user.keyboard('test'); + await user.click(listItem.getByRole('button', { name: 'issue.comment.formlink' })); + }); + expect( + listItem.queryByRole('button', { name: 'issue.comment.submit' }), + ).not.toBeInTheDocument(); + + // Assign issue to a different user + await act(async () => { + await user.click( + listItem.getByRole('combobox', { name: 'issue.assign.unassigned_click_to_assign' }), + ); + await user.click(screen.getByLabelText('search.search_for_users')); + await user.keyboard('luke'); + }); + expect(screen.getByText('Skywalker')).toBeInTheDocument(); + + await act(async () => { + await user.click(screen.getByText('Skywalker')); + }); + await listItem.findByRole('combobox', { + name: 'issue.assign.assigned_to_x_click_to_change.luke', + }); + expect( + listItem.getByRole('combobox', { + name: 'issue.assign.assigned_to_x_click_to_change.luke', + }), + ).toBeInTheDocument(); + + // Change tags + expect(listItem.getByText('issue.no_tag')).toBeInTheDocument(); + await act(async () => { + await user.click(listItem.getByText('issue.no_tag')); + }); + expect(listItem.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); + expect(listItem.getByText('android')).toBeInTheDocument(); + expect(listItem.getByText('accessibility')).toBeInTheDocument(); + + await act(async () => { + await user.click(listItem.getByText('accessibility')); + await user.click(listItem.getByText('android')); + }); + + await user.keyboard('{Escape}'); + await expect( + byRole('button', { name: 'accessibility android +' }).byText('accessibility').get(), + ).toHaveATooltipWithContent('accessibility, android'); + + await act(async () => { + await user.click(listItem.getByRole('button', { name: 'accessibility android +' })); + }); + + // Unselect + await act(async () => { + await user.click(screen.getByRole('checkbox', { name: 'accessibility' })); + }); + + await user.keyboard('{Escape}'); + await expect( + byRole('button', { name: 'android +' }).byText('android').get(), + ).toHaveATooltipWithContent('android'); + + await act(async () => { + await user.click(listItem.getByRole('button', { name: 'android +' })); + }); + + await act(async () => { + await user.click(screen.getByRole('searchbox', { name: 'search.search_for_tags' })); + await user.keyboard('addNewTag'); + }); + expect( + screen.getByRole('checkbox', { name: 'issue.create_tag: addnewtag' }), + ).toBeInTheDocument(); + }); + + it('should not allow performing actions when user does not have permission', async () => { + const user = userEvent.setup(); + renderIssueApp(); + + await act(async () => { + await user.click(await ui.issueItem4.find()); + }); + + expect( + screen.queryByRole('button', { + name: `issue.assign.unassigned_click_to_assign`, + }), + ).not.toBeInTheDocument(); + expect( + screen.queryByRole('button', { + name: `issue.type.type_x_click_to_change.issue.type.CODE_SMELL`, + }), + ).not.toBeInTheDocument(); + + expect( + screen.queryByRole('button', { + name: `issue.transition.status_x_click_to_change.issue.status.OPEN`, + }), + ).not.toBeInTheDocument(); + expect( + screen.queryByRole('button', { + name: `issue.severity.severity_x_click_to_change.severity.MAJOR`, + }), + ).not.toBeInTheDocument(); + }); + + it('should open the actions popup using keyboard shortcut', async () => { + const user = userEvent.setup(); + issuesHandler.setIsAdmin(true); + renderIssueApp(); + + // Select an issue with an advanced rule + await act(async () => { + await user.click(await ui.issueItemAction5.find()); + + // Open status popup on key press 'f' + await user.keyboard('f'); + }); + expect(screen.getByText('issue.transition.confirm')).toBeInTheDocument(); + expect(screen.getByText('issue.transition.resolve')).toBeInTheDocument(); + + // Open comment popup on key press 'c' + await act(async () => { + await user.keyboard('c'); + }); + expect(screen.getByText('issue.comment.formlink')).toBeInTheDocument(); + await act(async () => { + await user.keyboard('{Escape}'); + }); + + // Open tags popup on key press 't' + await act(async () => { + await user.keyboard('t'); + }); + expect(screen.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); + expect(screen.getByText('android')).toBeInTheDocument(); + expect(screen.getByText('accessibility')).toBeInTheDocument(); + + // Close tags popup + await act(async () => { + await user.click(screen.getByText('issue.no_tag')); + + // Open assign popup on key press 'a' + await user.keyboard('a'); + }); + expect(screen.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); + }); + + it('should not open the actions popup using keyboard shortcut when keyboard shortcut flag is disabled', async () => { + localStorage.setItem('sonarqube.preferences.keyboard_shortcuts_enabled', 'false'); + const user = userEvent.setup(); + issuesHandler.setIsAdmin(true); + renderIssueApp(); + + // Select an issue with an advanced rule + await act(async () => { + await user.click(await ui.issueItem5.find()); + }); + + // open status popup on key press 'f' + await user.keyboard('f'); + expect(screen.queryByText('issue.transition.confirm')).not.toBeInTheDocument(); + expect(screen.queryByText('issue.transition.resolve')).not.toBeInTheDocument(); + + // open comment popup on key press 'c' + await user.keyboard('c'); + expect(screen.queryByText('issue.comment.submit')).not.toBeInTheDocument(); + localStorage.setItem('sonarqube.preferences.keyboard_shortcuts_enabled', 'true'); + }); + + it('should show code tabs when any secondary location is selected', async () => { + const user = userEvent.setup(); + renderIssueApp(); + + await act(async () => { + await user.click(await ui.issueItemAction4.find()); + }); + expect(screen.getByRole('link', { name: 'location 1' })).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'location 2' })).toBeInTheDocument(); + + // Select the "why is this an issue" tab + await act(async () => { + await user.click( + screen.getByRole('tab', { name: 'coding_rules.description_section.title.root_cause' }), + ); + }); + expect( + screen.queryByRole('tab', { + name: `issue.tabs.${TabKeys.Code}`, + }), + ).toHaveAttribute('aria-current', 'false'); + + await act(async () => { + await user.click(screen.getByRole('link', { name: 'location 1' })); + }); + expect( + screen.queryByRole('tab', { + name: `issue.tabs.${TabKeys.Code}`, + }), + ).toHaveAttribute('aria-current', 'true'); + + // Select the same selected hotspot location should also navigate back to code page + await act(async () => { + await user.click( + screen.getByRole('tab', { name: 'coding_rules.description_section.title.root_cause' }), + ); + }); + expect( + screen.queryByRole('tab', { + name: `issue.tabs.${TabKeys.Code}`, + }), + ).toHaveAttribute('aria-current', 'false'); + + await act(async () => { + await user.click(screen.getByRole('link', { name: 'location 1' })); + }); + expect( + screen.queryByRole('tab', { + name: `issue.tabs.${TabKeys.Code}`, + }), + ).toHaveAttribute('aria-current', 'true'); + }); + + it('should show issue tags if applicable', async () => { + const user = userEvent.setup(); + issuesHandler.setIsAdmin(true); + renderIssueApp(); + + // Select an issue with an advanced rule + await act(async () => { + await user.click(await ui.issueItemAction7.find()); + }); + + await expect( + screen.getByText('issue.quick_fix_available_with_sonarlint_no_link'), + ).toHaveATooltipWithContent('issue.quick_fix_available_with_sonarlint'); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx index 2a109065e40..1f08341020f 100644 --- a/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/issues/__tests__/IssuesApp-it.tsx @@ -21,9 +21,7 @@ import { act, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { TabKeys } from '../../../components/rules/RuleTabViewer'; import { mockLoggedInUser } from '../../../helpers/testMocks'; -import { byRole } from '../../../helpers/testSelector'; import { ComponentQualifier } from '../../../types/component'; import { IssueType } from '../../../types/issues'; import { NoticeType } from '../../../types/users'; @@ -47,18 +45,6 @@ jest.mock('../sidebar/Sidebar', () => { }; }); -jest.mock('../../../components/common/ScreenPositionHelper', () => ({ - __esModule: true, - default: class ScreenPositionHelper extends React.Component<{ - children: (args: { top: number }) => React.ReactNode; - }> { - render() { - // eslint-disable-next-line testing-library/no-node-access - return this.props.children({ top: 10 }); - } - }, -})); - beforeEach(() => { issuesHandler.reset(); componentsHandler.reset(); @@ -259,6 +245,7 @@ describe('issues app', () => { // Improve this to include all the bulk change fonctionality it('should be able to bulk change', async () => { + jest.useRealTimers(); const user = userEvent.setup(); const currentUser = mockLoggedInUser({ dismissedNotices: { [NoticeType.ISSUE_GUIDE]: true }, @@ -306,360 +293,6 @@ describe('issues app', () => { }); }); -describe('issues item', () => { - it('should navigate to Why is this an issue tab', async () => { - renderProjectIssuesApp('project/issues?issues=issue2&open=issue2&id=myproject&why=1'); - - expect( - await screen.findByRole('tab', { - name: `coding_rules.description_section.title.root_cause`, - }), - ).toHaveAttribute('aria-current', 'true'); - }); - - it('should interact with flows and locations', async () => { - const user = userEvent.setup(); - renderProjectIssuesApp('project/issues?issues=issue11&open=issue11&id=myproject'); - - expect(await screen.findByLabelText('list_of_issues')).toBeInTheDocument(); - - const dataFlowButton = await screen.findByRole('button', { - name: 'issue.flow.x_steps.2 Backtracking 1', - }); - const exectionFlowButton = screen.getByRole('button', { - name: 'issue.flow.x_steps.3 issue.full_execution_flow', - }); - - let dataLocation1Button = screen.getByRole('link', { name: '1 Data location 1' }); - let dataLocation2Button = screen.getByRole('link', { name: '2 Data location 2' }); - - expect(dataFlowButton).toBeInTheDocument(); - expect(dataLocation1Button).toBeInTheDocument(); - expect(dataLocation2Button).toBeInTheDocument(); - - await user.click(dataFlowButton); - // Colapsing flow - expect(dataLocation1Button).not.toBeInTheDocument(); - expect(dataLocation2Button).not.toBeInTheDocument(); - - await user.click(exectionFlowButton); - expect(screen.getByRole('link', { name: '1 Execution location 1' })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: '2 Execution location 2' })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: '3 Execution location 3' })).toBeInTheDocument(); - - // Keyboard interaction - await user.click(dataFlowButton); - dataLocation1Button = screen.getByRole('link', { name: '1 Data location 1' }); - dataLocation2Button = screen.getByRole('link', { name: '2 Data location 2' }); - - // Location navigation - await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); - - expect(dataLocation1Button).toHaveAttribute('aria-current', 'true'); - await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); - expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); - expect(dataLocation2Button).toHaveAttribute('aria-current', 'true'); - await user.keyboard('{Alt>}{ArrowDown}{/Alt}'); - expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); - expect(dataLocation2Button).toHaveAttribute('aria-current', 'false'); - await user.keyboard('{Alt>}{ArrowUp}{/Alt}'); - expect(dataLocation1Button).toHaveAttribute('aria-current', 'false'); - - expect(dataLocation2Button).toHaveAttribute('aria-current', 'true'); - - // Flow navigation - await user.keyboard('{Alt>}{ArrowRight}{/Alt}'); - expect(screen.getByRole('link', { name: '1 Execution location 1' })).toHaveAttribute( - 'aria-current', - 'true', - ); - await user.keyboard('{Alt>}{ArrowLeft}{/Alt}'); - expect(screen.getByRole('link', { name: '1 Data location 1' })).toHaveAttribute( - 'aria-current', - 'true', - ); - }); - - it('should show education principles', async () => { - const user = userEvent.setup(); - renderProjectIssuesApp('project/issues?issues=issue2&open=issue2&id=myproject'); - await user.click( - await screen.findByRole('tab', { name: `coding_rules.description_section.title.more_info` }), - ); - expect(screen.getByRole('heading', { name: 'Defense-In-Depth', level: 3 })).toBeInTheDocument(); - }); - - it('should be able to perform action on issues', async () => { - const user = userEvent.setup(); - issuesHandler.setIsAdmin(true); - renderIssueApp(); - - // Get a specific issue list item - const listItem = within(await screen.findByRole('region', { name: 'Fix that' })); - - // Change issue status - expect(listItem.getByText('issue.status.OPEN')).toBeInTheDocument(); - - await act(async () => { - await user.click(listItem.getByText('issue.status.OPEN')); - }); - expect(listItem.getByText('issue.transition.confirm')).toBeInTheDocument(); - expect(listItem.getByText('issue.transition.resolve')).toBeInTheDocument(); - - await act(async () => { - await user.click(listItem.getByText('issue.transition.confirm')); - }); - expect( - listItem.getByLabelText('issue.transition.status_x_click_to_change.issue.status.CONFIRMED'), - ).toBeInTheDocument(); - - // As won't fix - await act(async () => { - await user.click(listItem.getByText('issue.status.CONFIRMED')); - await user.click(listItem.getByText('issue.transition.wontfix')); - }); - // Comment should open and close - expect(listItem.getByRole('button', { name: 'issue.comment.formlink' })).toBeInTheDocument(); - await act(async () => { - await user.keyboard('test'); - await user.click(listItem.getByRole('button', { name: 'issue.comment.formlink' })); - }); - expect( - listItem.queryByRole('button', { name: 'issue.comment.submit' }), - ).not.toBeInTheDocument(); - - // Assign issue to a different user - await act(async () => { - await user.click( - listItem.getByRole('combobox', { name: 'issue.assign.unassigned_click_to_assign' }), - ); - await user.click(screen.getByLabelText('search.search_for_users')); - await user.keyboard('luke'); - }); - expect(screen.getByText('Skywalker')).toBeInTheDocument(); - - await act(async () => { - await user.click(screen.getByText('Skywalker')); - }); - await listItem.findByRole('combobox', { - name: 'issue.assign.assigned_to_x_click_to_change.luke', - }); - expect( - listItem.getByRole('combobox', { - name: 'issue.assign.assigned_to_x_click_to_change.luke', - }), - ).toBeInTheDocument(); - - // Change tags - expect(listItem.getByText('issue.no_tag')).toBeInTheDocument(); - await act(async () => { - await user.click(listItem.getByText('issue.no_tag')); - }); - expect(listItem.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); - expect(listItem.getByText('android')).toBeInTheDocument(); - expect(listItem.getByText('accessibility')).toBeInTheDocument(); - - await act(async () => { - await user.click(listItem.getByText('accessibility')); - await user.click(listItem.getByText('android')); - }); - - await user.keyboard('{Escape}'); - await expect( - byRole('button', { name: 'accessibility android +' }).byText('accessibility').get(), - ).toHaveATooltipWithContent('accessibility, android'); - - await act(async () => { - await user.click(listItem.getByRole('button', { name: 'accessibility android +' })); - }); - - // Unselect - await act(async () => { - await user.click(screen.getByRole('checkbox', { name: 'accessibility' })); - }); - - await user.keyboard('{Escape}'); - await expect( - byRole('button', { name: 'android +' }).byText('android').get(), - ).toHaveATooltipWithContent('android'); - - await act(async () => { - await user.click(listItem.getByRole('button', { name: 'android +' })); - }); - - await act(async () => { - await user.click(screen.getByRole('searchbox', { name: 'search.search_for_tags' })); - await user.keyboard('addNewTag'); - }); - expect( - screen.getByRole('checkbox', { name: 'issue.create_tag: addnewtag' }), - ).toBeInTheDocument(); - }); - - it('should not allow performing actions when user does not have permission', async () => { - const user = userEvent.setup(); - renderIssueApp(); - - await act(async () => { - await user.click(await ui.issueItem4.find()); - }); - - expect( - screen.queryByRole('button', { - name: `issue.assign.unassigned_click_to_assign`, - }), - ).not.toBeInTheDocument(); - expect( - screen.queryByRole('button', { - name: `issue.type.type_x_click_to_change.issue.type.CODE_SMELL`, - }), - ).not.toBeInTheDocument(); - - expect( - screen.queryByRole('button', { - name: `issue.transition.status_x_click_to_change.issue.status.OPEN`, - }), - ).not.toBeInTheDocument(); - expect( - screen.queryByRole('button', { - name: `issue.severity.severity_x_click_to_change.severity.MAJOR`, - }), - ).not.toBeInTheDocument(); - }); - - it('should open the actions popup using keyboard shortcut', async () => { - const user = userEvent.setup(); - issuesHandler.setIsAdmin(true); - renderIssueApp(); - - // Select an issue with an advanced rule - await act(async () => { - await user.click(await ui.issueItemAction5.find()); - - // Open status popup on key press 'f' - await user.keyboard('f'); - }); - expect(screen.getByText('issue.transition.confirm')).toBeInTheDocument(); - expect(screen.getByText('issue.transition.resolve')).toBeInTheDocument(); - - // Open comment popup on key press 'c' - await act(async () => { - await user.keyboard('c'); - }); - expect(screen.getByText('issue.comment.formlink')).toBeInTheDocument(); - await act(async () => { - await user.keyboard('{Escape}'); - }); - - // Open tags popup on key press 't' - await act(async () => { - await user.keyboard('t'); - }); - expect(screen.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); - expect(screen.getByText('android')).toBeInTheDocument(); - expect(screen.getByText('accessibility')).toBeInTheDocument(); - - // Close tags popup - await act(async () => { - await user.click(screen.getByText('issue.no_tag')); - - // Open assign popup on key press 'a' - await user.keyboard('a'); - }); - expect(screen.getByRole('searchbox', { name: 'search.search_for_tags' })).toBeInTheDocument(); - }); - - it('should not open the actions popup using keyboard shortcut when keyboard shortcut flag is disabled', async () => { - localStorage.setItem('sonarqube.preferences.keyboard_shortcuts_enabled', 'false'); - const user = userEvent.setup(); - issuesHandler.setIsAdmin(true); - renderIssueApp(); - - // Select an issue with an advanced rule - await act(async () => { - await user.click(await ui.issueItem5.find()); - }); - - // open status popup on key press 'f' - await user.keyboard('f'); - expect(screen.queryByText('issue.transition.confirm')).not.toBeInTheDocument(); - expect(screen.queryByText('issue.transition.resolve')).not.toBeInTheDocument(); - - // open comment popup on key press 'c' - await user.keyboard('c'); - expect(screen.queryByText('issue.comment.submit')).not.toBeInTheDocument(); - localStorage.setItem('sonarqube.preferences.keyboard_shortcuts_enabled', 'true'); - }); - - it('should show code tabs when any secondary location is selected', async () => { - const user = userEvent.setup(); - renderIssueApp(); - - await act(async () => { - await user.click(await ui.issueItemAction4.find()); - }); - expect(screen.getByRole('link', { name: 'location 1' })).toBeInTheDocument(); - expect(screen.getByRole('link', { name: 'location 2' })).toBeInTheDocument(); - - // Select the "why is this an issue" tab - await act(async () => { - await user.click( - screen.getByRole('tab', { name: 'coding_rules.description_section.title.root_cause' }), - ); - }); - expect( - screen.queryByRole('tab', { - name: `issue.tabs.${TabKeys.Code}`, - }), - ).toHaveAttribute('aria-current', 'false'); - - await act(async () => { - await user.click(screen.getByRole('link', { name: 'location 1' })); - }); - expect( - screen.queryByRole('tab', { - name: `issue.tabs.${TabKeys.Code}`, - }), - ).toHaveAttribute('aria-current', 'true'); - - // Select the same selected hotspot location should also navigate back to code page - await act(async () => { - await user.click( - screen.getByRole('tab', { name: 'coding_rules.description_section.title.root_cause' }), - ); - }); - expect( - screen.queryByRole('tab', { - name: `issue.tabs.${TabKeys.Code}`, - }), - ).toHaveAttribute('aria-current', 'false'); - - await act(async () => { - await user.click(screen.getByRole('link', { name: 'location 1' })); - }); - expect( - screen.queryByRole('tab', { - name: `issue.tabs.${TabKeys.Code}`, - }), - ).toHaveAttribute('aria-current', 'true'); - }); - - it('should show issue tags if applicable', async () => { - const user = userEvent.setup(); - issuesHandler.setIsAdmin(true); - renderIssueApp(); - - // Select an issue with an advanced rule - await act(async () => { - await user.click(await ui.issueItemAction7.find()); - }); - - await expect( - screen.getByText('issue.quick_fix_available_with_sonarlint_no_link'), - ).toHaveATooltipWithContent('issue.quick_fix_available_with_sonarlint'); - }); -}); - describe('redirects', () => { it('should work for hotspots', () => { renderProjectIssuesApp(`project/issues?types=${IssueType.SecurityHotspot}`); -- 2.39.5