]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-23262 Divide tests RuleList from RuleDetails
authorViktor Vorona <viktor.vorona@sonarsource.com>
Mon, 7 Oct 2024 11:28:38 +0000 (13:28 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 16 Oct 2024 20:03:01 +0000 (20:03 +0000)
server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts [new file with mode: 0644]
server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRules-it.ts

diff --git a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts
new file mode 100644 (file)
index 0000000..805a4fc
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 { fireEvent, screen } from '@testing-library/react';
+import CodingRulesServiceMock, { RULE_TAGS_MOCK } from '../../../api/mocks/CodingRulesServiceMock';
+import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
+import { RULE_1 } from '../../../api/mocks/data/ids';
+import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
+import { byRole } from '../../../sonar-aligned/helpers/testSelector';
+import {
+  CleanCodeAttribute,
+  CleanCodeAttributeCategory,
+  SoftwareQuality,
+} from '../../../types/clean-code-taxonomy';
+import { Feature } from '../../../types/features';
+import { SettingsKey } from '../../../types/settings';
+import { getPageObjects, renderCodingRulesApp } from '../utils-tests';
+
+const rulesHandler = new CodingRulesServiceMock();
+const settingsHandler = new SettingsServiceMock();
+afterEach(() => {
+  rulesHandler.reset();
+  settingsHandler.reset();
+});
+
+describe('rendering', () => {
+  it('shows rule with default description section and params', async () => {
+    const { ui } = getPageObjects();
+    renderCodingRulesApp(undefined, 'coding_rules?open=' + RULE_1);
+    await ui.detailsloaded();
+    expect(ui.ruleTitle('Awsome java rule').get()).toBeInTheDocument();
+    expect(
+      ui.ruleCleanCodeAttributeCategory(CleanCodeAttributeCategory.Intentional).get(),
+    ).toBeInTheDocument();
+    expect(ui.ruleCleanCodeAttribute(CleanCodeAttribute.Clear).get()).toBeInTheDocument();
+    // 1 In Rule details + 1 in facet
+    expect(ui.ruleSoftwareQuality(SoftwareQuality.Maintainability).getAll()).toHaveLength(2);
+    expect(document.title).toEqual('page_title.template.with_category.coding_rules.page');
+    expect(screen.getByText('Why')).toBeInTheDocument();
+    expect(screen.getByText('Because')).toBeInTheDocument();
+
+    // Check params data
+    expect(screen.getByText('html description for key 1')).toBeInTheDocument();
+    expect(screen.getByText('default value for key 2')).toBeInTheDocument();
+    expect(ui.softwareQualitiesSection.get()).toBeInTheDocument();
+    expect(ui.cleanCodeAttributeSection.get()).toBeInTheDocument();
+  });
+
+  it('shows external rule', async () => {
+    const { ui } = getPageObjects();
+    renderCodingRulesApp(undefined, 'coding_rules?open=rule6');
+    await ui.detailsloaded();
+    expect(ui.ruleTitle('Bad Python rule').get()).toBeInTheDocument();
+    expect(ui.externalDescription('Bad Python rule').get()).toBeInTheDocument();
+  });
+
+  it('shows hotspot rule', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(undefined, 'coding_rules?open=rule2');
+    await ui.detailsloaded();
+    expect(ui.ruleTitle('Hot hotspot').get()).toBeInTheDocument();
+    expect(ui.introTitle.get()).toBeInTheDocument();
+    expect(ui.softwareQualitiesSection.query()).not.toBeInTheDocument();
+    expect(ui.cleanCodeAttributeSection.query()).not.toBeInTheDocument();
+
+    // Shows correct tabs
+    [ui.whatRiskTab, ui.assessTab, ui.moreInfoTab].forEach((tab) => {
+      expect(tab.get()).toBeInTheDocument();
+    });
+
+    await user.click(ui.moreInfoTab.get());
+    expect(ui.resourceLink.get()).toBeInTheDocument();
+  });
+
+  it('shows rule advanced section', async () => {
+    const { ui } = getPageObjects();
+    renderCodingRulesApp(undefined, 'coding_rules?open=rule5');
+    await ui.detailsloaded();
+    expect(ui.ruleTitle('Awsome Python rule').get()).toBeInTheDocument();
+    expect(ui.introTitle.get()).toBeInTheDocument();
+    // Shows correct tabs
+    [ui.howToFixTab, ui.moreInfoTab].forEach((tab) => {
+      expect(tab.get()).toBeInTheDocument();
+    });
+  });
+
+  it('shows rule advanced section with context', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(undefined, 'coding_rules?open=rule7');
+    await ui.detailsloaded();
+    expect(ui.ruleTitle('Python rule with context').get()).toBeInTheDocument();
+
+    await user.click(ui.howToFixTab.get());
+
+    expect(ui.contextSubtitle('Spring').get()).toBeInTheDocument();
+    expect(screen.getByText('This is how to fix for spring')).toBeInTheDocument();
+
+    await user.click(ui.contextRadio('Spring boot').get());
+    expect(ui.contextSubtitle('Spring boot').get()).toBeInTheDocument();
+    expect(screen.getByText('This is how to fix for spring boot')).toBeInTheDocument();
+
+    await user.click(ui.contextRadio('coding_rules.description_context.other').get());
+    expect(ui.otherContextTitle.get()).toBeInTheDocument();
+  });
+
+  it('should show CYAC notification for rule advanced section and removes it after user`s visit', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10');
+    await ui.detailsloaded();
+    await user.click(ui.moreInfoTab.get());
+
+    expect(ui.caycNotificationButton.get()).toBeInTheDocument();
+
+    // navigate away and come back
+    await user.click(ui.howToFixTab.get());
+    await user.click(ui.moreInfoTab.get());
+
+    expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
+  });
+
+  it('should show CaYC notification for rule advanced section and removes it when user scrolls to the principles', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10');
+    await ui.detailsloaded();
+    await user.click(ui.moreInfoTab.get());
+    expect(ui.caycNotificationButton.get()).toBeInTheDocument();
+
+    fireEvent.scroll(screen.getByText('coding_rules.more_info.education_principles.title'));
+
+    // navigate away and come back
+    await user.click(ui.howToFixTab.get());
+    await user.click(ui.moreInfoTab.get());
+
+    expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
+  });
+
+  it('should not show notification for anonymous users', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(mockCurrentUser(), 'coding_rules?open=rule10');
+
+    await ui.detailsloaded();
+    await user.click(ui.moreInfoTab.get());
+
+    expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
+  });
+
+  it('should show customized severity and prioritized rule', async () => {
+    const { ui, user } = getPageObjects();
+    renderCodingRulesApp(mockCurrentUser(), 'coding_rules?open=rule10');
+
+    await ui.detailsloaded();
+    await user.click(ui.moreInfoTab.get());
+
+    expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
+  });
+});
+
+it('can activate/change/deactivate rule in quality profile', async () => {
+  const { ui, user } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule1', [Feature.PrioritizedRules]);
+  expect(await ui.qpLink('QP Foo').find()).toBeInTheDocument();
+
+  // Activate rule in quality profile
+  expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument();
+  await user.click(ui.activateButton.get());
+
+  await user.click(ui.prioritizedSwitch.get());
+  await user.click(ui.mqrSwitch.get());
+  await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
+  await user.click(byRole('option', { name: 'severity_impact.LOW' }).get());
+  await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
+  expect(ui.qpLink('QP FooBar').get()).toBeInTheDocument();
+  expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
+  expect(ui.oldSeverityCustomizedCell.query()).not.toBeInTheDocument();
+  expect(ui.newSeverityCustomizedCell.get()).toBeInTheDocument();
+  await expect(ui.newSeverityCustomizedCell.get()).toHaveATooltipWithContent(
+    'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.LOW',
+  );
+
+  // Activate last java rule
+  await user.click(ui.activateButton.get());
+  await user.type(ui.paramInput('1').get(), 'paramInput');
+  await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
+  expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument();
+  expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument();
+
+  // Rule is activated in all quality profiles - show notification in dialog
+  await user.click(ui.activateButton.get(screen.getByRole('main')));
+  expect(ui.activaInAllQPs.get()).toBeInTheDocument();
+  expect(ui.activateButton.get(ui.activateQPDialog.get())).toBeDisabled();
+  await user.click(ui.cancelButton.get());
+
+  // Change rule details in quality profile
+  await user.click(ui.changeButton('QP FooBaz').get());
+  await user.clear(ui.paramInput('1').get());
+  await user.type(ui.paramInput('1').get(), 'New');
+  await user.click(ui.mqrSwitch.get());
+  await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
+  await user.click(byRole('option', { name: 'severity_impact.BLOCKER' }).get());
+  await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
+  expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
+  expect(ui.qualityProfileRow.getAt(5)).toHaveTextContent('New');
+  await expect(
+    ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5)),
+  ).toHaveATooltipWithContent(
+    'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.BLOCKER',
+  );
+
+  // Revert rule details in quality profile
+  await user.click(ui.revertToParentDefinitionButton.get());
+  await user.click(ui.yesButton.get());
+  expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
+  expect(await ui.qualityProfileRow.findAt(5)).not.toHaveTextContent('New');
+  expect(ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(5))).not.toBeInTheDocument();
+
+  // Deactivate rule in quality profile
+  await user.click(ui.deactivateInQPButton('QP FooBar').get());
+  await user.click(ui.yesButton.get());
+  expect(ui.qpLink('QP FooBar').query()).not.toBeInTheDocument();
+});
+
+it('can activate/change/deactivate rule in quality profile for legacy mode', async () => {
+  const { ui, user } = getPageObjects();
+  settingsHandler.set(SettingsKey.MQRMode, 'true');
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule1', [Feature.PrioritizedRules]);
+  await ui.detailsloaded();
+  expect(ui.qpLink('QP Foo').get()).toBeInTheDocument();
+
+  // Activate rule in quality profile
+  expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument();
+  await user.click(ui.activateButton.get());
+
+  await user.click(ui.prioritizedSwitch.get());
+  await user.click(ui.oldSeveritySelect.get());
+  await user.click(byRole('option', { name: 'severity.MINOR' }).get());
+  await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
+  expect(ui.qpLink('QP FooBar').get()).toBeInTheDocument();
+  expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
+  expect(ui.newSeverityCustomizedCell.query()).not.toBeInTheDocument();
+  expect(ui.oldSeverityCustomizedCell.get()).toBeInTheDocument();
+  expect(ui.oldSeverityCustomizedCell.get()).toHaveTextContent('severity.MAJORseverity.MINOR');
+
+  await user.click(ui.changeButton('QP FooBar').get());
+  await user.click(ui.oldSeveritySelect.get());
+  await user.click(
+    byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
+  );
+  await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
+  expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
+  expect(ui.oldSeverityCustomizedCell.query()).not.toBeInTheDocument();
+  expect(ui.newSeverityCustomizedCell.query()).not.toBeInTheDocument();
+
+  // Activate last java rule
+  await user.click(ui.activateButton.get());
+  await user.type(ui.paramInput('1').get(), 'paramInput');
+  await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
+  expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument();
+  expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument();
+
+  // Change rule details in quality profile
+  await user.click(ui.changeButton('QP FooBaz').get());
+  await user.click(ui.oldSeveritySelect.get());
+  await user.click(byRole('option', { name: 'severity.BLOCKER' }).get());
+  await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
+  expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
+  expect(ui.oldSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5))).toBeInTheDocument();
+  expect(ui.oldSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5))).toHaveTextContent(
+    'severity.MAJORseverity.BLOCKER',
+  );
+
+  // Revert rule details in quality profile
+  await user.click(ui.revertToParentDefinitionButton.get());
+  await user.click(ui.yesButton.get());
+  expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
+  expect(ui.oldSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(5))).not.toBeInTheDocument();
+});
+
+it('should show multiple customized severities', async () => {
+  const { ui, user } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10', [Feature.PrioritizedRules]);
+  await ui.detailsloaded();
+
+  expect(ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(1))).toBeInTheDocument();
+  await expect(
+    ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(1)),
+  ).toHaveATooltipWithContent(
+    'coding_rules.impact_customized.detailsoftware_quality.RELIABILITYseverity_impact.HIGHseverity_impact.INFO' +
+      'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.LOWseverity_impact.MEDIUM',
+  );
+
+  expect(ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(2))).toBeInTheDocument();
+  await expect(
+    ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(2)),
+  ).toHaveATooltipWithContent(
+    'coding_rules.impact_customized.detailsoftware_quality.RELIABILITYseverity_impact.HIGHseverity_impact.BLOCKER',
+  );
+
+  await user.click(ui.changeButton('QP Bar').get());
+  await user.click(ui.mqrSwitch.get());
+  await user.click(ui.newSeveritySelect(SoftwareQuality.Reliability).get());
+  await user.click(
+    byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
+  );
+  await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
+  await user.click(
+    byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
+  );
+  await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
+  expect(ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(1))).not.toBeInTheDocument();
+});
+
+it('can deactivate an inherrited rule', async () => {
+  const { ui, user } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule11');
+  await ui.detailsloaded();
+
+  // Should show 2 deactivate buttons: one for the parent, one for the child profile.
+  expect(ui.deactivateInQPButton('QP FooBarBaz').get()).toBeInTheDocument();
+  expect(ui.deactivateInQPButton('QP FooBaz').get()).toBeInTheDocument();
+
+  // Deactivate rule in inherited quality profile
+  await user.click(ui.deactivateInQPButton('QP FooBaz').get());
+  await user.click(ui.yesButton.get());
+  expect(ui.qpLink('QP FooBaz').query()).not.toBeInTheDocument();
+});
+
+it('cannot deactivate an inherrited rule if the setting is false', async () => {
+  const { ui } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  settingsHandler.set(SettingsKey.QPAdminCanDisableInheritedRules, 'false');
+  renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule11');
+  await ui.detailsloaded();
+
+  // Should show 1 deactivate button: one for the parent, none for the child profile.
+  expect(ui.deactivateInQPButton('QP FooBarBaz').get()).toBeInTheDocument();
+  expect(ui.deactivateInQPButton('QP FooBaz').query()).not.toBeInTheDocument();
+});
+
+it('can extend the rule description', async () => {
+  const { ui, user } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(undefined, 'coding_rules?open=rule5');
+  await ui.detailsloaded();
+  expect(ui.ruleTitle('Awsome Python rule').get()).toBeInTheDocument();
+
+  // Add
+  await user.click(ui.extendDescriptionButton.get());
+  await user.type(ui.extendDescriptionTextbox.get(), 'TEST DESC');
+  await user.click(ui.saveButton.get());
+  expect(await screen.findByText('TEST DESC')).toBeInTheDocument();
+
+  // Edit
+  await user.click(ui.extendDescriptionButton.get());
+  await user.clear(ui.extendDescriptionTextbox.get());
+  await user.type(ui.extendDescriptionTextbox.get(), 'NEW DESC');
+  await user.click(ui.saveButton.get());
+  expect(await screen.findByText('NEW DESC')).toBeInTheDocument();
+
+  // Cancel
+  await user.click(ui.extendDescriptionButton.get());
+  await user.type(ui.extendDescriptionTextbox.get(), 'Difference');
+  await user.click(ui.cancelButton.get());
+  expect(await screen.findByText('NEW DESC')).toBeInTheDocument();
+
+  // Remove
+  await user.click(ui.extendDescriptionButton.get());
+  await user.click(ui.removeButton.get());
+  await user.click(ui.removeButton.get(screen.getByRole('dialog')));
+  expect(screen.queryByText('NEW DESC')).not.toBeInTheDocument();
+});
+
+it('can set tags', async () => {
+  const { ui, user } = getPageObjects();
+  rulesHandler.setIsAdmin();
+  renderCodingRulesApp(undefined, 'coding_rules?open=rule10');
+  await ui.detailsloaded();
+
+  await user.click(ui.tagsDropdown.get());
+
+  RULE_TAGS_MOCK.forEach((tag) => {
+    expect(ui.tagCheckbox(tag).get()).toBeInTheDocument();
+  });
+
+  expect(ui.tagCheckbox(RULE_TAGS_MOCK[0]).get()).toBeChecked();
+
+  // Set tag
+  await user.click(ui.tagCheckbox(RULE_TAGS_MOCK[1]).get());
+  await user.keyboard('{Escape}');
+  await expect(ui.tagsDropdown.byText('multi-threading').get()).toHaveATooltipWithContent(
+    'multi-threading, awesome, cute',
+  );
+
+  await user.click(ui.tagsDropdown.get());
+
+  // Search for specific tag
+  await user.type(ui.tagSearch.get(), RULE_TAGS_MOCK[2]);
+  expect(ui.tagCheckbox(RULE_TAGS_MOCK[2]).get()).toBeInTheDocument();
+  expect(ui.tagCheckbox(RULE_TAGS_MOCK[1]).query()).not.toBeInTheDocument();
+});
index e9fe34527e5f1fd325a29cc515900b510822a07e..6af1e298d4d25c4f41194bd35f4ab954da747020 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { fireEvent, screen, within } from '@testing-library/react';
-import CodingRulesServiceMock, { RULE_TAGS_MOCK } from '../../../api/mocks/CodingRulesServiceMock';
+import { screen, within } from '@testing-library/react';
+import { byRole } from '~sonar-aligned/helpers/testSelector';
+import CodingRulesServiceMock from '../../../api/mocks/CodingRulesServiceMock';
 import SettingsServiceMock from '../../../api/mocks/SettingsServiceMock';
