]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22941 Update RTL and related deps
authorJeremy Davis <jeremy.davis@sonarsource.com>
Mon, 2 Sep 2024 13:22:59 +0000 (15:22 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 4 Sep 2024 20:03:11 +0000 (20:03 +0000)
37 files changed:
server/sonar-web/design-system/package.json
server/sonar-web/design-system/src/sonar-aligned/components/input/SelectCommon.tsx
server/sonar-web/package.json
server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx
server/sonar-web/src/main/js/apps/background-tasks/__tests__/BackgroundTasks-it.tsx
server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts
server/sonar-web/src/main/js/apps/coding-rules/__tests__/CustomRule-it.ts
server/sonar-web/src/main/js/apps/coding-rules/components/SeveritySelect.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/Azure-it.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/Bitbucket-it.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloud-it.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/GitHub-it.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/GitLab-it.tsx
server/sonar-web/src/main/js/apps/create/project/__tests__/MonorepoProjectCreate-it.tsx
server/sonar-web/src/main/js/apps/create/project/components/DopSettingDropdown.tsx
server/sonar-web/src/main/js/apps/permissions/test-utils.ts
server/sonar-web/src/main/js/apps/projectInformation/badges/__tests__/ProjectBadges-test.tsx
server/sonar-web/src/main/js/apps/projectNewCode/components/NewCodeDefinitionSettingReferenceBranch.tsx
server/sonar-web/src/main/js/apps/projectNewCode/components/__tests__/ProjectNewCodeDefinitionApp-it.tsx
server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/ProjectQualityGateApp-it.tsx
server/sonar-web/src/main/js/apps/projectQualityProfiles/__tests__/projectQualityProfilesApp-it.tsx
server/sonar-web/src/main/js/apps/projectQualityProfiles/components/LanguageProfileSelectOption.tsx
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
server/sonar-web/src/main/js/apps/projectsManagement/__tests__/ProjectManagementApp-it.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx
server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx
server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonForm.tsx
server/sonar-web/src/main/js/apps/settings/components/__tests__/SettingsApp-it.tsx
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/__tests__/PRDecorationBinding-it.tsx
server/sonar-web/src/main/js/apps/users/__tests__/UsersApp-it.tsx
server/sonar-web/src/main/js/components/devops-platform/AlmSettingsInstanceSelector.tsx
server/sonar-web/src/main/js/components/tutorials/bitbucket-pipelines/__tests__/BitbucketPipelinesTutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/__tests__/GithubActionTutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/gitlabci/__tests__/GitLabCITutorial-it.tsx
server/sonar-web/src/main/js/components/tutorials/other/__tests__/OtherTutorial-it.tsx
server/sonar-web/yarn.lock

index 33aa253317c255f2009861482aaff6d1f1cf6e2f..a237ff598cafc0ae39849f0b231c27e03d5a0ac8 100644 (file)
@@ -25,8 +25,8 @@
     "@emotion/babel-plugin-jsx-pragmatic": "0.2.1",
     "@sonarsource/echoes-react": "0.6.0",
     "@testing-library/dom": "10.2.0",
-    "@testing-library/jest-dom": "6.4.6",
-    "@testing-library/react": "16.0.0",
+    "@testing-library/jest-dom": "6.5.0",
+    "@testing-library/react": "16.0.1",
     "@testing-library/user-event": "14.5.2",
     "@types/d3-array": "3.2.1",
     "@types/d3-hierarchy": "~3.1.7",
index 8414e6f3b79a663745b7d019b05432d4a0e6417a..8e89171aeb7ad922cd67c11a05ef79a5778b2fcb 100644 (file)
@@ -61,9 +61,13 @@ export function IconOption<
   const { label, isSelected } = props;
   const { Icon } = props.data as { Icon: JSX.Element };
 
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = isSelected;
+
   return (
     <components.Option {...props}>
-      <div aria-selected={isSelected} className="sw-flex sw-items-center sw-gap-1" role="option">
+      <div className="sw-flex sw-items-center sw-gap-1">
         {Icon}
         <SearchHighlighter>{label}</SearchHighlighter>
       </div>
index 5dfb4282fc83028034cd91f59de7062561f39d2b..e8f1d9f5a424a44fbfdbbadafed4bd24e4457328 100644 (file)
@@ -55,9 +55,9 @@
     "@jupyterlab/nbformat": "4.2.4",
     "@swc/core": "1.6.6",
     "@swc/jest": "0.2.36",
-    "@testing-library/dom": "9.3.4",
-    "@testing-library/jest-dom": "6.4.6",
-    "@testing-library/react": "14.2.1",
+    "@testing-library/dom": "10.2.0",
+    "@testing-library/jest-dom": "6.5.0",
+    "@testing-library/react": "16.0.1",
     "@testing-library/user-event": "14.5.2",
     "@types/cheerio": "0.22.35",
     "@types/classnames": "2.3.1",
     "postcss-custom-properties": "12.1.11",
     "prettier": "3.3.2",
     "prettier-plugin-organize-imports": "3.2.4",
-    "react-select-event": "5.5.1",
     "tailwindcss": "3.4.4",
     "turbo": "1.11.3",
     "typescript": "5.5.3",
     "dep-check": "node scripts/validate-package-json.js"
   },
   "engines": {
-    "node": ">=14"
+    "node": ">=18.20"
   },
   "browser": {
     "path": "path-browserify"
index 6b24fdf711f1a3248386873844b65bc7a63dc17c..16f6bd6d9b49cfdf0ad5ad1a833e5069dee2f21c 100644 (file)
@@ -22,7 +22,6 @@ import userEvent from '@testing-library/user-event';
 import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
 import React from 'react';
 import { Outlet, Route } from 'react-router-dom';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { getMyProjects, getScannableProjects } from '../../../api/components';
 import NotificationsMock from '../../../api/mocks/NotificationsMock';
@@ -296,24 +295,23 @@ describe('security page', () => {
 
       // eslint-disable-next-line jest/no-conditional-in-test
       if (tokenTypeOption === TokenType.Project) {
-        await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [
-          tokenTypeLabel,
-        ]);
+        await user.click(ui.tokenTypeSelect.get());
+        await user.click(byRole('option', { name: tokenTypeLabel }).get());
+
         // eslint-disable-next-line jest/no-conditional-expect
         expect(generateButton).toBeDisabled();
         // eslint-disable-next-line jest/no-conditional-expect
         expect(screen.getByRole('textbox', { name: 'users.tokens.name' })).toBeInTheDocument();
         // eslint-disable-next-line jest/no-conditional-expect
         expect(screen.getAllByRole('combobox')).toHaveLength(3);
-        await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.project' }), [
-          'Project Name 1',
-        ]);
+
+        await user.click(ui.projectSelect.get());
+        await user.click(byRole('option', { name: 'Project Name 1' }).get());
         // eslint-disable-next-line jest/no-conditional-expect
         expect(generateButton).toBeEnabled();
       } else {
-        await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [
-          tokenTypeLabel,
-        ]);
+        await user.click(ui.tokenTypeSelect.get());
+        await user.click(byRole('option', { name: tokenTypeLabel }).get());
         // eslint-disable-next-line jest/no-conditional-expect
         expect(generateButton).toBeEnabled();
       }
