]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18441 RTL migration for Quality Profiles
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>
Tue, 4 Jul 2023 15:53:54 +0000 (17:53 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 18 Jul 2023 20:03:22 +0000 (20:03 +0000)
87 files changed:
server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
server/sonar-web/src/main/js/api/quality-profiles.ts
server/sonar-web/src/main/js/api/rules.ts
server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogContainer-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx
server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/BuiltInQualityProfileBadge-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/DeleteProfileForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/QualityProfilesApp-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/BuiltInQualityProfileBadge-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/DeleteProfileForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/ProfileActions-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/QualityProfilesApp-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeParentForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeProjectsForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileExporters-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritance-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritanceBox-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsFormSelect-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesDeprecatedWarning-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowOfType-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowTotal-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesSonarWayComparison-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeParentForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeProjectsForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileExporters-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritance-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritanceBox-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsGroup-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsUser-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowOfType-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowTotal-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/Evolution-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/EvolutionDeprecated-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/RestoreProfileForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/Evolution-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/EvolutionDeprecated-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/RestoreProfileForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-profiles/types.ts
server/sonar-web/src/main/js/helpers/testMocks.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 372d7afe6665df256a1d3eac4d022c3c7c395cd5..3810265466015c036b4fca68d7fe9d5601ba72dc 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import { cloneDeep } from 'lodash';
+import { ProfileChangelogEvent } from '../../apps/quality-profiles/types';
 import { RequestData } from '../../helpers/request';
 import {
   mockCompareResult,
+  mockGroup,
   mockPaging,
   mockQualityProfile,
+  mockQualityProfileChangelogEvent,
   mockRuleDetails,
+  mockUserSelected,
 } from '../../helpers/testMocks';
 import { SearchRulesResponse } from '../../types/coding-rules';
+import { SearchRulesQuery } from '../../types/rules';
 import { Dict, Paging, ProfileInheritanceDetails, RuleDetails } from '../../types/types';
 import {
   CompareResponse,
@@ -34,22 +39,41 @@ import {
   SearchQualityProfilesParameters,
   SearchQualityProfilesResponse,
   activateRule,
+  addGroup,
+  addUser,
+  associateProject,
   changeProfileParent,
   compareProfiles,
   copyProfile,
   createQualityProfile,
+  deleteProfile,
+  dissociateProject,
+  getExporters,
   getImporters,
+  getProfileChangelog,
   getProfileInheritance,
   getProfileProjects,
+  getQualityProfile,
+  removeGroup,
+  removeUser,
+  renameProfile,
+  restoreQualityProfile,
+  searchGroups,
   searchQualityProfiles,
+  searchUsers,
+  setDefaultProfile,
 } from '../quality-profiles';
 import { getRuleDetails, searchRules } from '../rules';
 
+jest.mock('../../api/rules');
+
 export default class QualityProfilesServiceMock {
   isAdmin = false;
   listQualityProfile: Profile[] = [];
   languageMapping: Dict<Partial<Profile>> = {
     c: { language: 'c', languageName: 'C' },
+    php: { language: 'php', languageName: 'PHP' },
+    java: { language: 'java', languageName: 'Java' },
   };
 
   comparisonResult: CompareResponse = mockCompareResult();
@@ -58,21 +82,43 @@ export default class QualityProfilesServiceMock {
     paging: mockPaging(),
   };
 
+  profileProjects: {
+    [profileKey: string]: ProfileProject[];
+  } = {};
+
+  changelogEvents: ProfileChangelogEvent[] = [];
+
   constructor() {
     this.resetQualityProfile();
     this.resetComparisonResult();
-
-    (searchQualityProfiles as jest.Mock).mockImplementation(this.handleSearchQualityProfiles);
-    (createQualityProfile as jest.Mock).mockImplementation(this.handleCreateQualityProfile);
-    (changeProfileParent as jest.Mock).mockImplementation(this.handleChangeProfileParent);
-    (getProfileInheritance as jest.Mock).mockImplementation(this.handleGetProfileInheritance);
-    (getProfileProjects as jest.Mock).mockImplementation(this.handleGetProfileProjects);
-    (copyProfile as jest.Mock).mockImplementation(this.handleCopyProfile);
-    (getImporters as jest.Mock).mockImplementation(this.handleGetImporters);
-    (searchRules as jest.Mock).mockImplementation(this.handleSearchRules);
-    (compareProfiles as jest.Mock).mockImplementation(this.handleCompareQualityProfiles);
-    (activateRule as jest.Mock).mockImplementation(this.handleActivateRule);
-    (getRuleDetails as jest.Mock).mockImplementation(this.handleGetRuleDetails);
+    this.resetChangelogEvents();
+
+    jest.mocked(searchQualityProfiles).mockImplementation(this.handleSearchQualityProfiles);
+    jest.mocked(createQualityProfile).mockImplementation(this.handleCreateQualityProfile);
+    jest.mocked(changeProfileParent).mockImplementation(this.handleChangeProfileParent);
+    jest.mocked(getProfileInheritance).mockImplementation(this.handleGetProfileInheritance);
+    jest.mocked(getProfileProjects).mockImplementation(this.handleGetProfileProjects);
+    jest.mocked(copyProfile).mockImplementation(this.handleCopyProfile);
+    jest.mocked(getImporters).mockImplementation(this.handleGetImporters);
+    jest.mocked(searchRules).mockImplementation(this.handleSearchRules);
+    jest.mocked(compareProfiles).mockImplementation(this.handleCompareQualityProfiles);
+    jest.mocked(activateRule).mockImplementation(this.handleActivateRule);
+    jest.mocked(getRuleDetails).mockImplementation(this.handleGetRuleDetails);
+    jest.mocked(restoreQualityProfile).mockImplementation(this.handleRestoreQualityProfile);
+    jest.mocked(searchUsers).mockImplementation(this.handleSearchUsers);
+    jest.mocked(addUser).mockImplementation(this.handleAddUser);
+    jest.mocked(searchGroups).mockImplementation(this.handleSearchGroups);
+    jest.mocked(addGroup).mockImplementation(this.handleAddGroup);
+    jest.mocked(removeGroup).mockImplementation(this.handleRemoveGroup);
+    jest.mocked(removeUser).mockImplementation(this.handleRemoveUser);
+    jest.mocked(associateProject).mockImplementation(this.handleAssociateProject);
+    jest.mocked(getProfileChangelog).mockImplementation(this.handleGetProfileChangelog);
+    jest.mocked(dissociateProject).mockImplementation(this.handleDissociateProject);
+    jest.mocked(getQualityProfile).mockImplementation(this.handleGetQualityProfile);
+    jest.mocked(getExporters).mockImplementation(this.handleGetExporters);
+    jest.mocked(deleteProfile).mockImplementation(this.handleDeleteProfile);
+    jest.mocked(renameProfile).mockImplementation(this.handleRenameProfile);
+    jest.mocked(setDefaultProfile).mockImplementation(this.handleSetDefaultProfile);
   }
 
   resetQualityProfile() {
@@ -98,9 +144,66 @@ export default class QualityProfilesServiceMock {
         name: 'java quality profile #2',
         activeDeprecatedRuleCount: 1,
         actions: {
-          edit: true,
+          edit: this.isAdmin,
+        },
+      }),
+      mockQualityProfile({
+        key: 'sonar',
+        language: 'java',
+        languageName: 'Java',
+        name: 'Sonar way',
+        isBuiltIn: true,
+        isDefault: true,
+      }),
+      mockQualityProfile({
+        key: 'old-php-qp',
+        language: 'php',
+        languageName: 'PHP',
+        name: 'Good old PHP quality profile',
+        activeDeprecatedRuleCount: 8,
+        rulesUpdatedAt: '2019-09-16T21:10:36+0000',
+        parentKey: 'php-sonar-way-1',
+        actions: {
+          edit: this.isAdmin,
+          associateProjects: this.isAdmin,
+          delete: this.isAdmin,
+          setAsDefault: this.isAdmin,
+          copy: this.isAdmin,
+        },
+      }),
+      mockQualityProfile({
+        key: 'no-rule-qp',
+        activeRuleCount: 0,
+        actions: {
+          associateProjects: true,
+          setAsDefault: this.isAdmin,
         },
       }),
+      mockQualityProfile({
+        activeRuleCount: 6,
+        isBuiltIn: true,
+        key: 'php-sonar-way-1',
+        name: 'PHP Sonar way 1',
+        language: 'php',
+        languageName: 'PHP',
+      }),
+      mockQualityProfile({
+        activeRuleCount: 6,
+        isBuiltIn: false,
+        key: 'php-sonar-way-2',
+        name: 'PHP Sonar way 2',
+        language: 'php',
+        languageName: 'PHP',
+      }),
+      mockQualityProfile({
+        activeRuleCount: 3,
+        isBuiltIn: false,
+        key: 'php-sonar-way',
+        parentKey: 'old-php-qp',
+        name: 'PHP way',
+        language: 'php',
+        languageName: 'PHP',
+      }),
     ];
   }
 
@@ -108,17 +211,95 @@ export default class QualityProfilesServiceMock {
     this.comparisonResult = mockCompareResult();
   }
 
+  resetChangelogEvents() {
+    this.changelogEvents = [
+      mockQualityProfileChangelogEvent({
+        date: '2019-05-23T04:12:32+0100',
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-05-23T03:12:32+0100',
+        action: 'DEACTIVATED',
+        ruleKey: 'php:rule1',
+        ruleName: 'PHP Rule',
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-05-23T03:12:32+0100',
+        action: 'ACTIVATED',
+        ruleKey: 'c:rule0',
+        ruleName: 'Rule 0',
+        params: {},
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-04-23T03:12:32+0100',
+        action: 'DEACTIVATED',
+        ruleKey: 'c:rule0',
+        ruleName: 'Rule 0',
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-04-23T03:12:32+0100',
+        action: 'DEACTIVATED',
+        ruleKey: 'c:rule1',
+        ruleName: 'Rule 1',
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-04-23T02:12:32+0100',
+        action: 'DEACTIVATED',
+        ruleKey: 'c:rule2',
+        ruleName: 'Rule 2',
+        authorName: 'John Doe',
+      }),
+      mockQualityProfileChangelogEvent({
+        date: '2019-03-23T02:12:32+0100',
+        ruleKey: 'c:rule2',
+        ruleName: 'Rule 2',
+        authorName: 'John Doe',
+        params: {
+          severity: 'CRITICAL',
+          credentialWords: 'foo,bar',
+        },
+      }),
+    ];
+  }
+
   resetSearchRulesResponse() {
     this.searchRulesResponse = {
+      facets: [
+        {
+          property: 'types',
+          values: [
+            { val: 'CODE_SMELL', count: 250 },
+            { val: 'BUG', count: 60 },
+            { val: 'VULNERABILITY', count: 40 },
+            { val: 'SECURITY_HOTSPOT', count: 50 },
+          ],
+        },
+      ],
       rules: [],
       paging: {
         pageIndex: 1,
-        pageSize: 500,
-        total: 0,
+        pageSize: 400,
+        total: 400,
       },
     };
   }
 
+  resetProfileProjects() {
+    this.profileProjects = {
+      'old-php-qp': [
+        {
+          key: 'Benflix',
+          name: 'Benflix',
+          selected: true,
+        },
+        {
+          key: 'Twitter',
+          name: 'Twitter',
+          selected: false,
+        },
+      ],
+    };
+  }
+
   handleGetImporters = () => {
     return this.reply([]);
   };
@@ -142,11 +323,19 @@ export default class QualityProfilesServiceMock {
     return this.reply(copiedQualityProfile);
   };
 
-  handleGetProfileProjects = (): Promise<{
+  handleGetProfileProjects = (
+    data: RequestData
+  ): Promise<{
     more: boolean;
     paging: Paging;
     results: ProfileProject[];
   }> => {
+    const results = (this.profileProjects[data.key] ?? []).filter(
+      (project) =>
+        project.selected ===
+        (data.selected !== undefined ? Boolean(data.selected === 'selected') : true)
+    );
+
     return this.reply({
       more: false,
       paging: {
@@ -154,7 +343,7 @@ export default class QualityProfilesServiceMock {
         pageSize: 10,
         total: 0,
       },
-      results: [],
+      results,
     });
   };
 
@@ -173,10 +362,16 @@ export default class QualityProfilesServiceMock {
       });
     }
 
-    // Lets fake it for now
+    const ancestors = this.listQualityProfile.filter(
+      (p) => p.key === profile.parentKey
+    ) as ProfileInheritanceDetails[];
+    const children = this.listQualityProfile.filter(
+      (p) => p.parentKey === profile.key
+    ) as ProfileInheritanceDetails[];
+
     return this.reply({
-      ancestors: [],
-      children: [],
+      ancestors,
+      children,
       profile: {
         name: profile.name,
         activeRuleCount: 0,
@@ -226,10 +421,54 @@ export default class QualityProfilesServiceMock {
     return this.reply({ profile: newQualityProfile });
   };
 
-  handleSearchRules = (): Promise<SearchRulesResponse> => {
+  handleSearchRules = (data: SearchRulesQuery): Promise<SearchRulesResponse> => {
+    if (data.activation) {
+      this.setRulesSearchResponse({
+        facets: [
+          {
+            property: 'types',
+            values: [
+              {
+                val: 'CODE_SMELL',
+                count: 200,
+              },
+              {
+                val: 'BUG',
+                count: 50,
+              },
+              {
+                val: 'VULNERABILITY',
+                count: 30,
+              },
+              {
+                val: 'SECURITY_HOTSPOT',
+                count: 20,
+              },
+            ],
+          },
+        ],
+        rules: [],
+        paging: {
+          pageIndex: 1,
+          pageSize: 1,
+          total: 300,
+        },
+      });
+    }
     return this.reply(this.searchRulesResponse);
   };
 
+  handleGetQualityProfile = () => {
+    return this.reply({
+      profile: mockQualityProfile(),
+      compareToSonarWay: {
+        profile: '',
+        profileName: 'Sonar way',
+        missingRuleCount: 2,
+      },
+    });
+  };
+
   handleSearchQualityProfiles = (
     parameters: SearchQualityProfilesParameters = {}
   ): Promise<SearchQualityProfilesResponse> => {
@@ -288,8 +527,169 @@ export default class QualityProfilesServiceMock {
     });
   };
 
+  handleRestoreQualityProfile = () => {
+    return this.reply({
+      profile: {
+        key: 'c-sonarsource-06756',
+        name: 'SonarSource',
+        language: 'c',
+        isDefault: false,
+        isInherited: false,
+        languageName: 'C',
+      },
+      ruleSuccesses: 231,
+      ruleFailures: 0,
+    });
+  };
+
+  handleSearchUsers = () => {
+    return this.reply({
+      users: [
+        mockUserSelected({
+          login: 'buzz',
+          name: 'Buzz',
+        }),
+      ],
+      paging: mockPaging(),
+    });
+  };
+
+  handleAddUser = () => {
+    return this.reply(undefined);
+  };
+
+  handleRemoveUser = () => {
+    return this.reply(undefined);
+  };
+
+  handleSearchGroups = () => {
+    return this.reply({
+      groups: [mockGroup({ name: 'ACDC' })],
+      paging: mockPaging(),
+    });
+  };
+
+  handleAddGroup = () => {
+    return this.reply(undefined);
+  };
+
+  handleRemoveGroup = () => {
+    return this.reply(undefined);
+  };
+
+  handleAssociateProject = ({ key }: Profile, project: string) => {
+    const projects = this.profileProjects[key].map((profileProject) => {
+      if (profileProject.key === project) {
+        return {
+          ...profileProject,
+          selected: true,
+        };
+      }
+      return profileProject;
+    });
+    this.profileProjects[key] = projects;
+
+    return this.reply({});
+  };
+
+  handleDissociateProject = ({ key }: Profile, project: string) => {
+    const projects = this.profileProjects[key].map((profileProject) => {
+      if (profileProject.key === project) {
+        return {
+          ...profileProject,
+          selected: false,
+        };
+      }
+      return profileProject;
+    });
+    this.profileProjects[key] = projects;
+
+    return this.reply({});
+  };
+
+  handleGetProfileChangelog: typeof getProfileChangelog = (since, to, { language }, page) => {
+    const PAGE_SIZE = 50;
+    const p = page || 1;
+    const events = this.changelogEvents.filter((event) => {
+      if (event.ruleKey.split(':')[0] !== language) {
+        return false;
+      }
+      if (since && new Date(since) >= new Date(event.date)) {
+        return false;
+      }
+      if (to && new Date(to) <= new Date(event.date)) {
+        return false;
+      }
+      return true;
+    });
+
+    return this.reply({
+      events: events.slice((p - 1) * PAGE_SIZE, (p - 1) * PAGE_SIZE + PAGE_SIZE),
+      paging: mockPaging({
+        total: events.length,
+        pageSize: PAGE_SIZE,
+        pageIndex: p,
+      }),
+    });
+  };
+
+  handleGetExporters = () => {
+    return this.reply([
+      {
+        key: 'sonarlint-vs',
+        name: 'SonarLint for Visual Studio',
+        languages: ['php'],
+      },
+      {
+        key: 'sonarlint-eclipse',
+        name: 'SonarLint for Eclipse',
+        languages: ['php'],
+      },
+    ]);
+  };
+
+  handleDeleteProfile = ({ name }: Profile) => {
+    // delete Children
+    const qualityProfileToDelete = this.listQualityProfile.find((profile) => profile.name === name);
+    this.listQualityProfile = this.listQualityProfile.filter(
+      (profile) => profile.parentKey !== qualityProfileToDelete?.key
+    );
+
+    // delete profile
+    this.listQualityProfile = this.listQualityProfile.filter((profile) => profile.name !== name);
+
+    return this.reply({});
+  };
+
+  handleRenameProfile = (key: string, newName: string) => {
+    this.listQualityProfile = this.listQualityProfile.map((profile) => {
+      if (profile.key === key) {
+        return {
+          ...profile,
+          name: newName,
+        };
+      }
+      return profile;
+    });
+    return this.reply({});
+  };
+
+  handleSetDefaultProfile = ({ name }: Profile) => {
+    this.listQualityProfile = this.listQualityProfile.map((profile) => {
+      if (profile.name === name) {
+        return {
+          ...profile,
+          isDefault: true,
+        };
+      }
+      return profile;
+    });
+    return Promise.resolve();
+  };
+
   setAdmin() {
     this.isAdmin = true;
+    this.resetQualityProfile();
   }
 
   setRulesSearchResponse(overrides: Partial<SearchRulesResponse>) {
@@ -304,6 +704,8 @@ export default class QualityProfilesServiceMock {
     this.resetQualityProfile();
     this.resetComparisonResult();
     this.resetSearchRulesResponse();
+    this.resetProfileProjects();
+    this.resetChangelogEvents();
   }
 
   reply<T>(response: T): Promise<T> {
index 5f1d0090082189e058bcea264fe1c730ed03377c..8e87cbe5107737884776ec77d0986e7289cd8cfe 100644 (file)
@@ -144,13 +144,6 @@ export function changeProfileParent(
   }).catch(throwGlobalError);
 }
 
-export function getQualityProfileBackupUrl({ language, name: qualityProfile }: Profile) {
-  const queryParams = Object.entries({ language, qualityProfile })
-    .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
-    .join('&');
-  return `/api/qualityprofiles/backup?${queryParams}`;
-}
-
 export function getQualityProfileExporterUrl(
   { key: exporterKey }: Exporter,
   { language, name: qualityProfile }: Profile
index 4ae50959e670c797b946453324ab7f4d070ee0ad..beb06283727b40fc9eae9b0d7e753c8bc3a9e5e3 100644 (file)
@@ -31,11 +31,6 @@ export function searchRules(data: SearchRulesQuery): Promise<SearchRulesResponse
   return getJSON('/api/rules/search', data).catch(throwGlobalError);
 }
 
-export function takeFacet(response: SearchRulesResponse, property: string) {
-  const facet = response.facets?.find((f) => f.property === property);
-  return facet ? facet.values : [];
-}
-
 export function getRuleRepositories(parameters: {
   q: string;
 }): Promise<Array<{ key: string; language: string; name: string }>> {
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx
new file mode 100644 (file)
index 0000000..7f82095
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * 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 } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import selectEvent from 'react-select-event';
+import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
+import { renderAppRoutes } from '../../../helpers/testReactTestingUtils';
+import { byRole, byText } from '../../../helpers/testSelector';
+import routes from '../routes';
+
+jest.mock('../../../api/quality-profiles');
+jest.mock('../../../api/rules');
+
+const serviceMock = new QualityProfilesServiceMock();
+const ui = {
+  permissionSection: byRole('region', { name: 'permissions.page' }),
+  projectSection: byRole('region', { name: 'projects' }),
+  rulesSection: byRole('region', { name: 'rules' }),
+  exportersSection: byRole('region', { name: 'quality_profiles.exporters' }),
+  inheritanceSection: byRole('region', { name: 'quality_profiles.profile_inheritance' }),
+  grantPermissionButton: byRole('button', {
+    name: 'quality_profiles.grant_permissions_to_more_users',
+  }),
+  grantPermissionDialog: byRole('dialog', {
+    name: 'quality_profiles.grant_permissions_to_user_or_group',
+  }),
+  removeGroupDialog: byRole('dialog', {
+    name: 'quality_profiles.permissions.remove.group',
+  }),
+  removeUserDialog: byRole('dialog', {
+    name: 'quality_profiles.permissions.remove.user',
+  }),
+  deleteProfileDialog: byRole('dialog', { name: 'quality_profiles.delete_confirm_title' }),
+  changeProjectsDialog: byRole('dialog', { name: 'projects' }),
+  changeParentDialog: byRole('dialog', { name: 'quality_profiles.change_parent' }),
+  extendDialog: byRole('dialog', { name: /quality_profiles.extend_x_title/ }),
+  copyDialog: byRole('dialog', { name: /quality_profiles.copy_x_title/ }),
+  renameDialog: byRole('dialog', { name: /quality_profiles.rename_x_title/ }),
+  selectparent: byRole('combobox', { name: /quality_profiles.parent/ }),
+  selectUserOrGroup: byRole('combobox', { name: 'quality_profiles.search_description' }),
+  twitterCheckbox: byRole('checkbox', { name: 'Twitter Twitter' }),
+  benflixCheckbox: byRole('checkbox', { name: 'Benflix Benflix' }),
+  addButton: byRole('button', { name: 'add_verb' }),
+  removeButton: byRole('button', { name: 'remove' }),
+  closeButton: byRole('button', { name: 'close' }),
+  changeProjectsButton: byRole('button', { name: 'quality_profiles.change_projects' }),
+  changeButton: byRole('button', { name: 'change_verb' }),
+  withoutFilterButton: byRole('button', { name: 'quality_gates.projects.without' }),
+  changeParentButton: byRole('button', { name: 'quality_profiles.change_parent' }),
+  qualityProfileActions: byRole('button', {
+    name: /quality_profiles.actions/,
+  }),
+  qualityProfilesHeader: byRole('heading', { name: 'quality_profiles.page' }),
+  deleteQualityProfileButton: byRole('button', { name: 'delete' }),
+  activateMoreRulesButton: byRole('button', { name: 'quality_profiles.activate_more' }),
+  activateMoreLink: byRole('link', { name: 'quality_profiles.activate_more' }),
+  activateMoreRulesLink: byRole('link', { name: 'quality_profiles.activate_more_rules' }),
+  backUpLink: byRole('link', { name: 'backup_verb' }),
+  compareLink: byRole('link', { name: 'compare' }),
+  extendButton: byRole('button', { name: 'extend' }),
+  copyButton: byRole('button', { name: 'copy' }),
+  renameButton: byRole('button', { name: 'rename' }),
+  setAsDefaultButton: byRole('button', { name: 'set_as_default' }),
+  newNameInput: byRole('textbox', { name: /quality_profiles.new_name/ }),
+  qualityProfilePageLink: byRole('link', { name: 'quality_profiles.page' }),
+  rulesTotalRow: byRole('row', { name: /total/ }),
+  rulesBugsRow: byRole('row', { name: /issue.type.BUG.plural/ }),
+  rulesVulnerabilitiesRow: byRole('row', { name: /issue.type.VULNERABILITY/ }),
+  rulesCodeSmellsRow: byRole('row', { name: /issue.type.CODE_SMELL/ }),
+  rulesSecurityHotspotsRow: byRole('row', { name: /issue.type.SECURITY_HOTSPOT/ }),
+  rulesMissingSonarWayWarning: byText('quality_profiles.sonarway_missing_rules_description'),
+  rulesMissingSonarWayLink: byRole('link', { name: '2' }),
+  rulesDeprecatedWarning: byText('quality_profiles.deprecated_rules_description'),
+  rulesDeprecatedLink: byRole('link', { name: '8' }),
+};
+
+beforeEach(() => {
+  serviceMock.reset();
+});
+
+describe('Admin or user with permission', () => {
+  beforeEach(() => {
+    serviceMock.setAdmin();
+  });
+
+  describe('Permissions', () => {
+    it('should be able to grant permission to a user and remove it', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await ui.permissionSection.find()).toBeInTheDocument();
+
+      // Add user
+      await act(async () => {
+        await user.click(ui.grantPermissionButton.get());
+      });
+      expect(ui.grantPermissionDialog.get()).toBeInTheDocument();
+      await selectEvent.select(ui.selectUserOrGroup.get(), 'Buzz');
+      await user.click(ui.addButton.get());
+      expect(ui.permissionSection.byText('Buzz').get()).toBeInTheDocument();
+
+      // Remove User
+      await user.click(
+        ui.permissionSection
+          .byRole('button', { name: 'quality_profiles.permissions.remove.user_x.Buzz' })
+          .get()
+      );
+      expect(ui.removeUserDialog.get()).toBeInTheDocument();
+      await user.click(ui.removeButton.get());
+      expect(ui.permissionSection.byText('buzz').query()).not.toBeInTheDocument();
+    });
+
+    it('should be able to grant permission to a group and remove it', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await ui.permissionSection.find()).toBeInTheDocument();
+
+      // Add Group
+      await act(async () => {
+        await user.click(ui.grantPermissionButton.get());
+      });
+      expect(ui.grantPermissionDialog.get()).toBeInTheDocument();
+      await selectEvent.select(ui.selectUserOrGroup.get(), 'ACDC');
+      await user.click(ui.addButton.get());
+      expect(ui.permissionSection.byText('ACDC').get()).toBeInTheDocument();
+
+      // Remove group
+      await user.click(
+        ui.permissionSection
+          .byRole('button', { name: 'quality_profiles.permissions.remove.group_x.ACDC' })
+          .get()
+      );
+      expect(ui.removeGroupDialog.get()).toBeInTheDocument();
+      await user.click(ui.removeButton.get());
+      expect(ui.permissionSection.byText('ACDC').query()).not.toBeInTheDocument();
+    });
+
+    it('should not be able to grant permission if the profile is built-in', async () => {
+      renderQualityProfile('sonar');
+      expect(await screen.findByText('Sonar way')).toBeInTheDocument();
+      expect(ui.permissionSection.query()).not.toBeInTheDocument();
+    });
+  });
+
+  describe('Projects', () => {
+    it('should be able to add a project to Quality Profile with active rules', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await ui.projectSection.find()).toBeInTheDocument();
+      expect(ui.projectSection.byText('Twitter').query()).not.toBeInTheDocument();
+      await user.click(ui.changeProjectsButton.get());
+      expect(ui.changeProjectsDialog.get()).toBeInTheDocument();
+
+      await user.click(ui.withoutFilterButton.get());
+      await user.click(ui.twitterCheckbox.get());
+      await user.click(ui.closeButton.get());
+      expect(ui.projectSection.byText('Twitter').get()).toBeInTheDocument();
+    });
+
+    it('should be able to remove a project from a Quality Profile with active rules', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await ui.projectSection.find()).toBeInTheDocument();
+      expect(ui.projectSection.byText('Benflix').get()).toBeInTheDocument();
+      await user.click(ui.changeProjectsButton.get());
+      expect(ui.changeProjectsDialog.get()).toBeInTheDocument();
+
+      await user.click(ui.benflixCheckbox.get());
+      await user.click(ui.closeButton.get());
+      expect(ui.projectSection.byText('Benflix').query()).not.toBeInTheDocument();
+    });
+
+    it('should not be able to change project for Quality Profile with no active rules', async () => {
+      renderQualityProfile('no-rule-qp');
+
+      expect(await ui.projectSection.find()).toBeInTheDocument();
+      expect(ui.changeProjectsButton.get()).toHaveAttribute('disabled');
+    });
+
+    it('should not be able to change projects for default profiles', async () => {
+      renderQualityProfile('sonar');
+      expect(await ui.projectSection.find()).toBeInTheDocument();
+      expect(
+        await ui.projectSection.byText('quality_profiles.projects_for_default').get()
+      ).toBeInTheDocument();
+    });
+  });
+
+  describe('Rules', () => {
+    it('should be able to activate more rules', async () => {
+      renderQualityProfile();
+
+      expect(await ui.rulesSection.find()).toBeInTheDocument();
+
+      expect(ui.activateMoreLink.get()).toBeInTheDocument();
+      expect(ui.activateMoreLink.get()).toHaveAttribute(
+        'href',
+        '/coding_rules?qprofile=old-php-qp&activation=false'
+      );
+    });
+
+    it("shouldn't be able to activate more rules for built in Quality Profile", async () => {
+      renderQualityProfile('sonar');
+      expect(await ui.rulesSection.find()).toBeInTheDocument();
+      expect(ui.activateMoreRulesButton.get()).toBeInTheDocument();
+      expect(ui.activateMoreRulesButton.get()).toHaveClass('disabled');
+    });
+  });
+
+  describe('Inheritance', () => {
+    it("should be able to change a quality profile's parents", async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await ui.inheritanceSection.find()).toBeInTheDocument();
+      // Parents
+      expect(ui.inheritanceSection.byText('PHP Sonar way 1').get()).toBeInTheDocument();
+      expect(ui.inheritanceSection.byText('PHP Sonar way 2').query()).not.toBeInTheDocument();
+      // Children
+      expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
+
+      await user.click(ui.changeParentButton.get());
+      expect(await ui.changeParentDialog.find()).toBeInTheDocument();
+      expect(ui.changeButton.get()).toBeDisabled();
+      await selectEvent.select(ui.selectparent.get(), 'PHP Sonar way 2');
+      await user.click(ui.changeButton.get());
+      expect(ui.changeParentDialog.query()).not.toBeInTheDocument();
+
+      // Parents
+      expect(ui.inheritanceSection.byText('PHP Sonar way 2').get()).toBeInTheDocument();
+      expect(ui.inheritanceSection.byText('PHP Sonar way 1').query()).not.toBeInTheDocument();
+      // Children
+      expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
+    });
+
+    it("should not be able to change a Built-in quality profile's parents", async () => {
+      renderQualityProfile('php-sonar-way-1');
+
+      expect(await ui.inheritanceSection.find()).toBeInTheDocument();
+      expect(ui.changeParentButton.query()).not.toBeInTheDocument();
+    });
+  });
+
+  describe('Actions', () => {
+    it('should be able to activate more rules', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      await user.click(await ui.qualityProfileActions.find());
+      expect(ui.activateMoreRulesLink.get()).toBeInTheDocument();
+      expect(ui.activateMoreRulesLink.get()).toHaveAttribute(
+        'href',
+        '/coding_rules?qprofile=old-php-qp&activation=false'
+      );
+    });
+
+    it('should be able to extend a quality profile', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      expect(await screen.findByText('Good old PHP quality profile')).toBeInTheDocument();
+
+      await user.click(ui.qualityProfileActions.get());
+      await user.click(ui.extendButton.get());
+
+      expect(ui.extendDialog.get()).toBeInTheDocument();
+      expect(ui.extendDialog.byRole('button', { name: 'extend' }).get()).toBeDisabled();
+
+      await user.clear(ui.newNameInput.get());
+      await user.type(ui.newNameInput.get(), 'Bad new PHP quality profile');
+      await act(async () => {
+        await user.click(ui.extendDialog.byRole('button', { name: 'extend' }).get());
+      });
+
+      expect(ui.extendDialog.query()).not.toBeInTheDocument();
+
+      expect(screen.getAllByText('Bad new PHP quality profile')).toHaveLength(2);
+      expect(screen.getAllByText('Good old PHP quality profile')).toHaveLength(2);
+    });
+
+    it('should be able to copy a quality profile', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      await user.click(await ui.qualityProfileActions.find());
+      await user.click(ui.copyButton.get());
+
+      expect(ui.copyDialog.get()).toBeInTheDocument();
+      expect(ui.copyDialog.byRole('button', { name: 'copy' }).get()).toBeDisabled();
+
+      await user.clear(ui.newNameInput.get());
+      await user.type(ui.newNameInput.get(), 'Good old PHP quality profile copy');
+      await act(async () => {
+        await user.click(ui.copyDialog.byRole('button', { name: 'copy' }).get());
+      });
+
+      expect(ui.copyDialog.query()).not.toBeInTheDocument();
+
+      expect(screen.getAllByText('Good old PHP quality profile copy')).toHaveLength(2);
+    });
+
+    it('should be able to rename a quality profile', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      await user.click(await ui.qualityProfileActions.find());
+      await user.click(ui.renameButton.get());
+
+      expect(ui.renameDialog.get()).toBeInTheDocument();
+      expect(ui.renameDialog.byRole('button', { name: 'rename' }).get()).toBeDisabled();
+
+      await user.clear(ui.newNameInput.get());
+      await user.type(ui.newNameInput.get(), 'Fossil PHP quality profile');
+      await act(async () => {
+        await user.click(ui.renameDialog.byRole('button', { name: 'rename' }).get());
+      });
+
+      expect(ui.renameDialog.query()).not.toBeInTheDocument();
+
+      expect(screen.getAllByText('Fossil PHP quality profile')).toHaveLength(2);
+    });
+
+    it('should be able to set a quality profile as default', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      await user.click(await ui.qualityProfileActions.find());
+      await user.click(ui.setAsDefaultButton.get());
+
+      expect(screen.getAllByText('default')).toHaveLength(2);
+    });
+
+    it('should NOT be able to set a quality profile as default if it has no active rules', async () => {
+      const user = userEvent.setup();
+      renderQualityProfile('no-rule-qp');
+
+      await user.click(await ui.qualityProfileActions.find());
+      expect(ui.setAsDefaultButton.query()).not.toBeInTheDocument();
+    });
+
+    it("should be able to delete a Quality Profile and it's children", async () => {
+      const user = userEvent.setup();
+      renderQualityProfile();
+
+      await user.click(await ui.qualityProfileActions.find());
+      await user.click(ui.deleteQualityProfileButton.get());
+
+      expect(ui.deleteProfileDialog.get()).toBeInTheDocument();
+      expect(
+        ui.deleteProfileDialog
+          .byText(/quality_profiles.are_you_sure_want_delete_profile_x_and_descendants/)
+          .get()
+      ).toBeInTheDocument();
+      await act(async () => {
+        await user.click(ui.deleteProfileDialog.byRole('button', { name: 'delete' }).get());
+      });
+
+      expect(ui.qualityProfilesHeader.get()).toBeInTheDocument();
+      // children
+      expect(screen.queryByText('PHP way')).not.toBeInTheDocument();
+      expect(screen.queryByText('Good old PHP quality profile')).not.toBeInTheDocument();
+    });
+  });
+});
+
+describe('Users with no permission', () => {
+  it('should not be able to activate more rules', async () => {
+    renderQualityProfile();
+
+    expect(await ui.rulesSection.find()).toBeInTheDocument();
+    expect(ui.activateMoreLink.query()).not.toBeInTheDocument();
+  });
+
+  it('should not be able to grant permission to a user', async () => {
+    renderQualityProfile();
+    expect(await screen.findByText('Good old PHP quality profile')).toBeInTheDocument();
+    expect(ui.permissionSection.query()).not.toBeInTheDocument();
+  });
+
+  it("should not be able to change a quality profile's parents", async () => {
+    renderQualityProfile();
+
+    expect(await ui.inheritanceSection.find()).toBeInTheDocument();
+    expect(ui.inheritanceSection.byText('PHP Sonar way 1').get()).toBeInTheDocument();
+    expect(ui.inheritanceSection.byText('PHP way').get()).toBeInTheDocument();
+
+    expect(ui.changeParentButton.query()).not.toBeInTheDocument();
+  });
+
+  it('should not be able to change projects for Quality Profile', async () => {
+    renderQualityProfile();
+
+    expect(await ui.projectSection.find()).toBeInTheDocument();
+    expect(ui.changeProjectsButton.query()).not.toBeInTheDocument();
+  });
+});
+
+describe('Every Users', () => {
+  it('should be able to see active/inactive rules for a Quality Profile', async () => {
+    renderQualityProfile();
+
+    expect(await ui.rulesSection.find()).toBeInTheDocument();
+
+    // Active rules
+    expect(ui.rulesTotalRow.byText('300').get()).toBeInTheDocument();
+    expect(ui.rulesBugsRow.byText('50').get()).toBeInTheDocument();
+    expect(ui.rulesVulnerabilitiesRow.byText('30').get()).toBeInTheDocument();
+    expect(ui.rulesCodeSmellsRow.byText('200').get()).toBeInTheDocument();
+    expect(ui.rulesSecurityHotspotsRow.byText('20').get()).toBeInTheDocument();
+
+    // Inactive rules
+    expect(ui.rulesTotalRow.byText('100').get()).toBeInTheDocument();
+    expect(ui.rulesBugsRow.byText('10').get()).toBeInTheDocument();
+    expect(ui.rulesVulnerabilitiesRow.byText('10').get()).toBeInTheDocument();
+    expect(ui.rulesCodeSmellsRow.byText('50').get()).toBeInTheDocument();
+    expect(ui.rulesSecurityHotspotsRow.byText('30').get()).toBeInTheDocument();
+  });
+
+  it('should be able to see a warning when some rules are missing compare to Sonar way', async () => {
+    renderQualityProfile();
+
+    expect(await ui.rulesMissingSonarWayWarning.findAll()).toHaveLength(2);
+    expect(ui.rulesMissingSonarWayLink.get()).toBeInTheDocument();
+    expect(ui.rulesMissingSonarWayLink.get()).toHaveAttribute(
+      'href',
+      '/coding_rules?qprofile=old-php-qp&activation=false&languages=php'
+    );
+  });
+
+  it('should be able to see a warning when some rules are deprecated', async () => {
+    renderQualityProfile();
+
+    expect(await ui.rulesDeprecatedWarning.findAll()).toHaveLength(2);
+    expect(ui.rulesDeprecatedLink.get()).toBeInTheDocument();
+    expect(ui.rulesDeprecatedLink.get()).toHaveAttribute(
+      'href',
+      '/coding_rules?qprofile=old-php-qp&activation=true&statuses=DEPRECATED'
+    );
+  });
+
+  it('should be able to see exporters links when there are exporters for the language', async () => {
+    renderQualityProfile();
+
+    expect(await ui.exportersSection.find()).toBeInTheDocument();
+    expect(ui.exportersSection.byText('SonarLint for Visual Studio').get()).toBeInTheDocument();
+    expect(ui.exportersSection.byText('SonarLint for Eclipse').get()).toBeInTheDocument();
+  });
+
+  it('should be informed when the quality profile has not been found', async () => {
+    renderQualityProfile('i-dont-exist');
+
+    expect(await screen.findByText('quality_profiles.not_found')).toBeInTheDocument();
+    expect(ui.qualityProfilePageLink.get()).toBeInTheDocument();
+  });
+
+  it('should be able to backup quality profile', async () => {
+    const user = userEvent.setup();
+    renderQualityProfile();
+
+    await user.click(await ui.qualityProfileActions.find());
+    expect(ui.backUpLink.get()).toHaveAttribute(
+      'href',
+      '/api/qualityprofiles/backup?language=php&qualityProfile=Good%20old%20PHP%20quality%20profile'
+    );
+    expect(ui.backUpLink.get()).toHaveAttribute('download', 'old-php-qp.xml');
+  });
+
+  it('should not be able to backup a built-in quality profile', async () => {
+    const user = userEvent.setup();
+    renderQualityProfile('sonar');
+
+    await user.click(await ui.qualityProfileActions.find());
+    expect(ui.backUpLink.query()).not.toBeInTheDocument();
+  });
+
+  it('should be able to compare quality profile', async () => {
+    const user = userEvent.setup();
+    renderQualityProfile();
+
+    await user.click(await ui.qualityProfileActions.find());
+
+    expect(ui.compareLink.get()).toBeInTheDocument();
+    expect(ui.compareLink.get()).toHaveAttribute(
+      'href',
+      '/profiles/compare?language=php&name=Good+old+PHP+quality+profile'
+    );
+  });
+});
+
+function renderQualityProfile(key = 'old-php-qp') {
+  renderAppRoutes(`profiles/show?key=${key}`, routes, {});
+}
index a3fa9b46259cee11482e3c29500e666fd67e0c01..057dff8439ee5e0d78abaa9ad7ca66a83417d473 100644 (file)
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { act, getByText } from '@testing-library/react';
+import { act, getByText, screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import selectEvent from 'react-select-event';
 import QualityProfilesServiceMock from '../../../api/mocks/QualityProfilesServiceMock';
@@ -50,10 +50,13 @@ const ui = {
     name: 'copy',
   }),
   createButton: byRole('button', { name: 'create' }),
