aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguillaume-peoch-sonarsource <guillaume.peoch@sonarsource.com>2023-07-04 17:53:54 +0200
committersonartech <sonartech@sonarsource.com>2023-07-18 20:03:22 +0000
commit5ebbed2a0f508d5bef63de4ed1e89a57e67e25df (patch)
tree9685cdca497f78821ca199c71931ec6bf1a9e0d4
parentee95bb3b3db83bbadf265c850138134bd740ecf3 (diff)
downloadsonarqube-5ebbed2a0f508d5bef63de4ed1e89a57e67e25df.tar.gz
sonarqube-5ebbed2a0f508d5bef63de4ed1e89a57e67e25df.zip
SONAR-18441 RTL migration for Quality Profiles
-rw-r--r--server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts444
-rw-r--r--server/sonar-web/src/main/js/api/quality-profiles.ts7
-rw-r--r--server/sonar-web/src/main/js/api/rules.ts5
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx513
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx190
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx100
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx140
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-test.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.tsx28
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.tsx29
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogContainer-test.tsx.snap95
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap24
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx12
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/BuiltInQualityProfileBadge-test.tsx31
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/DeleteProfileForm-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx342
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/QualityProfilesApp-test.tsx94
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/BuiltInQualityProfileBadge-test.tsx.snap21
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/DeleteProfileForm-test.tsx.snap134
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/ProfileActions-test.tsx.snap392
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/QualityProfilesApp-test.tsx.snap47
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeParentForm-test.tsx69
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeProjectsForm-test.tsx102
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileExporters-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritance-test.tsx69
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritanceBox-test.tsx49
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx119
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsForm-test.tsx96
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsFormSelect-test.tsx95
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx64
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx87
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx150
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesDeprecatedWarning-test.tsx28
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowOfType-test.tsx43
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowTotal-test.tsx37
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesSonarWayComparison-test.tsx35
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeParentForm-test.tsx.snap97
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeProjectsForm-test.tsx.snap79
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap506
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileExporters-test.tsx.snap34
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritance-test.tsx.snap147
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritanceBox-test.tsx.snap136
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap93
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap230
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap78
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsGroup-test.tsx.snap28
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsUser-test.tsx.snap29
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap247
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap101
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap32
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowOfType-test.tsx.snap132
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowTotal-test.tsx.snap124
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap33
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/Evolution-test.tsx30
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/EvolutionDeprecated-test.tsx65
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx61
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx41
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/RestoreProfileForm-test.tsx28
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/Evolution-test.tsx.snap15
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/EvolutionDeprecated-test.tsx.snap176
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap248
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap37
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/RestoreProfileForm-test.tsx.snap61
-rw-r--r--server/sonar-web/src/main/js/apps/quality-profiles/types.ts2
-rw-r--r--server/sonar-web/src/main/js/helpers/testMocks.ts17
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties4
87 files changed, 1288 insertions, 5845 deletions
diff --git a/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
index 372d7afe666..38102654660 100644
--- a/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
+++ b/server/sonar-web/src/main/js/api/mocks/QualityProfilesServiceMock.ts
@@ -18,14 +18,19 @@
* 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> {
diff --git a/server/sonar-web/src/main/js/api/quality-profiles.ts b/server/sonar-web/src/main/js/api/quality-profiles.ts
index 5f1d0090082..8e87cbe5107 100644
--- a/server/sonar-web/src/main/js/api/quality-profiles.ts
+++ b/server/sonar-web/src/main/js/api/quality-profiles.ts
@@ -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
diff --git a/server/sonar-web/src/main/js/api/rules.ts b/server/sonar-web/src/main/js/api/rules.ts
index 4ae50959e67..beb06283727 100644
--- a/server/sonar-web/src/main/js/api/rules.ts
+++ b/server/sonar-web/src/main/js/api/rules.ts
@@ -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
index 00000000000..7f8209579f8
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfileApp-it.tsx
@@ -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, {});
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
index a3fa9b46259..057dff8439e 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/__tests__/QualityProfilesApp-it.tsx
@@ -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 () => {
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx
index 61b0b3d4ef5..c2e38caeefd 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/ChangelogContainer.tsx
@@ -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
index 2834f8a31a2..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/Changelog-test.tsx
+++ /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
index 00000000000..19a0cc1d802
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-it.tsx
@@ -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
index 2e94f5d342a..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogContainer-test.tsx
+++ /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
index 94ce4da9398..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangelogSearch-test.tsx
+++ /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
index b50236cc336..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ChangesList-test.tsx
+++ /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
index e2f6587c874..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/ParameterChange-test.tsx
+++ /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
index 68a932cb4f4..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/SeverityChange-test.tsx
+++ /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
index b9549ee78b8..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogContainer-test.tsx.snap
+++ /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
index 77833089973..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/changelog/__tests__/__snapshots__/ChangelogSearch-test.tsx.snap
+++ /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
index e36f1ccf113..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonEmpty.tsx
+++ /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>;
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
index dde41ffd05f..9b3c925f815 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/compare/ComparisonResults.tsx
@@ -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 (
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx
index e27eceb397e..c57b6162977 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileActions.tsx
@@ -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,
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx
index 91ca77c9a25..b00ece4ea3f 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/components/ProfileModalForm.tsx
@@ -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
index 99d20926cf8..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/BuiltInQualityProfileBadge-test.tsx
+++ /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
index ca7ccc50d91..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/DeleteProfileForm-test.tsx
+++ /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
index 4a596640b4f..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/ProfileActions-test.tsx
+++ /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
index 616750fd1ab..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/QualityProfilesApp-test.tsx
+++ /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
index 823cfbafac1..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/BuiltInQualityProfileBadge-test.tsx.snap
+++ /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
index d24c01159c2..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/DeleteProfileForm-test.tsx.snap
+++ /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
index 2b7d547e5b0..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/ProfileActions-test.tsx.snap
+++ /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
index 791f5c37ced..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/__snapshots__/QualityProfilesApp-test.tsx.snap
+++ /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>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
index 632dc2336bf..c6a5e7ef240 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ChangeParentForm.tsx
@@ -19,10 +19,10 @@
*/
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';
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx
index 17361d35553..29032b3b215 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileDetails.tsx
@@ -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} />
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx
index a8569f1c1cd..baf9b2c1f66 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileExporters.tsx
@@ -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>
);
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
index 31a5e739521..c8f0b62b6b6 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileInheritance.tsx
@@ -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>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
index 4d939290446..00d35805c0d 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissions.tsx
@@ -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>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
index 2cbb49e7007..3b9cf80c7de 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsGroup.tsx
@@ -20,10 +20,10 @@
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}
/>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
index fc343d6e1e2..c12f76e8b4c 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfilePermissionsUser.tsx
@@ -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}
/>
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
index 59e19683ef8..a1447c0d1da 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileProjects.tsx
@@ -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>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
index b58616490df..18f521e76a4 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
@@ -20,12 +20,13 @@
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
index d8481629d34..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeParentForm-test.tsx
+++ /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
index d48a59bc77f..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ChangeProjectsForm-test.tsx
+++ /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
index 8de89c18ec4..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileDetails-test.tsx
+++ /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
index ca8d96a1520..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileExporters-test.tsx
+++ /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
index 88816590512..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritance-test.tsx
+++ /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
index 78143a90d02..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileInheritanceBox-test.tsx
+++ /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
index 37fd73766d2..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissions-test.tsx
+++ /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
index 69c079b8062..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsForm-test.tsx
+++ /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
index 8cffc0135d4..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsFormSelect-test.tsx
+++ /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
index 35bb7d46951..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsGroup-test.tsx
+++ /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
index 3f07228e2c4..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfilePermissionsUser-test.tsx
+++ /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
index c38aaeedff1..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileProjects-test.tsx
+++ /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
index 005c1a58f6b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRules-test.tsx
+++ /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
index 1d69d339ee3..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesDeprecatedWarning-test.tsx
+++ /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
index ba553ffa66d..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowOfType-test.tsx
+++ /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
index 547dd01ae9d..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesRowTotal-test.tsx
+++ /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
index 408e40249c4..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/ProfileRulesSonarWayComparison-test.tsx
+++ /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
index 74175891828..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeParentForm-test.tsx.snap
+++ /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
index 68a5559cfca..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ChangeProjectsForm-test.tsx.snap
+++ /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
index dabfc8c2481..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileDetails-test.tsx.snap
+++ /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
index 1f5eff13f09..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileExporters-test.tsx.snap
+++ /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
index 150831cc08e..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritance-test.tsx.snap
+++ /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
index 905d5f7b608..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileInheritanceBox-test.tsx.snap
+++ /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
index ce377a5cfa7..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissions-test.tsx.snap
+++ /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
index d5e25783a6b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsForm-test.tsx.snap
+++ /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
index d6b98558024..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsFormSelect-test.tsx.snap
+++ /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
index e44d1045924..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsGroup-test.tsx.snap
+++ /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
index a1fb25cecb6..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfilePermissionsUser-test.tsx.snap
+++ /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
index af24ef184d5..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileProjects-test.tsx.snap
+++ /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
index cd08c5b9d8e..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRules-test.tsx.snap
+++ /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
index 4c545386a0b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesDeprecatedWarning-test.tsx.snap
+++ /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
index 057ce492474..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowOfType-test.tsx.snap
+++ /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
index a8929baa77e..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesRowTotal-test.tsx.snap
+++ /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
index 222db872392..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/details/__tests__/__snapshots__/ProfileRulesSonarWayComparison-test.tsx.snap
+++ /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>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx
index 71f6f0b38e4..c3f583f44b3 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionDeprecated.tsx
@@ -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>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
index d45a5ebb11b..2386566554a 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionRules.tsx
@@ -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>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
index bd7f3e1c532..e5a1d5e4d26 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/EvolutionStagnant.tsx
@@ -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>
);
}
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
index b1e9213ec2c..a6b24b8b6f0 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/RestoreProfileForm.tsx
@@ -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
index 2df1a593437..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/Evolution-test.tsx
+++ /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
index 1eef0c4e032..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/EvolutionDeprecated-test.tsx
+++ /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
index 5d1e9057c8b..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/PageHeader-test.tsx
+++ /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
index 4f948502a3f..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesListHeader-test.tsx
+++ /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
index e9d3cbe6950..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/RestoreProfileForm-test.tsx
+++ /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
index 088705e5acd..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/Evolution-test.tsx.snap
+++ /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
index 3fb130a5d83..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/EvolutionDeprecated-test.tsx.snap
+++ /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
index f0c9b17a863..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/PageHeader-test.tsx.snap
+++ /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
index 82c185c43a3..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesListHeader-test.tsx.snap
+++ /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
index 725377d8d2a..00000000000
--- a/server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/RestoreProfileForm-test.tsx.snap
+++ /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>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/types.ts b/server/sonar-web/src/main/js/apps/quality-profiles/types.ts
index a7cd4771856..946cd3ead25 100644
--- a/server/sonar-web/src/main/js/apps/quality-profiles/types.ts
+++ b/server/sonar-web/src/main/js/apps/quality-profiles/types.ts
@@ -33,7 +33,7 @@ export interface Exporter {
export interface ProfileChangelogEvent {
action: string;
- authorName: string;
+ authorName?: string;
date: string;
params?: Dict<string | null>;
ruleKey: string;
diff --git a/server/sonar-web/src/main/js/helpers/testMocks.ts b/server/sonar-web/src/main/js/helpers/testMocks.ts
index b3948def2ca..735d6da13f8 100644
--- a/server/sonar-web/src/main/js/helpers/testMocks.ts
+++ b/server/sonar-web/src/main/js/helpers/testMocks.ts
@@ -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',
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index b4eb9e98c49..79aa25884c0 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -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.