@@ -393,6 +391,7 @@ describe('security page', () => {
   });
 
   it("should not suggest creating a Project token if the user doesn't have at least one scannable Projects", async () => {
+    const user = userEvent.setup();
     jest.mocked(getScannableProjects).mockResolvedValueOnce({
       projects: [],
     });
@@ -403,7 +402,7 @@ describe('security page', () => {
 
     expect(await screen.findByText('users.tokens.generate')).toBeInTheDocument();
 
-    await selectEvent.openMenu(screen.getByRole('combobox', { name: 'users.tokens.type' }));
+    await user.click(ui.tokenTypeSelect.get());
     expect(screen.queryByText(`users.tokens.${TokenType.Project}`)).not.toBeInTheDocument();
   });
 
@@ -418,6 +417,7 @@ describe('security page', () => {
   });
 
   it('should preselect the only project the user has access to if they select project token', async () => {
+    const user = userEvent.setup();
     jest.mocked(getScannableProjects).mockResolvedValueOnce({
       projects: [
         {
@@ -431,9 +431,9 @@ describe('security page', () => {
       securityPagePath,
     );
     expect(await screen.findByText('users.tokens.generate')).toBeInTheDocument();
-    await selectEvent.select(screen.getByRole('combobox', { name: 'users.tokens.type' }), [
-      `users.tokens.${TokenType.Project}`,
-    ]);
+
+    await user.click(ui.tokenTypeSelect.get());
+    await user.click(byRole('option', { name: `users.tokens.${TokenType.Project}` }).get());
 
     expect(screen.getByText('Project Name 1')).toBeInTheDocument();
   });
@@ -696,3 +696,8 @@ function renderAccountApp(currentUser: CurrentUser, navigateTo?: string) {
     { currentUser, navigateTo },
   );
 }
+
+const ui = {
+  tokenTypeSelect: byRole('combobox', { name: 'users.tokens.type' }),
+  projectSelect: byRole('combobox', { name: 'users.tokens.project' }),
+};
index 338205bfae1782b4028fb7a3e587ff511eead713..40626b9c301bd971ec64e4902569c9b195d7e7ef 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { screen, waitFor, within } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import selectEvent from 'react-select-event';
 import {
   byLabelText,
   byPlaceholderText,
@@ -354,7 +353,9 @@ function getPageObject() {
     },
 
     async changeTaskFilter(fieldLabel: string, value: string) {
-      await selectEvent.select(screen.getByRole('combobox', { name: fieldLabel }), [value]);
+      await user.click(byRole('combobox', { name: fieldLabel }).get());
+      await user.click(byRole('option', { name: value }).get());
+
       expect(await screen.findByRole('button', { name: 'reload' })).toBeEnabled();
     },
 
index d17faa7d4ed263588ac92f6733f1a8627b1bdda9..6fdf75b170702f73cdd6b9425b31aa2c049adc75 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { fireEvent, screen, within } from '@testing-library/react';
-import selectEvent from 'react-select-event';
 import CodingRulesServiceMock, { RULE_TAGS_MOCK } from '../../../api/mocks/CodingRulesServiceMock';
 import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
 import { QP_2, RULE_1, RULE_10, RULE_9 } from '../../../api/mocks/data/ids';
 import { CLEAN_CODE_CATEGORIES, SOFTWARE_QUALITIES } from '../../../helpers/constants';
 import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
+import { byRole } from '../../../sonar-aligned/helpers/testSelector';
 import {
   CleanCodeAttribute,
   CleanCodeAttributeCategory,
@@ -114,12 +114,15 @@ describe('Rules app list', () => {
       const monthSelector = within(ui.dateInputMonthSelect.get()).getByRole('combobox');
 
       await user.click(monthSelector);
-      await selectEvent.select(ui.dateInputMonthSelect.byRole('combobox').get(), 'Nov');
+      await user.click(ui.dateInputMonthSelect.byRole('combobox').get());
+      await user.click(byRole('option', { name: 'Nov' }).get());
 
       const yearSelector = within(ui.dateInputYearSelect.get()).getByRole('combobox');
 
       await user.click(yearSelector);
-      await selectEvent.select(ui.dateInputYearSelect.byRole('combobox').get(), '2022');
+      await user.click(ui.dateInputYearSelect.byRole('combobox').get());
+      await user.click(byRole('option', { name: '2022' }).get());
+
       await user.click(await screen.findByText('1', { selector: 'button' }));
 
       expect(ui.getAllRuleListItems()).toHaveLength(1);
@@ -351,7 +354,9 @@ describe('Rules app list', () => {
     await user.click(ui.activateButton.getAll()[0]);
     expect(ui.selectValue.get(ui.activateQPDialog.get())).toHaveTextContent('severity.MAJOR');
     expect(ui.prioritizedSwitch.get(ui.activateQPDialog.get())).not.toBeChecked();
-    await selectEvent.select(ui.oldSeveritySelect.get(), 'severity.MINOR');
+    await user.click(ui.oldSeveritySelect.get());
+    await user.click(byRole('option', { name: 'severity.MINOR' }).get());
+
     await user.click(ui.prioritizedSwitch.get(ui.activateQPDialog.get()));
     await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
 
@@ -363,7 +368,8 @@ describe('Rules app list', () => {
     await user.click(ui.changeButton('QP Bar').get());
     expect(ui.selectValue.get(ui.changeQPDialog.get())).toHaveTextContent('severity.MINOR');
     expect(ui.prioritizedSwitch.get(ui.changeQPDialog.get())).toBeChecked();
-    await selectEvent.select(ui.oldSeveritySelect.get(), 'severity.BLOCKER');
+    await user.click(ui.oldSeveritySelect.get());
+    await user.click(byRole('option', { name: 'severity.BLOCKER' }).get());
     await user.click(ui.prioritizedSwitch.get(ui.changeQPDialog.get()));
     await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
 
@@ -642,7 +648,7 @@ describe('Rule app details', () => {
     // Activate rule in quality profile
     expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument();
     await user.click(ui.activateButton.get());
-    await selectEvent.select(ui.qualityProfileSelect.get(), 'QP FooBar');
+
     await user.click(ui.prioritizedSwitch.get());
     await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
     expect(ui.qpLink('QP FooBar').get()).toBeInTheDocument();
index 8a89d79ea627d6d443ada8a469d164891f479093..208cc1a0b984fe4cf69d4439fa55c721112e065e 100644 (file)
@@ -17,8 +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 selectEvent from 'react-select-event';
-import { byText } from '~sonar-aligned/helpers/testSelector';
+import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import CodingRulesServiceMock from '../../../api/mocks/CodingRulesServiceMock';
 import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
 import { mockLoggedInUser } from '../../../helpers/testMocks';
@@ -58,19 +57,19 @@ describe('custom rule', () => {
     await user.clear(ui.keyTextbox.get());
     await user.type(ui.keyTextbox.get(), 'new_custom_rule');
 
-    await selectEvent.select(
-      ui.cleanCodeCategorySelect.get(),
-      'rule.clean_code_attribute_category.CONSISTENT',
-    );
-    await selectEvent.select(
-      ui.cleanCodeAttributeSelect.get(),
-      'rule.clean_code_attribute.IDENTIFIABLE',
+    await user.click(ui.cleanCodeCategorySelect.get());
+    await user.click(
+      byRole('option', { name: 'rule.clean_code_attribute_category.CONSISTENT' }).get(),
     );
 
-    await selectEvent.select(
-      ui.cleanCodeCategorySelect.get(),
-      'rule.clean_code_attribute_category.INTENTIONAL',
+    await user.click(ui.cleanCodeAttributeSelect.get());
+    await user.click(byRole('option', { name: 'rule.clean_code_attribute.IDENTIFIABLE' }).get());
+
+    await user.click(ui.cleanCodeCategorySelect.get());
+    await user.click(
+      byRole('option', { name: 'rule.clean_code_attribute_category.INTENTIONAL' }).get(),
     );
+
     // Setting default clean code category of a template should set corresponding attribute
     expect(
       ui.createCustomRuleDialog.byText('rule.clean_code_attribute.CLEAR').get(),
@@ -85,13 +84,14 @@ describe('custom rule', () => {
     ).toBeInTheDocument();
 
     await user.click(ui.cleanCodeQualityCheckbox(SoftwareQuality.Reliability).get());
-    await selectEvent.select(
-      ui.cleanCodeSeveritySelect(SoftwareQuality.Reliability).get(),
-      'severity.MEDIUM',
-    );
+
+    await user.click(ui.cleanCodeSeveritySelect(SoftwareQuality.Reliability).get());
+    await user.click(byRole('option', { name: 'severity.MEDIUM severity.MEDIUM' }).get());
+
     expect(ui.createCustomRuleDialog.byText('severity.MEDIUM').get()).toBeInTheDocument();
 
-    await selectEvent.select(ui.statusSelect.get(), 'rules.status.BETA');
+    await user.click(ui.statusSelect.get());
+    await user.click(byRole('option', { name: 'rules.status.BETA' }).get());
 
     await user.type(ui.descriptionTextbox.get(), 'Some description for custom rule');
     await user.type(ui.paramInput('1').get(), 'Default value');
index f6bd9792ed54a2d08d759cd795182d6d72e99888..6aa134c43ccf0e11bb84a38ad59cc289022b8a43 100644 (file)
@@ -32,6 +32,10 @@ export interface SeveritySelectProps {
 }
 
 function Option(props: Readonly<OptionProps<LabelValueSelectOption<IssueSeverity>, false>>) {
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return (
     <components.Option {...props}>
       <SeverityHelper className="sw-flex sw-items-center" severity={props.data.value} />
index af0547a00da82f2d9a69dfa4933e8512aa717a28..358d7db3b8b5ab4b9d3795070fdc632a1b5580e3 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { screen, waitFor } from '@testing-library/react';
-
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { searchAzureRepositories } from '../../../../api/alm-integrations';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
@@ -90,7 +88,8 @@ it('should ask for PAT when it is not set yet and show the import project featur
   expect(await screen.findByText('onboarding.create_project.azure.title')).toBeInTheDocument();
   expect(screen.getByText('alm.configuration.selector.label.alm.azure.long')).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-azure-1/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-azure-1/ }).get());
 
   expect(await screen.findByText('onboarding.create_project.enter_pat')).toBeInTheDocument();
   expect(screen.getByText('onboarding.create_project.pat_form.title')).toBeInTheDocument();
@@ -112,7 +111,8 @@ it('should show import project feature when PAT is already set', async () => {
   renderCreateProject();
   expect(await screen.findByText('onboarding.create_project.azure.title')).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-azure-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-azure-2/ }).get());
 
   expect(await screen.findByText('Azure project')).toBeInTheDocument();
   expect(screen.getByText('Azure project 2')).toBeInTheDocument();
@@ -194,7 +194,8 @@ it('should show search filter when PAT is already set', async () => {
   renderCreateProject();
   expect(await screen.findByText('onboarding.create_project.azure.title')).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-azure-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-azure-2/ }).get());
 
   // Should search with positive results
   const inputSearch = await screen.findByPlaceholderText(
@@ -241,10 +242,13 @@ describe('Azure monorepo setup navigation', () => {
   });
 
   it('should load every repositories from every projects in monorepo setup mode', async () => {
+    const user = userEvent.setup();
     renderCreateProject({ isMonorepo: true });
 
-    await selectEvent.select(await ui.monorepoDopSettingDropdown.find(), [/conf-azure-2/]);
-    selectEvent.openMenu(await ui.repositorySelector.find());
+    await user.click(await ui.monorepoDopSettingDropdown.find());
+    await user.click(byRole('option', { name: /conf-azure-2/ }).get());
+
+    await user.click(ui.repositorySelector.get());
 
     expect(screen.getByText('Azure repo 1')).toBeInTheDocument();
     expect(screen.getByText('Azure repo 2')).toBeInTheDocument();
index 72bf92af621353bef1c41c6692f52e6d50b30b79..d71369d4d9faacc9da60f9ac8fa3cddf7a906b3b 100644 (file)
@@ -21,7 +21,6 @@ import { screen, waitFor, within } from '@testing-library/react';
 
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { searchForBitbucketServerRepositories } from '../../../../api/alm-integrations';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
@@ -85,7 +84,9 @@ it('should ask for PAT when it is not set yet and show the import project featur
 
   expect(screen.getByText('onboarding.create_project.bitbucket.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketserver-1/]);
+
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketserver-1/ }).get());
 
   expect(await screen.findByText('onboarding.create_project.pat_form.title')).toBeInTheDocument();
 
@@ -113,7 +114,8 @@ it('should show import project feature when PAT is already set', async () => {
   expect(screen.getByText('onboarding.create_project.bitbucket.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketserver-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketserver-2/ }).get());
 
   expect(await screen.findByText('Bitbucket Project 1')).toBeInTheDocument();
 
@@ -167,7 +169,8 @@ it('should show search filter when PAT is already set', async () => {
   expect(screen.getByText('onboarding.create_project.bitbucket.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketserver-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketserver-2/ }).get());
 
   const inputSearch = await screen.findByRole('searchbox', {
     name: 'onboarding.create_project.search_repositories_by_name',
@@ -184,12 +187,14 @@ it('should show search filter when PAT is already set', async () => {
 });
 
 it('should show no result message when there are no projects', async () => {
+  const user = userEvent.setup();
   almIntegrationHandler.setBitbucketServerProjects([]);
   renderCreateProject();
   expect(screen.getByText('onboarding.create_project.bitbucket.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketserver-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketserver-2/ }).get());
 
   expect(await screen.findByText('onboarding.create_project.no_bbs_projects')).toBeInTheDocument();
 });
index e900b099e07f346d4da41683a135ebf9ea1227bc..75046e169d19f1f1771208f894ce4fbd5dd4ea5d 100644 (file)
@@ -21,7 +21,6 @@ import { screen, waitFor, within } from '@testing-library/react';
 
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { searchForBitbucketCloudRepositories } from '../../../../api/alm-integrations';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
@@ -96,7 +95,8 @@ it('should ask for PAT when it is not set yet and show the import project featur
   expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-1/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketcloud-1/ }).get());
 
   expect(
     await screen.findByText('onboarding.create_project.bitbucket_cloud.enter_password'),
@@ -138,7 +138,8 @@ it('should show import project feature when PAT is already set', async () => {
   expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketcloud-2/ }).get());
 
   expect(await screen.findByText('BitbucketCloud Repo 1')).toBeInTheDocument();
   expect(screen.getByText('BitbucketCloud Repo 2')).toBeInTheDocument();
@@ -184,7 +185,8 @@ it('should show search filter when PAT is already set', async () => {
   expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketcloud-2/ }).get());
 
   await waitFor(() =>
     expect(searchForBitbucketCloudRepositories).toHaveBeenLastCalledWith(
@@ -212,13 +214,15 @@ it('should show search filter when PAT is already set', async () => {
 });
 
 it('should show no result message when there are no projects', async () => {
+  const user = userEvent.setup();
   almIntegrationHandler.setBitbucketCloudRepositories([]);
   renderCreateProject();
 
   expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketcloud-2/ }).get());
 
   expect(
     await screen.findByText('onboarding.create_project.bitbucketcloud.no_projects'),
@@ -236,7 +240,8 @@ it('should have load more', async () => {
   expect(screen.getByText('onboarding.create_project.bitbucketcloud.title')).toBeInTheDocument();
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-bitbucketcloud-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-bitbucketcloud-2/ }).get());
 
   expect(await screen.findByRole('button', { name: 'show_more' })).toBeInTheDocument();
 
index e231ed99b3c93a3d8c626c98c8a6c55976b7ce9f..2ed43d55d56f8a4d3d1a2a4271210cb805046ce3 100644 (file)
@@ -21,7 +21,6 @@ import { screen, waitFor } from '@testing-library/react';
 
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { getGithubRepositories } from '../../../../api/alm-integrations';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
@@ -92,25 +91,29 @@ afterAll(() => {
 });
 
 it('should redirect to github authorization page when not already authorized', async () => {
+  const user = userEvent.setup();
   renderCreateProject('project/create?mode=github');
 
   expect(await screen.findByText('onboarding.create_project.github.title')).toBeInTheDocument();
   expect(screen.getByText('alm.configuration.selector.placeholder')).toBeInTheDocument();
   expect(ui.instanceSelector.get()).toBeInTheDocument();
 
-  await selectEvent.select(await ui.instanceSelector.find(), [/conf-github-1/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-github-1/ }).get());
 
   expect(window.location.replace).toHaveBeenCalled();
 });
 
 it('should not redirect to github when url is malformated', async () => {
+  const user = userEvent.setup();
   renderCreateProject('project/create?mode=github');
 
   expect(await screen.findByText('onboarding.create_project.github.title')).toBeInTheDocument();
   expect(screen.getByText('alm.configuration.selector.placeholder')).toBeInTheDocument();
   expect(ui.instanceSelector.get()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.instanceSelector.get(), [/conf-github-3/]));
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-github-3/ }).get());
 
   expect(await ui.createErrorMessage.find()).toBeInTheDocument();
 
@@ -124,7 +127,8 @@ it('should show import project feature when the authentication is successfull',
 
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.organizationSelector.get(), [/org-1/]));
+  await user.click(ui.organizationSelector.get());
+  await user.click(byRole('option', { name: /org-1/ }).get());
 
   expect(await ui.project1.find()).toBeInTheDocument();
   expect(ui.project2.get()).toBeInTheDocument();
@@ -176,7 +180,8 @@ it('should import several projects', async () => {
 
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.organizationSelector.get(), [/org-1/]));
+  await user.click(ui.organizationSelector.get());
+  await user.click(byRole('option', { name: /org-1/ }).get());
 
   expect(await ui.project1.find()).toBeInTheDocument();
   expect(ui.project1Checkbox.get()).not.toBeChecked();
@@ -241,7 +246,8 @@ it('should show search filter when the authentication is successful', async () =
 
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.organizationSelector.get(), [/org-1/]));
+  await user.click(ui.organizationSelector.get());
+  await user.click(byRole('option', { name: /org-1/ }).get());
 
   const inputSearch = screen.getByRole('searchbox');
   await user.click(inputSearch);
@@ -266,7 +272,8 @@ it('should have load more', async () => {
 
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.organizationSelector.get(), [/org-1/]));
+  await user.click(ui.organizationSelector.get());
+  await user.click(byRole('option', { name: /org-1/ }).get());
 
   const loadMore = await screen.findByRole('button', { name: 'show_more' });
   expect(loadMore).toBeInTheDocument();
@@ -288,13 +295,15 @@ it('should have load more', async () => {
 });
 
 it('should show no result message when there are no projects', async () => {
+  const user = userEvent.setup();
   almIntegrationHandler.setGithubRepositories([]);
 
   renderCreateProject('project/create?mode=github&dopSetting=conf-github-2&code=213321213');
 
   expect(await ui.instanceSelector.find()).toBeInTheDocument();
 
-  await waitFor(() => selectEvent.select(ui.organizationSelector.get(), [/org-1/]));
+  await user.click(ui.organizationSelector.get());
+  await user.click(byRole('option', { name: /org-1/ }).get());
 
   expect(screen.getByText('no_results')).toBeInTheDocument();
 });
index b6d08bb85a179343d0fbd4a4d26d3e02b5d0d251..04a2ead7fb76c3423bc133418c2e49c3db0a4c4f 100644 (file)
@@ -20,7 +20,6 @@
 import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { getGitlabProjects } from '../../../../api/alm-integrations';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
@@ -113,7 +112,8 @@ it('should ask for PAT when it is not set yet and show the import project featur
 
   expect(await ui.importProjectsTitle.find()).toBeInTheDocument();
   expect(ui.instanceSelector.get()).toBeInTheDocument();
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-final-1/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-final-1/ }).get());
 
   expect(await screen.findByText('onboarding.create_project.enter_pat')).toBeInTheDocument();
   expect(ui.patHelpInstructions.get()).toBeInTheDocument();
@@ -127,10 +127,12 @@ it('should ask for PAT when it is not set yet and show the import project featur
 });
 
 it('should show import project feature when PAT is already set', async () => {
+  const user = userEvent.setup();
   renderCreateProject();
 
   expect(await ui.importProjectsTitle.find()).toBeInTheDocument();
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-final-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-final-2/ }).get());
 
   expect(await ui.project1.find()).toBeInTheDocument();
   expect(ui.project1Link.get()).toHaveAttribute('href', '/dashboard?id=key');
@@ -146,7 +148,8 @@ it('should show search filter when PAT is already set', async () => {
 
   expect(await ui.importProjectsTitle.find()).toBeInTheDocument();
 
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-final-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-final-2/ }).get());
 
   const inputSearch = await screen.findByRole('searchbox');
   await user.click(inputSearch);
@@ -173,7 +176,8 @@ it('should import several projects', async () => {
   renderCreateProject();
 
   expect(await ui.importProjectsTitle.find()).toBeInTheDocument();
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-final-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-final-2/ }).get());
 
   expect(await ui.project1.find()).toBeInTheDocument();
   expect(ui.project1Checkbox.get()).not.toBeChecked();
@@ -237,7 +241,9 @@ it('should have load more', async () => {
   almIntegrationHandler.createRandomGitlabProjectsWithLoadMore(50, 75);
   renderCreateProject();
 
-  await selectEvent.select(await ui.instanceSelector.find(), [/conf-final-2/]);
+  await user.click(await ui.instanceSelector.find());
+  await user.click(byRole('option', { name: /conf-final-2/ }).get());
+
   const loadMore = await screen.findByRole('button', { name: 'show_more' });
   expect(loadMore).toBeInTheDocument();
 
@@ -257,11 +263,13 @@ it('should have load more', async () => {
 });
 
 it('should show no result message when there are no projects', async () => {
+  const user = userEvent.setup();
   almIntegrationHandler.setGitlabProjects([]);
   renderCreateProject();
 
   expect(await ui.importProjectsTitle.find()).toBeInTheDocument();
-  await selectEvent.select(ui.instanceSelector.get(), [/conf-final-2/]);
+  await user.click(ui.instanceSelector.get());
+  await user.click(byRole('option', { name: /conf-final-2/ }).get());
 
   expect(await screen.findByText('no_results')).toBeInTheDocument();
 });
index 2fdd09661d38b094f91aeee33eccd1be2c19c02f..2d03e74765b6643be59698c7129a7608bbd38149 100644 (file)
@@ -20,7 +20,6 @@
 import { waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import AlmIntegrationsServiceMock from '../../../../api/mocks/AlmIntegrationsServiceMock';
 import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
@@ -124,6 +123,7 @@ describe('github monorepo project setup', () => {
   });
 
   it('should display that selected repository is not bound to any existing project', async () => {
+    const user = userEvent.setup();
     renderCreateProject({ code: '123', dopSetting: 'dop-setting-test-id', isMonorepo: true });
 
     expect(await ui.monorepoTitle.find()).toBeInTheDocument();
@@ -131,17 +131,19 @@ describe('github monorepo project setup', () => {
     expect(await ui.dopSettingSelector.find()).toBeInTheDocument();
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await waitFor(async () => {
-      await selectEvent.select(await ui.organizationSelector.find(), 'org-1');
-    });
+    await user.click(ui.organizationSelector.get());
+    await user.click(byRole('option', { name: 'org-1' }).get());
+
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await selectEvent.select(await ui.repositorySelector.find(), 'Github repo 1');
+    await user.click(ui.repositorySelector.get());
+    await user.click(byRole('option', { name: 'Github repo 1' }).get());
 
     expect(await ui.notBoundRepositoryMessage.find()).toBeInTheDocument();
   });
 
   it('should display that selected repository is already bound to an existing project', async () => {
+    const user = userEvent.setup();
     projectManagementHandler.setProjects([
       mockProject({
         key: 'key123',
@@ -155,12 +157,13 @@ describe('github monorepo project setup', () => {
     expect(await ui.dopSettingSelector.find()).toBeInTheDocument();
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await waitFor(async () => {
-      await selectEvent.select(await ui.organizationSelector.find(), 'org-1');
-    });
+    await user.click(ui.organizationSelector.get());
+    await user.click(byRole('option', { name: 'org-1' }).get());
+
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await selectEvent.select(await ui.repositorySelector.find(), 'Github repo 1');
+    await user.click(ui.repositorySelector.get());
+    await user.click(byRole('option', { name: 'Github repo 1' }).get());
 
     expect(await ui.alreadyBoundRepositoryMessage.find()).toBeInTheDocument();
     expect(byRole('link', { name: 'Project GitHub 1' }).get()).toBeInTheDocument();
@@ -175,12 +178,14 @@ describe('github monorepo project setup', () => {
     expect(await ui.dopSettingSelector.find()).toBeInTheDocument();
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await waitFor(async () => {
-      await selectEvent.select(await ui.organizationSelector.find(), 'org-1');
-    });
+    await user.click(ui.organizationSelector.get());
+    await user.click(byRole('option', { name: 'org-1' }).get());
+
     expect(ui.monorepoProjectTitle.query()).not.toBeInTheDocument();
 
-    await selectEvent.select(await ui.repositorySelector.find(), 'Github repo 1');
+    await user.click(ui.repositorySelector.get());
+    await user.click(byRole('option', { name: 'Github repo 1' }).get());
+
     expect(await ui.monorepoProjectTitle.find()).toBeInTheDocument();
     let projects = byRole('textbox', {
       name: /onboarding.create_project.project_key/,
index 599318c0894e99106f51d97ee0a95193485de2a9..38a182477aa9b863d2f288c16f43fc05e7030cfe 100644 (file)
@@ -37,6 +37,10 @@ export interface DopSettingDropdownProps {
 const MIN_SIZE_INSTANCES = 2;
 
 function optionRenderer(props: OptionProps<LabelValueSelectOption<DopSetting>, false>) {
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return <components.Option {...props}>{customOptions(props.data.value)}</components.Option>;
 }
 
index f39396bd8cb567cb2c1383237d67bae023f2096b..2e2eb11c4ee61551277f1f43108431efdd32cc31 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { waitFor } from '@testing-library/react';
 import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { Visibility } from '~sonar-aligned/types/component';
 import { Permissions } from '../../types/permissions';
@@ -95,7 +94,9 @@ export function getPageObject(user: UserEvent) {
       await user.click(ui.closeModalBtn.get());
     },
     async chooseTemplate(name: string) {
-      await selectEvent.select(ui.templateSelect.get(), [name]);
+      await user.click(ui.templateSelect.get());
+      await user.click(byRole('option', { name }).get());
+
       await user.click(ui.confirmApplyTemplateBtn.get());
     },
     async toggleFilterByPermission(permission: Permissions) {
index 554a9cf5817aba59ee43f9de8c8b4cb885fbcf38..1ff688da6f80fd4363057ead3812c54c2740987c 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 { fireEvent, screen, waitFor } from '@testing-library/react';
+import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import { MetricKey } from '~sonar-aligned/types/metrics';
 import { getProjectBadgesToken } from '../../../../api/project-badges';
@@ -28,6 +27,7 @@ import { mockBranch } from '../../../../helpers/mocks/branch-like';
 import { mockComponent } from '../../../../helpers/mocks/component';
 import { renderComponent } from '../../../../helpers/testReactTestingUtils';
 import { Location } from '../../../../helpers/urls';
+import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
 import ProjectBadges, { ProjectBadgesProps } from '../ProjectBadges';
 import { BadgeType } from '../utils';
 
@@ -84,6 +84,7 @@ it('should renew token', async () => {
 });
 
 it('should update params', async () => {
+  const user = userEvent.setup();
   renderProjectBadges();
   await appLoaded();
 
@@ -93,10 +94,7 @@ it('should update params', async () => {
     ),
   ).toBeInTheDocument();
 
-  await selectEvent.select(
-    screen.getByLabelText('overview.badges.format'),
-    'overview.badges.options.formats.url',
-  );
+  await user.click(byRole('radio', { name: 'overview.badges.options.formats.url' }).get());
 
   expect(
     screen.getByText(
@@ -104,8 +102,8 @@ it('should update params', async () => {
     ),
   ).toBeInTheDocument();
 
-  await selectEvent.openMenu(screen.getByLabelText('overview.badges.metric'));
-  fireEvent.click(screen.getByText(`metric.${MetricKey.coverage}.name`));
+  await user.click(screen.getByLabelText('overview.badges.metric'));
+  await user.click(screen.getByText(`metric.${MetricKey.coverage}.name`));
 
   expect(
     screen.getByText(
@@ -113,7 +111,7 @@ it('should update params', async () => {
     ),
   ).toBeInTheDocument();
 
-  fireEvent.click(
+  await user.click(
     screen.getByRole('button', {
       name: `overview.badges.${BadgeType.qualityGate}.alt overview.badges.${BadgeType.qualityGate}.description.${ComponentQualifier.Project}`,
     }),
@@ -125,7 +123,7 @@ it('should update params', async () => {
     ),
   ).toBeInTheDocument();
 
-  fireEvent.click(
+  await user.click(
     screen.getByRole('button', {
       name: `overview.badges.${BadgeType.measure}.alt overview.badges.${BadgeType.measure}.description.${ComponentQualifier.Project}`,
     }),
@@ -139,11 +137,12 @@ it('should update params', async () => {
 });
 
 it('should warn about deprecated metrics', async () => {
+  const user = userEvent.setup();
   renderProjectBadges();
   await appLoaded();
 
-  await selectEvent.openMenu(screen.getByLabelText('overview.badges.metric'));
-  fireEvent.click(screen.getByText(`metric.${MetricKey.bugs}.name (deprecated)`));
+  await user.click(screen.getByLabelText('overview.badges.metric'));
+  await user.click(screen.getByText(`metric.${MetricKey.bugs}.name (deprecated)`));
 
   expect(
     screen.getByText(
index 972c76b4b12413761a85a5fd2ac5e536ada4cd12..6c5f3ea5c0be9da94603cea1a00b02a7c99c2a90 100644 (file)
@@ -52,6 +52,10 @@ export interface BranchOption {
 function renderBranchOption(props: OptionProps<BranchOption, false>) {
   const { data: option } = props;
 
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return (
     <components.Option {...props}>
       {option.isInvalid ? (
index 0e5888963cdc43dbbea276ada98eb7f226c0a991..9ef1cf8280ba8e21b4fc05ac0383347d481a05d8 100644 (file)
@@ -19,7 +19,6 @@
  */
 import userEvent from '@testing-library/user-event';
 import { last } from 'lodash';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { MessageTypes } from '../../../../api/messages';
 import BranchesServiceMock from '../../../../api/mocks/BranchesServiceMock';
@@ -429,13 +428,18 @@ function getPageObjects() {
   async function setReferenceBranchSetting(branch: string) {
     await user.click(ui.specificSettingRadio.get());
     await user.click(ui.referenceBranchRadio.get());
-    await selectEvent.select(ui.chooseBranchSelect.get(), branch);
+
+    await user.click(ui.chooseBranchSelect.get());
+    await user.click(byRole('option', { name: new RegExp(branch) }).get());
   }
 
   async function setBranchReferenceToBranchSetting(branch: string, branchRef: string) {
     await openBranchSettingModal(branch);
     await user.click(last(ui.referenceBranchRadio.getAll()) as HTMLElement);
-    await selectEvent.select(ui.chooseBranchSelect.get(), branchRef);
+
+    await user.click(ui.chooseBranchSelect.get());
+    await user.click(byRole('option', { name: new RegExp(branchRef) }).get());
+
     await user.click(last(ui.saveButton.getAll()) as HTMLElement);
   }
 
index 1daad90bad22646f871672c4493362f8b137f269..6be831f883b945065b049a92828dfb03b5d23c22 100644 (file)
@@ -21,7 +21,6 @@
 import { waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import { addGlobalErrorMessage, addGlobalSuccessMessage } from 'design-system';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { QualityGatesServiceMock } from '../../../api/mocks/QualityGatesServiceMock';
 import handleRequiredAuthorization from '../../../app/utils/handleRequiredAuthorization';
@@ -73,36 +72,45 @@ it('should require authorization if no permissions set', () => {
 });
 
 it('should be able to select and save specific Quality Gate', async () => {
+  const user = userEvent.setup();
   renderProjectQualityGateApp();
 
   expect(await ui.qualityGateHeading.find()).toBeInTheDocument();
   expect(ui.defaultRadioQualityGate.get()).toBeChecked();
 
-  await userEvent.click(ui.specificRadioQualityGate.get());
+  await user.click(ui.specificRadioQualityGate.get());
   expect(ui.qualityGatesSelect.get()).toBeEnabled();
 
-  await selectEvent.select(ui.qualityGatesSelect.get(), 'Sonar way');
-  await userEvent.click(ui.saveButton.get());
+  await user.click(ui.qualityGatesSelect.get());
+  await user.click(byText('Sonar way').get());
+
+  await user.click(ui.saveButton.get());
   expect(addGlobalSuccessMessage).toHaveBeenCalledWith('project_quality_gate.successfully_updated');
 
   // Set back default QG
-  await userEvent.click(ui.defaultRadioQualityGate.get());
+  await user.click(ui.defaultRadioQualityGate.get());
   expect(ui.qualityGatesSelect.get()).toBeDisabled();
   expect(ui.defaultRadioQualityGate.get()).toBeChecked();
 
-  await userEvent.click(ui.saveButton.get());
+  await user.click(ui.saveButton.get());
   expect(addGlobalSuccessMessage).toHaveBeenCalledWith('project_quality_gate.successfully_updated');
 });
 
 it('shows warning for quality gate that doesnt have conditions on new code', async () => {
+  const user = userEvent.setup();
   handler.setGetGateForProjectName('Sonar way');
   renderProjectQualityGateApp();
 
-  await userEvent.click(await ui.specificRadioQualityGate.find());
-  await selectEvent.select(ui.qualityGatesSelect.get(), 'QG without conditions');
+  await user.click(await ui.specificRadioQualityGate.find());
+
+  await user.click(ui.qualityGatesSelect.get());
+  await user.click(byText('QG without conditions').get());
+
   expect(ui.QGWithoutConditionsOptionLabel.query()).not.toBeInTheDocument();
 
-  await selectEvent.select(ui.qualityGatesSelect.get(), 'QG without new code conditions');
+  await user.click(ui.qualityGatesSelect.get());
+  await user.click(byText('QG without new code conditions').get());
+
   expect(ui.noConditionsNewCodeWarning.get()).toBeInTheDocument();
 });
 
index ad7168e7f2b2865d3f9d824fd79f5f48d56f2fb3..7e67174767e395af9a8fc4d27100b11710bcdb48 100644 (file)
@@ -19,7 +19,6 @@
  */
 import userEvent from '@testing-library/user-event';
 import { addGlobalSuccessMessage } from 'design-system';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import {
   ProfileProject,
@@ -170,9 +169,14 @@ it('should be able to add and change profile for languages', async () => {
   expect(ui.selectProfile.get()).toBeDisabled();
   expect(ui.buttonSave.get()).toBeInTheDocument();
 
-  await selectEvent.select(ui.selectLanguage.get(), 'HTML');
+  await user.click(ui.selectLanguage.get());
+  await user.click(byRole('option', { name: 'HTML' }).get());
+
   expect(ui.selectProfile.get()).toBeEnabled();
-  await selectEvent.select(ui.selectProfile.get(), 'html profile');
+
+  await user.click(ui.selectProfile.get());
+  await user.click(byRole('option', { name: 'html profile' }).get());
+
   await user.click(ui.buttonSave.get());
   expect(associateProject).toHaveBeenLastCalledWith(
     expect.objectContaining({ key: 'html', name: 'html profile' }),
@@ -207,7 +211,9 @@ it('should be able to add and change profile for languages', async () => {
   expect(ui.newAnalysisWarningMessage.get()).toBeInTheDocument();
   expect(ui.selectUseSpecificProfile.get()).toBeInTheDocument();
 
-  await selectEvent.select(ui.selectUseSpecificProfile.get(), 'html default profile');
+  await user.click(ui.selectUseSpecificProfile.get());
+  await user.click(byRole('option', { name: 'html default profile' }).get());
+
   await user.click(ui.buttonSave.get());
 
   expect(addGlobalSuccessMessage).toHaveBeenCalledWith(
index 582c48c0a3f4bef4f195f2cc69ed08d509d74c0f..786bc5d2ee0867cf9b27edba0ae1210e5f013f69 100644 (file)
@@ -53,6 +53,10 @@ export default function LanguageProfileSelectOption(props: LanguageProfileSelect
     [option.label, option.language],
   );
 
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return (
     <components.Option {...props}>
       <div>
index a699ef58aadcc748cde1ee930ead1fe030e3ba95..4ef59d041e0e3fc7ec14722642d0ca46bdc916e1 100644 (file)
@@ -115,9 +115,15 @@ class Search extends React.PureComponent<Props, State> {
   handleVisibilityChange = ({ value }: LabelValueSelectOption) =>
     this.props.onVisibilityChanged(value);
 
-  optionRenderer = (props: OptionProps<LabelValueSelectOption, false>) => (
-    <components.Option {...props}>{this.renderQualifierOption(props.data)}</components.Option>
-  );
+  optionRenderer = (props: OptionProps<LabelValueSelectOption, false>) => {
+    // For tests and a11y
+    props.innerProps.role = 'option';
+    props.innerProps['aria-selected'] = props.isSelected;
+
+    return (
+      <components.Option {...props}>{this.renderQualifierOption(props.data)}</components.Option>
+    );
+  };
 
   singleValueRenderer = (props: SingleValueProps<LabelValueSelectOption, false>) => (
     <components.SingleValue {...props}>
index b2599e0a88374a74b64bdf9829ae3847a5ec48a3..4c7441c8b9b68f0af2497a124964e9a74e7facec 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { screen, waitFor, within } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import selectEvent from 'react-select-event';
 import { byPlaceholderText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import DopTranslationServiceMock from '../../../api/mocks/DopTranslationServiceMock';
@@ -76,6 +75,7 @@ jest.mock('../../../api/navigation', () => ({
 }));
 
 const ui = {
+  pageDescription: byText('projects_management.page.description'),
   row: byRole('row'),
   firstProjectActions: byRole('button', {
     name: 'projects_management.show_actions_for_x.Project 1',
@@ -193,12 +193,10 @@ it('should filter projects', async () => {
   const user = userEvent.setup();
   renderProjectManagementApp();
   await waitFor(() => expect(ui.row.getAll()).toHaveLength(5));
-  // Should return Promise: (and same for all similar cases below)
-  // await waitFor(() => selectEvent.select(ui.visibilityFilter.get(), â€˜visibility.public’));
-  // Can be fixed by migrating ProjectManagementApp to functional component
-  await waitFor(() => {
-    selectEvent.select(ui.visibilityFilter.get(), 'visibility.public');
-  });
+
+  await user.click(ui.visibilityFilter.get());
+  await user.click(byRole('option', { name: 'visibility.public' }).get());
+
   await waitFor(() => expect(ui.row.getAll()).toHaveLength(4));
   await user.click(ui.analysisDateFilter.get());
   await user.click(await screen.findByRole('gridcell', { name: '5' }));
@@ -206,15 +204,17 @@ it('should filter projects', async () => {
   await user.click(ui.provisionedFilter.get());
   expect(ui.row.getAll()).toHaveLength(2);
   expect(ui.row.getAll()[1]).toHaveTextContent('Project 4');
-  await waitFor(() => {
-    selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW');
-  });
+
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.VW' }).get());
+
   await waitFor(() => expect(ui.provisionedFilter.query()).not.toBeInTheDocument());
   expect(ui.row.getAll()).toHaveLength(2);
   await waitFor(() => expect(ui.row.getAll()[1]).toHaveTextContent('Portfolio 1'));
-  await waitFor(() => {
-    selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP');
-  });
+
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.APP' }).get());
+
   expect(ui.provisionedFilter.query()).not.toBeInTheDocument();
   expect(ui.row.getAll()).toHaveLength(2);
   await waitFor(() => expect(ui.row.getAll()[1]).toHaveTextContent('Application 1'));
@@ -226,29 +226,35 @@ it('should search by text', async () => {
   await waitFor(() => expect(ui.row.getAll()).toHaveLength(5));
   await user.type(ui.searchFilter.get(), 'provision');
   expect(ui.row.getAll()).toHaveLength(2);
-  await waitFor(() => {
-    selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW');
-  });
+
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.VW' }).get());
+
   await waitFor(() => expect(ui.row.getAll()).toHaveLength(4));
   expect(ui.searchFilter.get()).toHaveValue('');
   await user.type(ui.searchFilter.get(), 'Portfolio 2');
   expect(ui.row.getAll()).toHaveLength(2);
-  await waitFor(() => {
-    selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP');
-  });
+
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.APP' }).get());
+
   await waitFor(() => expect(ui.row.getAll()).toHaveLength(4));
   expect(ui.searchFilter.get()).toHaveValue('');
   await user.type(ui.searchFilter.get(), 'Application 3');
   expect(ui.row.getAll()).toHaveLength(2);
 });
 
-it('should hide quilifier filter', () => {
+it('should hide qualifier filter', async () => {
   renderProjectManagementApp({ qualifiers: [ComponentQualifier.Project] });
+  // pretext to wait for loading
+  expect(await ui.pageDescription.find()).toBeInTheDocument();
   expect(ui.qualifierFilter.query()).not.toBeInTheDocument();
 });
 
-it('should hide create Project button', () => {
+it('should hide create Project button', async () => {
   renderProjectManagementApp();
+  // pretext to wait for loading
+  expect(await ui.pageDescription.find()).toBeInTheDocument();
   expect(ui.createProject.query()).not.toBeInTheDocument();
 });
 
@@ -313,10 +319,10 @@ describe('Bulk permission templates', () => {
         .byText('permission_templates.bulk_apply_permission_template.apply_to_selected.2')
         .get(),
     ).toBeInTheDocument();
-    await selectEvent.select(
-      ui.bulkApplyDialog.by(ui.selectTemplate('required')).get(),
-      'Permission Template 2',
-    );
+
+    await user.click(ui.bulkApplyDialog.by(ui.selectTemplate('required')).get());
+    await user.click(byRole('option', { name: 'Permission Template 2' }).get());
+
     await user.click(ui.bulkApplyDialog.by(ui.apply).get());
 
     expect(
@@ -492,9 +498,9 @@ it('should load more and change the filter without caching old pages', async ()
   expect(projectRows[1]).toHaveTextContent('Project 0');
   expect(projectRows[60]).toHaveTextContent('Project 59');
 
-  await waitFor(() => {
-    selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW');
-  });
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.VW' }).get());
+
   await waitFor(() => expect(projectRows[1]).not.toBeInTheDocument());
   const portfolioRows = ui.row.getAll();
   expect(portfolioRows).toHaveLength(51);
@@ -538,10 +544,10 @@ it('should apply template for single object', async () => {
   await user.click(ui.applyPermissionTemplate.get());
 
   expect(ui.applyTemplateDialog.get()).toBeInTheDocument();
-  await selectEvent.select(
-    ui.applyTemplateDialog.by(ui.selectTemplate('required')).get(),
-    'Permission Template 2',
-  );
+
+  await user.click(ui.applyTemplateDialog.by(ui.selectTemplate('required')).get());
+  await user.click(byRole('option', { name: 'Permission Template 2' }).get());
+
   await user.click(ui.applyTemplateDialog.by(ui.apply).get());
 
   expect(
@@ -642,16 +648,21 @@ it('should not apply permissions for github projects', async () => {
 });
 
 it('should not show local badge for applications and portfolios', async () => {
+  const user = userEvent.setup();
   dopTranslationHandler.gitHubConfigurations.push(
     mockGitHubConfiguration({ provisioningType: ProvisioningType.auto }),
   );
   renderProjectManagementApp({}, {}, { featureList: [Feature.GithubProvisioning] });
   await waitFor(() => expect(screen.getAllByText('local')).toHaveLength(3));
 
-  await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.VW');
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.VW' }).get());
+
   await waitFor(() => expect(screen.queryByText('local')).not.toBeInTheDocument());
 
-  await selectEvent.select(ui.qualifierFilter.get(), 'qualifiers.APP');
+  await user.click(ui.qualifierFilter.get());
+  await user.click(byRole('option', { name: 'qualifiers.APP' }).get());
+
   expect(screen.queryByText('local')).not.toBeInTheDocument();
 });
 
index 047c41069152012360f4f3d64fa0fb3f585d6839..7bb41e0f127b36487a83283ad37bd8d7b15c2970 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { screen, waitFor, within } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byTestId } from '~sonar-aligned/helpers/testSelector';
 import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock';
 import UsersServiceMock from '../../../../api/mocks/UsersServiceMock';
@@ -614,7 +613,7 @@ it('should not allow to add prioritized_rule_issues condition if feature is not
   const dialog = byRole('dialog');
 
   await user.click(dialog.byRole('radio', { name: 'quality_gates.conditions.overall_code' }).get());
-  await selectEvent.openMenu(dialog.byRole('combobox').get());
+  await user.click(dialog.byRole('combobox').get());
   expect(
     byRole('option', { name: 'Issues from prioritized rules' }).query(),
   ).not.toBeInTheDocument();
index 886c95b6fdeb16ef4bb81f5abef97456fcb28ab4..08e81e903aa060d0a7fa7b4ebb676fc51be264d5 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
 import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
@@ -109,7 +108,10 @@ describe('Admin or user with permission', () => {
       // Add user
       await user.click(ui.grantPermissionButton.get());
       expect(ui.dialog.get()).toBeInTheDocument();
-      await selectEvent.select(ui.selectUserOrGroup.get(), 'Buzz');
+
+      await user.click(ui.selectUserOrGroup.get());
+      await user.click(byRole('option', { name: /^Buzz/ }).get());
+
       await user.click(ui.addButton.get());
       expect(ui.permissionSection.byText('Buzz').get()).toBeInTheDocument();
 
@@ -134,7 +136,10 @@ describe('Admin or user with permission', () => {
       // Add Group
       await user.click(ui.grantPermissionButton.get());
       expect(ui.dialog.get()).toBeInTheDocument();
-      await selectEvent.select(ui.selectUserOrGroup.get(), 'ACDC');
+
+      await user.click(ui.selectUserOrGroup.get());
+      await user.click(byRole('option', { name: /^ACDC/ }).get());
+
       await user.click(ui.addButton.get());
       expect(ui.permissionSection.byText('ACDC').get()).toBeInTheDocument();
 
@@ -252,7 +257,10 @@ describe('Admin or user with permission', () => {
       await user.click(ui.changeParentButton.get());
       expect(await ui.dialog.find()).toBeInTheDocument();
       expect(ui.changeButton.get()).toBeDisabled();
-      await selectEvent.select(ui.selectField.get(), 'PHP Sonar way 2');
+
+      await user.click(ui.selectField.get());
+      await user.click(byRole('option', { name: 'PHP Sonar way 2' }).get());
+
       await user.click(ui.changeButton.get());
       expect(ui.dialog.query()).not.toBeInTheDocument();
 
index 3a2e6c88dd6be44db7014429595b20d48b39c4dd..534b8c480b1e26c53bde203536776c284dc887ea 100644 (file)
@@ -19,7 +19,6 @@
  */
 import { screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
 import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
@@ -136,7 +135,8 @@ it('should list Quality Profiles and filter by language', async () => {
   expect(await ui.listLinkCQualityProfile.find()).toBeInTheDocument();
   expect(ui.listLinkJavaQualityProfile.get()).toBeInTheDocument();
 
-  await selectEvent.select(ui.filterByLang.get(), 'C');
+  await user.click(ui.filterByLang.get());
+  await user.click(byRole('option', { name: 'C' }).get());
 
   expect(ui.listLinkJavaQualityProfile.query()).not.toBeInTheDocument();
 
@@ -326,7 +326,9 @@ it('should be able to compare profiles', async () => {
   expect(ui.profileActions('java quality profile', 'Java').query()).not.toBeInTheDocument();
   expect(ui.changelogLink.query()).not.toBeInTheDocument();
 
-  await selectEvent.select(ui.compareDropdown.get(), 'java quality profile #2');
+  await user.click(ui.compareDropdown.get());
+  await user.click(byRole('option', { name: 'java quality profile #2' }).get());
+
   expect(await ui.comparisonDiffTableHeading(1, 'java quality profile').find()).toBeInTheDocument();
   expect(ui.comparisonDiffTableHeading(1, 'java quality profile #2').get()).toBeInTheDocument();
   expect(ui.comparisonModifiedTableHeading(1).get()).toBeInTheDocument();
@@ -344,7 +346,9 @@ it('should be able to activate or deactivate rules in comparison page', async ()
 
   await user.click(await ui.listProfileActions('java quality profile #2', 'Java').find());
   await user.click(ui.compareButton.get());
-  await selectEvent.select(ui.compareDropdown.get(), 'java quality profile');
+
+  await user.click(ui.compareDropdown.get());
+  await user.click(byRole('option', { name: 'java quality profile' }).get());
 
   expect(await ui.summaryFewerRules(1).find()).toBeInTheDocument();
   expect(ui.summaryAdditionalRules(1).get()).toBeInTheDocument();
index a157b450d1b943bfd0f08801b0a54fbf244f5e6f..f40983053766199eef625d9bc5edc546ee0626ed 100644 (file)
@@ -77,6 +77,10 @@ function OptionRenderer(props: Readonly<OptionProps<Option, false>>) {
   const { isDefault, label } = props.data;
   const intl = useIntl();
 
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return (
     <components.Option {...props}>
       <span>{label}</span>
index 74dfe3068191114881919c8118bb92fe1767b71c..34efb6e342c61615623dd22a4634329441628fcf 100644 (file)
@@ -21,8 +21,7 @@ import { within } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import React from 'react';
 import { Route } from 'react-router-dom';
-import selectEvent from 'react-select-event';
-import { byRole } from '~sonar-aligned/helpers/testSelector';
+import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock';
 import { KeyboardKeys } from '../../../../helpers/keycodes';
 import { mockComponent } from '../../../../helpers/mocks/component';
@@ -108,7 +107,9 @@ describe('Global Settings', () => {
     await user.click(await ui.categoryLink('property.category.languages').find());
     expect(await ui.languagesHeading.find()).toBeInTheDocument();
 
-    await selectEvent.select(ui.languagesSelect.get(), 'property.category.javascript');
+    await user.click(ui.languagesSelect.get());
+    await user.click(byText('property.category.javascript').get());
+
     expect(await ui.jsGeneralSubCategoryHeading.find()).toBeInTheDocument();
   });
 
index 22abab10298cbe0692d2d21e78ba01ab819ff770..03f1d690a2178dd0ab6583b950ae02039af6e946 100644 (file)
@@ -19,7 +19,6 @@
  */
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import AlmSettingsServiceMock from '../../../../../api/mocks/AlmSettingsServiceMock';
 import CurrentUserContextProvider from '../../../../../app/components/current-user/CurrentUserContextProvider';
@@ -96,10 +95,8 @@ it.each([
     const { rerender } = renderPRDecorationBinding();
     expect(await ui.mainTitle.find()).toBeInTheDocument();
 
-    // Set form data
-    await selectEvent.select(ui.input('name', 'combobox').get(), (content) =>
-      content.includes(key),
-    );
+    await user.click(ui.input('name', 'combobox').get());
+    await user.click(byRole('option', { name: new RegExp(key) }).get());
 
     const list = inputsList[alm];
     for (const [inputId, value] of Object.entries(list)) {
index 2201fe6f32a6be5619877149fcd69db58f45e333..97c1404bf7c6cda3f8a5fcbc17c98d0288e85ff1 100644 (file)
@@ -20,7 +20,6 @@
 import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
-import selectEvent from 'react-select-event';
 import { byLabelText, byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import ComponentsServiceMock from '../../../api/mocks/ComponentsServiceMock';
 import DopTranslationServiceMock from '../../../api/mocks/DopTranslationServiceMock';
@@ -207,9 +206,9 @@ describe('different filters combinations', () => {
     await user.click(await ui.localFilter.find());
     await waitFor(() => expect(ui.activityFilter.get()).toBeEnabled());
 
-    await selectEvent.select(
-      ui.activityFilter.get(),
-      'users.activity_filter.active_sonarlint_users',
+    await user.click(ui.activityFilter.get());
+    await user.click(
+      byRole('option', { name: 'users.activity_filter.active_sonarlint_users' }).get(),
     );
 
     expect(await ui.userRows.findAll()).toHaveLength(1);
@@ -223,9 +222,9 @@ describe('different filters combinations', () => {
     await user.click(await ui.managedByScimFilter.find());
     await waitFor(() => expect(ui.activityFilter.get()).toBeEnabled());
 
-    await selectEvent.select(
-      ui.activityFilter.get(),
-      'users.activity_filter.active_sonarqube_users',
+    await user.click(ui.activityFilter.get());
+    await user.click(
+      byRole('option', { name: 'users.activity_filter.active_sonarqube_users' }).get(),
     );
 
     expect(await ui.userRows.findAll()).toHaveLength(1);
@@ -239,7 +238,8 @@ describe('different filters combinations', () => {
     await user.click(await ui.localAndManagedFilter.find());
     await waitFor(() => expect(ui.activityFilter.get()).toBeEnabled());
 
-    await selectEvent.select(ui.activityFilter.get(), 'users.activity_filter.inactive_users');
+    await user.click(ui.activityFilter.get());
+    await user.click(byRole('option', { name: 'users.activity_filter.inactive_users' }).get());
 
     expect(await ui.userRows.findAll()).toHaveLength(2);
     expect(ui.evaRow.get()).toBeInTheDocument();
@@ -626,7 +626,9 @@ describe('in manage mode', () => {
     expect(getTokensList()).toHaveLength(2); // header + "No tokens"
     expect(await screen.findByText('users.no_tokens')).toBeInTheDocument();
 
-    await selectEvent.select(ui.expiresInSelector.get(), 'users.tokens.expiration.0');
+    await user.click(ui.expiresInSelector.get());
+    await user.click(byRole('option', { name: 'users.tokens.expiration.0' }).get());
+
     await user.click(ui.generateButton.get());
     expect(getTokensList()).toHaveLength(2); // header + "test" token
     expect(screen.queryByText('users.no_tokens')).not.toBeInTheDocument();
index 761920d4b19dbd432b04fd911bdc9641c9881013..040d7ad7095d847cdf6106c5b5ee803397d49c4c 100644 (file)
@@ -24,6 +24,10 @@ import { translate } from '../../helpers/l10n';
 import { AlmInstanceBase } from '../../types/alm-settings';
 
 function optionRenderer(props: OptionProps<LabelValueSelectOption<AlmInstanceBase>, false>) {
+  // For tests and a11y
+  props.innerProps.role = 'option';
+  props.innerProps['aria-selected'] = props.isSelected;
+
   return <components.Option {...props}>{customOptions(props.data.value)}</components.Option>;
 }
 
index 0f3a5e8d3e2dd76a88ad609de978f4adad99469f..5efadd4646c56c74e3d83f0fa979d11314413d53 100644 (file)
  */
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
 import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
 import { mockComponent } from '../../../../helpers/mocks/component';
 import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
 import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
+import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
 import { AlmKeys } from '../../../../types/alm-settings';
 import { Feature } from '../../../../types/features';
 import {
@@ -154,7 +154,10 @@ it('should generate/delete a new token or use existing one', async () => {
   // Revoke current token and create new one
   await user.click(ui.deleteTokenButton.get());
   await user.type(ui.tokenNameInput.get(), 'newtoken');
-  await selectEvent.select(ui.expiresInSelect.get(), 'users.tokens.expiration.365');
+
+  await user.click(ui.expiresInSelect.get());
+  await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
+
   await user.click(ui.generateTokenButton.get());
   expect(ui.tokenValue.get()).toBeInTheDocument();
   await user.click(ui.continueButton.getAll()[0]);
index 06ff90c6eb6c7fdf413a338b0744182943f3cdd6..e6553192e9f8a8479f12dce6bd40f0aff4c7cdf7 100644 (file)
  */
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import AlmSettingsServiceMock from '../../../../api/mocks/AlmSettingsServiceMock';
 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
 import { mockAlmSettingsInstance } from '../../../../helpers/mocks/alm-settings';
 import { mockComponent } from '../../../../helpers/mocks/component';
 import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
 import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
+import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
 import { AlmKeys } from '../../../../types/alm-settings';
 import { Feature } from '../../../../types/features';
 import {
@@ -162,7 +162,10 @@ it('should generate/delete a new token or use existing one', async () => {
   // Revoke current token and create new one
   await user.click(ui.deleteTokenButton.get());
   await user.type(ui.tokenNameInput.get(), 'newtoken');
-  await selectEvent.select(ui.expiresInSelect.get(), 'users.tokens.expiration.365');
+
+  await user.click(ui.expiresInSelect.get());
+  await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
+
   await user.click(ui.generateTokenButton.get());
   expect(ui.tokenValue.get()).toBeInTheDocument();
   await user.click(ui.continueButton.getAll()[0]);
index fc5ac5c8a7e8d2b23a7d50467686a497e8633a6f..6ac323f6d0cc26e8db6ffbcb378d43506efddb79 100644 (file)
  */
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
 import { mockComponent } from '../../../../helpers/mocks/component';
 import { mockLanguage, mockLoggedInUser } from '../../../../helpers/testMocks';
 import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
+import { byRole } from '../../../../sonar-aligned/helpers/testSelector';
 import {
   getCommonNodes,
   getCopyToClipboardValue,
@@ -110,7 +110,9 @@ it('should generate/delete a new token or use existing one', async () => {
   // Revoke current token and create new one
   await user.click(ui.deleteTokenButton.get());
   await user.type(ui.tokenNameInput.get(), 'newtoken');
-  await selectEvent.select(ui.expiresInSelect.get(), 'users.tokens.expiration.365');
+  await user.click(ui.expiresInSelect.get());
+  await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
+
   await user.click(ui.generateTokenButton.get());
   expect(ui.tokenValue.get()).toBeInTheDocument();
   await user.click(ui.continueButton.getAll()[0]);
index dbc445d6326ec05c7027fd98bd346c4a1d9b9a6e..f99d456c3c8369e3774192a2b10474547988f7b2 100644 (file)
@@ -19,7 +19,6 @@
  */
 import userEvent from '@testing-library/user-event';
 import React from 'react';
-import selectEvent from 'react-select-event';
 import { byRole, byText } from '~sonar-aligned/helpers/testSelector';
 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
 import { mockComponent } from '../../../../helpers/mocks/component';
@@ -65,7 +64,9 @@ it('should generate/delete a new token or use existing one', async () => {
 
   // Generating token
   await user.type(ui.tokenNameInput.get(), 'Testing token');
-  await selectEvent.select(ui.expiresInSelect.get(), 'users.tokens.expiration.365');
+  await user.click(ui.expiresInSelect.get());
+  await user.click(byRole('option', { name: 'users.tokens.expiration.365' }).get());
+
   await user.click(ui.generateTokenButton.get());
 
   expect(ui.continueButton.get()).toBeEnabled();
index ca0baf45222cd801eab63fce33baa8195f0c56b8..8983d84e8b14167d605f0d7fd5b8d4825e388f88 100644 (file)
@@ -2084,7 +2084,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.9.2":
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3":
   version: 7.16.7
   resolution: "@babel/runtime@npm:7.16.7"
   dependencies:
@@ -5322,72 +5322,24 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@testing-library/dom@npm:9.3.4, @testing-library/dom@npm:>=7, @testing-library/dom@npm:^9.0.0":
-  version: 9.3.4
-  resolution: "@testing-library/dom@npm:9.3.4"
-  dependencies:
-    "@babel/code-frame": "npm:^7.10.4"
-    "@babel/runtime": "npm:^7.12.5"
-    "@types/aria-query": "npm:^5.0.1"
-    aria-query: "npm:5.1.3"
-    chalk: "npm:^4.1.0"
-    dom-accessibility-api: "npm:^0.5.9"
-    lz-string: "npm:^1.5.0"
-    pretty-format: "npm:^27.0.2"
-  checksum: 10/510da752ea76f4a10a0a4e3a77917b0302cf03effe576cd3534cab7e796533ee2b0e9fb6fb11b911a1ebd7c70a0bb6f235bf4f816c9b82b95b8fe0cddfd10975
-  languageName: node
-  linkType: hard
-
-"@testing-library/jest-dom@npm:6.4.6":
-  version: 6.4.6
-  resolution: "@testing-library/jest-dom@npm:6.4.6"
+"@testing-library/jest-dom@npm:6.5.0":
+  version: 6.5.0
+  resolution: "@testing-library/jest-dom@npm:6.5.0"
   dependencies:
     "@adobe/css-tools": "npm:^4.4.0"
-    "@babel/runtime": "npm:^7.9.2"
     aria-query: "npm:^5.0.0"
     chalk: "npm:^3.0.0"
     css.escape: "npm:^1.5.1"
     dom-accessibility-api: "npm:^0.6.3"
     lodash: "npm:^4.17.21"
     redent: "npm:^3.0.0"
-  peerDependencies:
-    "@jest/globals": ">= 28"
-    "@types/bun": "*"
-    "@types/jest": ">= 28"
-    jest: ">= 28"
-    vitest: ">= 0.32"
-  peerDependenciesMeta:
-    "@jest/globals":
-      optional: true
-    "@types/bun":
-      optional: true
-    "@types/jest":
-      optional: true
-    jest:
-      optional: true
-    vitest:
-      optional: true
-  checksum: 10/94fad29d740ff2c34967c644e2481a472aa8eeb1f11cdec5d4f81f14b2576660387551264c0fa718c15bfc61dd342f7621d888fe3e4ba1b7f830fe65bdd37bc8
-  languageName: node
-  linkType: hard
-
-"@testing-library/react@npm:14.2.1":
-  version: 14.2.1
-  resolution: "@testing-library/react@npm:14.2.1"
-  dependencies:
-    "@babel/runtime": "npm:^7.12.5"
-    "@testing-library/dom": "npm:^9.0.0"
-    "@types/react-dom": "npm:^18.0.0"
-  peerDependencies:
-    react: ^18.0.0
-    react-dom: ^18.0.0
-  checksum: 10/e02b2f32ae79665a79fc4d8ee053fd3832bfcd4753aa1dba05cdece1a9f59c72a0fae91e0a9387597dcb686d631a722729f2878e38dc95e6f23b291ad8d09b6c
+  checksum: 10/3d2080888af5fd7306f57448beb5a23f55d965e265b5e53394fffc112dfb0678d616a5274ff0200c46c7618f293520f86fc8562eecd8bdbc0dbb3294d63ec431
   languageName: node
   linkType: hard
 
-"@testing-library/react@npm:16.0.0":
-  version: 16.0.0
-  resolution: "@testing-library/react@npm:16.0.0"
+"@testing-library/react@npm:16.0.1":
+  version: 16.0.1
+  resolution: "@testing-library/react@npm:16.0.1"
   dependencies:
     "@babel/runtime": "npm:^7.12.5"
   peerDependencies:
@@ -5401,7 +5353,7 @@ __metadata:
       optional: true
     "@types/react-dom":
       optional: true
-  checksum: 10/b32894be94e31276138decfa6bcea69dfebc0c37cf91499ff6c878f41eb1154a43a7df6eb1e72e7bede78468af6cb67ca59e4acd3206b41f3ecdae2c6efdf67e
+  checksum: 10/904b48881cf5bd208e25899e168f5c99c78ed6d77389544838d9d861a038d2c5c5385863ee9a367436770cbf7d21c5e05a991b9e24a33806e9ac985df2448185
   languageName: node
   linkType: hard
 
@@ -5841,15 +5793,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/react-dom@npm:^18.0.0":
-  version: 18.2.17
-  resolution: "@types/react-dom@npm:18.2.17"
-  dependencies:
-    "@types/react": "npm:*"
-  checksum: 10/fe0dbb3224b48515da8fe25559e3777d756a27c3f22903f0b1b020de8d68bd57eb1f0af62b52ee65d9632637950afed8cbad24d158c4f3d910d083d49bd73fba
-  languageName: node
-  linkType: hard
-
 "@types/react-helmet@npm:6.1.11":
   version: 6.1.11
   resolution: "@types/react-helmet@npm:6.1.11"
@@ -6448,9 +6391,9 @@ __metadata:
     "@swc/core": "npm:1.6.6"
     "@swc/jest": "npm:0.2.36"
     "@tanstack/react-query": "npm:5.18.1"
-    "@testing-library/dom": "npm:9.3.4"
-    "@testing-library/jest-dom": "npm:6.4.6"
-    "@testing-library/react": "npm:14.2.1"
+    "@testing-library/dom": "npm:10.2.0"
+    "@testing-library/jest-dom": "npm:6.5.0"
+    "@testing-library/react": "npm:16.0.1"
     "@testing-library/user-event": "npm:14.5.2"
     "@types/cheerio": "npm:0.22.35"
     "@types/classnames": "npm:2.3.1"
@@ -6539,7 +6482,6 @@ __metadata:
     react-modal: "npm:3.16.1"
     react-router-dom: "npm:6.24.0"
     react-select: "npm:5.7.7"
-    react-select-event: "npm:5.5.1"
     react-virtualized: "npm:9.22.5"
     regenerator-runtime: "npm:0.14.1"
     shared-store-hook: "npm:0.0.4"
@@ -6818,15 +6760,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"aria-query@npm:5.1.3, aria-query@npm:~5.1.3":
-  version: 5.1.3
-  resolution: "aria-query@npm:5.1.3"
-  dependencies:
-    deep-equal: "npm:^2.0.5"
-  checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2
-  languageName: node
-  linkType: hard
-
 "aria-query@npm:5.3.0":
   version: 5.3.0
   resolution: "aria-query@npm:5.3.0"
@@ -6843,6 +6776,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"aria-query@npm:~5.1.3":
+  version: 5.1.3
+  resolution: "aria-query@npm:5.1.3"
+  dependencies:
+    deep-equal: "npm:^2.0.5"
+  checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2
+  languageName: node
+  linkType: hard
+
 "array-buffer-byte-length@npm:^1.0.0":
   version: 1.0.0
   resolution: "array-buffer-byte-length@npm:1.0.0"
@@ -8563,8 +8505,8 @@ __metadata:
     "@emotion/babel-plugin-jsx-pragmatic": "npm:0.2.1"
     "@sonarsource/echoes-react": "npm:0.6.0"
     "@testing-library/dom": "npm:10.2.0"
-    "@testing-library/jest-dom": "npm:6.4.6"
-    "@testing-library/react": "npm:16.0.0"
+    "@testing-library/jest-dom": "npm:6.5.0"
+    "@testing-library/react": "npm:16.0.1"
     "@testing-library/user-event": "npm:14.5.2"
     "@types/d3-array": "npm:3.2.1"
     "@types/d3-hierarchy": "npm:~3.1.7"
@@ -14824,15 +14766,6 @@ __metadata:
   languageName: node
   linkType: hard
 
-"react-select-event@npm:5.5.1":
-  version: 5.5.1
-  resolution: "react-select-event@npm:5.5.1"
-  dependencies:
-    "@testing-library/dom": "npm:>=7"
-  checksum: 10/b0917707ff9aa6eb887178107879403e483aeaacb14f2d74fef25a805538299be88adfc87709decc1b9f9280679a5ddf0d2c6f92178b7bbd416ea7c7a9149757
-  languageName: node
-  linkType: hard
-
 "react-select@npm:5.7.7":
   version: 5.7.7
   resolution: "react-select@npm:5.7.7"