+  restoreButton: byRole('button', { name: 'restore' }),
   compareButton: byRole('link', { name: 'compare' }),
+  cancelButton: byRole('button', { name: 'cancel' }),
   compareDropdown: byRole('combobox', { name: 'quality_profiles.compare_with' }),
   changelogLink: byRole('link', { name: 'changelog' }),
   popup: byRole('dialog'),
+  restoreProfileDialog: byRole('dialog', { name: 'quality_profiles.restore_profile' }),
   copyRadio: byRole('radio', {
     name: 'quality_profiles.creation_from_copy quality_profiles.creation_from_copy_description_1 quality_profiles.creation_from_copy_description_2',
   }),
@@ -90,6 +93,9 @@ const ui = {
     byRole('table', {
       name: `quality_profiles.x_rules_have_different_configuration.${rulesQuantity}`,
     }),
+  deprecatedRulesRegion: byRole('region', { name: 'quality_profiles.deprecated_rules' }),
+  stagnantProfilesRegion: byRole('region', { name: 'quality_profiles.stagnant_profiles' }),
+  recentlyAddedRulesRegion: byRole('region', { name: 'quality_profiles.latest_new_rules' }),
   newRuleLink: byRole('link', { name: 'Recently Added Rule' }),
   seeAllNewRulesLink: byRole('link', { name: 'see_all 20 quality_profiles.latest_new_rules' }),
 };
@@ -115,97 +121,139 @@ it('should list Quality Profiles and filter by language', async () => {
   expect(ui.createButton.get(ui.popup.get())).toBeEnabled();
 });
 
