| 'severities'
| 'repositories'
| 'qprofile'
+ | 'activation'
| 'sonarsourceSecurity'
| 'owaspTop10'
| 'owaspTop10-2021'
standardsToRules: Partial<{ [category in keyof Standards]: { [standard: string]: string[] } }> =
{};
- qualityProfilesToRules: { [qp: string]: string[] } = {};
-
constructor() {
this.repositories = [
mockRuleRepository({ key: 'repo1', name: 'Repository 1' }),
mockRuleRepository({ key: 'repo2', name: 'Repository 2' }),
];
this.qualityProfile = [
- mockQualityProfile({ key: 'p1', name: 'QP Foo', language: 'java', languageName: 'Java' }),
+ mockQualityProfile({
+ key: 'p1',
+ name: 'QP Foo',
+ language: 'java',
+ languageName: 'Java',
+ actions: { edit: true },
+ }),
mockQualityProfile({ key: 'p2', name: 'QP Bar', language: 'js' }),
mockQualityProfile({ key: 'p3', name: 'QP FooBar', language: 'java', languageName: 'Java' }),
mockQualityProfile({
],
templateKey: 'rule8',
}),
- // Keep this last
mockRuleDetails({
createdAt: '2022-12-16T17:26:54+0100',
key: 'rule10',
],
educationPrinciples: ['defense_in_depth', 'never_trust_user_input'],
}),
+ mockRuleDetails({
+ key: 'rule11',
+ type: 'BUG',
+ lang: 'java',
+ langName: 'Java',
+ name: 'Common java rule',
+ }),
];
this.defaultRulesActivations = {
},
};
- this.qualityProfilesToRules = {
- p3: ['rule1', 'rule2', 'rule3', 'rule4', 'rule5', 'rule6', 'rule7', 'rule8'],
- };
-
jest.mocked(updateRule).mockImplementation(this.handleUpdateRule);
jest.mocked(createRule).mockImplementation(this.handleCreateRule);
jest.mocked(deleteRule).mockImplementation(this.handleDeleteRule);
owaspTop10,
'owaspTop10-2021': owasp2021Top10,
cwe,
+ activation,
}: FacetFilter) {
let filteredRules = this.rules;
if (types) {
if (severities) {
filteredRules = filteredRules.filter((r) => r.severity && severities.includes(r.severity));
}
+ if (qprofile && activation !== undefined) {
+ const qProfileLang = this.qualityProfile.find((p) => p.key === qprofile)?.language;
+ filteredRules = filteredRules
+ .filter((r) => r.lang === qProfileLang)
+ .filter((r) => {
+ const qProfilesInRule = this.rulesActivations[r.key]?.map((ra) => ra.qProfile) ?? [];
+ const ruleHasQueriedProfile = qProfilesInRule.includes(qprofile);
+ return activation === 'true' ? ruleHasQueriedProfile : !ruleHasQueriedProfile;
+ });
+
+ console.log(filteredRules);
+ }
if (available_since) {
filteredRules = filteredRules.filter(
(r) => r.createdAt && new Date(r.createdAt) > new Date(available_since)
if (repositories) {
filteredRules = filteredRules.filter((r) => r.lang && repositories.includes(r.repo));
}
- if (qprofile) {
- const rules = this.qualityProfilesToRules[qprofile] ?? [];
- filteredRules = filteredRules.filter((r) => rules.includes(r.key));
- }
if (sonarsourceSecurity) {
const matchingRules =
this.standardsToRules[SecurityStandard.SONARSOURCE]?.[sonarsourceSecurity] ?? [];
q,
rule_key,
is_template,
+ activation,
}: SearchRulesQuery): Promise<SearchRulesResponse> => {
const standards = await getStandards();
const facetCounts: Array<{ property: string; values: { val: string; count: number }[] }> = [];
filteredRules = this.getRulesWithoutDetails(this.rules).filter((r) => r.key === rule_key);
} else {
filteredRules = this.filterFacet({
+ qprofile,
languages,
available_since,
q,
types,
tags,
is_template,
- qprofile,
sonarsourceSecurity,
owaspTop10,
'owaspTop10-2021': owasp2021Top10,
cwe,
+ activation,
});
}
const responseRules = filteredRules.slice((currentP - 1) * currentPs, currentP * currentPs);
severity?: string;
}) => {
const nextActivation = mockRuleActivation({ qProfile: data.key, severity: data.severity });
+
+ if (!this.rulesActivations[data.rule]) {
+ this.rulesActivations[data.rule] = [nextActivation];
+ return this.reply(undefined);
+ }
+
const activationIndex = this.rulesActivations[data.rule]?.findIndex((activation) => {
return activation.qProfile === data.key;
});
+
if (activationIndex !== -1) {
this.rulesActivations[data.rule][activationIndex] = nextActivation;
} else {
- this.rulesActivations[data.rule] = [...this.rulesActivations[data.rule], nextActivation];
+ this.rulesActivations[data.rule].push(nextActivation);
}
return this.reply(undefined);
};
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { act, fireEvent, screen } from '@testing-library/react';
-import { last } from 'lodash';
import selectEvent from 'react-select-event';
import CodingRulesServiceMock, { RULE_TAGS_MOCK } from '../../../api/mocks/CodingRulesServiceMock';
import { RULE_TYPES } from '../../../helpers/constants';
import { dateInputEvent, renderAppRoutes } from '../../../helpers/testReactTestingUtils';
import { CurrentUser } from '../../../types/users';
import routes from '../routes';
-import { getPageObjects } from '../utils-test';
+import { getPageObjects } from '../utils-tests';
jest.mock('../../../api/rules');
jest.mock('../../../api/issues');
renderCodingRulesApp(mockCurrentUser());
await ui.appLoaded();
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
// Filter by language facet
await act(async () => {
await act(async () => {
await user.click(ui.clearAllFiltersButton.get());
});
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
// Filter by repository
await act(async () => {
await act(async () => {
await user.click(ui.clearAllFiltersButton.get());
});
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
// Filter by quality profile
await act(async () => {
await user.click(ui.qpFacet.get());
- await user.click(ui.facetItem('QP FooBar Java').get());
+ await user.click(ui.facetItem('QP Foo Java').get());
});
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(8);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(1);
// Filter by tag
await act(async () => {
renderCodingRulesApp(mockCurrentUser());
await ui.appLoaded();
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
await act(async () => {
await user.click(ui.standardsFacet.get());
await user.click(ui.facetItem('Buffer Overflow').get());
await act(async () => {
await user.click(ui.facetClear('issues.facet.standards').get());
});
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
});
it('filters by similar rules', async () => {
renderCodingRulesApp(mockCurrentUser());
await ui.appLoaded();
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(10);
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(11);
- const lastRule = last(ui.ruleListItem.getAll());
+ const ruleName = 'Awesome Python rule with education principles';
- await user.click(ui.similarIssuesButton.get(lastRule));
- await user.click(ui.similarIssuesFilterByLang('Python').get(lastRule));
+ await user.click(ui.similarIssuesButton(ruleName).get());
+ await user.click(ui.similarIssuesFilterByLang('Python').get());
expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(6);
- await user.click(ui.similarIssuesButton.get(lastRule));
- await user.click(ui.similarIssuesFilterByType('issue.type.VULNERABILITY').get(lastRule));
+ await user.click(ui.similarIssuesButton(ruleName).get());
+ await user.click(ui.similarIssuesFilterByType('issue.type.VULNERABILITY').get());
expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(3);
expect(ui.facetItem('issue.type.VULNERABILITY').get()).toBeChecked();
- await user.click(ui.similarIssuesButton.get(lastRule));
- await user.click(ui.similarIssuesFilterBySeverity('MINOR').get(lastRule));
+ await user.click(ui.similarIssuesButton(ruleName).get());
+ await user.click(ui.similarIssuesFilterBySeverity('MINOR').get());
expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(2);
- await user.click(ui.similarIssuesButton.get(lastRule));
- await user.click(ui.similarIssuesFilterByTag('awesome').get(lastRule));
+ await user.click(ui.similarIssuesButton(ruleName).get());
+ await user.click(ui.similarIssuesFilterByTag('awesome').get());
expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(1);
});
it('should be able to deactivate for specific quality profile', async () => {});
});
- it('can activate/deactivate specific rule for quality profile', async () => {});
+ it('can activate/deactivate specific rule for quality profile', async () => {
+ const { ui, user } = getPageObjects();
+ renderCodingRulesApp(mockLoggedInUser());
+ await ui.appLoaded();
+
+ await user.click(ui.qpFacet.get());
+ await user.click(ui.facetItem('QP Foo Java').get());
+
+ // Only one rule is activated in selected QP
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(1);
+
+ // Switch to inactive rules
+ await user.click(ui.qpInactiveRadio.get(ui.facetItem('QP Foo Java').get()));
+ expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(1);
+
+ // Activate Rule for qp
+ await user.click(ui.activateButton.get());
+ await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
+ expect(ui.activateButton.query()).not.toBeInTheDocument();
+ expect(ui.deactivateButton.get()).toBeInTheDocument();
+
+ // Deactivate activated rule
+ await user.click(ui.deactivateButton.get());
+ await user.click(ui.yesButton.get());
+ expect(ui.deactivateButton.query()).not.toBeInTheDocument();
+ expect(ui.activateButton.get()).toBeInTheDocument();
+ });
it('navigates by keyboard', async () => {
const { user, ui } = getPageObjects();
await user.click(ui.cancelButton.get());
// Deactivate rule in quality profile
- await user.click(ui.deactivateButton('QP FooBar').get());
+ await user.click(ui.deactivateInQPButton('QP FooBar').get());
await act(() => user.click(ui.yesButton.get()));
expect(ui.qpLink('QP FooBar').query()).not.toBeInTheDocument();
});
await user.click(ui.deleteButton.get(ui.deleteCustomRuleDialog.get()));
// Shows the list of rules, custom rule should not be included
- expect(ui.ruleListItem.getAll(ui.rulesList.get())).toHaveLength(9);
expect(ui.ruleListItemLink('Custom Rule based on rule8').query()).not.toBeInTheDocument();
});
renderActions = () => {
const { activation, isLoggedIn, rule, selectedProfile } = this.props;
+
if (!selectedProfile || !isLoggedIn) {
return null;
}
*/
import classNames from 'classnames';
import * as React from 'react';
-import { Button, ButtonPlain } from '../../../components/controls/buttons';
import Dropdown from '../../../components/controls/Dropdown';
+import { Button, ButtonPlain } from '../../../components/controls/buttons';
import DropdownIcon from '../../../components/icons/DropdownIcon';
import FilterIcon from '../../../components/icons/FilterIcon';
import IssueTypeIcon from '../../../components/icons/IssueTypeIcon';
>
<Button
className="js-rule-filter spacer-left"
- title={translate('coding_rules.filter_similar_rules')}
+ title={translateWithParameters('coding_rules.filter_similar_rules_x', rule.name)}
>
<FilterIcon />
<DropdownIcon />
+++ /dev/null
-/*
- * 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 { waitFor } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import { Profile } from '../../api/quality-profiles';
-import { byLabelText, byPlaceholderText, byRole, byText } from '../../helpers/testSelector';
-
-const selectors = {
- loading: byLabelText('loading'),
-
- // List
- rulesList: byRole('list', { name: 'list_of_rules' }),
- ruleListItemLink: (name: string) => byRole('link', { name }),
- ruleListItem: byRole('listitem'),
- currentListItem: byRole('listitem', { current: true }),
- similarIssuesButton: byRole('button', { name: 'coding_rules.filter_similar_rules' }),
- similarIssuesFilterByLang: (lang: string) =>
- byRole('button', { name: `coding_rules.filter_by_language.${lang}` }),
- similarIssuesFilterByType: (type: string) =>
- byRole('button', { name: `coding_rules.filter_by_type.${type}` }),
- similarIssuesFilterBySeverity: (severity: string) =>
- byRole('button', { name: `coding_rules.filter_by_severity.${severity}` }),
- similarIssuesFilterByTag: (tag: string) =>
- byRole('button', { name: `coding_rules.filter_by_tag.${tag}` }),
-
- // Filters
- searchInput: byRole('searchbox', { name: 'search.search_for_rules' }),
- clearAllFiltersButton: byRole('button', { name: 'clear_all_filters' }),
-
- // Facets
- languagesFacet: byRole('button', { name: 'coding_rules.facet.languages' }),
- typeFacet: byRole('button', { name: 'coding_rules.facet.types' }),
- tagsFacet: byRole('button', { name: 'coding_rules.facet.tags' }),
- repositoriesFacet: byRole('button', { name: 'coding_rules.facet.repositories' }),
- severetiesFacet: byRole('button', { name: 'coding_rules.facet.severities' }),
- statusesFacet: byRole('button', { name: 'coding_rules.facet.statuses' }),
- standardsFacet: byRole('button', { name: 'issues.facet.standards' }),
- standardsOwasp2017Top10Facet: byRole('button', { name: 'issues.facet.owaspTop10' }),
- standardsOwasp2021Top10Facet: byRole('button', { name: 'issues.facet.owaspTop10_2021' }),
- standardsCweFacet: byRole('button', { name: 'issues.facet.cwe' }),
- availableSinceFacet: byRole('button', { name: 'coding_rules.facet.available_since' }),
- templateFacet: byRole('button', { name: 'coding_rules.facet.template' }),
- qpFacet: byRole('button', { name: 'coding_rules.facet.qprofile' }),
- facetClear: (name: string) => byRole('button', { name: `clear_x_filter.${name}` }),
- facetSearchInput: (name: string) => byRole('searchbox', { name }),
- facetItem: (name: string) => byRole('checkbox', { name }),
- availableSinceDateField: byPlaceholderText('date'),
-
- // Bulk change
- bulkChangeButton: byRole('button', { name: 'bulk_change' }),
- activateIn: byRole('link', { name: 'coding_rules.activate_in…' }),
- deactivateIn: byRole('link', { name: 'coding_rules.deactivate_in…' }),
- bulkChangeDialog: (count: number, activate = true) =>
- byRole('dialog', {
- name: `coding_rules.${
- activate ? 'ac' : 'deac'
- }tivate_in_quality_profile (${count} coding_rules._rules)`,
- }),
- activateInSelect: byRole('combobox', { name: 'coding_rules.activate_in' }),
- deactivateInSelect: byRole('combobox', { name: 'coding_rules.deactivate_in' }),
- noQualityProfiles: byText('coding_rules.bulk_change.no_quality_profile'),
- bulkApply: byRole('button', { name: 'apply' }),
- bulkSuccessMessage: (qpName: string, langName: string, count: number) =>
- byText(`coding_rules.bulk_change.success.${qpName}.${langName}.${count}`),
- bulkWarningMessage: (qpName: string, langName: string, count: number) =>
- byText(`coding_rules.bulk_change.warning.${qpName}.${langName}.${count}.1`),
- bulkClose: byRole('button', { name: 'close' }),
-
- // Rule details
- ruleTitle: (name: string) => byRole('heading', { level: 1, name }),
- externalDescription: (ruleName: string) => byText(`issue.external_issue_description.${ruleName}`),
- introTitle: byText(/Introduction to this rule/),
- rootCause: byText('Root cause'),
- howToFix: byText('This is how to fix'),
- resourceLink: byRole('link', { name: 'Awsome Reading' }),
- contextRadio: (name: string) => byRole('radio', { name }),
- contextSubtitle: (name: string) => byText(`coding_rules.description_context.subtitle.${name}`),
- otherContextTitle: byText('coding_rules.context.others.title'),
- caycNotificationButton: byRole('button', { name: 'coding_rules.more_info.scroll_message' }),
- extendDescriptionButton: byRole('button', { name: 'coding_rules.extend_description' }),
- extendDescriptionTextbox: byRole('textbox', { name: 'coding_rules.extend_description' }),
- saveButton: byRole('button', { name: 'save' }),
- cancelButton: byRole('button', { name: 'cancel' }),
- removeButton: byRole('button', { name: 'remove' }),
-
- // Rule tags
- tagsDropdown: byRole('button', { name: /tags_list_x/ }),
- tagsMenu: byRole('group', { name: 'select_tags' }),
- tagCheckbox: (tag: string) => byRole('checkbox', { name: tag }),
- tagSearch: byRole('searchbox', { name: 'search.search_for_tags' }),
-
- // Rule tabs
- whyIssueTab: byRole('tab', {
- name: 'coding_rules.description_section.title.root_cause',
- }),
- whatRiskTab: byRole('tab', {
- name: 'coding_rules.description_section.title.root_cause.SECURITY_HOTSPOT',
- }),
- assessTab: byRole('tab', {
- name: 'coding_rules.description_section.title.assess_the_problem',
- }),
- moreInfoTab: byRole('tab', {
- name: 'coding_rules.description_section.title.more_info',
- }),
- howToFixTab: byRole('tab', {
- name: 'coding_rules.description_section.title.how_to_fix',
- }),
-
- // Rule Quality Profiles
- qpLink: (name: string) => byRole('link', { name }),
- activateButton: byRole('button', { name: 'coding_rules.activate' }),
- severitySelect: byRole('combobox', { name: 'severity' }),
- qualityProfileSelect: byRole('combobox', { name: 'coding_rules.quality_profile' }),
- activateQPDialog: byRole('dialog', { name: 'coding_rules.activate_in_quality_profile' }),
- changeButton: (profile: string) =>
- byRole('button', { name: `coding_rules.change_details_x.${profile}` }),
- changeQPDialog: byRole('dialog', { name: 'coding_rules.change_details' }),
- deactivateButton: (profile: string) =>
- byRole('button', { name: `coding_rules.deactivate_in_quality_profile_x.${profile}` }),
- activaInAllQPs: byText('coding_rules.active_in_all_profiles'),
- yesButton: byRole('button', { name: 'yes' }),
- paramInput: (param: string) => byRole('textbox', { name: param }),
-
- // Custom rules
- customRuleSectionTitle: byRole('heading', { level: 2, name: 'coding_rules.custom_rules' }),
- createCustomRuleButton: byRole('button', { name: 'coding_rules.create' }),
- editCustomRuleButton: byRole('button', { name: 'edit' }),
- deleteCustomRuleButton: (rule: string) =>
- byRole('button', { name: `coding_rules.delete_rule_x.${rule}` }),
- customRuleItemLink: (name: string) => byRole('link', { name }),
-
- // Custom rule form
- createCustomRuleDialog: byRole('dialog', { name: 'coding_rules.create_custom_rule' }),
- updateCustomRuleDialog: byRole('dialog', { name: 'coding_rules.update_custom_rule' }),
- deleteCustomRuleDialog: byRole('dialog', { name: 'coding_rules.delete_rule' }),
- ruleNameTextbox: byRole('textbox', { name: 'name field_required' }),
- keyTextbox: byRole('textbox', { name: 'key field_required' }),
- typeSelect: byRole('combobox', { name: 'type' }),
- statusSelect: byRole('combobox', { name: 'coding_rules.filters.status' }),
- descriptionTextbox: byRole('textbox', { name: 'description field_required' }),
- createButton: byRole('button', { name: 'create' }),
- deleteButton: byRole('button', { name: 'delete' }),
-};
-
-export function getPageObjects() {
- const user = userEvent.setup();
-
- const ui = {
- ...selectors,
- async appLoaded() {
- await waitFor(() => {
- expect(selectors.loading.query()).not.toBeInTheDocument();
- });
- },
-
- async bulkActivate(rulesCount: number, profile: Profile) {
- await user.click(ui.bulkChangeButton.get());
- await user.click(ui.activateIn.get());
-
- const dialog = ui.bulkChangeDialog(rulesCount).get();
- expect(dialog).toBeInTheDocument();
-
- await user.click(ui.activateInSelect.get());
- await user.click(byText(`${profile.name} - ${profile.languageName}`).get(dialog));
-
- await user.click(ui.bulkApply.get());
- },
-
- async bulkDeactivate(rulesCount: number, profile: Profile) {
- await user.click(ui.bulkChangeButton.get());
- await user.click(ui.deactivateIn.get());
-
- const dialog = ui.bulkChangeDialog(rulesCount, false).get();
- expect(dialog).toBeInTheDocument();
-
- await user.click(ui.deactivateInSelect.get());
- await user.click(byText(`${profile.name} - ${profile.languageName}`).get(dialog));
-
- await user.click(ui.bulkApply.get());
- },
- };
-
- return {
- ui,
- user,
- };
-}
--- /dev/null
+/*
+ * 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 { waitFor } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { Profile } from '../../api/quality-profiles';
+import { byLabelText, byPlaceholderText, byRole, byText } from '../../helpers/testSelector';
+
+const selectors = {
+ loading: byLabelText('loading'),
+
+ // List
+ rulesList: byRole('list', { name: 'list_of_rules' }),
+ ruleListItemLink: (name: string) => byRole('link', { name }),
+ ruleListItem: byRole('listitem'),
+ currentListItem: byRole('listitem', { current: true }),
+ similarIssuesButton: (rule: string) =>
+ byRole('button', { name: `coding_rules.filter_similar_rules_x.${rule}` }),
+ similarIssuesFilterByLang: (lang: string) =>
+ byRole('button', { name: `coding_rules.filter_by_language.${lang}` }),
+ similarIssuesFilterByType: (type: string) =>
+ byRole('button', { name: `coding_rules.filter_by_type.${type}` }),
+ similarIssuesFilterBySeverity: (severity: string) =>
+ byRole('button', { name: `coding_rules.filter_by_severity.${severity}` }),
+ similarIssuesFilterByTag: (tag: string) =>
+ byRole('button', { name: `coding_rules.filter_by_tag.${tag}` }),
+
+ // Filters
+ searchInput: byRole('searchbox', { name: 'search.search_for_rules' }),
+ clearAllFiltersButton: byRole('button', { name: 'clear_all_filters' }),
+
+ // Facets
+ languagesFacet: byRole('button', { name: 'coding_rules.facet.languages' }),
+ typeFacet: byRole('button', { name: 'coding_rules.facet.types' }),
+ tagsFacet: byRole('button', { name: 'coding_rules.facet.tags' }),
+ repositoriesFacet: byRole('button', { name: 'coding_rules.facet.repositories' }),
+ severetiesFacet: byRole('button', { name: 'coding_rules.facet.severities' }),
+ statusesFacet: byRole('button', { name: 'coding_rules.facet.statuses' }),
+ standardsFacet: byRole('button', { name: 'issues.facet.standards' }),
+ standardsOwasp2017Top10Facet: byRole('button', { name: 'issues.facet.owaspTop10' }),
+ standardsOwasp2021Top10Facet: byRole('button', { name: 'issues.facet.owaspTop10_2021' }),
+ standardsCweFacet: byRole('button', { name: 'issues.facet.cwe' }),
+ availableSinceFacet: byRole('button', { name: 'coding_rules.facet.available_since' }),
+ templateFacet: byRole('button', { name: 'coding_rules.facet.template' }),
+ qpFacet: byRole('button', { name: 'coding_rules.facet.qprofile' }),
+ facetClear: (name: string) => byRole('button', { name: `clear_x_filter.${name}` }),
+ facetSearchInput: (name: string) => byRole('searchbox', { name }),
+ facetItem: (name: string) => byRole('checkbox', { name }),
+ availableSinceDateField: byPlaceholderText('date'),
+ qpActiveRadio: byRole('radio', { name: `active` }),
+ qpInactiveRadio: byRole('radio', { name: `inactive` }),
+
+ // Bulk change
+ bulkChangeButton: byRole('button', { name: 'bulk_change' }),
+ activateIn: byRole('link', { name: 'coding_rules.activate_in…' }),
+ deactivateIn: byRole('link', { name: 'coding_rules.deactivate_in…' }),
+ bulkChangeDialog: (count: number, activate = true) =>
+ byRole('dialog', {
+ name: `coding_rules.${
+ activate ? 'ac' : 'deac'
+ }tivate_in_quality_profile (${count} coding_rules._rules)`,
+ }),
+ activateInSelect: byRole('combobox', { name: 'coding_rules.activate_in' }),
+ deactivateInSelect: byRole('combobox', { name: 'coding_rules.deactivate_in' }),
+ noQualityProfiles: byText('coding_rules.bulk_change.no_quality_profile'),
+ bulkApply: byRole('button', { name: 'apply' }),
+ bulkSuccessMessage: (qpName: string, langName: string, count: number) =>
+ byText(`coding_rules.bulk_change.success.${qpName}.${langName}.${count}`),
+ bulkWarningMessage: (qpName: string, langName: string, count: number) =>
+ byText(`coding_rules.bulk_change.warning.${qpName}.${langName}.${count}.1`),
+ bulkClose: byRole('button', { name: 'close' }),
+
+ // Rule details
+ ruleTitle: (name: string) => byRole('heading', { level: 1, name }),
+ externalDescription: (ruleName: string) => byText(`issue.external_issue_description.${ruleName}`),
+ introTitle: byText(/Introduction to this rule/),
+ rootCause: byText('Root cause'),
+ howToFix: byText('This is how to fix'),
+ resourceLink: byRole('link', { name: 'Awsome Reading' }),
+ contextRadio: (name: string) => byRole('radio', { name }),
+ contextSubtitle: (name: string) => byText(`coding_rules.description_context.subtitle.${name}`),
+ otherContextTitle: byText('coding_rules.context.others.title'),
+ caycNotificationButton: byRole('button', { name: 'coding_rules.more_info.scroll_message' }),
+ extendDescriptionButton: byRole('button', { name: 'coding_rules.extend_description' }),
+ extendDescriptionTextbox: byRole('textbox', { name: 'coding_rules.extend_description' }),
+ saveButton: byRole('button', { name: 'save' }),
+ cancelButton: byRole('button', { name: 'cancel' }),
+ removeButton: byRole('button', { name: 'remove' }),
+
+ // Rule tags
+ tagsDropdown: byRole('button', { name: /tags_list_x/ }),
+ tagsMenu: byRole('group', { name: 'select_tags' }),
+ tagCheckbox: (tag: string) => byRole('checkbox', { name: tag }),
+ tagSearch: byRole('searchbox', { name: 'search.search_for_tags' }),
+
+ // Rule tabs
+ whyIssueTab: byRole('tab', {
+ name: 'coding_rules.description_section.title.root_cause',
+ }),
+ whatRiskTab: byRole('tab', {
+ name: 'coding_rules.description_section.title.root_cause.SECURITY_HOTSPOT',
+ }),
+ assessTab: byRole('tab', {
+ name: 'coding_rules.description_section.title.assess_the_problem',
+ }),
+ moreInfoTab: byRole('tab', {
+ name: 'coding_rules.description_section.title.more_info',
+ }),
+ howToFixTab: byRole('tab', {
+ name: 'coding_rules.description_section.title.how_to_fix',
+ }),
+
+ // Rule Quality Profiles
+ qpLink: (name: string) => byRole('link', { name }),
+ activateButton: byRole('button', { name: 'coding_rules.activate' }),
+ deactivateButton: byRole('button', { name: 'coding_rules.deactivate' }),
+ severitySelect: byRole('combobox', { name: 'severity' }),
+ qualityProfileSelect: byRole('combobox', { name: 'coding_rules.quality_profile' }),
+ activateQPDialog: byRole('dialog', { name: 'coding_rules.activate_in_quality_profile' }),
+ changeButton: (profile: string) =>
+ byRole('button', { name: `coding_rules.change_details_x.${profile}` }),
+ changeQPDialog: byRole('dialog', { name: 'coding_rules.change_details' }),
+ deactivateInQPButton: (profile: string) =>
+ byRole('button', { name: `coding_rules.deactivate_in_quality_profile_x.${profile}` }),
+ activaInAllQPs: byText('coding_rules.active_in_all_profiles'),
+ yesButton: byRole('button', { name: 'yes' }),
+ paramInput: (param: string) => byRole('textbox', { name: param }),
+
+ // Custom rules
+ customRuleSectionTitle: byRole('heading', { level: 2, name: 'coding_rules.custom_rules' }),
+ createCustomRuleButton: byRole('button', { name: 'coding_rules.create' }),
+ editCustomRuleButton: byRole('button', { name: 'edit' }),
+ deleteCustomRuleButton: (rule: string) =>
+ byRole('button', { name: `coding_rules.delete_rule_x.${rule}` }),
+ customRuleItemLink: (name: string) => byRole('link', { name }),
+
+ // Custom rule form
+ createCustomRuleDialog: byRole('dialog', { name: 'coding_rules.create_custom_rule' }),
+ updateCustomRuleDialog: byRole('dialog', { name: 'coding_rules.update_custom_rule' }),
+ deleteCustomRuleDialog: byRole('dialog', { name: 'coding_rules.delete_rule' }),
+ ruleNameTextbox: byRole('textbox', { name: 'name field_required' }),
+ keyTextbox: byRole('textbox', { name: 'key field_required' }),
+ typeSelect: byRole('combobox', { name: 'type' }),
+ statusSelect: byRole('combobox', { name: 'coding_rules.filters.status' }),
+ descriptionTextbox: byRole('textbox', { name: 'description field_required' }),
+ createButton: byRole('button', { name: 'create' }),
+ deleteButton: byRole('button', { name: 'delete' }),
+};
+
+export function getPageObjects() {
+ const user = userEvent.setup();
+
+ const ui = {
+ ...selectors,
+ async appLoaded() {
+ await waitFor(() => {
+ expect(selectors.loading.query()).not.toBeInTheDocument();
+ });
+ },
+
+ async bulkActivate(rulesCount: number, profile: Profile) {
+ await user.click(ui.bulkChangeButton.get());
+ await user.click(ui.activateIn.get());
+
+ const dialog = ui.bulkChangeDialog(rulesCount).get();
+ expect(dialog).toBeInTheDocument();
+
+ await user.click(ui.activateInSelect.get());
+ await user.click(byText(`${profile.name} - ${profile.languageName}`).get(dialog));
+
+ await user.click(ui.bulkApply.get());
+ },
+
+ async bulkDeactivate(rulesCount: number, profile: Profile) {
+ await user.click(ui.bulkChangeButton.get());
+ await user.click(ui.deactivateIn.get());
+
+ const dialog = ui.bulkChangeDialog(rulesCount, false).get();
+ expect(dialog).toBeInTheDocument();
+
+ await user.click(ui.deactivateInSelect.get());
+ await user.click(byText(`${profile.name} - ${profile.languageName}`).get(dialog));
+
+ await user.click(ui.bulkApply.get());
+ },
+ };
+
+ return {
+ ui,
+ user,
+ };
+}
coding_rules.type.tooltip.SECURITY_HOTSPOT=Security Hotspot Detection Rule
coding_rules.update_custom_rule=Update Custom Rule
coding_rules.filter_similar_rules=Filter Similar Rules
+coding_rules.filter_similar_rules_x=Filter rules similar with {0}
coding_rules.filter_by_language=Filter by {0} language
coding_rules.filter_by_type=Filter by {0} type
coding_rules.filter_by_severity=Filter by {0} severity