-import { QP_2, RULE_1, RULE_10, RULE_7, RULE_9 } from '../../../api/mocks/data/ids';
+import { QP_2, RULE_10, RULE_7, RULE_9 } from '../../../api/mocks/data/ids';
 import {
   IMPACT_SEVERITIES,
   ISSUE_TYPES,
@@ -28,12 +29,7 @@ import {
   SOFTWARE_QUALITIES,
 } from '../../../helpers/constants';
 import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks';
-import { byRole } from '../../../sonar-aligned/helpers/testSelector';
-import {
-  CleanCodeAttribute,
-  CleanCodeAttributeCategory,
-  SoftwareQuality,
-} from '../../../types/clean-code-taxonomy';
+import { SoftwareQuality } from '../../../types/clean-code-taxonomy';
 import { Feature } from '../../../types/features';
 import { SettingsKey } from '../../../types/settings';
 import { getPageObjects, renderCodingRulesApp } from '../utils-tests';
@@ -822,395 +818,6 @@ describe('Rules app list', () => {
   });
 });
 
-describe('Rule app details', () => {
-  describe('rendering', () => {
-    it('shows rule with default description section and params', async () => {
-      const { ui } = getPageObjects();
-      renderCodingRulesApp(undefined, 'coding_rules?open=' + RULE_1);
-      await ui.detailsloaded();
-      expect(ui.ruleTitle('Awsome java rule').get()).toBeInTheDocument();
-      expect(
-        ui.ruleCleanCodeAttributeCategory(CleanCodeAttributeCategory.Intentional).get(),
-      ).toBeInTheDocument();
-      expect(ui.ruleCleanCodeAttribute(CleanCodeAttribute.Clear).get()).toBeInTheDocument();
-      // 1 In Rule details + 1 in facet
-      expect(ui.ruleSoftwareQuality(SoftwareQuality.Maintainability).getAll()).toHaveLength(2);
-      expect(document.title).toEqual('page_title.template.with_category.coding_rules.page');
-      expect(screen.getByText('Why')).toBeInTheDocument();
-      expect(screen.getByText('Because')).toBeInTheDocument();
-
-      // Check params data
-      expect(screen.getByText('html description for key 1')).toBeInTheDocument();
-      expect(screen.getByText('default value for key 2')).toBeInTheDocument();
-      expect(ui.softwareQualitiesSection.get()).toBeInTheDocument();
-      expect(ui.cleanCodeAttributeSection.get()).toBeInTheDocument();
-    });
-
-    it('shows external rule', async () => {
-      const { ui } = getPageObjects();
-      renderCodingRulesApp(undefined, 'coding_rules?open=rule6');
-      await ui.detailsloaded();
-      expect(ui.ruleTitle('Bad Python rule').get()).toBeInTheDocument();
-      expect(ui.externalDescription('Bad Python rule').get()).toBeInTheDocument();
-    });
-
-    it('shows hotspot rule', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(undefined, 'coding_rules?open=rule2');
-      await ui.detailsloaded();
-      expect(ui.ruleTitle('Hot hotspot').get()).toBeInTheDocument();
-      expect(ui.introTitle.get()).toBeInTheDocument();
-      expect(ui.softwareQualitiesSection.query()).not.toBeInTheDocument();
-      expect(ui.cleanCodeAttributeSection.query()).not.toBeInTheDocument();
-
-      // Shows correct tabs
-      [ui.whatRiskTab, ui.assessTab, ui.moreInfoTab].forEach((tab) => {
-        expect(tab.get()).toBeInTheDocument();
-      });
-
-      await user.click(ui.moreInfoTab.get());
-      expect(ui.resourceLink.get()).toBeInTheDocument();
-    });
-
-    it('shows rule advanced section', async () => {
-      const { ui } = getPageObjects();
-      renderCodingRulesApp(undefined, 'coding_rules?open=rule5');
-      await ui.detailsloaded();
-      expect(ui.ruleTitle('Awsome Python rule').get()).toBeInTheDocument();
-      expect(ui.introTitle.get()).toBeInTheDocument();
-      // Shows correct tabs
-      [ui.howToFixTab, ui.moreInfoTab].forEach((tab) => {
-        expect(tab.get()).toBeInTheDocument();
-      });
-    });
-
-    it('shows rule advanced section with context', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(undefined, 'coding_rules?open=rule7');
-      await ui.detailsloaded();
-      expect(ui.ruleTitle('Python rule with context').get()).toBeInTheDocument();
-
-      await user.click(ui.howToFixTab.get());
-
-      expect(ui.contextSubtitle('Spring').get()).toBeInTheDocument();
-      expect(screen.getByText('This is how to fix for spring')).toBeInTheDocument();
-
-      await user.click(ui.contextRadio('Spring boot').get());
-      expect(ui.contextSubtitle('Spring boot').get()).toBeInTheDocument();
-      expect(screen.getByText('This is how to fix for spring boot')).toBeInTheDocument();
-
-      await user.click(ui.contextRadio('coding_rules.description_context.other').get());
-      expect(ui.otherContextTitle.get()).toBeInTheDocument();
-    });
-
-    it('should show CYAC notification for rule advanced section and removes it after user`s visit', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10');
-      await ui.detailsloaded();
-      await user.click(ui.moreInfoTab.get());
-
-      expect(ui.caycNotificationButton.get()).toBeInTheDocument();
-
-      // navigate away and come back
-      await user.click(ui.howToFixTab.get());
-      await user.click(ui.moreInfoTab.get());
-
-      expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
-    });
-
-    it('should show CaYC notification for rule advanced section and removes it when user scrolls to the principles', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10');
-      await ui.detailsloaded();
-      await user.click(ui.moreInfoTab.get());
-      expect(ui.caycNotificationButton.get()).toBeInTheDocument();
-
-      fireEvent.scroll(screen.getByText('coding_rules.more_info.education_principles.title'));
-
-      // navigate away and come back
-      await user.click(ui.howToFixTab.get());
-      await user.click(ui.moreInfoTab.get());
-
-      expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
-    });
-
-    it('should not show notification for anonymous users', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(mockCurrentUser(), 'coding_rules?open=rule10');
-
-      await ui.detailsloaded();
-      await user.click(ui.moreInfoTab.get());
-
-      expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
-    });
-
-    it('should show customized severity and prioritized rule', async () => {
-      const { ui, user } = getPageObjects();
-      renderCodingRulesApp(mockCurrentUser(), 'coding_rules?open=rule10');
-
-      await ui.detailsloaded();
-      await user.click(ui.moreInfoTab.get());
-
-      expect(ui.caycNotificationButton.query()).not.toBeInTheDocument();
-    });
-  });
-
-  it('can activate/change/deactivate rule in quality profile', async () => {
-    const { ui, user } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule1', [Feature.PrioritizedRules]);
-    expect(await ui.qpLink('QP Foo').find()).toBeInTheDocument();
-
-    // Activate rule in quality profile
-    expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument();
-    await user.click(ui.activateButton.get());
-
-    await user.click(ui.prioritizedSwitch.get());
-    await user.click(ui.mqrSwitch.get());
-    await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
-    await user.click(byRole('option', { name: 'severity_impact.LOW' }).get());
-    await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
-    expect(ui.qpLink('QP FooBar').get()).toBeInTheDocument();
-    expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
-    expect(ui.oldSeverityCustomizedCell.query()).not.toBeInTheDocument();
-    expect(ui.newSeverityCustomizedCell.get()).toBeInTheDocument();
-    await expect(ui.newSeverityCustomizedCell.get()).toHaveATooltipWithContent(
-      'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.LOW',
-    );
-
-    // Activate last java rule
-    await user.click(ui.activateButton.get());
-    await user.type(ui.paramInput('1').get(), 'paramInput');
-    await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
-    expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument();
-    expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument();
-
-    // Rule is activated in all quality profiles - show notification in dialog
-    await user.click(ui.activateButton.get(screen.getByRole('main')));
-    expect(ui.activaInAllQPs.get()).toBeInTheDocument();
-    expect(ui.activateButton.get(ui.activateQPDialog.get())).toBeDisabled();
-    await user.click(ui.cancelButton.get());
-
-    // Change rule details in quality profile
-    await user.click(ui.changeButton('QP FooBaz').get());
-    await user.clear(ui.paramInput('1').get());
-    await user.type(ui.paramInput('1').get(), 'New');
-    await user.click(ui.mqrSwitch.get());
-    await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
-    await user.click(byRole('option', { name: 'severity_impact.BLOCKER' }).get());
-    await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
-    expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
-    expect(ui.qualityProfileRow.getAt(5)).toHaveTextContent('New');
-    await expect(
-      ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5)),
-    ).toHaveATooltipWithContent(
-      'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.BLOCKER',
-    );
-
-    // Revert rule details in quality profile
-    await user.click(ui.revertToParentDefinitionButton.get());
-    await user.click(ui.yesButton.get());
-    expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
-    expect(await ui.qualityProfileRow.findAt(5)).not.toHaveTextContent('New');
-    expect(
-      ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(5)),
-    ).not.toBeInTheDocument();
-
-    // Deactivate rule in quality profile
-    await user.click(ui.deactivateInQPButton('QP FooBar').get());
-    await user.click(ui.yesButton.get());
-    expect(ui.qpLink('QP FooBar').query()).not.toBeInTheDocument();
-  });
-
-  it('can activate/change/deactivate rule in quality profile for legacy mode', async () => {
-    const { ui, user } = getPageObjects();
-    settingsHandler.set(SettingsKey.LegacyMode, 'true');
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule1', [Feature.PrioritizedRules]);
-    await ui.detailsloaded();
-    expect(ui.qpLink('QP Foo').get()).toBeInTheDocument();
-
-    // Activate rule in quality profile
-    expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument();
-    await user.click(ui.activateButton.get());
-
-    await user.click(ui.prioritizedSwitch.get());
-    await user.click(ui.oldSeveritySelect.get());
-    await user.click(byRole('option', { name: 'severity.MINOR' }).get());
-    await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
-    expect(ui.qpLink('QP FooBar').get()).toBeInTheDocument();
-    expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
-    expect(ui.newSeverityCustomizedCell.query()).not.toBeInTheDocument();
-    expect(ui.oldSeverityCustomizedCell.get()).toBeInTheDocument();
-    expect(ui.oldSeverityCustomizedCell.get()).toHaveTextContent('severity.MAJORseverity.MINOR');
-
-    await user.click(ui.changeButton('QP FooBar').get());
-    await user.click(ui.oldSeveritySelect.get());
-    await user.click(
-      byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
-    );
-    await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
-    expect(ui.prioritizedRuleCell.get()).toBeInTheDocument();
-    expect(ui.oldSeverityCustomizedCell.query()).not.toBeInTheDocument();
-    expect(ui.newSeverityCustomizedCell.query()).not.toBeInTheDocument();
-
-    // Activate last java rule
-    await user.click(ui.activateButton.get());
-    await user.type(ui.paramInput('1').get(), 'paramInput');
-    await user.click(ui.activateButton.get(ui.activateQPDialog.get()));
-    expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument();
-    expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument();
-
-    // Change rule details in quality profile
-    await user.click(ui.changeButton('QP FooBaz').get());
-    await user.click(ui.oldSeveritySelect.get());
-    await user.click(byRole('option', { name: 'severity.BLOCKER' }).get());
-    await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
-    expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
-    expect(ui.oldSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5))).toBeInTheDocument();
-    expect(ui.oldSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5))).toHaveTextContent(
-      'severity.MAJORseverity.BLOCKER',
-    );
-
-    // Revert rule details in quality profile
-    await user.click(ui.revertToParentDefinitionButton.get());
-    await user.click(ui.yesButton.get());
-    expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz');
-    expect(
-      ui.oldSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(5)),
-    ).not.toBeInTheDocument();
-  });
-
-  it('should show multiple customized severities', async () => {
-    const { ui, user } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule10', [
-      Feature.PrioritizedRules,
-    ]);
-    await ui.detailsloaded();
-
-    expect(ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(1))).toBeInTheDocument();
-    await expect(
-      ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(1)),
-    ).toHaveATooltipWithContent(
-      'coding_rules.impact_customized.detailsoftware_quality.RELIABILITYseverity_impact.HIGHseverity_impact.INFO' +
-        'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.LOWseverity_impact.MEDIUM',
-    );
-
-    expect(ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(2))).toBeInTheDocument();
-    await expect(
-      ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(2)),
-    ).toHaveATooltipWithContent(
-      'coding_rules.impact_customized.detailsoftware_quality.RELIABILITYseverity_impact.HIGHseverity_impact.BLOCKER',
-    );
-
-    await user.click(ui.changeButton('QP Bar').get());
-    await user.click(ui.mqrSwitch.get());
-    await user.click(ui.newSeveritySelect(SoftwareQuality.Reliability).get());
-    await user.click(
-      byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
-    );
-    await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get());
-    await user.click(
-      byRole('option', { name: /coding_rules.custom_severity.severity_with_recommended/ }).get(),
-    );
-    await user.click(ui.saveButton.get(ui.changeQPDialog.get()));
-    expect(
-      ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(1)),
-    ).not.toBeInTheDocument();
-  });
-
-  it('can deactivate an inherrited rule', async () => {
-    const { ui, user } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule11');
-    await ui.detailsloaded();
-
-    // Should show 2 deactivate buttons: one for the parent, one for the child profile.
-    expect(ui.deactivateInQPButton('QP FooBarBaz').get()).toBeInTheDocument();
-    expect(ui.deactivateInQPButton('QP FooBaz').get()).toBeInTheDocument();
-
-    // Deactivate rule in inherited quality profile
-    await user.click(ui.deactivateInQPButton('QP FooBaz').get());
-    await user.click(ui.yesButton.get());
-    expect(ui.qpLink('QP FooBaz').query()).not.toBeInTheDocument();
-  });
-
-  it('cannot deactivate an inherrited rule if the setting is false', async () => {
-    const { ui } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    settingsHandler.set(SettingsKey.QPAdminCanDisableInheritedRules, 'false');
-    renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule11');
-    await ui.detailsloaded();
-
-    // Should show 1 deactivate button: one for the parent, none for the child profile.
-    expect(ui.deactivateInQPButton('QP FooBarBaz').get()).toBeInTheDocument();
-    expect(ui.deactivateInQPButton('QP FooBaz').query()).not.toBeInTheDocument();
-  });
-
-  it('can extend the rule description', async () => {
-    const { ui, user } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(undefined, 'coding_rules?open=rule5');
-    await ui.detailsloaded();
-    expect(ui.ruleTitle('Awsome Python rule').get()).toBeInTheDocument();
-
-    // Add
-    await user.click(ui.extendDescriptionButton.get());
-    await user.type(ui.extendDescriptionTextbox.get(), 'TEST DESC');
-    await user.click(ui.saveButton.get());
-    expect(await screen.findByText('TEST DESC')).toBeInTheDocument();
-
-    // Edit
-    await user.click(ui.extendDescriptionButton.get());
-    await user.clear(ui.extendDescriptionTextbox.get());
-    await user.type(ui.extendDescriptionTextbox.get(), 'NEW DESC');
-    await user.click(ui.saveButton.get());
-    expect(await screen.findByText('NEW DESC')).toBeInTheDocument();
-
-    // Cancel
-    await user.click(ui.extendDescriptionButton.get());
-    await user.type(ui.extendDescriptionTextbox.get(), 'Difference');
-    await user.click(ui.cancelButton.get());
-    expect(await screen.findByText('NEW DESC')).toBeInTheDocument();
-
-    // Remove
-    await user.click(ui.extendDescriptionButton.get());
-    await user.click(ui.removeButton.get());
-    await user.click(ui.removeButton.get(screen.getByRole('dialog')));
-    expect(screen.queryByText('NEW DESC')).not.toBeInTheDocument();
-  });
-
-  it('can set tags', async () => {
-    const { ui, user } = getPageObjects();
-    rulesHandler.setIsAdmin();
-    renderCodingRulesApp(undefined, 'coding_rules?open=rule10');
-    await ui.detailsloaded();
-
-    await user.click(ui.tagsDropdown.get());
-
-    RULE_TAGS_MOCK.forEach((tag) => {
-      expect(ui.tagCheckbox(tag).get()).toBeInTheDocument();
-    });
-
-    expect(ui.tagCheckbox(RULE_TAGS_MOCK[0]).get()).toBeChecked();
-
-    // Set tag
-    await user.click(ui.tagCheckbox(RULE_TAGS_MOCK[1]).get());
-    await user.keyboard('{Escape}');
-    await expect(ui.tagsDropdown.byText('multi-threading').get()).toHaveATooltipWithContent(
-      'multi-threading, awesome, cute',
-    );
-
-    await user.click(ui.tagsDropdown.get());
-
-    // Search for specific tag
-    await user.type(ui.tagSearch.get(), RULE_TAGS_MOCK[2]);
-    expect(ui.tagCheckbox(RULE_TAGS_MOCK[2]).get()).toBeInTheDocument();
-    expect(ui.tagCheckbox(RULE_TAGS_MOCK[1]).query()).not.toBeInTheDocument();
-  });
-});
-
 describe('redirects', () => {
   it('should open with permalink', async () => {
     const { ui } = getPageObjects();