-it('should list recently added rules', async () => {
-  serviceMock.setAdmin();
-  serviceMock.setRulesSearchResponse({
-    rules: [mockRule({ name: 'Recently Added Rule' })],
-    paging: mockPaging({
-      total: 20,
-    }),
+describe('Evolution', () => {
+  it('should list deprecated rules', async () => {
+    serviceMock.setAdmin();
+    renderQualityProfiles();
+
+    expect(await ui.deprecatedRulesRegion.find()).toBeInTheDocument();
+    expect(
+      ui.deprecatedRulesRegion.byRole('link', { name: 'Good old PHP quality profile' }).get()
+    ).toBeInTheDocument();
+    expect(
+      ui.deprecatedRulesRegion.byRole('link', { name: 'java quality profile #2' }).get()
+    ).toBeInTheDocument();
   });
 
-  renderQualityProfiles();
-  expect(await ui.newRuleLink.find()).toBeInTheDocument();
-  expect(ui.seeAllNewRulesLink.get()).toBeInTheDocument();
-});
-
-it('should be able to extend Quality Profile', async () => {
-  // From the list page
-  const user = userEvent.setup();
-  serviceMock.setAdmin();
-  renderQualityProfiles();
-
-  await user.click(await ui.profileActions('c quality profile', 'C').find());
-  await user.click(ui.extendButton.get());
+  it('should list stagnant profiles', async () => {
+    serviceMock.setAdmin();
+    renderQualityProfiles();
 
-  await user.clear(ui.namePropupInput.get());
-  await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
-  await act(async () => {
-    await user.click(ui.extendButton.get());
+    expect(await ui.stagnantProfilesRegion.find()).toBeInTheDocument();
+    expect(
+      ui.stagnantProfilesRegion.byRole('link', { name: 'Good old PHP quality profile' }).get()
+    ).toBeInTheDocument();
   });
-  expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
-
-  // From the create form
-  await user.click(ui.returnToList.get());
-  await user.click(ui.createButton.get());
 
-  await selectEvent.select(ui.languageSelect.get(), 'C');
-  await selectEvent.select(ui.profileExtendSelect.get(), ui.newCQualityProfileName);
-  await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
-  await act(async () => {
-    await user.click(ui.createButton.get(ui.popup.get()));
+  it('should list recently added rules', async () => {
+    serviceMock.setAdmin();
+    serviceMock.setRulesSearchResponse({
+      rules: [mockRule({ name: 'Recently Added Rule' })],
+      paging: mockPaging({
+        total: 20,
+      }),
+    });
+
+    renderQualityProfiles();
+    expect(await ui.recentlyAddedRulesRegion.find()).toBeInTheDocument();
+    expect(ui.newRuleLink.get()).toBeInTheDocument();
+    expect(ui.seeAllNewRulesLink.get()).toBeInTheDocument();
   });
-
-  expect(await ui.listLinkNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
 });
 
-it('should be able to copy Quality Profile', async () => {
-  // From the list page
-  const user = userEvent.setup();
-  serviceMock.setAdmin();
-  renderQualityProfiles();
+describe('Create', () => {
+  it('should be able to extend an existing Quality Profile', async () => {
+    const user = userEvent.setup();
+    serviceMock.setAdmin();
+    renderQualityProfiles();
 
-  await user.click(await ui.profileActions('c quality profile', 'C').find());
-  await user.click(ui.copyButton.get());
-
-  await user.clear(ui.namePropupInput.get());
-  await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
-  await act(async () => {
-    await user.click(ui.copyButton.get(ui.popup.get()));
+    await user.click(await ui.profileActions('c quality profile', 'C').find());
+    await user.click(ui.extendButton.get());
+    await user.clear(ui.namePropupInput.get());
+    await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
+    await act(async () => {
+      await user.click(ui.extendButton.get());
+    });
+
+    expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
+
+    await user.click(ui.returnToList.get());
+    await user.click(ui.createButton.get());
+    await selectEvent.select(ui.languageSelect.get(), 'C');
+    await selectEvent.select(ui.profileExtendSelect.get(), ui.newCQualityProfileName);
+    await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
+    await act(async () => {
+      await user.click(ui.createButton.get(ui.popup.get()));
+    });
+
+    expect(await ui.listLinkNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
   });
-  expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
-
-  // From the create form
-  await user.click(ui.returnToList.get());
-  await user.click(ui.createButton.get());
-
-  await user.click(ui.copyRadio.get());
-  await selectEvent.select(ui.languageSelect.get(), 'C');
-  await selectEvent.select(ui.profileCopySelect.get(), ui.newCQualityProfileName);
-  await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
-  await act(async () => {
-    await user.click(ui.createButton.get(ui.popup.get()));
+
+  it('should be able to copy an existing Quality Profile', async () => {
+    const user = userEvent.setup();
+    serviceMock.setAdmin();
+    renderQualityProfiles();
+
+    await user.click(await ui.profileActions('c quality profile', 'C').find());
+    await user.click(ui.copyButton.get());
+    await user.clear(ui.namePropupInput.get());
+    await user.type(ui.namePropupInput.get(), ui.newCQualityProfileName);
+    await act(async () => {
+      await user.click(ui.copyButton.get(ui.popup.get()));
+    });
+
+    expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
+
+    await user.click(ui.returnToList.get());
+    await user.click(ui.createButton.get());
+    await user.click(ui.copyRadio.get());
+    await selectEvent.select(ui.languageSelect.get(), 'C');
+    await selectEvent.select(ui.profileCopySelect.get(), ui.newCQualityProfileName);
+    await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileNameFromCreateButton);
+    await act(async () => {
+      await user.click(ui.createButton.get(ui.popup.get()));
+    });
+
+    expect(await ui.listLinkNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
   });
 
-  expect(await ui.listLinkNewCQualityProfileFromCreateButton.find()).toBeInTheDocument();
+  it('should be able to create blank Quality Profile', async () => {
+    const user = userEvent.setup();
+    serviceMock.setAdmin();
+    renderQualityProfiles();
+    await user.click(await ui.createButton.find());
+    await user.click(ui.blankRadio.get());
+    await selectEvent.select(ui.languageSelect.get(), 'C');
+    await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileName);
+    await act(async () => {
+      await user.click(ui.createButton.get(ui.popup.get()));
+    });
+
+    expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
+  });
 });
 
-it('should be able to create blank Quality Profile', async () => {
-  // From the list page
+it('should be able to restore a quality profile', async () => {
   const user = userEvent.setup();
   serviceMock.setAdmin();
   renderQualityProfiles();
 
-  await user.click(await ui.createButton.find());
+  await user.click(await ui.restoreButton.find());
+  expect(await ui.restoreProfileDialog.find()).toBeInTheDocument();
 
-  await user.click(ui.blankRadio.get());
-  await selectEvent.select(ui.languageSelect.get(), 'C');
-  await user.type(ui.nameCreatePopupInput.get(), ui.newCQualityProfileName);
-  await act(async () => {
-    await user.click(ui.createButton.get(ui.popup.get()));
+  const profileXMLBackup = new File(['c-sonarsource-06756'], 'c-sonarsource-06756', {
+    type: 'application/xml',
   });
+  const input = screen.getByLabelText<HTMLInputElement>(/backup/);
+  // Very hacky way to upload the file in the test
+  input.removeAttribute('required');
+
+  await userEvent.upload(input, profileXMLBackup);
+  expect(input.files?.item(0)).toStrictEqual(profileXMLBackup);
+
+  await user.click(ui.restoreProfileDialog.byRole('button', { name: 'restore' }).get());
 
-  expect(await ui.listLinkNewCQualityProfile.find()).toBeInTheDocument();
+  expect(await screen.findByText(/quality_profiles.restore_profile.success/)).toBeInTheDocument();
 });
 
 it('should be able to compare profiles', async () => {
index 61b0b3d4ef50603514097167383afcdaaea6aba4..c2e38caeefd48dad0aa005ae2b446c3f7f859876 100644 (file)
@@ -43,7 +43,7 @@ interface State {
   total?: number;
 }
 
-export class ChangelogContainer extends React.PureComponent<Props, State> {
+class ChangelogContainer extends React.PureComponent<Props, State> {
   mounted = false;
   state: State = { loading: true };
 
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx
deleted file mode 100644 (file)
index 2834f8a..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import Link from '../../../../components/common/Link';
-import { ProfileChangelogEvent } from '../../types';
-import Changelog from '../Changelog';
-import ChangesList from '../ChangesList';
-
-function createEvent(overrides?: Partial<ProfileChangelogEvent>): ProfileChangelogEvent {
-  return {
-    date: '2016-01-01',
-    authorName: 'John',
-    action: 'ACTIVATED',
-    ruleKey: 'squid1234',
-    ruleName: 'Do not do this',
-    params: {},
-    ...overrides,
-  };
-}
-
-it('should render events', () => {
-  const events = [createEvent(), createEvent()];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.find('tbody').find('tr').length).toBe(2);
-});
-
-it('should render event date', () => {
-  const events = [createEvent()];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.find('DateTimeFormatter')).toHaveLength(1);
-});
-
-it('should render author', () => {
-  const events = [createEvent()];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.text()).toContain('John');
-});
-
-it('should render system author', () => {
-  const events = [createEvent({ authorName: undefined })];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.text()).toContain('System');
-});
-
-it('should render action', () => {
-  const events = [createEvent()];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.text()).toContain('ACTIVATED');
-});
-
-it('should render rule', () => {
-  const events = [createEvent()];
-  const changelog = shallow(<Changelog events={events} />);
-  expect(changelog.find(Link).prop('to')).toHaveProperty('search', '?rule_key=squid1234');
-});
-
-it('should render ChangesList', () => {
-  const params = { severity: 'BLOCKER' };
-  const events = [createEvent({ params })];
-  const changelog = shallow(<Changelog events={events} />);
-  const changesList = changelog.find(ChangesList);
-  expect(changesList.length).toBe(1);
-  expect(changesList.prop('changes')).toBe(params);
-});
-
-it('should render events sorted by time and action', () => {
-  const events = [
-    createEvent({ date: '2019-02-07T14:03:45', action: 'DEACTIVATED' }),
-    createEvent({ date: '2019-02-07T14:03:14', action: 'DEACTIVATED' }),
-    createEvent({ date: '2019-02-07T14:03:14', action: 'ACTIVATED' }),
-    createEvent({ date: '2019-02-07T14:03:07', action: 'ACTIVATED' }),
-  ];
-  const changelog = shallow(<Changelog events={events} />);
-  const rows = changelog.find('tbody').find('tr');
-
-  const getAction = (index: number) => rows.at(index).childAt(2).childAt(0).text();
-
-  expect(getAction(0)).toBe('quality_profiles.changelog.DEACTIVATED');
-  expect(getAction(1)).toBe('quality_profiles.changelog.ACTIVATED');
-  expect(getAction(2)).toBe('quality_profiles.changelog.DEACTIVATED');
-  expect(getAction(3)).toBe('quality_profiles.changelog.ACTIVATED');
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx
new file mode 100644 (file)
index 0000000..19a0cc1
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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 { screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import QualityProfilesServiceMock from '../../../../api/mocks/QualityProfilesServiceMock';
+import { mockQualityProfileChangelogEvent } from '../../../../helpers/testMocks';
+import { renderAppRoutes } from '../../../../helpers/testReactTestingUtils';
+import { byRole, byText } from '../../../../helpers/testSelector';
+import routes from '../../routes';
+
+jest.mock('../../../../api/quality-profiles');
+
+const serviceMock = new QualityProfilesServiceMock();
+const ui = {
+  row: byRole('row'),
+  link: byRole('link'),
+  emptyPage: byText('no_results'),
+  showMore: byRole('link', { name: 'show_more' }),
+  startDate: byRole('textbox', { name: 'start_date' }),
+  endDate: byRole('textbox', { name: 'end_date' }),
+  reset: byRole('button', { name: 'reset_verb' }),
+};
+
+beforeEach(() => {
+  jest.useFakeTimers({
+    advanceTimers: true,
+    now: new Date('2019-04-25T03:12:32+0100'),
+  });
+});
+
+afterEach(() => {
+  jest.runOnlyPendingTimers();
+  jest.useRealTimers();
+
+  serviceMock.reset();
+});
+
+it('should see the changelog', async () => {
+  const user = userEvent.setup();
+  renderChangeLog();
+
+  const rows = await ui.row.findAll();
+  expect(rows).toHaveLength(6);
+  expect(ui.emptyPage.query()).not.toBeInTheDocument();
+  expect(rows[1]).toHaveTextContent('May 23, 2019');
+  expect(rows[1]).not.toHaveTextContent('quality_profiles.severity');
+  expect(rows[2]).toHaveTextContent('April 23, 2019');
+  expect(rows[2]).toHaveTextContent(
+    'Systemquality_profiles.changelog.DEACTIVATEDRule 0quality_profiles.severity_set_to severity.MAJOR'
+  );
+  expect(rows[3]).not.toHaveTextContent('April 23, 2019');
+  expect(rows[3]).not.toHaveTextContent('Systemquality_profiles.changelog.DEACTIVATED');
+  expect(rows[3]).toHaveTextContent('Rule 1quality_profiles.severity_set_to severity.MAJOR');
+  expect(rows[4]).toHaveTextContent('John Doe');
+  expect(rows[4]).not.toHaveTextContent('System');
+  expect(rows[5]).toHaveTextContent('March 23, 2019');
+  expect(rows[5]).toHaveTextContent('John Doequality_profiles.changelog.ACTIVATEDRule 2');
+  expect(rows[5]).toHaveTextContent(
+    'quality_profiles.severity_set_to severity.CRITICALquality_profiles.parameter_set_to.credentialWords.foo,bar'
+  );
+  await user.click(ui.link.get(rows[1]));
+  expect(screen.getByText('/coding_rules?rule_key=c%3Arule0')).toBeInTheDocument();
+});
+
+it('should filter the changelog', async () => {
+  const user = userEvent.setup();
+  renderChangeLog();
+
+  expect(await ui.row.findAll()).toHaveLength(6);
+  await user.click(ui.startDate.get());
+  await user.click(screen.getByRole('gridcell', { name: '20' }));
+  await user.click(document.body);
+  expect(await ui.row.findAll()).toHaveLength(5);
+  await user.click(ui.endDate.get());
+  await user.click(screen.getByRole('gridcell', { name: '25' }));
+  await user.click(document.body);
+  expect(await ui.row.findAll()).toHaveLength(4);
+  await user.click(ui.reset.get());
+  expect(await ui.row.findAll()).toHaveLength(6);
+});
+
+it('should load more', async () => {
+  const user = userEvent.setup();
+  serviceMock.changelogEvents = new Array(100).fill(null).map((_, i) =>
+    mockQualityProfileChangelogEvent({
+      ruleKey: `c:rule${i}`,
+      ruleName: `Rule ${i}`,
+    })
+  );
+  renderChangeLog();
+
+  expect(await ui.row.findAll()).toHaveLength(51);
+  expect(ui.showMore.get()).toBeInTheDocument();
+  await user.click(ui.showMore.get());
+  expect(await ui.row.findAll()).toHaveLength(101);
+  await user.click(ui.reset.get());
+  expect(await ui.row.findAll()).toHaveLength(51);
+});
+
+it('should see short changelog for php', async () => {
+  renderChangeLog('php', 'Good old PHP quality profile');
+
+  const rows = await ui.row.findAll();
+  expect(rows).toHaveLength(2);
+  expect(rows[1]).toHaveTextContent('May 23, 2019');
+  expect(rows[1]).toHaveTextContent(
+    'Systemquality_profiles.changelog.DEACTIVATEDPHP Rulequality_profiles.severity_set_to severity.MAJOR'
+  );
+  expect(ui.showMore.query()).not.toBeInTheDocument();
+});
+
+it('should show empty list for java', async () => {
+  renderChangeLog('java', 'java quality profile');
+
+  expect(await ui.emptyPage.find()).toBeInTheDocument();
+  expect(ui.row.query()).not.toBeInTheDocument();
+  expect(ui.showMore.query()).not.toBeInTheDocument();
+});
+
+function renderChangeLog(language = 'c', name = 'c quality profile') {
+  renderAppRoutes(`profiles/changelog?name=${name}&language=${language}`, routes, {});
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-test.tsx
deleted file mode 100644 (file)
index 2e94f5d..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { getProfileChangelog } from '../../../../api/quality-profiles';
-import {
-  mockLocation,
-  mockPaging,
-  mockQualityProfile,
-  mockRouter,
-} from '../../../../helpers/testMocks';
-import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils';
-import { ChangelogContainer } from '../ChangelogContainer';
-
-beforeEach(() => jest.clearAllMocks());
-
-jest.mock('../../../../api/quality-profiles', () => {
-  const { mockQualityProfileChangelogEvent, mockPaging } = jest.requireActual(
-    '../../../../helpers/testMocks'
-  );
-  return {
-    getProfileChangelog: jest.fn().mockResolvedValue({
-      events: [
-        mockQualityProfileChangelogEvent(),
-        mockQualityProfileChangelogEvent(),
-        mockQualityProfileChangelogEvent(),
-      ],
-      paging: mockPaging({
-        total: 6,
-        pageIndex: 1,
-      }),
-    }),
-  };
-});
-
-it('should render correctly without events', async () => {
-  (getProfileChangelog as jest.Mock).mockResolvedValueOnce({
-    events: [],
-    paging: mockPaging({ total: 0 }),
-  });
-  const wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should render correctly', async () => {
-  const wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should load more properly', async () => {
-  const wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-
-  wrapper.instance().loadMore(mockEvent());
-  await waitAndUpdate(wrapper);
-
-  expect(getProfileChangelog).toHaveBeenLastCalledWith(undefined, undefined, expect.anything(), 2);
-  expect(wrapper.state().events?.length).toBe(6);
-});
-
-function shallowRender() {
-  return shallow<ChangelogContainer>(
-    <ChangelogContainer
-      location={mockLocation()}
-      profile={mockQualityProfile()}
-      router={mockRouter()}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx
deleted file mode 100644 (file)
index 94ce4da..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { parseDate } from '../../../../helpers/dates';
-import { click } from '../../../../helpers/testUtils';
-import ChangelogSearch from '../ChangelogSearch';
-
-it('should render', () => {
-  const output = shallow(
-    <ChangelogSearch
-      dateRange={{
-        from: parseDate('2016-01-01T00:00:00.000Z'),
-        to: parseDate('2016-05-05T00:00:00.000Z'),
-      }}
-      onDateRangeChange={jest.fn()}
-      onReset={jest.fn()}
-    />
-  );
-  expect(output).toMatchSnapshot();
-});
-
-it('should reset', () => {
-  const onReset = jest.fn();
-  const output = shallow(
-    <ChangelogSearch
-      dateRange={{
-        from: parseDate('2016-01-01T00:00:00.000Z'),
-        to: parseDate('2016-05-05T00:00:00.000Z'),
-      }}
-      onDateRangeChange={jest.fn()}
-      onReset={onReset}
-    />
-  );
-  expect(onReset).not.toHaveBeenCalled();
-  click(output.find('Button'));
-  expect(onReset).toHaveBeenCalled();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.tsx
deleted file mode 100644 (file)
index b50236c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ChangesList from '../ChangesList';
-import ParameterChange from '../ParameterChange';
-import SeverityChange from '../SeverityChange';
-
-it('should render changes', () => {
-  const changes = { severity: 'BLOCKER', foo: 'bar' };
-  const output = shallow(<ChangesList changes={changes} />);
-  expect(output.find('li').length).toBe(2);
-});
-
-it('should render severity change', () => {
-  const changes = { severity: 'BLOCKER' };
-  const output = shallow(<ChangesList changes={changes} />).find(SeverityChange);
-  expect(output.length).toBe(1);
-  expect(output.prop('severity')).toBe('BLOCKER');
-});
-
-it('should render parameter change', () => {
-  const changes = { foo: 'bar' };
-  const output = shallow(<ChangesList changes={changes} />).find(ParameterChange);
-  expect(output.length).toBe(1);
-  expect(output.prop('name')).toBe('foo');
-  expect(output.prop('value')).toBe('bar');
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.tsx
deleted file mode 100644 (file)
index e2f6587..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ParameterChange from '../ParameterChange';
-
-it('should render different messages', () => {
-  const first = shallow(<ParameterChange name="foo" value={null} />);
-  const second = shallow(<ParameterChange name="foo" value="bar" />);
-  expect(first.text()).not.toBe(second.text());
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.tsx
deleted file mode 100644 (file)
index 68a932c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import SeverityHelper from '../../../../components/shared/SeverityHelper';
-import SeverityChange from '../SeverityChange';
-
-it('should render SeverityHelper', () => {
-  const output = shallow(<SeverityChange severity="BLOCKER" />).find(SeverityHelper);
-  expect(output.length).toBe(1);
-  expect(output.prop('severity')).toBe('BLOCKER');
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogContainer-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogContainer-test.tsx.snap
deleted file mode 100644 (file)
index b9549ee..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="boxed-group boxed-group-inner js-profile-changelog"
->
-  <div
-    className="spacer-bottom"
-  >
-    <ChangelogSearch
-      dateRange={
-        {
-          "from": undefined,
-          "to": undefined,
-        }
-      }
-      onDateRangeChange={[Function]}
-      onReset={[Function]}
-    />
-    <DeferredSpinner
-      className="spacer-left"
-      loading={false}
-    />
-  </div>
-  <Changelog
-    events={
-      [
-        {
-          "action": "ACTIVATED",
-          "date": "2019-04-23T02:12:32+0100",
-          "params": {
-            "severity": "MAJOR",
-          },
-          "ruleKey": "rule-key",
-          "ruleName": "rule-name",
-        },
-        {
-          "action": "ACTIVATED",
-          "date": "2019-04-23T02:12:32+0100",
-          "params": {
-            "severity": "MAJOR",
-          },
-          "ruleKey": "rule-key",
-          "ruleName": "rule-name",
-        },
-        {
-          "action": "ACTIVATED",
-          "date": "2019-04-23T02:12:32+0100",
-          "params": {
-            "severity": "MAJOR",
-          },
-          "ruleKey": "rule-key",
-          "ruleName": "rule-name",
-        },
-      ]
-    }
-  />
-  <footer
-    className="text-center spacer-top small"
-  >
-    <a
-      href="#"
-      onClick={[Function]}
-    >
-      show_more
-    </a>
-  </footer>
-</div>
-`;
-
-exports[`should render correctly without events 1`] = `
-<div
-  className="boxed-group boxed-group-inner js-profile-changelog"
->
-  <div
-    className="spacer-bottom"
-  >
-    <ChangelogSearch
-      dateRange={
-        {
-          "from": undefined,
-          "to": undefined,
-        }
-      }
-      onDateRangeChange={[Function]}
-      onReset={[Function]}
-    />
-    <DeferredSpinner
-      className="spacer-left"
-      loading={false}
-    />
-  </div>
-  <ChangelogEmpty />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap
deleted file mode 100644 (file)
index 7783308..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
-  className="display-flex-end"
-  id="quality-profile-changelog-form"
->
-  <DateRangeInput
-    onChange={[MockFunction]}
-    value={
-      {
-        "from": 2016-01-01T00:00:00.000Z,
-        "to": 2016-05-05T00:00:00.000Z,
-      }
-    }
-  />
-  <Button
-    className="spacer-left text-top"
-    onClick={[MockFunction]}
-  >
-    reset_verb
-  </Button>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.tsx
deleted file mode 100644 (file)
index e36f1cc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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 * as React from 'react';
-import { translate } from '../../../helpers/l10n';
-
-export default function ComparisonEmpty() {
-  return <div className="big-spacer-top">{translate('quality_profile.empty_comparison')}</div>;
-}
index dde41ffd05f08b17eedb51cdb963effe4a72248c..9b3c925f815389edd84845751a3f5405dfb18f15 100644 (file)
@@ -27,7 +27,6 @@ import SeverityIcon from '../../../components/icons/SeverityIcon';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getRulesUrl } from '../../../helpers/urls';
 import { Dict } from '../../../types/types';
-import ComparisonEmpty from './ComparisonEmpty';
 import ComparisonResultActivation from './ComparisonResultActivation';
 
 type Params = Dict<string>;
@@ -201,7 +200,7 @@ export default class ComparisonResults extends React.PureComponent<Props> {
 
   render() {
     if (!this.props.inLeft.length && !this.props.inRight.length && !this.props.modified.length) {
-      return <ComparisonEmpty />;
+      return <div className="big-spacer-top">{translate('quality_profile.empty_comparison')}</div>;
     }
 
     return (
index e27eceb397ee95118ac368f47cd58cebe769e771..c57b616297772ae3ac8aada900de04e3f35bfbc7 100644 (file)
@@ -25,7 +25,6 @@ import {
   copyProfile,
   createQualityProfile,
   deleteProfile,
-  getQualityProfileBackupUrl,
   renameProfile,
   setDefaultProfile,
 } from '../../../api/quality-profiles';
@@ -57,7 +56,7 @@ interface State {
   openModal?: ProfileActionModals;
 }
 
-export class ProfileActions extends React.PureComponent<Props, State> {
+class ProfileActions extends React.PureComponent<Props, State> {
   mounted = false;
   state: State = {
     loading: false,
@@ -178,12 +177,19 @@ export class ProfileActions extends React.PureComponent<Props, State> {
     }
   };
 
+  getQualityProfileBackupUrl = ({ language, name: qualityProfile }: Profile) => {
+    const queryParams = Object.entries({ language, qualityProfile })
+      .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
+      .join('&');
+    return `/api/qualityprofiles/backup?${queryParams}`;
+  };
+
   render() {
     const { profile, isComparable } = this.props;
     const { loading, openModal } = this.state;
     const { actions = {} } = profile;
 
-    const backupUrl = `${getBaseUrl()}${getQualityProfileBackupUrl(profile)}`;
+    const backupUrl = `${getBaseUrl()}${this.getQualityProfileBackupUrl(profile)}`;
 
     const activateMoreUrl = getRulesUrl({
       qprofile: profile.key,
index 91ca77c9a258e0fbd5527e7be39a3a13d9a828de..b00ece4ea3f507149fef0f50f5afbc9d7a81b7c7 100644 (file)
@@ -18,8 +18,8 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import Modal from '../../../components/controls/Modal';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
 import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/BuiltInQualityProfileBadge-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/BuiltInQualityProfileBadge-test.tsx
deleted file mode 100644 (file)
index 99d2092..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import BuiltInQualityProfileBadge from '../BuiltInQualityProfileBadge';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(shallowRender({ tooltip: false })).toMatchSnapshot();
-});
-
-function shallowRender(props = {}) {
-  return shallow(<BuiltInQualityProfileBadge {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/DeleteProfileForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/DeleteProfileForm-test.tsx
deleted file mode 100644 (file)
index ca7ccc5..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile } from '../../../../helpers/testMocks';
-import { mockEvent } from '../../../../helpers/testUtils';
-import DeleteProfileForm, { DeleteProfileFormProps } from '../DeleteProfileForm';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('default');
-  expect(shallowRender({ loading: true })).toMatchSnapshot('loading');
-  expect(shallowRender({ profile: mockQualityProfile({ childrenCount: 2 }) })).toMatchSnapshot(
-    'profile has children'
-  );
-});
-
-it('should correctly submit the form', () => {
-  const onDelete = jest.fn();
-  const wrapper = shallowRender({ onDelete });
-
-  const formOnSubmit = wrapper.find('form').props().onSubmit;
-  if (formOnSubmit) {
-    formOnSubmit(mockEvent());
-  }
-  expect(onDelete).toHaveBeenCalled();
-});
-
-function shallowRender(props: Partial<DeleteProfileFormProps> = {}) {
-  return shallow<DeleteProfileFormProps>(
-    <DeleteProfileForm
-      loading={false}
-      onClose={jest.fn()}
-      onDelete={jest.fn()}
-      profile={mockQualityProfile()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx
deleted file mode 100644 (file)
index 4a59664..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
-  changeProfileParent,
-  copyProfile,
-  createQualityProfile,
-  deleteProfile,
-  renameProfile,
-  setDefaultProfile,
-} from '../../../../api/quality-profiles';
-import { mockQualityProfile, mockRouter } from '../../../../helpers/testMocks';
-import { click, waitAndUpdate } from '../../../../helpers/testUtils';
-import { queryToSearch } from '../../../../helpers/urls';
-import { PROFILE_PATH } from '../../constants';
-import { ProfileActionModals } from '../../types';
-import DeleteProfileForm from '../DeleteProfileForm';
-import { ProfileActions } from '../ProfileActions';
-import ProfileModalForm from '../ProfileModalForm';
-
-jest.mock('../../../../api/quality-profiles', () => {
-  const { mockQualityProfile } = jest.requireActual('../../../../helpers/testMocks');
-
-  return {
-    ...jest.requireActual('../../../../api/quality-profiles'),
-    copyProfile: jest.fn().mockResolvedValue(null),
-    changeProfileParent: jest.fn().mockResolvedValue(null),
-    createQualityProfile: jest
-      .fn()
-      .mockResolvedValue({ profile: mockQualityProfile({ key: 'newProfile' }) }),
-    deleteProfile: jest.fn().mockResolvedValue(null),
-    setDefaultProfile: jest.fn().mockResolvedValue(null),
-    renameProfile: jest.fn().mockResolvedValue(null),
-  };
-});
-
-const PROFILE = mockQualityProfile({
-  activeRuleCount: 68,
-  activeDeprecatedRuleCount: 0,
-  depth: 0,
-  language: 'js',
-  rulesUpdatedAt: '2017-06-28T12:58:44+0000',
-});
-
-beforeEach(() => jest.clearAllMocks());
-
-it('renders correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('no permissions');
-  expect(shallowRender({ profile: { ...PROFILE, actions: { edit: true } } })).toMatchSnapshot(
-    'edit only'
-  );
-  expect(
-    shallowRender({
-      profile: {
-        ...PROFILE,
-        actions: {
-          copy: true,
-          edit: true,
-          delete: true,
-          setAsDefault: true,
-          associateProjects: true,
-        },
-      },
-    })
-  ).toMatchSnapshot('all permissions');
-
-  expect(shallowRender().setState({ openModal: ProfileActionModals.Copy })).toMatchSnapshot(
-    'copy modal'
-  );
-  expect(shallowRender().setState({ openModal: ProfileActionModals.Extend })).toMatchSnapshot(
-    'extend modal'
-  );
-  expect(shallowRender().setState({ openModal: ProfileActionModals.Rename })).toMatchSnapshot(
-    'rename modal'
-  );
-  expect(shallowRender().setState({ openModal: ProfileActionModals.Delete })).toMatchSnapshot(
-    'delete modal'
-  );
-});
-
-describe('copy a profile', () => {
-  it('should correctly copy a profile', async () => {
-    const name = 'new-name';
-    const updateProfiles = jest.fn().mockResolvedValue(null);
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { copy: true } },
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-
-    click(wrapper.find('.it__quality-profiles__copy'));
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(true);
-
-    wrapper.find(ProfileModalForm).props().onSubmit(name);
-    expect(copyProfile).toHaveBeenCalledWith(PROFILE.key, name);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).toHaveBeenCalled();
-    expect(push).toHaveBeenCalledWith({
-      pathname: '/profiles/show',
-      search: queryToSearch({ name, language: 'js' }),
-    });
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(false);
-  });
-
-  it('should correctly keep the modal open in case of an error', async () => {
-    (copyProfile as jest.Mock).mockRejectedValueOnce(null);
-
-    const name = 'new-name';
-    const updateProfiles = jest.fn();
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { copy: true } },
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-    wrapper.setState({ openModal: ProfileActionModals.Copy });
-
-    wrapper.instance().handleProfileCopy(name);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).not.toHaveBeenCalled();
-    await waitAndUpdate(wrapper);
-
-    expect(push).not.toHaveBeenCalled();
-    expect(wrapper.state().openModal).toBe(ProfileActionModals.Copy);
-  });
-});
-
-describe('extend a profile', () => {
-  it('should correctly extend a profile', async () => {
-    const name = 'new-name';
-    const profile = { ...PROFILE, actions: { copy: true } };
-    const updateProfiles = jest.fn().mockResolvedValue(null);
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile,
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-
-    click(wrapper.find('.it__quality-profiles__extend'));
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(true);
-
-    wrapper.find(ProfileModalForm).props().onSubmit(name);
-    expect(createQualityProfile).toHaveBeenCalledWith({ language: profile.language, name });
-    await waitAndUpdate(wrapper);
-    expect(changeProfileParent).toHaveBeenCalledWith(
-      expect.objectContaining({
-        key: 'newProfile',
-      }),
-      profile
-    );
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).toHaveBeenCalled();
-    await waitAndUpdate(wrapper);
-
-    expect(push).toHaveBeenCalledWith({
-      pathname: '/profiles/show',
-      search: queryToSearch({ name, language: 'js' }),
-    });
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(false);
-  });
-
-  it('should correctly keep the modal open in case of an error', async () => {
-    (createQualityProfile as jest.Mock).mockRejectedValueOnce(null);
-
-    const name = 'new-name';
-    const updateProfiles = jest.fn();
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { copy: true } },
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-    wrapper.setState({ openModal: ProfileActionModals.Extend });
-
-    wrapper.instance().handleProfileExtend(name);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).not.toHaveBeenCalled();
-    expect(changeProfileParent).not.toHaveBeenCalled();
-    expect(push).not.toHaveBeenCalled();
-    expect(wrapper.state().openModal).toBe(ProfileActionModals.Extend);
-  });
-});
-
-describe('rename a profile', () => {
-  it('should correctly rename a profile', async () => {
-    const name = 'new-name';
-    const updateProfiles = jest.fn().mockResolvedValue(null);
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { edit: true } },
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-
-    click(wrapper.find('.it__quality-profiles__rename'));
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(true);
-
-    wrapper.find(ProfileModalForm).props().onSubmit(name);
-    expect(renameProfile).toHaveBeenCalledWith(PROFILE.key, name);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).toHaveBeenCalled();
-    expect(push).toHaveBeenCalledWith({
-      pathname: '/profiles/show',
-      search: queryToSearch({ name, language: 'js' }),
-    });
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(false);
-  });
-
-  it('should correctly keep the modal open in case of an error', async () => {
-    (renameProfile as jest.Mock).mockRejectedValueOnce(null);
-
-    const name = 'new-name';
-    const updateProfiles = jest.fn();
-    const push = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { copy: true } },
-      router: mockRouter({ push }),
-      updateProfiles,
-    });
-    wrapper.setState({ openModal: ProfileActionModals.Rename });
-
-    wrapper.instance().handleProfileRename(name);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).not.toHaveBeenCalled();
-    await waitAndUpdate(wrapper);
-
-    expect(push).not.toHaveBeenCalled();
-    expect(wrapper.state().openModal).toBe(ProfileActionModals.Rename);
-  });
-});
-
-describe('delete a profile', () => {
-  it('should correctly delete a profile', async () => {
-    const updateProfiles = jest.fn().mockResolvedValue(null);
-    const replace = jest.fn();
-    const profile = { ...PROFILE, actions: { delete: true } };
-    const wrapper = shallowRender({
-      profile,
-      router: mockRouter({ replace }),
-      updateProfiles,
-    });
-
-    click(wrapper.find('.it__quality-profiles__delete'));
-    expect(wrapper.find(DeleteProfileForm).exists()).toBe(true);
-
-    wrapper.find(DeleteProfileForm).props().onDelete();
-    expect(deleteProfile).toHaveBeenCalledWith(profile);
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).toHaveBeenCalled();
-    expect(replace).toHaveBeenCalledWith(PROFILE_PATH);
-    expect(wrapper.find(ProfileModalForm).exists()).toBe(false);
-  });
-
-  it('should correctly keep the modal open in case of an error', async () => {
-    (deleteProfile as jest.Mock).mockRejectedValueOnce(null);
-
-    const updateProfiles = jest.fn();
-    const replace = jest.fn();
-    const wrapper = shallowRender({
-      profile: { ...PROFILE, actions: { copy: true } },
-      router: mockRouter({ replace }),
-      updateProfiles,
-    });
-    wrapper.setState({ openModal: ProfileActionModals.Delete });
-
-    wrapper.instance().handleProfileDelete();
-    await waitAndUpdate(wrapper);
-
-    expect(updateProfiles).not.toHaveBeenCalled();
-    await waitAndUpdate(wrapper);
-
-    expect(replace).not.toHaveBeenCalled();
-    expect(wrapper.state().openModal).toBe(ProfileActionModals.Delete);
-  });
-});
-
-it('should correctly set a profile as the default', async () => {
-  const updateProfiles = jest.fn();
-
-  const wrapper = shallowRender({ updateProfiles });
-  wrapper.instance().handleSetDefaultClick();
-  await waitAndUpdate(wrapper);
-
-  expect(setDefaultProfile).toHaveBeenCalledWith(PROFILE);
-  expect(updateProfiles).toHaveBeenCalled();
-});
-
-it('should not allow to set a profile as the default if the profile has no active rules', async () => {
-  const profile = mockQualityProfile({
-    activeRuleCount: 0,
-    actions: {
-      setAsDefault: true,
-    },
-  });
-
-  const wrapper = shallowRender({ profile });
-  wrapper.instance().handleSetDefaultClick();
-  await waitAndUpdate(wrapper);
-
-  expect(setDefaultProfile).not.toHaveBeenCalled();
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ProfileActions['props']> = {}) {
-  const router = mockRouter();
-  return shallow<ProfileActions>(
-    <ProfileActions
-      isComparable
-      profile={PROFILE}
-      router={router}
-      updateProfiles={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/QualityProfilesApp-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/QualityProfilesApp-test.tsx
deleted file mode 100644 (file)
index 616750f..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { Actions, getExporters, searchQualityProfiles } from '../../../../api/quality-profiles';
-import {
-  mockLanguage,
-  mockQualityProfile,
-  mockQualityProfileExporter,
-} from '../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import { QualityProfilesApp } from '../QualityProfilesApp';
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  getExporters: jest.fn().mockResolvedValue([]),
-  searchQualityProfiles: jest.fn().mockResolvedValue({ profiles: [] }),
-}));
-
-it('should render correctly', async () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot('loading');
-
-  expect(getExporters).toHaveBeenCalled();
-  expect(searchQualityProfiles).toHaveBeenCalled();
-
-  await waitAndUpdate(wrapper);
-  expect(wrapper).toMatchSnapshot('full');
-});
-
-it('should render child with additional props', () => {
-  const language = mockLanguage();
-  const wrapper = shallowRender({ languages: { [language.key]: language } });
-
-  const actions: Actions = { create: true };
-  const profiles = [mockQualityProfile()];
-  const exporters = [mockQualityProfileExporter()];
-
-  wrapper.setState({ loading: false, actions, profiles, exporters });
-
-  expect(wrapper.childAt(2).props()).toEqual({
-    context: {
-      actions,
-      profiles,
-      languages: [language],
-      exporters,
-      updateProfiles: wrapper.instance().updateProfiles,
-    },
-  });
-});
-
-it('should handle update', async () => {
-  const profile1 = mockQualityProfile({ key: 'qp1', name: 'An amazing profile' });
-  const profile2 = mockQualityProfile({ key: 'qp2', name: 'Quality Profile' });
-
-  // Mock one call for the initial load, one for the update
-  (searchQualityProfiles as jest.Mock)
-    .mockResolvedValueOnce({ profiles: [] })
-    .mockResolvedValueOnce({ profiles: [profile2, profile1] });
-
-  const wrapper = shallowRender();
-
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().profiles).toHaveLength(0);
-
-  wrapper.instance().updateProfiles();
-
-  await waitAndUpdate(wrapper);
-  expect(wrapper.state().profiles).toEqual([profile1, profile2]);
-});
-
-function shallowRender(props: Partial<QualityProfilesApp['props']> = {}) {
-  return shallow<QualityProfilesApp>(
-    <QualityProfilesApp languages={{}} {...props}>
-      <div />
-    </QualityProfilesApp>
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/BuiltInQualityProfileBadge-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/BuiltInQualityProfileBadge-test.tsx.snap
deleted file mode 100644 (file)
index 823cfba..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Tooltip
-  overlay="quality_profiles.built_in.description"
->
-  <div
-    className="badge badge-info"
-  >
-    quality_profiles.built_in
-  </div>
-</Tooltip>
-`;
-
-exports[`should render correctly 2`] = `
-<div
-  className="badge badge-info"
->
-  quality_profiles.built_in
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/DeleteProfileForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/DeleteProfileForm-test.tsx.snap
deleted file mode 100644 (file)
index d24c011..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<Modal
-  contentLabel="quality_profiles.delete_confirm_title"
-  onRequestClose={[MockFunction]}
->
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-head"
-    >
-      <h2>
-        quality_profiles.delete_confirm_title
-      </h2>
-    </div>
-    <div
-      className="modal-body"
-    >
-      <p>
-        quality_profiles.are_you_sure_want_delete_profile_x.name.JavaScript
-      </p>
-    </div>
-    <div
-      className="modal-foot"
-    >
-      <SubmitButton
-        className="button-red"
-        disabled={false}
-      >
-        delete
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </div>
-  </form>
-</Modal>
-`;
-
-exports[`should render correctly: loading 1`] = `
-<Modal
-  contentLabel="quality_profiles.delete_confirm_title"
-  onRequestClose={[MockFunction]}
->
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-head"
-    >
-      <h2>
-        quality_profiles.delete_confirm_title
-      </h2>
-    </div>
-    <div
-      className="modal-body"
-    >
-      <p>
-        quality_profiles.are_you_sure_want_delete_profile_x.name.JavaScript
-      </p>
-    </div>
-    <div
-      className="modal-foot"
-    >
-      <i
-        className="spinner spacer-right"
-      />
-      <SubmitButton
-        className="button-red"
-        disabled={true}
-      >
-        delete
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </div>
-  </form>
-</Modal>
-`;
-
-exports[`should render correctly: profile has children 1`] = `
-<Modal
-  contentLabel="quality_profiles.delete_confirm_title"
-  onRequestClose={[MockFunction]}
->
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-head"
-    >
-      <h2>
-        quality_profiles.delete_confirm_title
-      </h2>
-    </div>
-    <div
-      className="modal-body"
-    >
-      <div>
-        <Alert
-          variant="warning"
-        >
-          quality_profiles.this_profile_has_descendants
-        </Alert>
-        <p>
-          quality_profiles.are_you_sure_want_delete_profile_x_and_descendants.name.JavaScript
-        </p>
-      </div>
-    </div>
-    <div
-      className="modal-foot"
-    >
-      <SubmitButton
-        className="button-red"
-        disabled={false}
-      >
-        delete
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </div>
-  </form>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/ProfileActions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/ProfileActions-test.tsx.snap
deleted file mode 100644 (file)
index 2b7d547..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly: all permissions 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__activate-more-rules"
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=key&activation=false",
-        }
-      }
-    >
-      quality_profiles.activate_more_rules
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__extend"
-      onClick={[Function]}
-      tooltipOverlay="quality_profiles.extend_help.name"
-      tooltipPlacement="left"
-    >
-      extend
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__copy"
-      onClick={[Function]}
-      tooltipOverlay="quality_profiles.copy_help.name"
-      tooltipPlacement="left"
-    >
-      copy
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__rename"
-      onClick={[Function]}
-    >
-      rename
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__set-as-default"
-      onClick={[Function]}
-    >
-      set_as_default
-    </ActionsDropdownItem>
-    <ActionsDropdownDivider />
-    <ActionsDropdownItem
-      className="it__quality-profiles__delete"
-      destructive={true}
-      onClick={[Function]}
-    >
-      delete
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-</Fragment>
-`;
-
-exports[`renders correctly: copy modal 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-  <ProfileModalForm
-    action="COPY"
-    loading={false}
-    onClose={[Function]}
-    onSubmit={[Function]}
-    profile={
-      {
-        "activeDeprecatedRuleCount": 0,
-        "activeRuleCount": 68,
-        "childrenCount": 0,
-        "depth": 0,
-        "isBuiltIn": false,
-        "isDefault": false,
-        "isInherited": false,
-        "key": "key",
-        "language": "js",
-        "languageName": "JavaScript",
-        "name": "name",
-        "projectCount": 3,
-        "rulesUpdatedAt": "2017-06-28T12:58:44+0000",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`renders correctly: delete modal 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-  <DeleteProfileForm
-    loading={false}
-    onClose={[Function]}
-    onDelete={[Function]}
-    profile={
-      {
-        "activeDeprecatedRuleCount": 0,
-        "activeRuleCount": 68,
-        "childrenCount": 0,
-        "depth": 0,
-        "isBuiltIn": false,
-        "isDefault": false,
-        "isInherited": false,
-        "key": "key",
-        "language": "js",
-        "languageName": "JavaScript",
-        "name": "name",
-        "projectCount": 3,
-        "rulesUpdatedAt": "2017-06-28T12:58:44+0000",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`renders correctly: edit only 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__activate-more-rules"
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=key&activation=false",
-        }
-      }
-    >
-      quality_profiles.activate_more_rules
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__rename"
-      onClick={[Function]}
-    >
-      rename
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-</Fragment>
-`;
-
-exports[`renders correctly: extend modal 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-  <ProfileModalForm
-    action="EXTEND"
-    loading={false}
-    onClose={[Function]}
-    onSubmit={[Function]}
-    profile={
-      {
-        "activeDeprecatedRuleCount": 0,
-        "activeRuleCount": 68,
-        "childrenCount": 0,
-        "depth": 0,
-        "isBuiltIn": false,
-        "isDefault": false,
-        "isInherited": false,
-        "key": "key",
-        "language": "js",
-        "languageName": "JavaScript",
-        "name": "name",
-        "projectCount": 3,
-        "rulesUpdatedAt": "2017-06-28T12:58:44+0000",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`renders correctly: no permissions 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-</Fragment>
-`;
-
-exports[`renders correctly: rename modal 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-  </ActionsDropdown>
-  <ProfileModalForm
-    action="RENAME"
-    loading={false}
-    onClose={[Function]}
-    onSubmit={[Function]}
-    profile={
-      {
-        "activeDeprecatedRuleCount": 0,
-        "activeRuleCount": 68,
-        "childrenCount": 0,
-        "depth": 0,
-        "isBuiltIn": false,
-        "isDefault": false,
-        "isInherited": false,
-        "key": "key",
-        "language": "js",
-        "languageName": "JavaScript",
-        "name": "name",
-        "projectCount": 3,
-        "rulesUpdatedAt": "2017-06-28T12:58:44+0000",
-      }
-    }
-  />
-</Fragment>
-`;
-
-exports[`should not allow to set a profile as the default if the profile has no active rules 1`] = `
-<Fragment>
-  <ActionsDropdown
-    disabled={false}
-    label="quality_profiles.actions.name.JavaScript"
-  >
-    <ActionsDropdownItem
-      className="it__quality-profiles__backup"
-      download="key.xml"
-      to="/api/qualityprofiles/backup?language=js&qualityProfile=name"
-    >
-      backup_verb
-    </ActionsDropdownItem>
-    <ActionsDropdownItem
-      className="it__quality-profiles__compare"
-      to={
-        {
-          "pathname": "/profiles/compare",
-          "search": "?language=js&name=name",
-        }
-      }
-    >
-      compare
-    </ActionsDropdownItem>
-    <li>
-      <Tooltip
-        overlay="quality_profiles.cannot_set_default_no_rules"
-        placement="left"
-      >
-        <span
-          className="it__quality-profiles__set-as-default text-muted-2"
-        >
-          set_as_default
-        </span>
-      </Tooltip>
-    </li>
-  </ActionsDropdown>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/QualityProfilesApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/QualityProfilesApp-test.tsx.snap
deleted file mode 100644 (file)
index 791f5c3..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: full 1`] = `
-<div
-  className="page page-limited"
->
-  <Suggestions
-    suggestions="quality_profiles"
-  />
-  <Helmet
-    defer={false}
-    encodeSpecialCharacters={true}
-    prioritizeSeoTags={false}
-    title="quality_profiles.page"
-  />
-  <Outlet
-    context={
-      {
-        "actions": {},
-        "exporters": [],
-        "languages": [],
-        "profiles": [],
-        "updateProfiles": [Function],
-      }
-    }
-  />
-</div>
-`;
-
-exports[`should render correctly: loading 1`] = `
-<div
-  className="page page-limited"
->
-  <Suggestions
-    suggestions="quality_profiles"
-  />
-  <Helmet
-    defer={false}
-    encodeSpecialCharacters={true}
-    prioritizeSeoTags={false}
-    title="quality_profiles.page"
-  />
-  <i
-    className="spinner"
-  />
-</div>
-`;
index 632dc2336bf5d7c5b71b7cdabf10c508f9e00023..c6a5e7ef2402b9604f40242eaab566b7c13250b1 100644 (file)
  */
 import { sortBy } from 'lodash';
 import * as React from 'react';
-import Select from '../../../components/controls/Select';
 import { changeProfileParent } from '../../../api/quality-profiles';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import Modal from '../../../components/controls/Modal';
+import Select from '../../../components/controls/Select';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
 import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
 import { translate } from '../../../helpers/l10n';
index 17361d3555350fdeb74753e372bef809f3019c72..29032b3b21538415765c9de261889bf83c576467 100644 (file)
@@ -28,24 +28,23 @@ import ProfilePermissions from './ProfilePermissions';
 import ProfileProjects from './ProfileProjects';
 import ProfileRules from './ProfileRules';
 
-export interface ProfileDetailsProps {
+interface ProfileDetailsProps {
   exporters: Exporter[];
   profile: Profile;
   profiles: Profile[];
   updateProfiles: () => Promise<void>;
 }
 
-export function ProfileDetails(props: ProfileDetailsProps) {
-  const { profile } = props;
+function ProfileDetails(props: ProfileDetailsProps) {
+  const { profile, profiles, exporters } = props;
+
   return (
     <div>
       <div className="quality-profile-grid">
         <div className="quality-profile-grid-left">
           <ProfileRules profile={profile} />
-          <ProfileExporters exporters={props.exporters} profile={profile} />
-          {profile.actions && profile.actions.edit && !profile.isBuiltIn && (
-            <ProfilePermissions profile={profile} />
-          )}
+          <ProfileExporters exporters={exporters} profile={profile} />
+          {profile.actions?.edit && !profile.isBuiltIn && <ProfilePermissions profile={profile} />}
         </div>
         <div className="quality-profile-grid-right">
           {profile.activeRuleCount === 0 && (profile.projectCount || profile.isDefault) && (
@@ -61,7 +60,7 @@ export function ProfileDetails(props: ProfileDetailsProps) {
 
           <ProfileInheritance
             profile={profile}
-            profiles={props.profiles}
+            profiles={profiles}
             updateProfiles={props.updateProfiles}
           />
           <ProfileProjects profile={profile} />
index a8569f1c1cd24f3cf3ba4f06e8d9f4e68a8377ec..baf9b2c1f66fad4e65ebfb386df570370ca6f5fd 100644 (file)
@@ -37,7 +37,10 @@ export default function ProfileExporters({ exporters, profile }: Props) {
   }
 
   return (
-    <div className="boxed-group quality-profile-exporters">
+    <section
+      aria-label={translate('quality_profiles.exporters')}
+      className="boxed-group quality-profile-exporters"
+    >
       <h2>{translate('quality_profiles.exporters')}</h2>
       <div className="boxed-group-inner">
         <Alert className="big-spacer-bottom" variant="warning">
@@ -57,6 +60,6 @@ export default function ProfileExporters({ exporters, profile }: Props) {
           ))}
         </ul>
       </div>
-    </div>
+    </section>
   );
 }
index 31a5e739521105084f0ea85e873fcde4cd61c393..c8f0b62b6b672855e9557f19462305f5bc54f0cd 100644 (file)
@@ -118,7 +118,10 @@ export default class ProfileInheritance extends React.PureComponent<Props, State
     const extendsBuiltIn = ancestors != null && ancestors.some((profile) => profile.isBuiltIn);
 
     return (
-      <div className="boxed-group quality-profile-inheritance">
+      <section
+        aria-label={translate('quality_profiles.profile_inheritance')}
+        className="boxed-group quality-profile-inheritance"
+      >
         {profile.actions && profile.actions.edit && !profile.isBuiltIn && (
           <div className="boxed-group-actions">
             <Button className="pull-right js-change-parent" onClick={this.handleChangeParentClick}>
@@ -184,7 +187,7 @@ export default class ProfileInheritance extends React.PureComponent<Props, State
             profiles={profiles.filter((p) => p !== profile && p.language === profile.language)}
           />
         )}
-      </div>
+      </section>
     );
   }
 }
index 4d939290446e498c5407d5599cd99084e02ae2a5..00d35805c0d1835ef4b4669f602ed425f34a332d 100644 (file)
@@ -20,9 +20,9 @@
 import { sortBy, uniqBy } from 'lodash';
 import * as React from 'react';
 import {
+  SearchUsersGroupsParameters,
   searchGroups,
   searchUsers,
-  SearchUsersGroupsParameters,
 } from '../../../api/quality-profiles';
 import { Button } from '../../../components/controls/buttons';
 import { translate } from '../../../helpers/l10n';
@@ -138,7 +138,7 @@ export default class ProfilePermissions extends React.PureComponent<Props, State
 
   render() {
     return (
-      <div className="boxed-group">
+      <section aria-label={translate('permissions.page')} className="boxed-group">
         <h2>{translate('permissions.page')}</h2>
         <div className="boxed-group-inner">
           <p className="note">{translate('quality_profiles.default_permissions')}</p>
@@ -184,7 +184,7 @@ export default class ProfilePermissions extends React.PureComponent<Props, State
             profile={this.props.profile}
           />
         )}
-      </div>
+      </section>
     );
   }
 }
index 2cbb49e7007087067c9fb2c3d7ec85dd0e5cc936..3b9cf80c7de4f51850790dcb9a5984d15cbf6da0 100644 (file)
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { removeGroup } from '../../../api/quality-profiles';
-import { Button, DeleteButton, ResetButtonLink } from '../../../components/controls/buttons';
 import SimpleModal, { ChildrenProps } from '../../../components/controls/SimpleModal';
+import { Button, DeleteButton, ResetButtonLink } from '../../../components/controls/buttons';
 import GroupIcon from '../../../components/icons/GroupIcon';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { Group } from './ProfilePermissions';
 
 interface Props {
@@ -103,6 +103,10 @@ export default class ProfilePermissionsGroup extends React.PureComponent<Props,
     return (
       <div className="clearfix big-spacer-bottom">
         <DeleteButton
+          aria-label={translateWithParameters(
+            'quality_profiles.permissions.remove.group_x',
+            group.name
+          )}
           className="pull-right spacer-top spacer-left spacer-right button-small"
           onClick={this.handleDeleteClick}
         />
index fc343d6e1e265b269ce3cc2867d70edcaea1d883..c12f76e8b4cc1d1bfe712a06b8516b312be1e16c 100644 (file)
@@ -23,7 +23,7 @@ import { removeUser } from '../../../api/quality-profiles';
 import SimpleModal, { ChildrenProps } from '../../../components/controls/SimpleModal';
 import { DeleteButton, ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import LegacyAvatar from '../../../components/ui/LegacyAvatar';
-import { translate } from '../../../helpers/l10n';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { UserSelected } from '../../../types/types';
 
 interface Props {
@@ -107,6 +107,10 @@ export default class ProfilePermissionsUser extends React.PureComponent<Props, S
     return (
       <div className="clearfix big-spacer-bottom">
         <DeleteButton
+          aria-label={translateWithParameters(
+            'quality_profiles.permissions.remove.user_x',
+            user.name
+          )}
           className="pull-right spacer-top spacer-left spacer-right button-small"
           onClick={this.handleDeleteClick}
         />
index 59e19683ef8ed9647123fc7168386f2cec127796..a1447c0d1da1e04b45152fa4e1585fcae53ef4cd 100644 (file)
@@ -169,7 +169,7 @@ export default class ProfileProjects extends React.PureComponent<Props, State> {
     const { profile } = this.props;
     const hasNoActiveRules = profile.activeRuleCount === 0;
     return (
-      <div className="boxed-group quality-profile-projects">
+      <section className="boxed-group quality-profile-projects" aria-label={translate('projects')}>
         {profile.actions && profile.actions.associateProjects && (
           <div className="boxed-group-actions">
             <Tooltip
@@ -199,7 +199,7 @@ export default class ProfileProjects extends React.PureComponent<Props, State> {
         </div>
 
         {this.state.formOpen && <ChangeProjectsForm onClose={this.closeForm} profile={profile} />}
-      </div>
+      </section>
     );
   }
 }
index b58616490dfe79c9384f0c04d7c2f876f885bec5..18f521e76a497629b22bcbc0431da818248fd5bc 100644 (file)
 import { keyBy } from 'lodash';
 import * as React from 'react';
 import { getQualityProfile } from '../../../api/quality-profiles';
-import { searchRules, takeFacet } from '../../../api/rules';
+import { searchRules } from '../../../api/rules';
 import Link from '../../../components/common/Link';
 import Tooltip from '../../../components/controls/Tooltip';
 import { Button } from '../../../components/controls/buttons';
 import { translate } from '../../../helpers/l10n';
 import { getRulesUrl } from '../../../helpers/urls';
+import { SearchRulesResponse } from '../../../types/coding-rules';
 import { Dict } from '../../../types/types';
 import { Profile } from '../types';
 import ProfileRulesDeprecatedWarning from './ProfileRulesDeprecatedWarning';
@@ -118,8 +119,8 @@ export default class ProfileRules extends React.PureComponent<Props, State> {
           const [allRules, activatedRules, showProfile] = responses;
           this.setState({
             activatedTotal: activatedRules.paging.total,
-            allByType: keyBy<ByType>(takeFacet(allRules, 'types'), 'val'),
-            activatedByType: keyBy<ByType>(takeFacet(activatedRules, 'types'), 'val'),
+            allByType: keyBy<ByType>(this.takeFacet(allRules, 'types'), 'val'),
+            activatedByType: keyBy<ByType>(this.takeFacet(activatedRules, 'types'), 'val'),
             compareToSonarWay: showProfile && showProfile.compareToSonarWay,
             total: allRules.paging.total,
           });
@@ -140,6 +141,11 @@ export default class ProfileRules extends React.PureComponent<Props, State> {
       : null;
   }
 
+  takeFacet(response: SearchRulesResponse, property: string) {
+    const facet = response.facets?.find((f) => f.property === property);
+    return facet ? facet.values : [];
+  }
+
   render() {
     const { profile } = this.props;
     const { compareToSonarWay } = this.state;
@@ -147,7 +153,7 @@ export default class ProfileRules extends React.PureComponent<Props, State> {
     const { actions = {} } = profile;
 
     return (
-      <div className="boxed-group quality-profile-rules">
+      <section aria-label={translate('rules')} className="boxed-group quality-profile-rules">
         <div className="quality-profile-rules-distribution">
           <table className="data condensed">
             <thead>
@@ -212,7 +218,7 @@ export default class ProfileRules extends React.PureComponent<Props, State> {
             sonarway={compareToSonarWay.profile}
           />
         )}
-      </div>
+      </section>
     );
   }
 }
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeParentForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeParentForm-test.tsx
deleted file mode 100644 (file)
index d848162..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile } from '../../../../helpers/testMocks';
-import { mockEvent, waitAndUpdate } from '../../../../helpers/testUtils';
-import ChangeParentForm from '../ChangeParentForm';
-
-beforeEach(() => jest.clearAllMocks());
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  changeProfileParent: jest.fn().mockResolvedValue({}),
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should handle form submit correcty', async () => {
-  const onChange = jest.fn();
-
-  const wrapper = shallowRender({ onChange });
-  wrapper.instance().handleFormSubmit(mockEvent());
-  await waitAndUpdate(wrapper);
-
-  expect(onChange).toHaveBeenCalled();
-});
-
-it('should handle select change correcty', async () => {
-  const wrapper = shallowRender();
-  wrapper.instance().handleSelectChange({ value: 'val' });
-  await waitAndUpdate(wrapper);
-
-  expect(wrapper.instance().state.selected).toEqual('val');
-});
-
-function shallowRender(props?: Partial<ChangeParentForm['props']>) {
-  return shallow<ChangeParentForm>(
-    <ChangeParentForm
-      onChange={jest.fn()}
-      onClose={jest.fn()}
-      profile={mockQualityProfile()}
-      profiles={[
-        mockQualityProfile(),
-        mockQualityProfile(),
-        mockQualityProfile(),
-        mockQualityProfile(),
-      ]}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeProjectsForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeProjectsForm-test.tsx
deleted file mode 100644 (file)
index d48a59b..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
-  associateProject,
-  dissociateProject,
-  getProfileProjects,
-} from '../../../../api/quality-profiles';
-import SelectList, { SelectListFilter } from '../../../../components/controls/SelectList';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import ChangeProjectsForm from '../ChangeProjectsForm';
-
-const profile: any = { key: 'profFile_key' };
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  getProfileProjects: jest.fn().mockResolvedValue({
-    paging: { pageIndex: 1, pageSize: 3, total: 55 },
-    results: [
-      { id: 'test1', key: 'test1', name: 'test1', selected: false },
-      { id: 'test2', key: 'test2', name: 'test2', selected: false },
-      { id: 'test3', key: 'test3', name: 'test3', selected: true },
-    ],
-  }),
-  associateProject: jest.fn().mockResolvedValue({}),
-  dissociateProject: jest.fn().mockResolvedValue({}),
-}));
-
-beforeEach(() => {
-  jest.clearAllMocks();
-});
-
-it('should render correctly', async () => {
-  const wrapper = shallowRender();
-  wrapper.find(SelectList).props().onSearch({
-    query: '',
-    filter: SelectListFilter.Selected,
-    page: 1,
-    pageSize: 100,
-  });
-  await waitAndUpdate(wrapper);
-
-  expect(wrapper.instance().mounted).toBe(true);
-  expect(wrapper).toMatchSnapshot();
-  expect(wrapper.instance().renderElement('test1')).toMatchSnapshot();
-  expect(wrapper.instance().renderElement('test_foo')).toMatchSnapshot();
-
-  expect(getProfileProjects).toHaveBeenCalledWith(
-    expect.objectContaining({
-      key: profile.key,
-      p: 1,
-      ps: 100,
-      q: undefined,
-      selected: SelectListFilter.Selected,
-    })
-  );
-  expect(wrapper.state().needToReload).toBe(false);
-
-  wrapper.instance().componentWillUnmount();
-  expect(wrapper.instance().mounted).toBe(false);
-});
-
-it('should handle selection properly', async () => {
-  const wrapper = shallowRender();
-  wrapper.instance().handleSelect('toto');
-  await waitAndUpdate(wrapper);
-
-  expect(associateProject).toHaveBeenCalledWith(profile, 'toto');
-  expect(wrapper.state().needToReload).toBe(true);
-});
-
-it('should handle deselection properly', async () => {
-  const wrapper = shallowRender();
-  wrapper.instance().handleUnselect('tata');
-  await waitAndUpdate(wrapper);
-
-  expect(dissociateProject).toHaveBeenCalledWith(profile, 'tata');
-  expect(wrapper.state().needToReload).toBe(true);
-});
-
-function shallowRender(props: Partial<ChangeProjectsForm['props']> = {}) {
-  return shallow<ChangeProjectsForm>(
-    <ChangeProjectsForm onClose={jest.fn()} profile={profile} {...props} />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx
deleted file mode 100644 (file)
index 8de89c1..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile } from '../../../../helpers/testMocks';
-import { ProfileDetails, ProfileDetailsProps } from '../ProfileDetails';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('default');
-  expect(
-    shallowRender({ profile: mockQualityProfile({ actions: { edit: true } }) })
-  ).toMatchSnapshot('edit permissions');
-  expect(
-    shallowRender({
-      profile: mockQualityProfile({ activeRuleCount: 0, projectCount: 0 }),
-    })
-  ).toMatchSnapshot('no active rules (same as default)');
-  expect(
-    shallowRender({
-      profile: mockQualityProfile({ projectCount: 0, isDefault: true, activeRuleCount: 0 }),
-    })
-  ).toMatchSnapshot('is default profile, no active rules');
-  expect(
-    shallowRender({ profile: mockQualityProfile({ projectCount: 10, activeRuleCount: 0 }) })
-  ).toMatchSnapshot('projects associated, no active rules');
-});
-
-function shallowRender(props: Partial<ProfileDetailsProps> = {}) {
-  return shallow<ProfileDetailsProps>(
-    <ProfileDetails
-      exporters={[]}
-      profile={mockQualityProfile()}
-      profiles={[]}
-      updateProfiles={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileExporters-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileExporters-test.tsx
deleted file mode 100644 (file)
index ca8d96a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile, mockQualityProfileExporter } from '../../../../helpers/testMocks';
-import { FCProps } from '../../../../types/misc';
-import ProfileExporters from '../ProfileExporters';
-
-it('should render correctly', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<FCProps<typeof ProfileExporters>> = {}) {
-  const profile = mockQualityProfile();
-  return shallow(
-    <ProfileExporters
-      exporters={[mockQualityProfileExporter({ languages: [profile.language] })]}
-      profile={profile}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritance-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritance-test.tsx
deleted file mode 100644 (file)
index 8881659..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile, mockQualityProfileInheritance } from '../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import ProfileInheritance from '../ProfileInheritance';
-
-beforeEach(() => jest.clearAllMocks());
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  getProfileInheritance: jest.fn().mockResolvedValue({
-    children: [mockQualityProfileInheritance()],
-    ancestors: [mockQualityProfileInheritance()],
-  }),
-}));
-
-it('should render correctly', async () => {
-  const wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should render modal correctly', async () => {
-  const wrapper = shallowRender();
-  wrapper.instance().handleChangeParentClick();
-  await waitAndUpdate(wrapper);
-
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should handle parent change correctly', async () => {
-  const updateProfiles = jest.fn().mockResolvedValueOnce({});
-
-  const wrapper = shallowRender({ updateProfiles });
-  wrapper.instance().handleParentChange();
-  await waitAndUpdate(wrapper);
-
-  expect(updateProfiles).toHaveBeenCalled();
-});
-
-function shallowRender(props: Partial<ProfileInheritance['props']> = {}) {
-  return shallow<ProfileInheritance>(
-    <ProfileInheritance
-      profile={mockQualityProfile()}
-      profiles={[mockQualityProfile()]}
-      updateProfiles={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritanceBox-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritanceBox-test.tsx
deleted file mode 100644 (file)
index 78143a9..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfileInheritance } from '../../../../helpers/testMocks';
-import ProfileInheritanceBox from '../ProfileInheritanceBox';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(
-    shallowRender({
-      depth: 3,
-      displayLink: true,
-      profile: mockQualityProfileInheritance({ isBuiltIn: true }),
-    })
-  ).toMatchSnapshot();
-  expect(shallowRender({ extendsBuiltIn: true })).toMatchSnapshot();
-  expect(
-    shallowRender({ profile: mockQualityProfileInheritance({ overridingRuleCount: 10 }) })
-  ).toMatchSnapshot();
-});
-
-function shallowRender(props = {}) {
-  return shallow(
-    <ProfileInheritanceBox
-      depth={1}
-      language="foo"
-      profile={mockQualityProfileInheritance()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx
deleted file mode 100644 (file)
index 37fd737..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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 { mount, shallow } from 'enzyme';
-import * as React from 'react';
-import { searchGroups, searchUsers } from '../../../../api/quality-profiles';
-import { click, waitAndUpdate } from '../../../../helpers/testUtils';
-import ProfilePermissions from '../ProfilePermissions';
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  searchUsers: jest.fn(() => Promise.resolve([])),
-  searchGroups: jest.fn(() => Promise.resolve([])),
-}));
-
-beforeEach(() => {
-  jest.clearAllMocks();
-});
-
-it('renders', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot();
-
-  wrapper.setState({
-    groups: [{ name: 'Lambda' }],
-    loading: false,
-    users: [{ login: 'luke', name: 'Luke Skywalker', selected: false }],
-  });
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should update correctly', () => {
-  const wrapper = shallowRender();
-
-  wrapper.setProps({ profile: { key: 'otherKey', name: 'new profile', language: 'js' } });
-
-  expect(searchGroups).toHaveBeenCalledTimes(2);
-  expect(searchUsers).toHaveBeenCalledTimes(2);
-});
-
-it('opens add users form', async () => {
-  (searchUsers as jest.Mock).mockImplementationOnce(() =>
-    Promise.resolve({ users: [{ login: 'luke', name: 'Luke Skywalker' }] })
-  );
-  const wrapper = shallowRender();
-  expect(searchUsers).toHaveBeenCalled();
-  await waitAndUpdate(wrapper);
-  expect(wrapper.find('ProfilePermissionsForm').exists()).toBe(false);
-
-  click(wrapper.find('Button'));
-  expect(wrapper.find('ProfilePermissionsForm').exists()).toBe(true);
-
-  wrapper.find('ProfilePermissionsForm').prop<Function>('onClose')();
-  wrapper.update();
-  expect(wrapper.find('ProfilePermissionsForm').exists()).toBe(false);
-});
-
-it('removes user', () => {
-  const wrapper = shallowRender();
-  (wrapper.instance() as ProfilePermissions).mounted = true;
-
-  const joda = { login: 'joda', name: 'Joda', selected: false };
-  wrapper.setState({
-    loading: false,
-    users: [{ login: 'luke', name: 'Luke Skywalker', selected: false }, joda],
-  });
-  expect(wrapper.find('ProfilePermissionsUser')).toHaveLength(2);
-
-  wrapper.find('ProfilePermissionsUser').first().prop<Function>('onDelete')(joda);
-  wrapper.update();
-  expect(wrapper.find('ProfilePermissionsUser')).toHaveLength(1);
-});
-
-it('removes group', () => {
-  const wrapper = shallowRender();
-  (wrapper.instance() as ProfilePermissions).mounted = true;
-
-  const lambda = { name: 'Lambda' };
-  wrapper.setState({ loading: false, groups: [{ name: 'Atlas' }, lambda] });
-  expect(wrapper.find('ProfilePermissionsGroup')).toHaveLength(2);
-
-  wrapper.find('ProfilePermissionsGroup').first().prop<Function>('onDelete')(lambda);
-  wrapper.update();
-  expect(wrapper.find('ProfilePermissionsGroup')).toHaveLength(1);
-});
-
-it('fetches users and groups on mount', () => {
-  mount(<ProfilePermissions profile={{ key: 'sonar-way', name: 'Sonar way', language: 'js' }} />);
-  expect(searchUsers).toHaveBeenCalledWith({
-    language: 'js',
-    qualityProfile: 'Sonar way',
-    selected: 'selected',
-  });
-  expect(searchGroups).toHaveBeenCalledWith({
-    language: 'js',
-    qualityProfile: 'Sonar way',
-    selected: 'selected',
-  });
-});
-
-function shallowRender(overrides: Partial<{ key: string; name: string; language: string }> = {}) {
-  const profile = { key: 'sonar-way', name: 'Sonar way', language: 'js', ...overrides };
-  return shallow<ProfilePermissions>(<ProfilePermissions profile={profile} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsForm-test.tsx
deleted file mode 100644 (file)
index 69c079b..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { addGroup, addUser } from '../../../../api/quality-profiles';
-import { mockGroup, mockUser } from '../../../../helpers/testMocks';
-import { submit, waitAndUpdate } from '../../../../helpers/testUtils';
-import { UserSelected } from '../../../../types/types';
-import ProfilePermissionsForm from '../ProfilePermissionsForm';
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  addUser: jest.fn().mockResolvedValue(null),
-  addGroup: jest.fn().mockResolvedValue(null),
-  searchGroups: jest.fn().mockResolvedValue({ groups: [] }),
-  searchUsers: jest.fn().mockResolvedValue({ users: [] }),
-}));
-
-const PROFILE = { language: 'js', name: 'Sonar way' };
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('default');
-  expect(shallowRender().setState({ submitting: true })).toMatchSnapshot('submitting');
-});
-
-it('correctly adds users', async () => {
-  const onUserAdd = jest.fn();
-  const wrapper = shallowRender({ onUserAdd });
-
-  const user: UserSelected = { ...mockUser(), name: 'John doe', active: true, selected: true };
-  wrapper.instance().handleValueChange(user);
-  expect(wrapper.state().selected).toBe(user);
-
-  submit(wrapper.find('form'));
-  expect(wrapper).toMatchSnapshot();
-  expect(addUser).toHaveBeenCalledWith(
-    expect.objectContaining({
-      language: PROFILE.language,
-      qualityProfile: PROFILE.name,
-      login: user.login,
-    })
-  );
-
-  await waitAndUpdate(wrapper);
-  expect(onUserAdd).toHaveBeenCalledWith(user);
-});
-
-it('correctly adds groups', async () => {
-  const onGroupAdd = jest.fn();
-  const wrapper = shallowRender({ onGroupAdd });
-
-  const group = mockGroup();
-  wrapper.instance().handleValueChange(group);
-  expect(wrapper.state().selected).toBe(group);
-
-  submit(wrapper.find('form'));
-  expect(wrapper).toMatchSnapshot();
-  expect(addGroup).toHaveBeenCalledWith(
-    expect.objectContaining({
-      language: PROFILE.language,
-      qualityProfile: PROFILE.name,
-      group: group.name,
-    })
-  );
-
-  await waitAndUpdate(wrapper);
-  expect(onGroupAdd).toHaveBeenCalledWith(group);
-});
-
-function shallowRender(props: Partial<ProfilePermissionsForm['props']> = {}) {
-  return shallow<ProfilePermissionsForm>(
-    <ProfilePermissionsForm
-      onClose={jest.fn()}
-      onGroupAdd={jest.fn()}
-      onUserAdd={jest.fn()}
-      profile={PROFILE}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsFormSelect-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsFormSelect-test.tsx
deleted file mode 100644 (file)
index 8cffc01..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { searchGroups, searchUsers } from '../../../../api/quality-profiles';
-import {
-  mockReactSelectControlProps,
-  mockReactSelectOptionProps,
-} from '../../../../helpers/mocks/react-select';
-import { mockUser } from '../../../../helpers/testMocks';
-import ProfilePermissionsFormSelect from '../ProfilePermissionsFormSelect';
-
-jest.mock('lodash', () => {
-  const lodash = jest.requireActual('lodash');
-  lodash.debounce =
-    (fn: Function) =>
-    (...args: any[]) =>
-      fn(...args);
-  return lodash;
-});
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  searchGroups: jest.fn().mockResolvedValue([]),
-  searchUsers: jest.fn().mockResolvedValue([]),
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should handle search', async () => {
-  (searchUsers as jest.Mock).mockResolvedValueOnce({ users: [mockUser()] });
-  (searchGroups as jest.Mock).mockResolvedValueOnce({ groups: [{ name: 'group1' }] });
-
-  const wrapper = shallowRender();
-  const query = 'Waldo';
-  const results = await new Promise((resolve) => {
-    wrapper.instance().handleSearch(query, resolve);
-  });
-  expect(searchUsers).toHaveBeenCalledWith(expect.objectContaining({ q: query }));
-  expect(searchGroups).toHaveBeenCalledWith(expect.objectContaining({ q: query }));
-
-  expect(results).toHaveLength(2);
-});
-
-it('should render option correctly', () => {
-  const wrapper = shallowRender();
-  const OptionRenderer = wrapper.instance().optionRenderer;
-  expect(
-    shallow(<OptionRenderer {...mockReactSelectOptionProps({ value: 'test', name: 'name' })} />)
-  ).toMatchSnapshot('option renderer');
-});
-
-it('should render value correctly', () => {
-  const wrapper = shallowRender();
-  const ValueRenderer = wrapper.instance().singleValueRenderer;
-  expect(
-    shallow(<ValueRenderer {...mockReactSelectOptionProps({ value: 'test', name: 'name' })} />)
-  ).toMatchSnapshot('value renderer');
-});
-
-it('should render control correctly', () => {
-  const wrapper = shallowRender();
-  const ControlRenderer = wrapper.instance().controlRenderer;
-  expect(shallow(<ControlRenderer {...mockReactSelectControlProps()} />)).toMatchSnapshot(
-    'control renderer'
-  );
-});
-
-function shallowRender(overrides: Partial<ProfilePermissionsFormSelect['props']> = {}) {
-  return shallow<ProfilePermissionsFormSelect>(
-    <ProfilePermissionsFormSelect
-      onChange={jest.fn()}
-      profile={{ language: 'Java', name: 'Sonar Way' }}
-      {...overrides}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx
deleted file mode 100644 (file)
index 35bb7d4..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.
- */
-/* eslint-disable import/first */
-jest.mock('../../../../api/quality-profiles', () => ({
-  removeGroup: jest.fn(() => Promise.resolve()),
-}));
-
-import { shallow } from 'enzyme';
-import * as React from 'react';
-import { click } from '../../../../helpers/testUtils';
-import ProfilePermissionsGroup from '../ProfilePermissionsGroup';
-
-const removeGroup = require('../../../../api/quality-profiles').removeGroup as jest.Mock<any>;
-
-const profile = { language: 'js', name: 'Sonar way' };
-const group = { name: 'lambda' };
-
-beforeEach(() => {
-  removeGroup.mockClear();
-});
-
-it('renders', () => {
-  expect(
-    shallow(<ProfilePermissionsGroup group={group} onDelete={jest.fn()} profile={profile} />)
-  ).toMatchSnapshot();
-});
-
-it('removes user', async () => {
-  const onDelete = jest.fn();
-  const wrapper = shallow(
-    <ProfilePermissionsGroup group={group} onDelete={onDelete} profile={profile} />
-  );
-  (wrapper.instance() as ProfilePermissionsGroup).mounted = true;
-  expect(wrapper.find('SimpleModal').exists()).toBe(false);
-
-  click(wrapper.find('DeleteButton'));
-  expect(wrapper.find('SimpleModal').exists()).toBe(true);
-
-  wrapper.find('SimpleModal').prop<Function>('onSubmit')();
-  expect(removeGroup).toHaveBeenCalledWith({
-    group: 'lambda',
-    language: 'js',
-    qualityProfile: 'Sonar way',
-  });
-
-  await new Promise(setImmediate);
-  expect(onDelete).toHaveBeenCalledWith(group);
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx
deleted file mode 100644 (file)
index 3f07228..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { removeUser } from '../../../../api/quality-profiles';
-import { click } from '../../../../helpers/testUtils';
-import { UserSelected } from '../../../../types/types';
-import ProfilePermissionsUser from '../ProfilePermissionsUser';
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  removeUser: jest.fn(() => Promise.resolve()),
-}));
-
-const profile = { language: 'js', name: 'Sonar way' };
-const user: UserSelected = { login: 'luke', name: 'Luke Skywalker', selected: true };
-
-beforeEach(() => {
-  jest.clearAllMocks();
-});
-
-it('renders', () => {
-  expect(
-    shallow(<ProfilePermissionsUser onDelete={jest.fn()} profile={profile} user={user} />)
-  ).toMatchSnapshot();
-});
-
-it('removes user', async () => {
-  const onDelete = jest.fn();
-  const wrapper = shallow(
-    <ProfilePermissionsUser onDelete={onDelete} profile={profile} user={user} />
-  );
-  (wrapper.instance() as ProfilePermissionsUser).mounted = true;
-  expect(wrapper.find('SimpleModal').exists()).toBe(false);
-
-  click(wrapper.find('DeleteButton'));
-  expect(wrapper.find('SimpleModal').exists()).toBe(true);
-
-  wrapper.find('SimpleModal').prop<Function>('onSubmit')();
-  expect(removeUser).toHaveBeenCalledWith({
-    language: 'js',
-    login: 'luke',
-    qualityProfile: 'Sonar way',
-  });
-
-  await new Promise(setImmediate);
-  expect(onDelete).toHaveBeenCalledWith(user);
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx
deleted file mode 100644 (file)
index c38aaee..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { getProfileProjects } from '../../../../api/quality-profiles';
-import { mockQualityProfile } from '../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import ChangeProjectsForm from '../ChangeProjectsForm';
-import ProfileProjects from '../ProfileProjects';
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  getProfileProjects: jest.fn().mockResolvedValue({
-    results: [
-      {
-        id: '633a5180-1ad7-4008-a5cb-e1d3cec4c816',
-        key: 'org.sonarsource.xml:xml',
-        name: 'SonarXML',
-        selected: true,
-      },
-    ],
-    paging: { pageIndex: 1, pageSize: 2, total: 10 },
-    more: true,
-  }),
-}));
-
-it('should render correctly', async () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot('loading');
-  await waitAndUpdate(wrapper);
-  expect(wrapper).toMatchSnapshot('default');
-  wrapper.setProps({
-    profile: mockQualityProfile({ actions: { associateProjects: false } }),
-  });
-  expect(wrapper).toMatchSnapshot('no rights');
-  wrapper.setProps({
-    profile: mockQualityProfile({
-      projectCount: 0,
-      activeRuleCount: 0,
-      actions: { associateProjects: true },
-    }),
-  });
-  expect(wrapper).toMatchSnapshot('no active rules, but associated projects');
-  wrapper.setProps({
-    profile: mockQualityProfile({ activeRuleCount: 0, actions: { associateProjects: true } }),
-  });
-  wrapper.setState({ projects: [] });
-  expect(wrapper).toMatchSnapshot('no active rules, no associated projects');
-  wrapper.instance().loadMore();
-  expect(getProfileProjects).toHaveBeenLastCalledWith({ p: 2, key: 'key' });
-});
-
-it('should open and close the form', async () => {
-  const wrapper = shallowRender();
-  await waitAndUpdate(wrapper);
-
-  wrapper.instance().handleChangeClick();
-  expect(wrapper.find(ChangeProjectsForm).exists()).toBe(true);
-
-  wrapper.instance().closeForm();
-  expect(wrapper.find(ChangeProjectsForm).exists()).toBe(false);
-});
-
-function shallowRender(props: Partial<ProfileProjects['props']> = {}) {
-  return shallow<ProfileProjects>(
-    <ProfileProjects
-      profile={mockQualityProfile({ actions: { associateProjects: true } })}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx
deleted file mode 100644 (file)
index 005c1a5..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { getQualityProfile } from '../../../../api/quality-profiles';
-import { mockPaging, mockQualityProfile } from '../../../../helpers/testMocks';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-import ProfileRules from '../ProfileRules';
-
-const PROFILE = mockQualityProfile({
-  activeRuleCount: 68,
-  activeDeprecatedRuleCount: 0,
-  depth: 0,
-  language: 'js',
-  rulesUpdatedAt: '2017-06-28T12:58:44+0000',
-});
-
-const EDITABLE_PROFILE = { ...PROFILE, actions: { edit: true } };
-
-const apiResponseAll = {
-  facets: [
-    {
-      property: 'types',
-      values: [
-        { val: 'CODE_SMELL', count: 168 },
-        { val: 'BUG', count: 68 },
-        { val: 'VULNERABILITY', count: 7 },
-        { val: 'SECURITY_HOTSPOT', count: 10 },
-      ],
-    },
-  ],
-  paging: mockPaging({
-    total: 253,
-  }),
-};
-
-const apiResponseActive = {
-  facets: [
-    {
-      property: 'types',
-      values: [
-        { val: 'BUG', count: 68 },
-        { val: 'CODE_SMELL', count: 0 },
-        { val: 'VULNERABILITY', count: 0 },
-        { val: 'SECURITY_HOTSPOT', count: 0 },
-      ],
-    },
-  ],
-  paging: mockPaging({
-    total: 68,
-  }),
-};
-
-jest.mock('../../../../api/rules', () => ({
-  ...jest.requireActual('../../../../api/rules'),
-  searchRules: jest
-    .fn()
-    .mockImplementation((data: any) =>
-      Promise.resolve(data.activation === 'true' ? apiResponseActive : apiResponseAll)
-    ),
-}));
-
-jest.mock('../../../../api/quality-profiles', () => ({
-  ...jest.requireActual('../../../../api/quality-profiles'),
-  getQualityProfile: jest.fn().mockImplementation(() =>
-    Promise.resolve({
-      compareToSonarWay: {
-        profile: 'sonarway',
-        profileName: 'Sonar way',
-        missingRuleCount: 4,
-      },
-    })
-  ),
-}));
-
-beforeEach(jest.clearAllMocks);
-
-it('should render the quality profiles rules with sonarway comparison', async () => {
-  const wrapper = shallow(<ProfileRules profile={PROFILE} />);
-  const instance = wrapper.instance() as ProfileRules;
-  instance.mounted = true;
-  instance.loadRules();
-  await waitAndUpdate(wrapper);
-  expect(wrapper.find('ProfileRulesSonarWayComparison')).toHaveLength(1);
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should show a button to activate more rules for admins', () => {
-  const wrapper = shallow(<ProfileRules profile={EDITABLE_PROFILE} />);
-  expect(wrapper.find('.js-activate-rules')).toMatchSnapshot();
-});
-
-it('should show a disabled button to activate more rules for built-in profiles', () => {
-  const wrapper = shallow(
-    <ProfileRules profile={{ ...EDITABLE_PROFILE, actions: { copy: true }, isBuiltIn: true }} />
-  );
-  expect(wrapper.find('.js-activate-rules')).toMatchSnapshot();
-});
-
-it('should show a deprecated rules warning message', () => {
-  const wrapper = shallow(
-    <ProfileRules profile={{ ...EDITABLE_PROFILE, activeDeprecatedRuleCount: 8 }} />
-  );
-  expect(wrapper.find('ProfileRulesDeprecatedWarning')).toMatchSnapshot();
-});
-
-it('should not show a button to activate more rules on built in profiles', () => {
-  const wrapper = shallow(<ProfileRules profile={{ ...EDITABLE_PROFILE, isBuiltIn: true }} />);
-  expect(wrapper.find('.js-activate-rules').exists()).toBe(false);
-});
-
-it('should not show sonarway comparison for built in profiles', async () => {
-  (getQualityProfile as jest.Mock).mockReturnValueOnce({});
-  const wrapper = shallow(<ProfileRules profile={{ ...PROFILE, isBuiltIn: true }} />);
-  await new Promise(setImmediate);
-  wrapper.update();
-  expect(getQualityProfile).toHaveBeenCalledTimes(0);
-  expect(wrapper.find('ProfileRulesSonarWayComparison')).toHaveLength(0);
-});
-
-it('should not show sonarway comparison if there is no missing rules', async () => {
-  (getQualityProfile as jest.Mock).mockReturnValueOnce({
-    compareToSonarWay: {
-      profile: 'sonarway',
-      profileName: 'Sonar way',
-      missingRuleCount: 0,
-    },
-  });
-  const wrapper = shallow(<ProfileRules profile={PROFILE} />);
-  await waitAndUpdate(wrapper);
-  expect(getQualityProfile).toHaveBeenCalledTimes(1);
-  expect(wrapper.find('ProfileRulesSonarWayComparison')).toHaveLength(0);
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesDeprecatedWarning-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesDeprecatedWarning-test.tsx
deleted file mode 100644 (file)
index 1d69d33..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ProfileRulesDeprecatedWarning from '../ProfileRulesDeprecatedWarning';
-
-it('should render correctly', () => {
-  expect(
-    shallow(<ProfileRulesDeprecatedWarning activeDeprecatedRules={18} profile="bar" />)
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowOfType-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowOfType-test.tsx
deleted file mode 100644 (file)
index ba553ff..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ProfileRulesRowOfType from '../ProfileRulesRowOfType';
-
-it('should render correctly', () => {
-  expect(
-    shallow(<ProfileRulesRowOfType count={3} qprofile="bar" total={10} type="BUG" />)
-  ).toMatchSnapshot();
-});
-
-it('should render correctly if there is 0 rules', () => {
-  expect(
-    shallow(<ProfileRulesRowOfType count={0} qprofile="bar" total={0} type="VULNERABILITY" />)
-  ).toMatchSnapshot();
-});
-
-it('should render correctly if there is missing data', () => {
-  expect(
-    shallow(<ProfileRulesRowOfType count={5} qprofile="bar" total={null} type="VULNERABILITY" />)
-  ).toMatchSnapshot();
-  expect(
-    shallow(<ProfileRulesRowOfType count={null} qprofile="foo" total={10} type="VULNERABILITY" />)
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowTotal-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowTotal-test.tsx
deleted file mode 100644 (file)
index 547dd01..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ProfileRulesRowTotal from '../ProfileRulesRowTotal';
-
-it('should render correctly', () => {
-  expect(shallow(<ProfileRulesRowTotal count={3} qprofile="bar" total={10} />)).toMatchSnapshot();
-});
-
-it('should render correctly if there is 0 rules', () => {
-  expect(shallow(<ProfileRulesRowTotal count={0} qprofile="bar" total={0} />)).toMatchSnapshot();
-});
-
-it('should render correctly if there is missing data', () => {
-  expect(shallow(<ProfileRulesRowTotal count={5} qprofile="bar" total={null} />)).toMatchSnapshot();
-  expect(
-    shallow(<ProfileRulesRowTotal count={null} qprofile="foo" total={10} />)
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesSonarWayComparison-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesSonarWayComparison-test.tsx
deleted file mode 100644 (file)
index 408e402..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import ProfileRulesSonarWayComparison from '../ProfileRulesSonarWayComparison';
-
-it('should render correctly', () => {
-  expect(
-    shallow(
-      <ProfileRulesSonarWayComparison
-        language="Java"
-        profile="bar"
-        sonarWayMissingRules={158}
-        sonarway="baz"
-      />
-    )
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeParentForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeParentForm-test.tsx.snap
deleted file mode 100644 (file)
index 7417589..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Modal
-  contentLabel="quality_profiles.change_parent"
-  onRequestClose={[MockFunction]}
-  size="small"
->
-  <form
-    id="change-profile-parent-form"
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-head"
-    >
-      <h2>
-        quality_profiles.change_parent
-      </h2>
-    </div>
-    <div
-      className="modal-body"
-    >
-      <MandatoryFieldsExplanation
-        className="modal-field"
-      />
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="change-profile-parent-input"
-        >
-          quality_profiles.parent
-          <MandatoryFieldMarker />
-        </label>
-        <Select
-          autoFocus={true}
-          className="width-100"
-          id="change-profile-parent"
-          inputId="change-profile-parent-input"
-          isClearable={false}
-          isSearchable={true}
-          name="parentKey"
-          onChange={[Function]}
-          options={
-            [
-              {
-                "label": "none",
-                "value": "",
-              },
-              {
-                "label": "name",
-                "value": "key",
-              },
-              {
-                "label": "name",
-                "value": "key",
-              },
-              {
-                "label": "name",
-                "value": "key",
-              },
-              {
-                "label": "name",
-                "value": "key",
-              },
-            ]
-          }
-          value={
-            [
-              {
-                "label": "none",
-                "value": "",
-              },
-            ]
-          }
-        />
-      </div>
-    </div>
-    <div
-      className="modal-foot"
-    >
-      <SubmitButton
-        disabled={true}
-        id="change-profile-parent-submit"
-      >
-        change_verb
-      </SubmitButton>
-      <ResetButtonLink
-        id="change-profile-parent-cancel"
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </div>
-  </form>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeProjectsForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeProjectsForm-test.tsx.snap
deleted file mode 100644 (file)
index 68a5559..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Modal
-  contentLabel="projects"
-  onRequestClose={[MockFunction]}
->
-  <div
-    className="modal-head"
-  >
-    <h2>
-      projects
-    </h2>
-  </div>
-  <div
-    className="modal-body modal-container"
-    id="profile-projects"
-  >
-    <SelectList
-      allowBulkSelection={true}
-      elements={
-        [
-          "test1",
-          "test2",
-          "test3",
-        ]
-      }
-      elementsTotalCount={55}
-      labelAll="quality_gates.projects.all"
-      labelSelected="quality_gates.projects.with"
-      labelUnselected="quality_gates.projects.without"
-      needToReload={false}
-      onSearch={[Function]}
-      onSelect={[Function]}
-      onUnselect={[Function]}
-      renderElement={[Function]}
-      selectedElements={
-        [
-          "test3",
-        ]
-      }
-      withPaging={true}
-    />
-  </div>
-  <div
-    className="modal-foot"
-  >
-    <ResetButtonLink
-      onClick={[MockFunction]}
-    >
-      close
-    </ResetButtonLink>
-  </div>
-</Modal>
-`;
-
-exports[`should render correctly 2`] = `
-<div
-  className="select-list-list-item"
->
-  <React.Fragment>
-    test1
-    <br />
-    <span
-      className="note"
-    >
-      test1
-    </span>
-  </React.Fragment>
-</div>
-`;
-
-exports[`should render correctly 3`] = `
-<div
-  className="select-list-list-item"
->
-  test_foo
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap
deleted file mode 100644 (file)
index dabfc8c..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<div>
-  <div
-    className="quality-profile-grid"
-  >
-    <div
-      className="quality-profile-grid-left"
-    >
-      <ProfileRules
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-      <ProfileExporters
-        exporters={[]}
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-    </div>
-    <div
-      className="quality-profile-grid-right"
-    >
-      <ProfileInheritance
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-        profiles={[]}
-        updateProfiles={[MockFunction]}
-      />
-      <ProfileProjects
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: edit permissions 1`] = `
-<div>
-  <div
-    className="quality-profile-grid"
-  >
-    <div
-      className="quality-profile-grid-left"
-    >
-      <ProfileRules
-        profile={
-          {
-            "actions": {
-              "edit": true,
-            },
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-      <ProfileExporters
-        exporters={[]}
-        profile={
-          {
-            "actions": {
-              "edit": true,
-            },
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-      <ProfilePermissions
-        profile={
-          {
-            "actions": {
-              "edit": true,
-            },
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-    </div>
-    <div
-      className="quality-profile-grid-right"
-    >
-      <ProfileInheritance
-        profile={
-          {
-            "actions": {
-              "edit": true,
-            },
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-        profiles={[]}
-        updateProfiles={[MockFunction]}
-      />
-      <ProfileProjects
-        profile={
-          {
-            "actions": {
-              "edit": true,
-            },
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 10,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 3,
-          }
-        }
-      />
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: is default profile, no active rules 1`] = `
-<div>
-  <div
-    className="quality-profile-grid"
-  >
-    <div
-      className="quality-profile-grid-left"
-    >
-      <ProfileRules
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": true,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-      <ProfileExporters
-        exporters={[]}
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": true,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-    </div>
-    <div
-      className="quality-profile-grid-right"
-    >
-      <Alert
-        className="big-spacer-bottom"
-        variant="warning"
-      >
-        quality_profiles.warning.is_default_no_rules
-      </Alert>
-      <ProfileInheritance
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": true,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-        profiles={[]}
-        updateProfiles={[MockFunction]}
-      />
-      <ProfileProjects
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": true,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: no active rules (same as default) 1`] = `
-<div>
-  <div
-    className="quality-profile-grid"
-  >
-    <div
-      className="quality-profile-grid-left"
-    >
-      <ProfileRules
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-      <ProfileExporters
-        exporters={[]}
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-    </div>
-    <div
-      className="quality-profile-grid-right"
-    >
-      <ProfileInheritance
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-        profiles={[]}
-        updateProfiles={[MockFunction]}
-      />
-      <ProfileProjects
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 0,
-          }
-        }
-      />
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: projects associated, no active rules 1`] = `
-<div>
-  <div
-    className="quality-profile-grid"
-  >
-    <div
-      className="quality-profile-grid-left"
-    >
-      <ProfileRules
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 10,
-          }
-        }
-      />
-      <ProfileExporters
-        exporters={[]}
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 10,
-          }
-        }
-      />
-    </div>
-    <div
-      className="quality-profile-grid-right"
-    >
-      <Alert
-        className="big-spacer-bottom"
-        variant="warning"
-      >
-        quality_profiles.warning.used_by_projects_no_rules
-      </Alert>
-      <ProfileInheritance
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 10,
-          }
-        }
-        profiles={[]}
-        updateProfiles={[MockFunction]}
-      />
-      <ProfileProjects
-        profile={
-          {
-            "activeDeprecatedRuleCount": 2,
-            "activeRuleCount": 0,
-            "childrenCount": 0,
-            "depth": 1,
-            "isBuiltIn": false,
-            "isDefault": false,
-            "isInherited": false,
-            "key": "key",
-            "language": "js",
-            "languageName": "JavaScript",
-            "name": "name",
-            "projectCount": 10,
-          }
-        }
-      />
-    </div>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileExporters-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileExporters-test.tsx.snap
deleted file mode 100644 (file)
index 1f5eff1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="boxed-group quality-profile-exporters"
->
-  <h2>
-    quality_profiles.exporters
-  </h2>
-  <div
-    className="boxed-group-inner"
-  >
-    <Alert
-      className="big-spacer-bottom"
-      variant="warning"
-    >
-      quality_profiles.exporters.deprecated
-    </Alert>
-    <ul>
-      <li
-        data-key="exporter-key"
-        key="exporter-key"
-      >
-        <ForwardRef(Link)
-          target="_blank"
-          to="/api/qualityprofiles/export?exporterKey=exporter-key&language=js&qualityProfile=name"
-        >
-          exporter-name
-        </ForwardRef(Link)>
-      </li>
-    </ul>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritance-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritance-test.tsx.snap
deleted file mode 100644 (file)
index 150831c..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="boxed-group quality-profile-inheritance"
->
-  <div
-    className="boxed-group-header"
-  >
-    <h2>
-      quality_profiles.profile_inheritance
-    </h2>
-  </div>
-  <div
-    className="boxed-group-inner"
-  >
-    <table
-      className="data zebra"
-    >
-      <tbody>
-        <ProfileInheritanceBox
-          depth={0}
-          key="foo"
-          language="js"
-          profile={
-            {
-              "activeRuleCount": 4,
-              "isBuiltIn": false,
-              "key": "foo",
-              "name": "Foo",
-              "overridingRuleCount": 0,
-            }
-          }
-          type="ancestor"
-        />
-        <ProfileInheritanceBox
-          depth={2}
-          key="foo"
-          language="js"
-          profile={
-            {
-              "activeRuleCount": 4,
-              "isBuiltIn": false,
-              "key": "foo",
-              "name": "Foo",
-              "overridingRuleCount": 0,
-            }
-          }
-          type="child"
-        />
-      </tbody>
-    </table>
-  </div>
-</div>
-`;
-
-exports[`should render modal correctly 1`] = `
-<div
-  className="boxed-group quality-profile-inheritance"
->
-  <div
-    className="boxed-group-header"
-  >
-    <h2>
-      quality_profiles.profile_inheritance
-    </h2>
-  </div>
-  <div
-    className="boxed-group-inner"
-  >
-    <table
-      className="data zebra"
-    >
-      <tbody>
-        <ProfileInheritanceBox
-          depth={0}
-          key="foo"
-          language="js"
-          profile={
-            {
-              "activeRuleCount": 4,
-              "isBuiltIn": false,
-              "key": "foo",
-              "name": "Foo",
-              "overridingRuleCount": 0,
-            }
-          }
-          type="ancestor"
-        />
-        <ProfileInheritanceBox
-          depth={2}
-          key="foo"
-          language="js"
-          profile={
-            {
-              "activeRuleCount": 4,
-              "isBuiltIn": false,
-              "key": "foo",
-              "name": "Foo",
-              "overridingRuleCount": 0,
-            }
-          }
-          type="child"
-        />
-      </tbody>
-    </table>
-  </div>
-  <ChangeParentForm
-    onChange={[Function]}
-    onClose={[Function]}
-    profile={
-      {
-        "activeDeprecatedRuleCount": 2,
-        "activeRuleCount": 10,
-        "childrenCount": 0,
-        "depth": 1,
-        "isBuiltIn": false,
-        "isDefault": false,
-        "isInherited": false,
-        "key": "key",
-        "language": "js",
-        "languageName": "JavaScript",
-        "name": "name",
-        "projectCount": 3,
-      }
-    }
-    profiles={
-      [
-        {
-          "activeDeprecatedRuleCount": 2,
-          "activeRuleCount": 10,
-          "childrenCount": 0,
-          "depth": 1,
-          "isBuiltIn": false,
-          "isDefault": false,
-          "isInherited": false,
-          "key": "key",
-          "language": "js",
-          "languageName": "JavaScript",
-          "name": "name",
-          "projectCount": 3,
-        },
-      ]
-    }
-  />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritanceBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritanceBox-test.tsx.snap
deleted file mode 100644 (file)
index 905d5f7..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<tr
-  className="it__quality-profiles__inheritance-current"
->
-  <td>
-    <div
-      style={
-        {
-          "paddingLeft": 25,
-        }
-      }
-    >
-      <ProfileLink
-        className="text-middle"
-        language="foo"
-        name="Foo"
-      >
-        Foo
-      </ProfileLink>
-    </div>
-  </td>
-  <td>
-    quality_profile.x_active_rules.4
-  </td>
-  <td>
-    <p>
-      quality_profiles.x_overridden_rules.0
-    </p>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly 2`] = `
-<tr
-  className="it__quality-profiles__inheritance-current"
->
-  <td>
-    <div
-      style={
-        {
-          "paddingLeft": 75,
-        }
-      }
-    >
-      <ProfileLink
-        className="text-middle"
-        language="foo"
-        name="Foo"
-      >
-        Foo
-      </ProfileLink>
-      <BuiltInQualityProfileBadge
-        className="spacer-left"
-      />
-    </div>
-  </td>
-  <td>
-    quality_profile.x_active_rules.4
-  </td>
-  <td>
-    <p>
-      quality_profiles.x_overridden_rules.0
-    </p>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly 3`] = `
-<tr
-  className="it__quality-profiles__inheritance-current"
->
-  <td>
-    <div
-      style={
-        {
-          "paddingLeft": 25,
-        }
-      }
-    >
-      <ProfileLink
-        className="text-middle"
-        language="foo"
-        name="Foo"
-      >
-        Foo
-      </ProfileLink>
-      <HelpTooltip
-        className="spacer-left"
-        overlay="quality_profiles.extends_built_in"
-      />
-    </div>
-  </td>
-  <td>
-    quality_profile.x_active_rules.4
-  </td>
-  <td>
-    <p>
-      quality_profiles.x_overridden_rules.0
-    </p>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly 4`] = `
-<tr
-  className="it__quality-profiles__inheritance-current"
->
-  <td>
-    <div
-      style={
-        {
-          "paddingLeft": 25,
-        }
-      }
-    >
-      <ProfileLink
-        className="text-middle"
-        language="foo"
-        name="Foo"
-      >
-        Foo
-      </ProfileLink>
-    </div>
-  </td>
-  <td>
-    quality_profile.x_active_rules.4
-  </td>
-  <td>
-    <p>
-      quality_profiles.x_overridden_rules.10
-    </p>
-  </td>
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap
deleted file mode 100644 (file)
index ce377a5..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
-  className="boxed-group"
->
-  <h2>
-    permissions.page
-  </h2>
-  <div
-    className="boxed-group-inner"
-  >
-    <p
-      className="note"
-    >
-      quality_profiles.default_permissions
-    </p>
-    <div
-      className="big-spacer-top"
-    >
-      <i
-        className="spinner"
-      />
-    </div>
-  </div>
-</div>
-`;
-
-exports[`renders 2`] = `
-<div
-  className="boxed-group"
->
-  <h2>
-    permissions.page
-  </h2>
-  <div
-    className="boxed-group-inner"
-  >
-    <p
-      className="note"
-    >
-      quality_profiles.default_permissions
-    </p>
-    <div
-      className="big-spacer-top"
-    >
-      <ProfilePermissionsUser
-        key="luke"
-        onDelete={[Function]}
-        profile={
-          {
-            "key": "sonar-way",
-            "language": "js",
-            "name": "Sonar way",
-          }
-        }
-        user={
-          {
-            "login": "luke",
-            "name": "Luke Skywalker",
-            "selected": false,
-          }
-        }
-      />
-      <ProfilePermissionsGroup
-        group={
-          {
-            "name": "Lambda",
-          }
-        }
-        key="Lambda"
-        onDelete={[Function]}
-        profile={
-          {
-            "key": "sonar-way",
-            "language": "js",
-            "name": "Sonar way",
-          }
-        }
-      />
-      <div
-        className="text-right"
-      >
-        <Button
-          onClick={[Function]}
-        >
-          quality_profiles.grant_permissions_to_more_users
-        </Button>
-      </div>
-    </div>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap
deleted file mode 100644 (file)
index d5e2578..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`correctly adds groups 1`] = `
-<Modal
-  contentLabel="quality_profiles.grant_permissions_to_user_or_group"
-  onRequestClose={[MockFunction]}
->
-  <header
-    className="modal-head"
-  >
-    <h2>
-      quality_profiles.grant_permissions_to_user_or_group
-    </h2>
-  </header>
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-body"
-    >
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="change-profile-permission-input"
-        >
-          quality_profiles.search_description
-        </label>
-        <ProfilePermissionsFormSelect
-          onChange={[Function]}
-          profile={
-            {
-              "language": "js",
-              "name": "Sonar way",
-            }
-          }
-        />
-      </div>
-    </div>
-    <footer
-      className="modal-foot"
-    >
-      <i
-        className="spinner spacer-right"
-      />
-      <SubmitButton
-        disabled={true}
-      >
-        add_verb
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </footer>
-  </form>
-</Modal>
-`;
-
-exports[`correctly adds users 1`] = `
-<Modal
-  contentLabel="quality_profiles.grant_permissions_to_user_or_group"
-  onRequestClose={[MockFunction]}
->
-  <header
-    className="modal-head"
-  >
-    <h2>
-      quality_profiles.grant_permissions_to_user_or_group
-    </h2>
-  </header>
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-body"
-    >
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="change-profile-permission-input"
-        >
-          quality_profiles.search_description
-        </label>
-        <ProfilePermissionsFormSelect
-          onChange={[Function]}
-          profile={
-            {
-              "language": "js",
-              "name": "Sonar way",
-            }
-          }
-        />
-      </div>
-    </div>
-    <footer
-      className="modal-foot"
-    >
-      <i
-        className="spinner spacer-right"
-      />
-      <SubmitButton
-        disabled={true}
-      >
-        add_verb
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </footer>
-  </form>
-</Modal>
-`;
-
-exports[`should render correctly: default 1`] = `
-<Modal
-  contentLabel="quality_profiles.grant_permissions_to_user_or_group"
-  onRequestClose={[MockFunction]}
->
-  <header
-    className="modal-head"
-  >
-    <h2>
-      quality_profiles.grant_permissions_to_user_or_group
-    </h2>
-  </header>
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-body"
-    >
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="change-profile-permission-input"
-        >
-          quality_profiles.search_description
-        </label>
-        <ProfilePermissionsFormSelect
-          onChange={[Function]}
-          profile={
-            {
-              "language": "js",
-              "name": "Sonar way",
-            }
-          }
-        />
-      </div>
-    </div>
-    <footer
-      className="modal-foot"
-    >
-      <SubmitButton
-        disabled={true}
-      >
-        add_verb
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </footer>
-  </form>
-</Modal>
-`;
-
-exports[`should render correctly: submitting 1`] = `
-<Modal
-  contentLabel="quality_profiles.grant_permissions_to_user_or_group"
-  onRequestClose={[MockFunction]}
->
-  <header
-    className="modal-head"
-  >
-    <h2>
-      quality_profiles.grant_permissions_to_user_or_group
-    </h2>
-  </header>
-  <form
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-body"
-    >
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="change-profile-permission-input"
-        >
-          quality_profiles.search_description
-        </label>
-        <ProfilePermissionsFormSelect
-          onChange={[Function]}
-          profile={
-            {
-              "language": "js",
-              "name": "Sonar way",
-            }
-          }
-        />
-      </div>
-    </div>
-    <footer
-      className="modal-foot"
-    >
-      <i
-        className="spinner spacer-right"
-      />
-      <SubmitButton
-        disabled={true}
-      >
-        add_verb
-      </SubmitButton>
-      <ResetButtonLink
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </footer>
-  </form>
-</Modal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap
deleted file mode 100644 (file)
index d6b9855..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render control correctly: control renderer 1`] = `
-<Control
-  className="abs-height-100"
-/>
-`;
-
-exports[`should render correctly 1`] = `
-<SearchSelect
-  autoFocus={true}
-  className="width-100"
-  components={
-    {
-      "Control": [Function],
-      "Option": [Function],
-      "SingleValue": [Function],
-    }
-  }
-  defaultOptions={true}
-  id="change-profile-permission"
-  inputId="change-profile-permission-input"
-  isClearable={false}
-  large={true}
-  loadOptions={[Function]}
-  noOptionsMessage={[Function]}
-  onChange={[MockFunction]}
-  placeholder=""
-/>
-`;
-
-exports[`should render option correctly: option renderer 1`] = `
-<Option
-  data={
-    {
-      "name": "name",
-      "value": "test",
-    }
-  }
->
-  <span
-    className="display-flex-center"
-  >
-    <GroupIcon
-      size={16}
-    />
-    <strong
-      className="spacer-left"
-    >
-      name
-    </strong>
-  </span>
-</Option>
-`;
-
-exports[`should render value correctly: value renderer 1`] = `
-<SingleValue
-  data={
-    {
-      "name": "name",
-      "value": "test",
-    }
-  }
->
-  <span
-    className="display-flex-center"
-  >
-    <GroupIcon
-      size={16}
-    />
-    <strong
-      className="spacer-left"
-    >
-      name
-    </strong>
-  </span>
-</SingleValue>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsGroup-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsGroup-test.tsx.snap
deleted file mode 100644 (file)
index e44d104..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
-  className="clearfix big-spacer-bottom"
->
-  <DeleteButton
-    className="pull-right spacer-top spacer-left spacer-right button-small"
-    onClick={[Function]}
-  />
-  <GroupIcon
-    className="pull-left spacer-right"
-    size={32}
-  />
-  <div
-    className="overflow-hidden"
-    style={
-      {
-        "lineHeight": "32px",
-      }
-    }
-  >
-    <strong>
-      lambda
-    </strong>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsUser-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsUser-test.tsx.snap
deleted file mode 100644 (file)
index a1fb25c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
-  className="clearfix big-spacer-bottom"
->
-  <DeleteButton
-    className="pull-right spacer-top spacer-left spacer-right button-small"
-    onClick={[Function]}
-  />
-  <withAppStateContext(LegacyAvatar)
-    className="pull-left spacer-right"
-    name="Luke Skywalker"
-    size={32}
-  />
-  <div
-    className="overflow-hidden"
-  >
-    <strong>
-      Luke Skywalker
-    </strong>
-    <div
-      className="note"
-    >
-      luke
-    </div>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap
deleted file mode 100644 (file)
index af24ef1..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<div
-  className="boxed-group quality-profile-projects"
->
-  <div
-    className="boxed-group-actions"
-  >
-    <Tooltip
-      overlay={null}
-    >
-      <Button
-        className="js-change-projects"
-        disabled={false}
-        onClick={[Function]}
-      >
-        quality_profiles.change_projects
-      </Button>
-    </Tooltip>
-  </div>
-  <header
-    className="boxed-group-header"
-  >
-    <h2>
-      projects
-    </h2>
-  </header>
-  <div
-    className="boxed-group-inner"
-  >
-    <ul>
-      <li
-        className="spacer-top js-profile-project"
-        data-key="org.sonarsource.xml:xml"
-        key="org.sonarsource.xml:xml"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "pathname": "/dashboard",
-              "search": "?id=org.sonarsource.xml%3Axml",
-            }
-          }
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            SonarXML
-          </span>
-        </ForwardRef(Link)>
-      </li>
-    </ul>
-    <ListFooter
-      count={1}
-      loadMore={[Function]}
-      ready={true}
-      total={10}
-    />
-  </div>
-</div>
-`;
-
-exports[`should render correctly: loading 1`] = `
-<div
-  className="boxed-group quality-profile-projects"
->
-  <div
-    className="boxed-group-actions"
-  >
-    <Tooltip
-      overlay={null}
-    >
-      <Button
-        className="js-change-projects"
-        disabled={false}
-        onClick={[Function]}
-      >
-        quality_profiles.change_projects
-      </Button>
-    </Tooltip>
-  </div>
-  <header
-    className="boxed-group-header"
-  >
-    <h2>
-      projects
-    </h2>
-  </header>
-  <div
-    className="boxed-group-inner"
-  >
-    <i
-      className="spinner"
-    />
-  </div>
-</div>
-`;
-
-exports[`should render correctly: no active rules, but associated projects 1`] = `
-<div
-  className="boxed-group quality-profile-projects"
->
-  <div
-    className="boxed-group-actions"
-  >
-    <Tooltip
-      overlay="quality_profiles.cannot_associate_projects_no_rules"
-    >
-      <Button
-        className="js-change-projects"
-        disabled={true}
-        onClick={[Function]}
-      >
-        quality_profiles.change_projects
-      </Button>
-    </Tooltip>
-  </div>
-  <header
-    className="boxed-group-header"
-  >
-    <h2>
-      projects
-    </h2>
-  </header>
-  <div
-    className="boxed-group-inner"
-  >
-    <ul>
-      <li
-        className="spacer-top js-profile-project"
-        data-key="org.sonarsource.xml:xml"
-        key="org.sonarsource.xml:xml"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "pathname": "/dashboard",
-              "search": "?id=org.sonarsource.xml%3Axml",
-            }
-          }
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            SonarXML
-          </span>
-        </ForwardRef(Link)>
-      </li>
-    </ul>
-    <ListFooter
-      count={1}
-      loadMore={[Function]}
-      ready={true}
-      total={10}
-    />
-  </div>
-</div>
-`;
-
-exports[`should render correctly: no active rules, no associated projects 1`] = `
-<div
-  className="boxed-group quality-profile-projects"
->
-  <div
-    className="boxed-group-actions"
-  >
-    <Tooltip
-      overlay="quality_profiles.cannot_associate_projects_no_rules"
-    >
-      <Button
-        className="js-change-projects"
-        disabled={true}
-        onClick={[Function]}
-      >
-        quality_profiles.change_projects
-      </Button>
-    </Tooltip>
-  </div>
-  <header
-    className="boxed-group-header"
-  >
-    <h2>
-      projects
-    </h2>
-  </header>
-  <div
-    className="boxed-group-inner"
-  >
-    <div>
-      quality_profiles.cannot_associate_projects_no_rules
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should render correctly: no rights 1`] = `
-<div
-  className="boxed-group quality-profile-projects"
->
-  <header
-    className="boxed-group-header"
-  >
-    <h2>
-      projects
-    </h2>
-  </header>
-  <div
-    className="boxed-group-inner"
-  >
-    <ul>
-      <li
-        className="spacer-top js-profile-project"
-        data-key="org.sonarsource.xml:xml"
-        key="org.sonarsource.xml:xml"
-      >
-        <ForwardRef(Link)
-          to={
-            {
-              "pathname": "/dashboard",
-              "search": "?id=org.sonarsource.xml%3Axml",
-            }
-          }
-        >
-          <QualifierIcon
-            qualifier="TRK"
-          />
-           
-          <span>
-            SonarXML
-          </span>
-        </ForwardRef(Link)>
-      </li>
-    </ul>
-    <ListFooter
-      count={1}
-      loadMore={[Function]}
-      ready={true}
-      total={10}
-    />
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap
deleted file mode 100644 (file)
index cd08c5b..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render the quality profiles rules with sonarway comparison 1`] = `
-<div
-  className="boxed-group quality-profile-rules"
->
-  <div
-    className="quality-profile-rules-distribution"
-  >
-    <table
-      className="data condensed"
-    >
-      <thead>
-        <tr>
-          <th>
-            <h2>
-              rules
-            </h2>
-          </th>
-          <th>
-            active
-          </th>
-          <th>
-            inactive
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <ProfileRulesRowTotal
-          count={68}
-          qprofile="key"
-          total={253}
-        />
-        <ProfileRulesRowOfType
-          count={68}
-          key="BUG"
-          qprofile="key"
-          total={68}
-          type="BUG"
-        />
-        <ProfileRulesRowOfType
-          count={0}
-          key="VULNERABILITY"
-          qprofile="key"
-          total={7}
-          type="VULNERABILITY"
-        />
-        <ProfileRulesRowOfType
-          count={0}
-          key="CODE_SMELL"
-          qprofile="key"
-          total={168}
-          type="CODE_SMELL"
-        />
-        <ProfileRulesRowOfType
-          count={0}
-          key="SECURITY_HOTSPOT"
-          qprofile="key"
-          total={10}
-          type="SECURITY_HOTSPOT"
-        />
-      </tbody>
-    </table>
-  </div>
-  <ProfileRulesSonarWayComparison
-    language="js"
-    profile="key"
-    sonarWayMissingRules={4}
-    sonarway="sonarway"
-  />
-</div>
-`;
-
-exports[`should show a button to activate more rules for admins 1`] = `
-<ForwardRef(Link)
-  className="button js-activate-rules"
-  to={
-    {
-      "pathname": "/coding_rules",
-      "search": "?qprofile=key&activation=false",
-    }
-  }
->
-  quality_profiles.activate_more
-</ForwardRef(Link)>
-`;
-
-exports[`should show a deprecated rules warning message 1`] = `
-<ProfileRulesDeprecatedWarning
-  activeDeprecatedRules={8}
-  profile="key"
-/>
-`;
-
-exports[`should show a disabled button to activate more rules for built-in profiles 1`] = `
-<Button
-  className="disabled js-activate-rules"
->
-  quality_profiles.activate_more
-</Button>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap
deleted file mode 100644 (file)
index 4c54538..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="quality-profile-rules-deprecated clearfix"
->
-  <span
-    className="pull-left"
-  >
-    <span
-      className="text-middle"
-    >
-      quality_profiles.deprecated_rules
-    </span>
-    <HelpTooltip
-      className="spacer-left"
-      overlay="quality_profiles.deprecated_rules_description"
-    />
-  </span>
-  <ForwardRef(Link)
-    className="pull-right"
-    to={
-      {
-        "pathname": "/coding_rules",
-        "search": "?qprofile=bar&activation=true&statuses=DEPRECATED",
-      }
-    }
-  >
-    18
-  </ForwardRef(Link)>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowOfType-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowOfType-test.tsx.snap
deleted file mode 100644 (file)
index 057ce49..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<tr>
-  <td>
-    <span>
-      <IssueTypeIcon
-        className="little-spacer-right"
-        query="BUG"
-      />
-      issue.type.BUG.plural
-    </span>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true&types=BUG",
-        }
-      }
-    >
-      3
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      className="small"
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=false&types=BUG",
-        }
-      }
-    >
-      7
-    </ForwardRef(Link)>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly if there is 0 rules 1`] = `
-<tr>
-  <td>
-    <span>
-      <IssueTypeIcon
-        className="little-spacer-right"
-        query="VULNERABILITY"
-      />
-      issue.type.VULNERABILITY.plural
-    </span>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true&types=VULNERABILITY",
-        }
-      }
-    >
-      0
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <span
-      className="note"
-    >
-      0
-    </span>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly if there is missing data 1`] = `
-<tr>
-  <td>
-    <span>
-      <IssueTypeIcon
-        className="little-spacer-right"
-        query="VULNERABILITY"
-      />
-      issue.type.VULNERABILITY.plural
-    </span>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true&types=VULNERABILITY",
-        }
-      }
-    >
-      5
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  />
-</tr>
-`;
-
-exports[`should render correctly if there is missing data 2`] = `
-<tr>
-  <td>
-    <span>
-      <IssueTypeIcon
-        className="little-spacer-right"
-        query="VULNERABILITY"
-      />
-      issue.type.VULNERABILITY.plural
-    </span>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  />
-  <td
-    className="thin nowrap text-right"
-  />
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowTotal-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowTotal-test.tsx.snap
deleted file mode 100644 (file)
index a8929ba..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<tr>
-  <td>
-    <strong>
-      total
-    </strong>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true",
-        }
-      }
-    >
-      <strong>
-        3
-      </strong>
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      className="small"
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=false",
-        }
-      }
-    >
-      <strong>
-        7
-      </strong>
-    </ForwardRef(Link)>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly if there is 0 rules 1`] = `
-<tr>
-  <td>
-    <strong>
-      total
-    </strong>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true",
-        }
-      }
-    >
-      <strong>
-        0
-      </strong>
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <span
-      className="note"
-    >
-      0
-    </span>
-  </td>
-</tr>
-`;
-
-exports[`should render correctly if there is missing data 1`] = `
-<tr>
-  <td>
-    <strong>
-      total
-    </strong>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  >
-    <ForwardRef(Link)
-      to={
-        {
-          "pathname": "/coding_rules",
-          "search": "?qprofile=bar&activation=true",
-        }
-      }
-    >
-      <strong>
-        5
-      </strong>
-    </ForwardRef(Link)>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  />
-</tr>
-`;
-
-exports[`should render correctly if there is missing data 2`] = `
-<tr>
-  <td>
-    <strong>
-      total
-    </strong>
-  </td>
-  <td
-    className="thin nowrap text-right"
-  />
-  <td
-    className="thin nowrap text-right"
-  />
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap
deleted file mode 100644 (file)
index 222db87..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="quality-profile-rules-sonarway-missing clearfix"
->
-  <span
-    className="pull-left"
-  >
-    <span
-      className="text-middle"
-    >
-      quality_profiles.sonarway_missing_rules
-    </span>
-    <HelpTooltip
-      className="spacer-left"
-      overlay="quality_profiles.sonarway_missing_rules_description"
-    />
-  </span>
-  <ForwardRef(Link)
-    className="pull-right"
-    data-test="rules"
-    to={
-      {
-        "pathname": "/coding_rules",
-        "search": "?qprofile=bar&activation=false&compareToProfile=baz&languages=Java",
-      }
-    }
-  >
-    158
-  </ForwardRef(Link)>
-</div>
-`;
index 71f6f0b38e43737c042a697165ea4a1b226947ed..c3f583f44b393e2268660088fa66b4b3e8880fd2 100644 (file)
@@ -106,7 +106,10 @@ export default class EvolutionDeprecated extends React.PureComponent<Props> {
     const sortedProfiles = sortBy(profilesWithDeprecations, (p) => -p.activeDeprecatedRuleCount);
 
     return (
-      <div className="boxed-group boxed-group-inner quality-profiles-evolution-deprecated">
+      <section
+        className="boxed-group boxed-group-inner quality-profiles-evolution-deprecated"
+        aria-label={translate('quality_profiles.deprecated_rules')}
+      >
         <h2 className="h4 spacer-bottom">{translate('quality_profiles.deprecated_rules')}</h2>
         <div className="spacer-bottom">
           {translateWithParameters(
@@ -144,7 +147,7 @@ export default class EvolutionDeprecated extends React.PureComponent<Props> {
             </li>
           ))}
         </ul>
-      </div>
+      </section>
     );
   }
 }
index d45a5ebb11b449261e15726a2e0b6dd776eec3ab..2386566554a739a726713532d0171393755c62fa 100644 (file)
@@ -106,7 +106,10 @@ export default class EvolutionRules extends React.PureComponent<{}, State> {
     )}`;
 
     return (
-      <div className="boxed-group boxed-group-inner quality-profiles-evolution-rules">
+      <section
+        className="boxed-group boxed-group-inner quality-profiles-evolution-rules"
+        aria-label={newRulesTitle}
+      >
         <h2 className="h4 spacer-bottom">{newRulesTitle}</h2>
         <ul>
           {latestRules.map((rule) => (
@@ -143,7 +146,7 @@ export default class EvolutionRules extends React.PureComponent<{}, State> {
             </Link>
           </div>
         )}
-      </div>
+      </section>
     );
   }
 }
index bd7f3e1c5326b02edf2bb1821d949dac466c4f11..e5a1d5e4d266dd892670d37683b0c0a2e92f6ada 100644 (file)
@@ -36,7 +36,10 @@ export default function EvolutionStagnant(props: Props) {
   }
 
   return (
-    <div className="boxed-group boxed-group-inner quality-profiles-evolution-stagnant">
+    <section
+      className="boxed-group boxed-group-inner quality-profiles-evolution-stagnant"
+      aria-label={translate('quality_profiles.stagnant_profiles')}
+    >
       <h2 className="h4 spacer-bottom">{translate('quality_profiles.stagnant_profiles')}</h2>
       <div className="spacer-bottom">
         {translate('quality_profiles.not_updated_more_than_year')}
@@ -69,6 +72,6 @@ export default function EvolutionStagnant(props: Props) {
           </li>
         ))}
       </ul>
-    </div>
+    </section>
   );
 }
index b1e9213ec2c42398b3c1aea6e53aff6aca077cf4..a6b24b8b6f05c426c7f6b5454ae2c4b4eb8f1d13 100644 (file)
@@ -19,8 +19,8 @@
  */
 import * as React from 'react';
 import { restoreQualityProfile } from '../../../api/quality-profiles';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import Modal from '../../../components/controls/Modal';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
 import { Alert } from '../../../components/ui/Alert';
 import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
 import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/Evolution-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/Evolution-test.tsx
deleted file mode 100644 (file)
index 2df1a59..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import Evolution, { EvolutionProps } from '../Evolution';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<EvolutionProps> = {}) {
-  return shallow(<Evolution profiles={[]} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/EvolutionDeprecated-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/EvolutionDeprecated-test.tsx
deleted file mode 100644 (file)
index 1eef0c4..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockQualityProfile } from '../../../../helpers/testMocks';
-import EvolutionDeprecated from '../EvolutionDeprecated';
-
-it('should render correctly', () => {
-  const wrapper = shallow(
-    <EvolutionDeprecated
-      profiles={[
-        mockQualityProfile({
-          key: 'qp-1',
-          name: 'Quality Profile 1',
-          activeDeprecatedRuleCount: 0,
-        }),
-        mockQualityProfile({
-          key: 'qp-2',
-          name: 'Quality Profile 2',
-          childrenCount: 1,
-          activeDeprecatedRuleCount: 2,
-        }),
-        mockQualityProfile({
-          key: 'qp-3',
-          name: 'Quality Profile 3',
-          depth: 2,
-          activeDeprecatedRuleCount: 2,
-          parentKey: 'qp-2',
-        }),
-        mockQualityProfile({
-          key: 'qp-4',
-          name: 'Quality Profile 4',
-          depth: 3,
-          activeDeprecatedRuleCount: 3,
-          parentKey: 'qp-3',
-        }),
-        mockQualityProfile({
-          key: 'qp-5',
-          name: 'Quality Profile 5',
-          depth: 4,
-          activeDeprecatedRuleCount: 4,
-          parentKey: 'qp-4',
-        }),
-      ]}
-    />
-  );
-  expect(wrapper).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx
deleted file mode 100644 (file)
index 5d1e905..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import {
-  mockLanguage,
-  mockLocation,
-  mockQualityProfile,
-  mockRouter,
-} from '../../../../helpers/testMocks';
-import { click } from '../../../../helpers/testUtils';
-import { PageHeader } from '../PageHeader';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(shallowRender({ actions: { create: true } })).toMatchSnapshot();
-  expect(shallowRender({ actions: { create: true }, languages: [] })).toMatchSnapshot();
-});
-
-it('should show a create form', () => {
-  const wrapper = shallowRender({ actions: { create: true } });
-  click(wrapper.find('#quality-profiles-create'));
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should show a restore form', () => {
-  const wrapper = shallowRender({ actions: { create: true } });
-  click(wrapper.find('#quality-profiles-restore'));
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<PageHeader['props']> = {}) {
-  return shallow(
-    <PageHeader
-      actions={{ create: false }}
-      languages={[mockLanguage()]}
-      location={mockLocation()}
-      profiles={[mockQualityProfile()]}
-      router={mockRouter()}
-      updateProfiles={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx
deleted file mode 100644 (file)
index 4f94850..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import { mockRouter } from '../../../../helpers/testMocks';
-import { ProfilesListHeader } from '../ProfilesListHeader';
-
-it('should render correctly', () => {
-  const wrapper = shallowRender();
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ProfilesListHeader['props']> = {}) {
-  return shallow<ProfilesListHeader>(
-    <ProfilesListHeader
-      languages={[
-        { key: 'js', name: 'JavaScript' },
-        { key: 'java', name: 'Java' },
-      ]}
-      router={mockRouter()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/RestoreProfileForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/RestoreProfileForm-test.tsx
deleted file mode 100644 (file)
index e9d3cbe..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 { shallow } from 'enzyme';
-import * as React from 'react';
-import RestoreProfileForm from '../RestoreProfileForm';
-
-it('should render correctly', () => {
-  expect(
-    shallow(<RestoreProfileForm onClose={jest.fn()} onRestore={jest.fn()} />)
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/Evolution-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/Evolution-test.tsx.snap
deleted file mode 100644 (file)
index 088705e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="quality-profiles-evolution"
->
-  <EvolutionDeprecated
-    profiles={[]}
-  />
-  <EvolutionStagnant
-    profiles={[]}
-  />
-  <EvolutionRules />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/EvolutionDeprecated-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/EvolutionDeprecated-test.tsx.snap
deleted file mode 100644 (file)
index 3fb130a..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="boxed-group boxed-group-inner quality-profiles-evolution-deprecated"
->
-  <h2
-    className="h4 spacer-bottom"
-  >
-    quality_profiles.deprecated_rules
-  </h2>
-  <div
-    className="spacer-bottom"
-  >
-    quality_profiles.deprecated_rules_are_still_activated.4
-  </div>
-  <ul>
-    <li
-      className="spacer-top"
-      key="qp-5"
-    >
-      <div
-        className="text-ellipsis little-spacer-bottom"
-      >
-        <ProfileLink
-          language="js"
-          name="Quality Profile 5"
-        >
-          Quality Profile 5
-        </ProfileLink>
-      </div>
-      <div
-        className="note"
-      >
-        JavaScript
-        , 
-        <ForwardRef(Link)
-          aria-label="quality_profile.lang_deprecated_x_rules.JavaScript.4"
-          className="link-no-underline"
-          to={
-            {
-              "pathname": "/coding_rules",
-              "search": "?qprofile=qp-5&activation=true&statuses=DEPRECATED",
-            }
-          }
-        >
-          quality_profile.x_rules.4
-        </ForwardRef(Link)>
-        <div
-          key="qp-2"
-        >
-           
-          coding_rules.filters.inheritance.x_inherited_from_y.2.Quality Profile 2
-        </div>
-        <div
-          key="qp-4"
-        >
-           
-          coding_rules.filters.inheritance.x_inherited_from_y.1.Quality Profile 4
-        </div>
-      </div>
-    </li>
-    <li
-      className="spacer-top"
-      key="qp-4"
-    >
-      <div
-        className="text-ellipsis little-spacer-bottom"
-      >
-        <ProfileLink
-          language="js"
-          name="Quality Profile 4"
-        >
-          Quality Profile 4
-        </ProfileLink>
-      </div>
-      <div
-        className="note"
-      >
-        JavaScript
-        , 
-        <ForwardRef(Link)
-          aria-label="quality_profile.lang_deprecated_x_rules.JavaScript.3"
-          className="link-no-underline"
-          to={
-            {
-              "pathname": "/coding_rules",
-              "search": "?qprofile=qp-4&activation=true&statuses=DEPRECATED",
-            }
-          }
-        >
-          quality_profile.x_rules.3
-        </ForwardRef(Link)>
-        <div
-          key="qp-2"
-        >
-           
-          coding_rules.filters.inheritance.x_inherited_from_y.2.Quality Profile 2
-        </div>
-      </div>
-    </li>
-    <li
-      className="spacer-top"
-      key="qp-2"
-    >
-      <div
-        className="text-ellipsis little-spacer-bottom"
-      >
-        <ProfileLink
-          language="js"
-          name="Quality Profile 2"
-        >
-          Quality Profile 2
-        </ProfileLink>
-      </div>
-      <div
-        className="note"
-      >
-        JavaScript
-        , 
-        <ForwardRef(Link)
-          aria-label="quality_profile.lang_deprecated_x_rules.JavaScript.2"
-          className="link-no-underline"
-          to={
-            {
-              "pathname": "/coding_rules",
-              "search": "?qprofile=qp-2&activation=true&statuses=DEPRECATED",
-            }
-          }
-        >
-          quality_profile.x_rules.2
-        </ForwardRef(Link)>
-      </div>
-    </li>
-    <li
-      className="spacer-top"
-      key="qp-3"
-    >
-      <div
-        className="text-ellipsis little-spacer-bottom"
-      >
-        <ProfileLink
-          language="js"
-          name="Quality Profile 3"
-        >
-          Quality Profile 3
-        </ProfileLink>
-      </div>
-      <div
-        className="note"
-      >
-        JavaScript
-        , 
-        <ForwardRef(Link)
-          aria-label="quality_profile.lang_deprecated_x_rules.JavaScript.2"
-          className="link-no-underline"
-          to={
-            {
-              "pathname": "/coding_rules",
-              "search": "?qprofile=qp-3&activation=true&statuses=DEPRECATED",
-            }
-          }
-        >
-          quality_profile.x_rules.2
-        </ForwardRef(Link)>
-        <div
-          key="qp-2"
-        >
-           
-          coding_rules.filters.inheritance.x_inherited_from_y.2.Quality Profile 2
-        </div>
-      </div>
-    </li>
-  </ul>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
deleted file mode 100644 (file)
index f0c9b17..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<header
-  className="page-header"
->
-  <h1
-    className="page-title"
-  >
-    quality_profiles.page
-  </h1>
-  <div
-    className="page-description markdown"
-  >
-    quality_profiles.intro1
-    <br />
-    quality_profiles.intro2
-    <DocLink
-      className="spacer-left"
-      to="/instance-administration/quality-profiles/"
-    >
-      learn_more
-    </DocLink>
-  </div>
-</header>
-`;
-
-exports[`should render correctly 2`] = `
-<header
-  className="page-header"
->
-  <h1
-    className="page-title"
-  >
-    quality_profiles.page
-  </h1>
-  <div
-    className="page-actions"
-  >
-    <Button
-      disabled={false}
-      id="quality-profiles-create"
-      onClick={[Function]}
-    >
-      create
-    </Button>
-    <Button
-      className="little-spacer-left"
-      id="quality-profiles-restore"
-      onClick={[Function]}
-    >
-      restore
-    </Button>
-  </div>
-  <div
-    className="page-description markdown"
-  >
-    quality_profiles.intro1
-    <br />
-    quality_profiles.intro2
-    <DocLink
-      className="spacer-left"
-      to="/instance-administration/quality-profiles/"
-    >
-      learn_more
-    </DocLink>
-  </div>
-</header>
-`;
-
-exports[`should render correctly 3`] = `
-<header
-  className="page-header"
->
-  <h1
-    className="page-title"
-  >
-    quality_profiles.page
-  </h1>
-  <div
-    className="page-actions"
-  >
-    <Button
-      disabled={true}
-      id="quality-profiles-create"
-      onClick={[Function]}
-    >
-      create
-    </Button>
-    <Button
-      className="little-spacer-left"
-      id="quality-profiles-restore"
-      onClick={[Function]}
-    >
-      restore
-    </Button>
-    <Alert
-      className="spacer-top"
-      variant="warning"
-    >
-      quality_profiles.no_languages_available
-    </Alert>
-  </div>
-  <div
-    className="page-description markdown"
-  >
-    quality_profiles.intro1
-    <br />
-    quality_profiles.intro2
-    <DocLink
-      className="spacer-left"
-      to="/instance-administration/quality-profiles/"
-    >
-      learn_more
-    </DocLink>
-  </div>
-</header>
-`;
-
-exports[`should show a create form 1`] = `
-<header
-  className="page-header"
->
-  <h1
-    className="page-title"
-  >
-    quality_profiles.page
-  </h1>
-  <div
-    className="page-actions"
-  >
-    <Button
-      disabled={false}
-      id="quality-profiles-create"
-      onClick={[Function]}
-    >
-      create
-    </Button>
-    <Button
-      className="little-spacer-left"
-      id="quality-profiles-restore"
-      onClick={[Function]}
-    >
-      restore
-    </Button>
-  </div>
-  <div
-    className="page-description markdown"
-  >
-    quality_profiles.intro1
-    <br />
-    quality_profiles.intro2
-    <DocLink
-      className="spacer-left"
-      to="/instance-administration/quality-profiles/"
-    >
-      learn_more
-    </DocLink>
-  </div>
-  <CreateProfileForm
-    languages={
-      [
-        {
-          "key": "css",
-          "name": "CSS",
-        },
-      ]
-    }
-    location={
-      {
-        "hash": "",
-        "key": "key",
-        "pathname": "/path",
-        "query": {},
-        "search": "",
-        "state": {},
-      }
-    }
-    onClose={[Function]}
-    onCreate={[Function]}
-    profiles={
-      [
-        {
-          "activeDeprecatedRuleCount": 2,
-          "activeRuleCount": 10,
-          "childrenCount": 0,
-          "depth": 1,
-          "isBuiltIn": false,
-          "isDefault": false,
-          "isInherited": false,
-          "key": "key",
-          "language": "js",
-          "languageName": "JavaScript",
-          "name": "name",
-          "projectCount": 3,
-        },
-      ]
-    }
-  />
-</header>
-`;
-
-exports[`should show a restore form 1`] = `
-<header
-  className="page-header"
->
-  <h1
-    className="page-title"
-  >
-    quality_profiles.page
-  </h1>
-  <div
-    className="page-actions"
-  >
-    <Button
-      disabled={false}
-      id="quality-profiles-create"
-      onClick={[Function]}
-    >
-      create
-    </Button>
-    <Button
-      className="little-spacer-left"
-      id="quality-profiles-restore"
-      onClick={[Function]}
-    >
-      restore
-    </Button>
-  </div>
-  <div
-    className="page-description markdown"
-  >
-    quality_profiles.intro1
-    <br />
-    quality_profiles.intro2
-    <DocLink
-      className="spacer-left"
-      to="/instance-administration/quality-profiles/"
-    >
-      learn_more
-    </DocLink>
-  </div>
-  <RestoreProfileForm
-    onClose={[Function]}
-    onRestore={[MockFunction]}
-  />
-</header>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap
deleted file mode 100644 (file)
index 82c185c..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="quality-profiles-list-header clearfix"
->
-  <label
-    className="spacer-right"
-    htmlFor="quality-profiles-filter-input"
-  >
-    quality_profiles.filter_by
-    :
-  </label>
-  <Select
-    autoFocus={true}
-    className="input-medium"
-    id="quality-profiles-filter"
-    inputId="quality-profiles-filter-input"
-    isClearable={true}
-    isSearchable={true}
-    onChange={[Function]}
-    options={
-      [
-        {
-          "label": "JavaScript",
-          "value": "js",
-        },
-        {
-          "label": "Java",
-          "value": "java",
-        },
-      ]
-    }
-    value={[]}
-  />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/RestoreProfileForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/RestoreProfileForm-test.tsx.snap
deleted file mode 100644 (file)
index 725377d..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Modal
-  contentLabel="quality_profiles.restore_profile"
-  onRequestClose={[MockFunction]}
-  size="small"
->
-  <form
-    id="restore-profile-form"
-    onSubmit={[Function]}
-  >
-    <div
-      className="modal-head"
-    >
-      <h2>
-        quality_profiles.restore_profile
-      </h2>
-    </div>
-    <div
-      className="modal-body"
-    >
-      <MandatoryFieldsExplanation
-        className="modal-field"
-      />
-      <div
-        className="modal-field"
-      >
-        <label
-          htmlFor="restore-profile-backup"
-        >
-          backup
-          <MandatoryFieldMarker />
-        </label>
-        <input
-          id="restore-profile-backup"
-          name="backup"
-          required={true}
-          type="file"
-        />
-      </div>
-    </div>
-    <div
-      className="modal-foot"
-    >
-      <SubmitButton
-        disabled={false}
-        id="restore-profile-submit"
-      >
-        restore
-      </SubmitButton>
-      <ResetButtonLink
-        id="restore-profile-cancel"
-        onClick={[MockFunction]}
-      >
-        cancel
-      </ResetButtonLink>
-    </div>
-  </form>
-</Modal>
-`;
index a7cd47718566780961848414d9b41909e7319ab3..946cd3ead252be173d9dc359a8b5b20ce1488d4b 100644 (file)
@@ -33,7 +33,7 @@ export interface Exporter {
 
 export interface ProfileChangelogEvent {
   action: string;
-  authorName: string;
+  authorName?: string;
   date: string;
   params?: Dict<string | null>;
   ruleKey: string;
index b3948def2ca0c8814372eab36f9ba538f25c3945..735d6da13f8933c14cbe7ff708e81f67eef00645 100644 (file)
@@ -20,7 +20,7 @@
 import { To } from 'react-router-dom';
 import { CompareResponse } from '../api/quality-profiles';
 import { RuleDescriptionSections } from '../apps/coding-rules/rule';
-import { Exporter, Profile } from '../apps/quality-profiles/types';
+import { Exporter, Profile, ProfileChangelogEvent } from '../apps/quality-profiles/types';
 import { LogsLevels } from '../apps/system/utils';
 import { Location, Router } from '../components/hoc/withRouter';
 import { AppState } from '../types/appstate';
@@ -54,6 +54,7 @@ import {
   SysInfoLogging,
   SysInfoStandalone,
   UserGroupMember,
+  UserSelected,
 } from '../types/types';
 import { CurrentUser, LoggedInUser, User } from '../types/users';
 
@@ -500,7 +501,9 @@ export function mockQualityProfileInheritance(
   };
 }
 
-export function mockQualityProfileChangelogEvent(eventOverride?: any) {
+export function mockQualityProfileChangelogEvent(
+  eventOverride?: Partial<ProfileChangelogEvent>
+): ProfileChangelogEvent {
   return {
     action: 'ACTIVATED',
     date: '2019-04-23T02:12:32+0100',
@@ -677,6 +680,16 @@ export function mockUser(overrides: Partial<User> = {}): User {
   };
 }
 
+export function mockUserSelected(overrides: Partial<UserSelected> = {}): UserSelected {
+  return {
+    active: true,
+    login: 'john.doe',
+    name: 'John Doe',
+    selected: true,
+    ...overrides,
+  };
+}
+
 export function mockUserGroupMember(overrides: Partial<UserGroupMember> = {}): UserGroupMember {
   return {
     login: 'john.doe',
index b4eb9e98c49ecebc4ae586bf6c91db791acb0d32..79aa25884c05734381202a7909c4ec960460d1d0 100644 (file)
@@ -1938,10 +1938,12 @@ quality_profiles.default_permissions=Users with the global "Administer Quality P
 quality_profiles.grant_permissions_to_more_users=Grant permissions to more users
 quality_profiles.grant_permissions_to_user_or_group=Grant permissions to a user or a group
 quality_profiles.additional_user_groups=Additional users / groups:
-quality_profiles.search_description=Search users by login or name, and groups by name:
+quality_profiles.search_description=Search users by login or name, and groups by name: 
 quality_profiles.permissions.remove.user=Remove permission from user
+quality_profiles.permissions.remove.user_x=Remove permission from user {0}
 quality_profiles.permissions.remove.user.confirmation=Are you sure you want to remove permission on this quality profile from user {user}?
 quality_profiles.permissions.remove.group=Remove permission from group
+quality_profiles.permissions.remove.group_x=Remove permission for {0}
 quality_profiles.permissions.remove.group.confirmation=Are you sure you want to remove permission on this quality profile from group {user}?
 quality_profiles.copy_help=Create a new quality profile as a replica of "{0}".  The two profiles will then evolve independently.
 quality_profiles.extend_help=Create a child quality profile inheriting all active rules from "{0}". Changes to "{0}" will impact the child profile.