]> source.dussan.org Git - sonarqube.git/commitdiff
[NO JIRA] Migrate part of quality gates app to RTL
authorMathieu Suen <mathieu.suen@sonarsource.com>
Mon, 21 Feb 2022 13:29:11 +0000 (14:29 +0100)
committersonartech <sonartech@sonarsource.com>
Fri, 11 Mar 2022 10:30:55 +0000 (10:30 +0000)
51 files changed:
server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts [new file with mode: 0644]
server/sonar-web/src/main/js/api/quality-gates.ts
server/sonar-web/src/main/js/apps/projectQualityGate/__tests__/__snapshots__/ProjectQualityGateApp-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionOperator.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/BuiltInQualityGateBadge-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionOperator-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CreateQualityGateForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Details-test.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/List-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ListHeader-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/MetricSelect-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.tsx [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Condition-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionOperator-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CreateQualityGateForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsHeader-test.tsx.snap
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/List-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/MetricSelect-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/RenameQualityGateForm-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/controls/Tooltip.tsx
server/sonar-web/src/main/js/components/controls/__tests__/Tooltip-test.tsx
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/ActionsDropdown-test.tsx.snap
server/sonar-web/src/main/js/components/controls/__tests__/__snapshots__/Tooltip-test.tsx.snap
server/sonar-web/src/main/js/components/controls/__tests__/buttons-test.tsx
server/sonar-web/src/main/js/components/controls/buttons.tsx
server/sonar-web/src/main/js/helpers/testMocks.ts
server/sonar-web/src/main/js/types/types.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

diff --git a/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts b/server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
new file mode 100644 (file)
index 0000000..0ca29ed
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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 { cloneDeep, flatten, omit, remove } from 'lodash';
+import { mockQualityGate } from '../../helpers/mocks/quality-gates';
+import { Condition, QualityGate } from '../../types/types';
+import {
+  copyQualityGate,
+  createCondition,
+  createQualityGate,
+  deleteCondition,
+  deleteQualityGate,
+  fetchQualityGate,
+  fetchQualityGates,
+  renameQualityGate,
+  searchGroups,
+  searchProjects,
+  searchUsers,
+  updateCondition
+} from '../quality-gates';
+
+export class QualityGatesServiceMock {
+  isAdmin = false;
+  readOnlyList: QualityGate[];
+  list: QualityGate[];
+
+  constructor(list?: QualityGate[], defaultId = 'AWBWEMe2qGAMGEYPjJlm') {
+    this.readOnlyList = list || [
+      mockQualityGate({
+        id: defaultId,
+        name: 'SonarSource way',
+        conditions: [
+          { id: 'AXJMbIUGPAOIsUIE3eNC', metric: 'new_coverage', op: 'LT', error: '85' },
+          { id: 'AXJMbIUGPAOIsUIE3eNE', metric: 'reliability_rating', op: 'GT', error: '4' },
+          { id: 'AXJMbIUGPAOIsUIE3eND', metric: 'security_rating', op: 'GT', error: '4' },
+          {
+            id: 'AXJMbIUGPAOIsUIE3eNT',
+            metric: 'new_maintainability_rating',
+            op: 'GT',
+            error: '1'
+          },
+          { id: 'AXJMbIUGPAOIsUIE3eNU', metric: 'new_reliability_rating', op: 'GT', error: '1' },
+          { id: 'AXJMbIUGPAOIsUIE3eNV', metric: 'new_security_rating', op: 'GT', error: '1' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eNc',
+            metric: 'new_duplicated_lines_density',
+            op: 'GT',
+            error: '3'
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOi',
+            metric: 'new_security_hotspots_reviewed',
+            op: 'LT',
+            error: '100'
+          }
+        ],
+        isDefault: true,
+        isBuiltIn: false
+      }),
+      mockQualityGate({
+        id: 'AXGYZrDqC-YjVCvvbRDY',
+        name: 'SonarSource way - CFamily',
+        conditions: [
+          { id: 'AXJMbIUHPAOIsUIE3eOu', metric: 'new_coverage', op: 'LT', error: '0' },
+          { id: 'AXJMbIUHPAOIsUIE3eOubis', metric: 'new_coverage', op: 'LT', error: '1' },
+          { id: 'deprecated', metric: 'function_complexity', op: 'LT', error: '1' }
+        ],
+        isDefault: false,
+        isBuiltIn: false
+      }),
+      mockQualityGate({
+        id: 'AWBWEMe4qGAMGEYPjJlr',
+        name: 'Sonar way',
+        conditions: [
+          { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
+          { id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOE',
+            metric: 'new_maintainability_rating',
+            op: 'GT',
+            error: '1'
+          },
+          { id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOG',
+            metric: 'new_duplicated_lines_density',
+            op: 'GT',
+            error: '3'
+          },
+          {
+            id: 'AXJMbIUHPAOIsUIE3eOk',
+            metric: 'new_security_hotspots_reviewed',
+            op: 'LT',
+            error: '100'
+          }
+        ],
+        isDefault: false,
+        isBuiltIn: true
+      })
+    ];
+
+    this.list = cloneDeep(this.readOnlyList);
+
+    (fetchQualityGate as jest.Mock).mockImplementation(this.showHandler);
+    (fetchQualityGates as jest.Mock).mockImplementation(this.listHandler);
+    (createQualityGate as jest.Mock).mockImplementation(this.createHandler);
+    (deleteQualityGate as jest.Mock).mockImplementation(this.destroyHandler);
+    (copyQualityGate as jest.Mock).mockImplementation(this.copyHandler);
+    (renameQualityGate as jest.Mock).mockImplementation(this.renameHandler);
+    (createCondition as jest.Mock).mockImplementation(this.createConditionHandler);
+    (updateCondition as jest.Mock).mockImplementation(this.updateConditionHandler);
+    (deleteCondition as jest.Mock).mockImplementation(this.deleteConditionHandler);
+
+    // To be implemented.
+    (searchUsers as jest.Mock).mockResolvedValue({ users: [] });
+    (searchGroups as jest.Mock).mockResolvedValue({ groups: [] });
+    (searchProjects as jest.Mock).mockResolvedValue({
+      paging: {
+        pageIndex: 1,
+        pageSize: 100,
+        total: 0
+      },
+      results: []
+    });
+  }
+
+  getCorruptedQualityGateName() {
+    return 'SonarSource way - CFamily';
+  }
+
+  reset() {
+    this.setIsAdmin(false);
+    this.list = cloneDeep(this.readOnlyList);
+  }
+
+  getDefaultQualityGate() {
+    return this.list.find(q => q.isDefault) || mockQualityGate({ isDefault: true });
+  }
+
+  getBuiltInQualityGate() {
+    return this.list.find(q => q.isBuiltIn) || mockQualityGate({ isBuiltIn: true });
+  }
+
+  setIsAdmin(isAdmin: boolean) {
+    this.isAdmin = isAdmin;
+  }
+
+  computeActions(q: QualityGate) {
+    return {
+      rename: q.isBuiltIn ? false : this.isAdmin,
+      setAsDefault: q.isDefault ? false : this.isAdmin,
+      copy: this.isAdmin,
+      associateProjects: this.isAdmin,
+      delete: q.isBuiltIn ? false : this.isAdmin,
+      manageConditions: this.isAdmin,
+      delegate: this.isAdmin
+    };
+  }
+
+  listHandler = () => {
+    return this.reply({
+      qualitygates: this.list
+        .map(q => omit(q, 'conditions'))
+        .map(q => ({
+          ...q,
+          actions: this.computeActions(q)
+        })),
+      default: this.getDefaultQualityGate().id,
+      actions: { create: this.isAdmin }
+    });
+  };
+
+  showHandler = ({ id }: { id: string }) => {
+    const qualityGate = omit(
+      this.list.find(q => q.id === id),
+      'isDefault'
+    );
+    return this.reply({ ...qualityGate, actions: this.computeActions(qualityGate) });
+  };
+
+  createHandler = ({ name }: { name: string }) => {
+    const newId = `newId${this.list.length}`;
+    this.list.push(
+      mockQualityGate({
+        id: newId,
+        name,
+        conditions: [],
+        isDefault: false,
+        isBuiltIn: false
+      })
+    );
+    return this.reply({
+      id: newId,
+      name
+    });
+  };
+
+  destroyHandler = ({ id }: { id: string }) => {
+    this.list = this.list.filter(q => q.id !== id);
+    return Promise.resolve();
+  };
+
+  copyHandler = ({ id, name }: { id: string; name: string }) => {
+    const newQG = cloneDeep(this.list.find(q => q.id === id));
+    if (newQG === undefined) {
+      return Promise.reject({ errors: [{ msg: `No quality gate has been found for id ${id}` }] });
+    }
+    newQG.name = name;
+    newQG.id = `newId${this.list.length}`;
+
+    newQG.isDefault = false;
+    newQG.isBuiltIn = false;
+
+    this.list.push(newQG);
+
+    return this.reply({
+      id: newQG.id,
+      name
+    });
+  };
+
+  renameHandler = ({ id, name }: { id: string; name: string }) => {
+    const renameQG = this.list.find(q => q.id === id);
+    if (renameQG === undefined) {
+      return Promise.reject({ errors: [{ msg: `No quality gate has been found for id ${id}` }] });
+    }
+    renameQG.name = name;
+    return this.reply({
+      id: renameQG.id,
+      name
+    });
+  };
+
+  createConditionHandler = (
+    data: {
+      gateId: string;
+    } & Omit<Condition, 'id'>
+  ) => {
+    const { metric, gateId, op, error } = data;
+    const qg = this.list.find(q => q.id === gateId);
+    if (qg === undefined) {
+      return Promise.reject({
+        errors: [{ msg: `No quality gate has been found for id ${gateId}` }]
+      });
+    }
+
+    const conditions = qg.conditions || [];
+    const id = `condId${qg.id}${conditions.length}`;
+    const newCondition = { id, metric, op, error };
+    conditions.push(newCondition);
+    qg.conditions = conditions;
+    return this.reply(newCondition);
+  };
+
+  updateConditionHandler = ({ id, metric, op, error }: Condition) => {
+    const condition = flatten(this.list.map(q => q.conditions || [])).find(q => q.id === id);
+    if (condition === undefined) {
+      return Promise.reject({ errors: [{ msg: `No condition has been found for id ${id}` }] });
+    }
+
+    condition.metric = metric;
+    condition.op = op;
+    condition.error = error;
+
+    return this.reply(condition);
+  };
+
+  deleteConditionHandler = ({ id }: { id: string }) => {
+    this.list.forEach(q => {
+      remove(q.conditions || [], c => c.id === id);
+    });
+    return Promise.resolve();
+  };
+
+  reply<T>(response: T): Promise<T> {
+    return Promise.resolve(cloneDeep(response));
+  }
+}
index af4bad890cb2ff0022928cb823109f33206e6d55..cc3d83be8e0d37de6e142c2d4af79b8047b61f13 100644 (file)
@@ -73,7 +73,7 @@ export function updateCondition(data: Condition): Promise<Condition> {
   return postJSON('/api/qualitygates/update_condition', data).catch(throwGlobalError);
 }
 
-export function deleteCondition(data: { id: number }): Promise<void> {
+export function deleteCondition(data: { id: string }): Promise<void> {
   return post('/api/qualitygates/delete_condition', data);
 }
 
index 03331f67dbaf56194e515b4a5e71e01a47ff85f6..13d8d45338bf64d3724f31c7239a8e41fd4c814d 100644 (file)
@@ -8,13 +8,13 @@ exports[`renders correctly 1`] = `
         "conditions": Array [
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "coverage",
             "op": "LT",
           },
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "new_bugs",
             "op": "LT",
           },
@@ -26,13 +26,13 @@ exports[`renders correctly 1`] = `
         "conditions": Array [
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "coverage",
             "op": "LT",
           },
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "new_bugs",
             "op": "LT",
           },
@@ -45,13 +45,13 @@ exports[`renders correctly 1`] = `
         "conditions": Array [
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "coverage",
             "op": "LT",
           },
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "new_bugs",
             "op": "LT",
           },
index 4f1b4203e15cf0d5695c4b7fe585c91a0a3fdca0..97d3834a76b928d7fb4c46964c6d1e33d3a96e52 100644 (file)
@@ -108,12 +108,14 @@ export class ConditionComponent extends React.PureComponent<Props, State> {
           <>
             <td className="text-center thin">
               <EditButton
+                aria-label={translateWithParameters('quality_gates.condition.edit', metric.name)}
                 data-test="quality-gates__condition-update"
                 onClick={this.handleOpenUpdate}
               />
             </td>
             <td className="text-center thin">
               <DeleteButton
+                aria-label={translateWithParameters('quality_gates.condition.delete', metric.name)}
                 data-test="quality-gates__condition-delete"
                 onClick={this.handleDeleteClick}
               />
index 03e45767dec227c636996203505cb05f2b82dd97..be2a21299592ba34bba0dfd35107c924505f320d 100644 (file)
@@ -65,19 +65,16 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
   }
 
   handleFormSubmit = () => {
-    if (this.state.metric) {
-      const { condition, qualityGate } = this.props;
-      const newCondition: Omit<Condition, 'id'> = {
-        metric: this.state.metric.key,
-        op: this.getSinglePossibleOperator(this.state.metric) || this.state.op,
-        error: this.state.error
-      };
-      const submitPromise = condition
-        ? updateCondition({ id: condition.id, ...newCondition })
-        : createCondition({ gateId: qualityGate.id, ...newCondition });
-      return submitPromise.then(this.props.onAddCondition);
-    }
-    return Promise.reject();
+    const { condition, qualityGate } = this.props;
+    const newCondition: Omit<Condition, 'id'> = {
+      metric: this.state.metric!.key,
+      op: this.getSinglePossibleOperator(this.state.metric!) || this.state.op,
+      error: this.state.error
+    };
+    const submitPromise = condition
+      ? updateCondition({ id: condition.id, ...newCondition })
+      : createCondition({ gateId: qualityGate.id, ...newCondition });
+    return submitPromise.then(this.props.onAddCondition);
   };
 
   handleScopeChange = (scope: 'new' | 'overall') => {
@@ -160,7 +157,7 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
         {metric && (
           <>
             <div className="modal-field display-inline-block">
-              <label htmlFor="condition-operator">
+              <label id="condition-operator-label">
                 {translate('quality_gates.conditions.operator')}
               </label>
               <ConditionOperator
@@ -170,7 +167,7 @@ export default class ConditionModal extends React.PureComponent<Props, State> {
               />
             </div>
             <div className="modal-field display-inline-block spacer-left">
-              <label htmlFor="condition-threshold">
+              <label id="condition-threshold-label">
                 {translate('quality_gates.conditions.value')}
               </label>
               <ThresholdInput
index a104ce59671cfc07f386881a3b862dc494c72ca2..ebad2b9038ccba990ae9575db29e4151641b10ad 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import Select from '../../../components/controls/Select';
 import { translate } from '../../../helpers/l10n';
 import { Metric } from '../../../types/types';
 import { getPossibleOperators } from '../utils';
@@ -50,16 +50,17 @@ export default class ConditionOperator extends React.PureComponent<Props> {
       });
 
       return (
-        <SelectLegacy
+        <Select
           autoFocus={true}
+          aria-labelledby="condition-operator-label"
           className="input-medium"
-          clearable={false}
+          isClearable={false}
           id="condition-operator"
           name="operator"
           onChange={this.handleChange}
           options={operatorOptions}
-          searchable={false}
-          value={this.props.op}
+          isSearchable={false}
+          value={operatorOptions.filter(o => o.value === this.props.op)}
         />
       );
     } else {
index 81dbb739289393cb45f46d09d2ed020ab9f0d941..ef92de4334b0c5343a48acc72eaf04050cfc894d 100644 (file)
@@ -47,7 +47,7 @@ interface Props {
   onRemoveCondition: (Condition: ConditionType) => void;
   onSaveCondition: (newCondition: ConditionType, oldCondition: ConditionType) => void;
   qualityGate: QualityGate;
-  updatedConditionId?: number;
+  updatedConditionId?: string;
 }
 
 const FORBIDDEN_METRIC_TYPES = ['DATA', 'DISTRIB', 'STRING', 'BOOL'];
@@ -61,6 +61,7 @@ const FORBIDDEN_METRICS: string[] = [
 export class Conditions extends React.PureComponent<Props> {
   renderConditionsTable = (conditions: ConditionType[], scope: 'new' | 'overall') => {
     const {
+      appState,
       qualityGate,
       metrics,
       canEdit,
@@ -68,8 +69,22 @@ export class Conditions extends React.PureComponent<Props> {
       onSaveCondition,
       updatedConditionId
     } = this.props;
+
+    const captionTranslationId =
+      scope === 'new'
+        ? 'quality_gates.conditions.new_code'
+        : 'quality_gates.conditions.overall_code';
     return (
       <table className="data zebra" data-test={`quality-gates__conditions-${scope}`}>
+        <caption>
+          <h4>{translate(captionTranslationId, 'long')}</h4>
+
+          {appState.branchesEnabled && (
+            <p className="spacer-top spacer-bottom">
+              {translate(captionTranslationId, 'description')}
+            </p>
+          )}
+        </caption>
         <thead>
           <tr>
             <th className="nowrap" style={{ width: 300 }}>
@@ -104,7 +119,7 @@ export class Conditions extends React.PureComponent<Props> {
   };
 
   render() {
-    const { appState, conditions, metrics, canEdit } = this.props;
+    const { conditions, metrics, canEdit } = this.props;
 
     const existingConditions = conditions.filter(condition => metrics[condition.metric]);
     const sortedConditions = sortBy(
@@ -194,28 +209,12 @@ export class Conditions extends React.PureComponent<Props> {
 
         {sortedConditionsOnNewMetrics.length > 0 && (
           <div className="big-spacer-top">
-            <h4>{translate('quality_gates.conditions.new_code.long')}</h4>
-
-            {appState.branchesEnabled && (
-              <p className="spacer-top spacer-bottom">
-                {translate('quality_gates.conditions.new_code.description')}
-              </p>
-            )}
-
             {this.renderConditionsTable(sortedConditionsOnNewMetrics, 'new')}
           </div>
         )}
 
         {sortedConditionsOnOverallMetrics.length > 0 && (
           <div className="big-spacer-top">
-            <h4>{translate('quality_gates.conditions.overall_code.long')}</h4>
-
-            {appState.branchesEnabled && (
-              <p className="spacer-top spacer-bottom">
-                {translate('quality_gates.conditions.overall_code.description')}
-              </p>
-            )}
-
             {this.renderConditionsTable(sortedConditionsOnOverallMetrics, 'overall')}
           </div>
         )}
index b90652e8739e6d4ed2b88a0a100cfbecb0e69c60..a76b821462522d0bbfa5a41341df8953a7368693 100644 (file)
@@ -52,10 +52,6 @@ export class CopyQualityGateForm extends React.PureComponent<Props, State> {
     const { qualityGate } = this.props;
     const { name } = this.state;
 
-    if (!name) {
-      return undefined;
-    }
-
     return copyQualityGate({ id: qualityGate.id, name }).then(newQualityGate => {
       this.props.onCopy();
       this.props.router.push(getQualityGateUrl(String(newQualityGate.id)));
index b63b1eed83d7b51375dfbc31d8db0864b046d170..3132ff9cffba27f1fba050c5ae74273fb68b1326 100644 (file)
@@ -38,7 +38,7 @@ interface Props {
 interface State {
   loading: boolean;
   qualityGate?: QualityGate;
-  updatedConditionId?: number;
+  updatedConditionId?: string;
 }
 
 export default class Details extends React.PureComponent<Props, State> {
index 6542c48f1aea61287b543c99f29f1a8a583074cc..51ee032d76206a03df4a1280d8bc6775bc0cc857 100644 (file)
@@ -32,7 +32,7 @@ export interface DetailsContentProps {
   onRemoveCondition: (Condition: Condition) => void;
   onSaveCondition: (newCondition: Condition, oldCondition: Condition) => void;
   qualityGate: QualityGate;
-  updatedConditionId?: number;
+  updatedConditionId?: string;
 }
 
 export function DetailsContent(props: DetailsContentProps) {
index c8ab508b2caa80d41f83e178a79a34fc9272ae24..b6d63e089e1bd91d6ee5d28652f38a2ccfdf5ea5 100644 (file)
@@ -30,11 +30,12 @@ interface Props {
 
 export default function List({ qualityGates }: Props) {
   return (
-    <div className="list-group">
+    <div className="list-group" role="menu">
       {qualityGates.map(qualityGate => (
         <Link
           activeClassName="active"
           className="list-group-item display-flex-center"
+          role="menuitem"
           data-id={qualityGate.id}
           key={qualityGate.id}
           to={getQualityGateUrl(String(qualityGate.id))}>
index 10d431f44c5f0afdaeb478a06645f99bdd2e8a0e..aae7c62b03cea700f92aa9a7054665922285b742 100644 (file)
@@ -49,10 +49,6 @@ export default class RenameQualityGateForm extends React.PureComponent<Props, St
     const { qualityGate } = this.props;
     const { name } = this.state;
 
-    if (!name) {
-      return undefined;
-    }
-
     return renameQualityGate({ id: qualityGate.id, name }).then(() => this.props.onRename());
   };
 
index 0739643b577446591047fd601352a15733d3c097..58c69ce43bd46498519630e31e821244e2c13658 100644 (file)
@@ -18,7 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import * as React from 'react';
-import SelectLegacy from '../../../components/controls/SelectLegacy';
+import Select from '../../../components/controls/Select';
 import { Metric } from '../../../types/types';
 
 interface Props {
@@ -33,12 +33,8 @@ export default class ThresholdInput extends React.PureComponent<Props> {
     this.props.onChange(e.currentTarget.value);
   };
 
-  handleSelectChange = (option: { value: string } | null) => {
-    if (option) {
-      this.props.onChange(option.value);
-    } else {
-      this.props.onChange('');
-    }
+  handleSelectChange = (option: { value: string }) => {
+    this.props.onChange(option.value);
   };
 
   renderRatingInput() {
@@ -52,16 +48,17 @@ export default class ThresholdInput extends React.PureComponent<Props> {
     ];
 
     return (
-      <SelectLegacy
+      <Select
         className="input-tiny text-middle"
-        clearable={true}
+        aria-labelledby="condition-threshold-label"
+        isClearable={false}
         id="condition-threshold"
         name={name}
         onChange={this.handleSelectChange}
         options={options}
         placeholder=""
-        searchable={false}
-        value={value}
+        isSearchable={false}
+        value={options.find(o => o.value === value)}
       />
     );
   }
@@ -76,6 +73,7 @@ export default class ThresholdInput extends React.PureComponent<Props> {
     return (
       <input
         className="input-tiny text-middle"
+        aria-labelledby="condition-threshold-label"
         data-type={metric.type}
         id="condition-threshold"
         name={name}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx
new file mode 100644 (file)
index 0000000..d02fc40
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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, waitFor, within } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock';
+import { mockAppState } from '../../../../helpers/testMocks';
+import { renderApp } from '../../../../helpers/testReactTestingUtils';
+import { AppState } from '../../../../types/types';
+import routes from '../../routes';
+
+jest.mock('../../../../api/quality-gates');
+
+let handler: QualityGatesServiceMock;
+
+beforeAll(() => {
+  handler = new QualityGatesServiceMock();
+});
+
+afterEach(() => handler.reset());
+
+jest.setTimeout(10_000);
+
+it('should open the default quality gates', async () => {
+  renderQualityGateApp();
+
+  expect(await screen.findAllByRole('menuitem')).toHaveLength(handler.list.length);
+
+  const defaultQualityGate = handler.getDefaultQualityGate();
+  expect(await screen.findAllByText(defaultQualityGate.name)).toHaveLength(2);
+});
+
+it('should list all quality gates', async () => {
+  renderQualityGateApp();
+
+  expect(
+    await screen.findByRole('menuitem', {
+      name: `${handler.getDefaultQualityGate().name} default`
+    })
+  ).toBeInTheDocument();
+  expect(
+    await screen.findByRole('menuitem', {
+      name: `${handler.getBuiltInQualityGate().name} quality_gates.built_in`
+    })
+  ).toBeInTheDocument();
+});
+
+it('should be able to create a quality gate then delete it', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  let createButton = await screen.findByRole('button', { name: 'create' });
+
+  // Using keyboard
+  await user.click(createButton);
+  let nameInput = screen.getByRole('textbox', { name: /name.*/ });
+  expect(nameInput).toBeInTheDocument();
+  await user.click(nameInput);
+  await user.keyboard('testone{Enter}');
+  expect(await screen.findByRole('menuitem', { name: 'testone' })).toBeInTheDocument();
+
+  // Using modal button
+  createButton = await screen.findByRole('button', { name: 'create' });
+  await user.click(createButton);
+  nameInput = screen.getByRole('textbox', { name: /name.*/ });
+  const saveButton = screen.getByRole('button', { name: 'save' });
+
+  expect(saveButton).toBeDisabled();
+  await user.click(nameInput);
+  await user.keyboard('testtwo');
+  await user.click(saveButton);
+
+  const newQG = await screen.findByRole('menuitem', { name: 'testtwo' });
+  expect(newQG).toBeInTheDocument();
+
+  // Delete the quality gate
+  await user.click(newQG);
+  const deleteButton = await screen.findByRole('button', { name: 'delete' });
+  await user.click(deleteButton);
+  const popup = screen.getByRole('dialog');
+  const dialogDeleteButton = within(popup).getByRole('button', { name: 'delete' });
+  await user.click(dialogDeleteButton);
+
+  await waitFor(() => {
+    expect(screen.queryByRole('menuitem', { name: 'testtwo' })).not.toBeInTheDocument();
+  });
+});
+
+it('should be able to copy a quality gate', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const copyButton = await screen.findByRole('button', { name: 'copy' });
+
+  await user.click(copyButton);
+  const nameInput = screen.getByRole('textbox', { name: /name.*/ });
+  expect(nameInput).toBeInTheDocument();
+  await user.click(nameInput);
+  await user.keyboard(' bis{Enter}');
+
+  expect(await screen.findByRole('menuitem', { name: /.* bis/ })).toBeInTheDocument();
+});
+
+it('should be able to rename a quality gate', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const renameButton = await screen.findByRole('button', { name: 'rename' });
+
+  await user.click(renameButton);
+  const nameInput = screen.getByRole('textbox', { name: /name.*/ });
+  expect(nameInput).toBeInTheDocument();
+  await user.click(nameInput);
+  await user.keyboard('{Control>}a{/Control}New Name{Enter}');
+
+  expect(await screen.findByRole('menuitem', { name: /New Name.*/ })).toBeInTheDocument();
+});
+
+it('should be able to add a condition', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  // On new code
+  await user.click(await screen.findByText('quality_gates.add_condition'));
+
+  let dialog = within(screen.getByRole('dialog'));
+
+  await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.new_code' }));
+  await user.click(dialog.getByRole('combobox'));
+  await user.click(dialog.getByRole('option', { name: 'Issues' }));
+  await user.click(dialog.getByRole('textbox', { name: 'quality_gates.conditions.value' }));
+  await user.keyboard('12{Enter}');
+
+  const newConditions = within(
+    await screen.findByRole('table', { name: 'quality_gates.conditions.new_code.long' })
+  );
+  expect(await newConditions.findByRole('cell', { name: 'Issues' })).toBeInTheDocument();
+  expect(await newConditions.findByRole('cell', { name: '12' })).toBeInTheDocument();
+
+  // On overall code
+  await user.click(await screen.findByText('quality_gates.add_condition'));
+
+  dialog = within(screen.getByRole('dialog'));
+
+  await user.click(dialog.getByLabelText('quality_gates.conditions.fails_when'));
+  await user.click(dialog.getByRole('option', { name: 'Info Issues' }));
+  await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.overall_code' }));
+  await user.click(dialog.getByLabelText('quality_gates.conditions.operator'));
+
+  await user.click(dialog.getByText('quality_gates.operator.LT'));
+  await user.click(dialog.getByRole('textbox', { name: 'quality_gates.conditions.value' }));
+  await user.keyboard('42{Enter}');
+
+  let overallConditions = within(
+    await screen.findByRole('table', { name: 'quality_gates.conditions.overall_code.long' })
+  );
+
+  expect(await overallConditions.findByRole('cell', { name: 'Info Issues' })).toBeInTheDocument();
+  expect(await overallConditions.findByRole('cell', { name: '42' })).toBeInTheDocument();
+
+  // Select a rating
+  await user.click(await screen.findByText('quality_gates.add_condition'));
+
+  dialog = within(screen.getByRole('dialog'));
+  await user.click(dialog.getByRole('radio', { name: 'quality_gates.conditions.overall_code' }));
+  await user.click(dialog.getByLabelText('quality_gates.conditions.fails_when'));
+  await user.click(dialog.getByRole('option', { name: 'Maintainability Rating' }));
+  await user.click(dialog.getByLabelText('quality_gates.conditions.value'));
+  await user.click(dialog.getByText('B'));
+  await user.click(dialog.getByRole('button', { name: 'quality_gates.add_condition' }));
+
+  overallConditions = within(
+    await screen.findByRole('table', { name: 'quality_gates.conditions.overall_code.long' })
+  );
+
+  expect(
+    await overallConditions.findByRole('cell', { name: 'Maintainability Rating' })
+  ).toBeInTheDocument();
+  expect(await overallConditions.findByRole('cell', { name: 'B' })).toBeInTheDocument();
+});
+
+it('should be able to edit a condition', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const newConditions = within(
+    await screen.findByRole('table', {
+      name: 'quality_gates.conditions.new_code.long'
+    })
+  );
+
+  await user.click(
+    newConditions.getByLabelText('quality_gates.condition.edit.Coverage on New Code')
+  );
+  const dialog = within(screen.getByRole('dialog'));
+  await user.click(dialog.getByRole('textbox', { name: 'quality_gates.conditions.value' }));
+  await user.keyboard('{Backspace}{Backspace}23{Enter}');
+
+  expect(await newConditions.findByText('Coverage')).toBeInTheDocument();
+  expect(await newConditions.findByText('23.0%')).toBeInTheDocument();
+});
+
+it('should be able to handle duplicate or deprecated condition', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+  await user.click(
+    await screen.findByRole('menuitem', { name: handler.getCorruptedQualityGateName() })
+  );
+
+  expect(await screen.findByText('quality_gates.duplicated_conditions')).toBeInTheDocument();
+  expect(
+    await screen.findByRole('cell', { name: 'Complexity / Function deprecated' })
+  ).toBeInTheDocument();
+});
+
+it('should be able to handle delete condition', async () => {
+  const user = userEvent.setup();
+  handler.setIsAdmin(true);
+  renderQualityGateApp();
+
+  const newConditions = within(
+    await screen.findByRole('table', {
+      name: 'quality_gates.conditions.new_code.long'
+    })
+  );
+
+  await user.click(
+    newConditions.getByLabelText('quality_gates.condition.delete.Coverage on New Code')
+  );
+
+  const dialog = within(screen.getByRole('dialog'));
+  await user.click(dialog.getByRole('button', { name: 'delete' }));
+
+  await waitFor(() => {
+    expect(newConditions.queryByRole('cell', { name: 'Coverage' })).not.toBeInTheDocument();
+  });
+});
+
+it('should explain condition on branch', async () => {
+  renderQualityGateApp(mockAppState({ branchesEnabled: true }));
+
+  expect(
+    await screen.findByText('quality_gates.conditions.new_code.description')
+  ).toBeInTheDocument();
+  expect(
+    await screen.findByText('quality_gates.conditions.overall_code.description')
+  ).toBeInTheDocument();
+});
+
+function renderQualityGateApp(appState?: AppState) {
+  renderApp('quality_gates', routes, { appState });
+}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/BuiltInQualityGateBadge-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/BuiltInQualityGateBadge-test.tsx
deleted file mode 100644 (file)
index b07bce7..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 BuiltInQualityGateBadge from '../BuiltInQualityGateBadge';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props = {}) {
-  return shallow(<BuiltInQualityGateBadge {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Condition-test.tsx
deleted file mode 100644 (file)
index 94805c6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockCondition, mockMetric } from '../../../../helpers/testMocks';
-import { ConditionComponent } from '../Condition';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('default');
-  expect(shallowRender({ canEdit: true })).toMatchSnapshot('with edit rights');
-  expect(shallowRender({ updated: true })).toMatchSnapshot('updated');
-});
-
-it('should render the update modal correctly', () => {
-  const wrapper = shallowRender({ canEdit: true });
-  wrapper.instance().handleOpenUpdate();
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should render the delete modal correctly', () => {
-  const wrapper = shallowRender({ canEdit: true });
-  wrapper.instance().handleDeleteClick();
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ConditionComponent['props']> = {}) {
-  return shallow<ConditionComponent>(
-    <ConditionComponent
-      canEdit={false}
-      condition={mockCondition()}
-      metric={mockMetric()}
-      metrics={{}}
-      onRemoveCondition={jest.fn()}
-      onSaveCondition={jest.fn()}
-      qualityGate={mockQualityGate()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx
deleted file mode 100644 (file)
index 41e1ca0..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { createCondition, updateCondition } from '../../../../api/quality-gates';
-import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockCondition, mockMetric } from '../../../../helpers/testMocks';
-import { MetricKey } from '../../../../types/metrics';
-import ConditionModal from '../ConditionModal';
-
-jest.mock('../../../../api/quality-gates', () => ({
-  createCondition: jest.fn().mockResolvedValue({}),
-  updateCondition: jest.fn().mockResolvedValue({})
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(shallowRender({ metric: mockMetric() })).toMatchSnapshot();
-});
-
-it('should correctly handle a metric selection', () => {
-  const wrapper = shallowRender();
-  const metric = mockMetric();
-
-  expect(wrapper.find('withMetricsContext(MetricSelectComponent)').prop('metric')).toBeUndefined();
-
-  wrapper.instance().handleMetricChange(metric);
-  expect(wrapper.find('withMetricsContext(MetricSelectComponent)').prop('metric')).toEqual(metric);
-});
-
-it('should correctly switch scope', () => {
-  const wrapper = shallowRender({
-    metrics: [
-      mockMetric({ key: MetricKey.new_coverage }),
-      mockMetric({
-        key: MetricKey.new_duplicated_lines
-      }),
-      mockMetric(),
-      mockMetric({ key: MetricKey.duplicated_lines })
-    ]
-  });
-  expect(wrapper).toMatchSnapshot();
-
-  wrapper.instance().handleScopeChange('overall');
-  expect(wrapper).toMatchSnapshot();
-
-  wrapper.instance().handleScopeChange('new');
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should handle submission', async () => {
-  const onAddCondition = jest.fn();
-  const wrapper = shallowRender({ onAddCondition });
-
-  wrapper.setState({ metric: mockMetric() });
-
-  await wrapper.instance().handleFormSubmit();
-
-  expect(createCondition).toBeCalled();
-  expect(updateCondition).not.toBeCalled();
-
-  jest.clearAllMocks();
-
-  wrapper.setProps({ condition: mockCondition() });
-  await wrapper.instance().handleFormSubmit();
-
-  expect(createCondition).not.toBeCalled();
-  expect(updateCondition).toBeCalled();
-});
-
-function shallowRender(props: Partial<ConditionModal['props']> = {}) {
-  return shallow<ConditionModal>(
-    <ConditionModal
-      header="header"
-      metrics={[
-        mockMetric({ key: MetricKey.new_coverage }),
-        mockMetric({ key: MetricKey.new_duplicated_lines })
-      ]}
-      onAddCondition={jest.fn()}
-      onClose={jest.fn()}
-      qualityGate={mockQualityGate()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionOperator-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionOperator-test.tsx
deleted file mode 100644 (file)
index ac76272..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 ConditionOperator from '../ConditionOperator';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<ConditionOperator['props']> = {}) {
-  return shallow(
-    <ConditionOperator
-      metric={{ id: '1', key: 'foo', name: 'Foo', type: 'PERCENT' }}
-      onOperatorChange={jest.fn()}
-      op="LT"
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Conditions-test.tsx
deleted file mode 100644 (file)
index 2963e8c..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockAppState, mockCondition, mockMetric } from '../../../../helpers/testMocks';
-import { MetricKey } from '../../../../types/metrics';
-import { Conditions } from '../Conditions';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render correctly with an updated condition', () => {
-  expect(shallowRender({ updatedConditionId: mockCondition().id })).toMatchSnapshot();
-});
-
-it('should render correctly with new code conditions', () => {
-  const wrapper = shallowRender({
-    conditions: [
-      mockCondition(),
-      mockCondition({ id: 2, metric: MetricKey.duplicated_lines }),
-      mockCondition({ id: 3, metric: MetricKey.new_coverage }),
-      mockCondition({ id: 4, metric: MetricKey.new_duplicated_lines })
-    ]
-  });
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should render correctly for no conditions', () => {
-  const wrapper = shallowRender({ conditions: [] });
-  expect(wrapper).toMatchSnapshot();
-});
-
-it('should render the add conditions button and modal', () => {
-  const wrapper = shallowRender({ canEdit: true });
-  expect(wrapper).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<Conditions['props']> = {}) {
-  return shallow<Conditions>(
-    <Conditions
-      appState={mockAppState({ branchesEnabled: true })}
-      canEdit={false}
-      conditions={[mockCondition(), mockCondition({ id: 2, metric: MetricKey.duplicated_lines })]}
-      metrics={{
-        [MetricKey.coverage]: mockMetric(),
-        [MetricKey.duplicated_lines]: mockMetric({ key: MetricKey.duplicated_lines }),
-        [MetricKey.new_coverage]: mockMetric({
-          key: MetricKey.new_coverage
-        }),
-        [MetricKey.new_duplicated_lines]: mockMetric({
-          key: MetricKey.new_duplicated_lines
-        })
-      }}
-      onAddCondition={jest.fn()}
-      onRemoveCondition={jest.fn()}
-      onSaveCondition={jest.fn()}
-      qualityGate={mockQualityGate()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx
deleted file mode 100644 (file)
index 89ba4ea..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { copyQualityGate } from '../../../../api/quality-gates';
-import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockRouter } from '../../../../helpers/testMocks';
-import { CopyQualityGateForm } from '../CopyQualityGateForm';
-
-jest.mock('../../../../api/quality-gates', () => ({
-  copyQualityGate: jest.fn().mockResolvedValue({})
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should handle copy', async () => {
-  const onCopy = jest.fn();
-  const router = mockRouter();
-  const qualityGate = mockQualityGate();
-  const wrapper = shallowRender({ onCopy, qualityGate, router });
-
-  const name = 'name';
-  wrapper.setState({ name });
-
-  await wrapper.instance().handleCopy();
-
-  expect(copyQualityGate).toBeCalledWith({ id: qualityGate.id, name });
-  expect(onCopy).toBeCalled();
-  expect(router.push).toBeCalled();
-
-  jest.clearAllMocks();
-
-  wrapper.setState({ name: '' });
-  await wrapper.instance().handleCopy();
-
-  expect(copyQualityGate).not.toBeCalled();
-});
-
-function shallowRender(overrides: Partial<CopyQualityGateForm['props']> = {}) {
-  return shallow<CopyQualityGateForm>(
-    <CopyQualityGateForm
-      onClose={jest.fn()}
-      onCopy={jest.fn()}
-      qualityGate={mockQualityGate()}
-      router={mockRouter()}
-      {...overrides}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CreateQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CreateQualityGateForm-test.tsx
deleted file mode 100644 (file)
index 0755def..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { createQualityGate } from '../../../../api/quality-gates';
-import ConfirmModal from '../../../../components/controls/ConfirmModal';
-import { mockRouter } from '../../../../helpers/testMocks';
-import { change, waitAndUpdate } from '../../../../helpers/testUtils';
-import { getQualityGateUrl } from '../../../../helpers/urls';
-import { CreateQualityGateForm } from '../CreateQualityGateForm';
-
-jest.mock('../../../../api/quality-gates', () => ({
-  createQualityGate: jest.fn().mockResolvedValue({ id: '1', name: 'newValue' })
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should correctly handle create', async () => {
-  const onCreate = jest.fn().mockResolvedValue(undefined);
-  const push = jest.fn();
-  const wrapper = shallowRender({ onCreate, router: mockRouter({ push }) });
-
-  wrapper
-    .find(ConfirmModal)
-    .props()
-    .onConfirm();
-  expect(createQualityGate).not.toHaveBeenCalled();
-
-  change(wrapper.find('#quality-gate-form-name'), 'newValue');
-  expect(wrapper.state().name).toBe('newValue');
-
-  wrapper
-    .find(ConfirmModal)
-    .props()
-    .onConfirm();
-  expect(createQualityGate).toHaveBeenCalledWith({ name: 'newValue' });
-
-  await waitAndUpdate(wrapper);
-  expect(onCreate).toHaveBeenCalled();
-  expect(push).toHaveBeenCalledWith(getQualityGateUrl('1'));
-});
-
-function shallowRender(props: Partial<CreateQualityGateForm['props']> = {}) {
-  return shallow<CreateQualityGateForm>(
-    <CreateQualityGateForm
-      onClose={jest.fn()}
-      onCreate={jest.fn()}
-      router={mockRouter()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx
deleted file mode 100644 (file)
index 56cb8fc..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { deleteQualityGate } from '../../../../api/quality-gates';
-import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import { mockRouter } from '../../../../helpers/testMocks';
-import { DeleteQualityGateForm } from '../DeleteQualityGateForm';
-
-jest.mock('../../../../api/quality-gates', () => ({
-  deleteQualityGate: jest.fn().mockResolvedValue({})
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should handle onDelete', async () => {
-  const onDelete = jest.fn();
-  const router = mockRouter();
-  const qualityGate = mockQualityGate();
-  const wrapper = shallowRender({ onDelete, qualityGate, router });
-
-  await wrapper.instance().onDelete();
-
-  expect(deleteQualityGate).toBeCalledWith({ id: qualityGate.id });
-  expect(onDelete).toBeCalled();
-  expect(router.push).toBeCalled();
-});
-
-function shallowRender(overrides: Partial<DeleteQualityGateForm['props']> = {}) {
-  return shallow<DeleteQualityGateForm>(
-    <DeleteQualityGateForm
-      onDelete={jest.fn()}
-      qualityGate={mockQualityGate()}
-      router={mockRouter()}
-      {...overrides}
-    />
-  );
-}
index 960f7379dd1944b6c3440bd5fab099efb15c63f0..3f634504205c5c1852bb0551e0eefc9ea8486154 100644 (file)
@@ -78,7 +78,7 @@ it('should correctly add/replace/remove conditions', async () => {
 
   await waitAndUpdate(wrapper);
 
-  const newCondition = mockCondition({ metric: 'bugs', id: 2 });
+  const newCondition = mockCondition({ metric: 'bugs', id: '2' });
   instance.handleAddCondition(newCondition);
   expect(addCondition).toBeCalledWith(qualityGate, newCondition);
 
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/List-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/List-test.tsx
deleted file mode 100644 (file)
index 790f5d0..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import List from '../List';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender() {
-  return shallow(
-    <List
-      qualityGates={[
-        mockQualityGate(),
-        mockQualityGate({ isBuiltIn: true }),
-        mockQualityGate({ isDefault: true })
-      ]}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ListHeader-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ListHeader-test.tsx
deleted file mode 100644 (file)
index d63656c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 ListHeader from '../ListHeader';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  const wrapper = shallowRender({ canCreate: true });
-  expect(wrapper.find('ModalButton').exists()).toBe(true);
-  expect(wrapper.find('ModalButton').dive()).toMatchSnapshot();
-});
-
-function shallowRender(props = {}) {
-  return shallow(<ListHeader canCreate={false} refreshQualityGates={jest.fn()} {...props} />);
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/MetricSelect-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/MetricSelect-test.tsx
deleted file mode 100644 (file)
index 2368e5c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { mockMetric } from '../../../../helpers/testMocks';
-import { MetricSelectComponent } from '../MetricSelect';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should correctly handle change', () => {
-  const onMetricChange = jest.fn();
-  const metric = mockMetric();
-  const metricsArray = [mockMetric({ key: 'duplication' }), metric];
-  const wrapper = shallowRender({ metricsArray, onMetricChange });
-  wrapper.instance().handleChange({ label: metric.name, value: metric.key });
-  expect(onMetricChange).toBeCalledWith(metric);
-});
-
-function shallowRender(props: Partial<MetricSelectComponent['props']> = {}) {
-  return shallow<MetricSelectComponent>(
-    <MetricSelectComponent
-      metricsArray={[mockMetric()]}
-      metrics={{}}
-      onMetricChange={jest.fn()}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx
deleted file mode 100644 (file)
index 1ae7723..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 { renameQualityGate } from '../../../../api/quality-gates';
-import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
-import RenameQualityGateForm from '../RenameQualityGateForm';
-
-jest.mock('../../../../api/quality-gates', () => ({
-  renameQualityGate: jest.fn().mockResolvedValue({})
-}));
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should handle rename', async () => {
-  const qualityGate = mockQualityGate();
-  const wrapper = shallowRender({ qualityGate });
-
-  const name = 'new name';
-
-  wrapper.setState({ name });
-
-  await wrapper.instance().handleRename();
-
-  expect(renameQualityGate).toBeCalledWith({ ...qualityGate, name });
-
-  jest.clearAllMocks();
-
-  wrapper.setState({ name: '' });
-
-  await wrapper.instance().handleRename();
-
-  expect(renameQualityGate).not.toBeCalled();
-});
-
-function shallowRender(overrides: Partial<RenameQualityGateForm['props']> = {}) {
-  return shallow<RenameQualityGateForm>(
-    <RenameQualityGateForm
-      onClose={jest.fn()}
-      onRename={jest.fn()}
-      qualityGate={mockQualityGate()}
-      {...overrides}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ThresholdInput-test.tsx
deleted file mode 100644 (file)
index e51ec27..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2022 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 SelectLegacy from '../../../../components/controls/SelectLegacy';
-import { change } from '../../../../helpers/testUtils';
-import ThresholdInput from '../ThresholdInput';
-
-describe('on strings', () => {
-  const metric = { id: '1', key: 'foo', name: 'Foo', type: 'INTEGER' };
-  it('should render text input', () => {
-    const input = shallow(
-      <ThresholdInput metric={metric} name="foo" onChange={jest.fn()} value="2" />
-    ).find('input');
-    expect(input.length).toEqual(1);
-    expect(input.prop('name')).toEqual('foo');
-    expect(input.prop('value')).toEqual('2');
-  });
-
-  it('should change', () => {
-    const onChange = jest.fn();
-    const input = shallow(
-      <ThresholdInput metric={metric} name="foo" onChange={onChange} value="2" />
-    ).find('input');
-    change(input, 'bar');
-    expect(onChange).toBeCalledWith('bar');
-  });
-});
-
-describe('on ratings', () => {
-  const metric = { id: '1', key: 'foo', name: 'Foo', type: 'RATING' };
-  it('should render Select', () => {
-    const select = shallow(
-      <ThresholdInput metric={metric} name="foo" onChange={jest.fn()} value="2" />
-    ).find(SelectLegacy);
-    expect(select.length).toEqual(1);
-    expect(select.prop('value')).toEqual('2');
-  });
-
-  it('should set', () => {
-    const onChange = jest.fn();
-    const select = shallow(
-      <ThresholdInput metric={metric} name="foo" onChange={onChange} value="2" />
-    ).find(SelectLegacy);
-    (select.prop('onChange') as Function)({ label: 'D', value: '4' });
-    expect(onChange).toBeCalledWith('4');
-  });
-
-  it('should unset', () => {
-    const onChange = jest.fn();
-    const select = shallow(
-      <ThresholdInput metric={metric} name="foo" onChange={onChange} value="2" />
-    ).find(SelectLegacy);
-    (select.prop('onChange') as Function)(null);
-    expect(onChange).toBeCalledWith('');
-  });
-});
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/BuiltInQualityGateBadge-test.tsx.snap
deleted file mode 100644 (file)
index 04bf352..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Tooltip
-  overlay="quality_gates.built_in.help"
->
-  <div
-    className="badge"
-  >
-    quality_gates.built_in
-  </div>
-</Tooltip>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Condition-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Condition-test.tsx.snap
deleted file mode 100644 (file)
index 50f735e..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<tr
-  className=""
->
-  <td
-    className="text-middle"
-  >
-    Coverage
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    quality_gates.operator.LT
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    10.0%
-  </td>
-</tr>
-`;
-
-exports[`should render correctly: updated 1`] = `
-<tr
-  className="highlighted"
->
-  <td
-    className="text-middle"
-  >
-    Coverage
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    quality_gates.operator.LT
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    10.0%
-  </td>
-</tr>
-`;
-
-exports[`should render correctly: with edit rights 1`] = `
-<tr
-  className=""
->
-  <td
-    className="text-middle"
-  >
-    Coverage
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    quality_gates.operator.LT
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    10.0%
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <EditButton
-      data-test="quality-gates__condition-update"
-      onClick={[Function]}
-    />
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <DeleteButton
-      data-test="quality-gates__condition-delete"
-      onClick={[Function]}
-    />
-  </td>
-</tr>
-`;
-
-exports[`should render the delete modal correctly 1`] = `
-<tr
-  className=""
->
-  <td
-    className="text-middle"
-  >
-    Coverage
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    quality_gates.operator.LT
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    10.0%
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <EditButton
-      data-test="quality-gates__condition-update"
-      onClick={[Function]}
-    />
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <DeleteButton
-      data-test="quality-gates__condition-delete"
-      onClick={[Function]}
-    />
-  </td>
-  <ConfirmModal
-    confirmButtonText="delete"
-    confirmData={
-      Object {
-        "error": "10",
-        "id": 1,
-        "metric": "coverage",
-        "op": "LT",
-      }
-    }
-    header="quality_gates.delete_condition"
-    isDestructive={true}
-    onClose={[Function]}
-    onConfirm={[Function]}
-  >
-    quality_gates.delete_condition.confirm.message.Coverage
-  </ConfirmModal>
-</tr>
-`;
-
-exports[`should render the update modal correctly 1`] = `
-<tr
-  className=""
->
-  <td
-    className="text-middle"
-  >
-    Coverage
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    quality_gates.operator.LT
-  </td>
-  <td
-    className="text-middle nowrap"
-  >
-    10.0%
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <EditButton
-      data-test="quality-gates__condition-update"
-      onClick={[Function]}
-    />
-  </td>
-  <td
-    className="text-center thin"
-  >
-    <DeleteButton
-      data-test="quality-gates__condition-delete"
-      onClick={[Function]}
-    />
-  </td>
-  <ConditionModal
-    condition={
-      Object {
-        "error": "10",
-        "id": 1,
-        "metric": "coverage",
-        "op": "LT",
-      }
-    }
-    header="quality_gates.update_condition"
-    metric={
-      Object {
-        "id": "coverage",
-        "key": "coverage",
-        "name": "Coverage",
-        "type": "PERCENT",
-      }
-    }
-    onAddCondition={[Function]}
-    onClose={[Function]}
-    qualityGate={
-      Object {
-        "id": "1",
-        "name": "qualitygate",
-      }
-    }
-  />
-</tr>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionModal-test.tsx.snap
deleted file mode 100644 (file)
index 29e4136..0000000
+++ /dev/null
@@ -1,364 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly switch scope 1`] = `
-<ConfirmModal
-  confirmButtonText="header"
-  confirmDisable={true}
-  header="header"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <div
-    className="modal-field display-flex-center"
-  >
-    <Radio
-      checked={true}
-      onCheck={[Function]}
-      value="new"
-    >
-      <span
-        data-test="quality-gates__condition-scope-new"
-      >
-        quality_gates.conditions.new_code
-      </span>
-    </Radio>
-    <Radio
-      checked={false}
-      className="big-spacer-left"
-      onCheck={[Function]}
-      value="overall"
-    >
-      <span
-        data-test="quality-gates__condition-scope-overall"
-      >
-        quality_gates.conditions.overall_code
-      </span>
-    </Radio>
-  </div>
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="condition-metric"
-    >
-      quality_gates.conditions.fails_when
-    </label>
-    <withMetricsContext(MetricSelectComponent)
-      metricsArray={
-        Array [
-          Object {
-            "id": "new_coverage",
-            "key": "new_coverage",
-            "name": "New_coverage",
-            "type": "PERCENT",
-          },
-          Object {
-            "id": "new_duplicated_lines",
-            "key": "new_duplicated_lines",
-            "name": "New_duplicated_lines",
-            "type": "PERCENT",
-          },
-        ]
-      }
-      onMetricChange={[Function]}
-    />
-  </div>
-</ConfirmModal>
-`;
-
-exports[`should correctly switch scope 2`] = `
-<ConfirmModal
-  confirmButtonText="header"
-  confirmDisable={true}
-  header="header"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <div
-    className="modal-field display-flex-center"
-  >
-    <Radio
-      checked={false}
-      onCheck={[Function]}
-      value="new"
-    >
-      <span
-        data-test="quality-gates__condition-scope-new"
-      >
-        quality_gates.conditions.new_code
-      </span>
-    </Radio>
-    <Radio
-      checked={true}
-      className="big-spacer-left"
-      onCheck={[Function]}
-      value="overall"
-    >
-      <span
-        data-test="quality-gates__condition-scope-overall"
-      >
-        quality_gates.conditions.overall_code
-      </span>
-    </Radio>
-  </div>
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="condition-metric"
-    >
-      quality_gates.conditions.fails_when
-    </label>
-    <withMetricsContext(MetricSelectComponent)
-      metricsArray={
-        Array [
-          Object {
-            "id": "coverage",
-            "key": "coverage",
-            "name": "Coverage",
-            "type": "PERCENT",
-          },
-          Object {
-            "id": "duplicated_lines",
-            "key": "duplicated_lines",
-            "name": "Duplicated_lines",
-            "type": "PERCENT",
-          },
-        ]
-      }
-      onMetricChange={[Function]}
-    />
-  </div>
-</ConfirmModal>
-`;
-
-exports[`should correctly switch scope 3`] = `
-<ConfirmModal
-  confirmButtonText="header"
-  confirmDisable={true}
-  header="header"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <div
-    className="modal-field display-flex-center"
-  >
-    <Radio
-      checked={true}
-      onCheck={[Function]}
-      value="new"
-    >
-      <span
-        data-test="quality-gates__condition-scope-new"
-      >
-        quality_gates.conditions.new_code
-      </span>
-    </Radio>
-    <Radio
-      checked={false}
-      className="big-spacer-left"
-      onCheck={[Function]}
-      value="overall"
-    >
-      <span
-        data-test="quality-gates__condition-scope-overall"
-      >
-        quality_gates.conditions.overall_code
-      </span>
-    </Radio>
-  </div>
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="condition-metric"
-    >
-      quality_gates.conditions.fails_when
-    </label>
-    <withMetricsContext(MetricSelectComponent)
-      metricsArray={
-        Array [
-          Object {
-            "id": "new_coverage",
-            "key": "new_coverage",
-            "name": "New_coverage",
-            "type": "PERCENT",
-          },
-          Object {
-            "id": "new_duplicated_lines",
-            "key": "new_duplicated_lines",
-            "name": "New_duplicated_lines",
-            "type": "PERCENT",
-          },
-        ]
-      }
-      onMetricChange={[Function]}
-    />
-  </div>
-</ConfirmModal>
-`;
-
-exports[`should render correctly 1`] = `
-<ConfirmModal
-  confirmButtonText="header"
-  confirmDisable={true}
-  header="header"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <div
-    className="modal-field display-flex-center"
-  >
-    <Radio
-      checked={true}
-      onCheck={[Function]}
-      value="new"
-    >
-      <span
-        data-test="quality-gates__condition-scope-new"
-      >
-        quality_gates.conditions.new_code
-      </span>
-    </Radio>
-    <Radio
-      checked={false}
-      className="big-spacer-left"
-      onCheck={[Function]}
-      value="overall"
-    >
-      <span
-        data-test="quality-gates__condition-scope-overall"
-      >
-        quality_gates.conditions.overall_code
-      </span>
-    </Radio>
-  </div>
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="condition-metric"
-    >
-      quality_gates.conditions.fails_when
-    </label>
-    <withMetricsContext(MetricSelectComponent)
-      metricsArray={
-        Array [
-          Object {
-            "id": "new_coverage",
-            "key": "new_coverage",
-            "name": "New_coverage",
-            "type": "PERCENT",
-          },
-          Object {
-            "id": "new_duplicated_lines",
-            "key": "new_duplicated_lines",
-            "name": "New_duplicated_lines",
-            "type": "PERCENT",
-          },
-        ]
-      }
-      onMetricChange={[Function]}
-    />
-  </div>
-</ConfirmModal>
-`;
-
-exports[`should render correctly 2`] = `
-<ConfirmModal
-  confirmButtonText="header"
-  confirmDisable={false}
-  header="header"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="condition-metric"
-    >
-      quality_gates.conditions.fails_when
-    </label>
-    <withMetricsContext(MetricSelectComponent)
-      metric={
-        Object {
-          "id": "coverage",
-          "key": "coverage",
-          "name": "Coverage",
-          "type": "PERCENT",
-        }
-      }
-      metricsArray={
-        Array [
-          Object {
-            "id": "new_coverage",
-            "key": "new_coverage",
-            "name": "New_coverage",
-            "type": "PERCENT",
-          },
-          Object {
-            "id": "new_duplicated_lines",
-            "key": "new_duplicated_lines",
-            "name": "New_duplicated_lines",
-            "type": "PERCENT",
-          },
-        ]
-      }
-      onMetricChange={[Function]}
-    />
-    <span
-      className="note"
-    >
-      Coverage
-    </span>
-  </div>
-  <div
-    className="modal-field display-inline-block"
-  >
-    <label
-      htmlFor="condition-operator"
-    >
-      quality_gates.conditions.operator
-    </label>
-    <ConditionOperator
-      metric={
-        Object {
-          "id": "coverage",
-          "key": "coverage",
-          "name": "Coverage",
-          "type": "PERCENT",
-        }
-      }
-      onOperatorChange={[Function]}
-    />
-  </div>
-  <div
-    className="modal-field display-inline-block spacer-left"
-  >
-    <label
-      htmlFor="condition-threshold"
-    >
-      quality_gates.conditions.value
-    </label>
-    <ThresholdInput
-      metric={
-        Object {
-          "id": "coverage",
-          "key": "coverage",
-          "name": "Coverage",
-          "type": "PERCENT",
-        }
-      }
-      name="error"
-      onChange={[Function]}
-      value=""
-    />
-  </div>
-</ConfirmModal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionOperator-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ConditionOperator-test.tsx.snap
deleted file mode 100644 (file)
index b527169..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<SelectLegacy
-  autoFocus={true}
-  className="input-medium"
-  clearable={false}
-  id="condition-operator"
-  name="operator"
-  onChange={[Function]}
-  options={
-    Array [
-      Object {
-        "label": "quality_gates.operator.LT",
-        "value": "LT",
-      },
-      Object {
-        "label": "quality_gates.operator.GT",
-        "value": "GT",
-      },
-    ]
-  }
-  searchable={false}
-  value="LT"
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Conditions-test.tsx.snap
deleted file mode 100644 (file)
index 66ea9de..0000000
+++ /dev/null
@@ -1,660 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="quality-gate-section"
->
-  <header
-    className="display-flex-center spacer-bottom"
-  >
-    <h3>
-      quality_gates.conditions
-    </h3>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.conditions.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/clean-as-you-code/",
-            "label": "quality_gates.conditions.help.link",
-          },
-        ]
-      }
-    />
-  </header>
-  <div
-    className="big-spacer-top"
-  >
-    <h4>
-      quality_gates.conditions.overall_code.long
-    </h4>
-    <p
-      className="spacer-top spacer-bottom"
-    >
-      quality_gates.conditions.overall_code.description
-    </p>
-    <table
-      className="data zebra"
-      data-test="quality-gates__conditions-overall"
-    >
-      <thead>
-        <tr>
-          <th
-            className="nowrap"
-            style={
-              Object {
-                "width": 300,
-              }
-            }
-          >
-            quality_gates.conditions.metric
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.operator
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.value
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 1,
-              "metric": "coverage",
-              "op": "LT",
-            }
-          }
-          key="1"
-          metric={
-            Object {
-              "id": "coverage",
-              "key": "coverage",
-              "name": "Coverage",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 2,
-              "metric": "duplicated_lines",
-              "op": "LT",
-            }
-          }
-          key="2"
-          metric={
-            Object {
-              "id": "duplicated_lines",
-              "key": "duplicated_lines",
-              "name": "Duplicated_lines",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-      </tbody>
-    </table>
-  </div>
-</div>
-`;
-
-exports[`should render correctly for no conditions 1`] = `
-<div
-  className="quality-gate-section"
->
-  <header
-    className="display-flex-center spacer-bottom"
-  >
-    <h3>
-      quality_gates.conditions
-    </h3>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.conditions.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/clean-as-you-code/",
-            "label": "quality_gates.conditions.help.link",
-          },
-        ]
-      }
-    />
-  </header>
-  <div
-    className="big-spacer-top"
-  >
-    quality_gates.no_conditions
-  </div>
-</div>
-`;
-
-exports[`should render correctly with an updated condition 1`] = `
-<div
-  className="quality-gate-section"
->
-  <header
-    className="display-flex-center spacer-bottom"
-  >
-    <h3>
-      quality_gates.conditions
-    </h3>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.conditions.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/clean-as-you-code/",
-            "label": "quality_gates.conditions.help.link",
-          },
-        ]
-      }
-    />
-  </header>
-  <div
-    className="big-spacer-top"
-  >
-    <h4>
-      quality_gates.conditions.overall_code.long
-    </h4>
-    <p
-      className="spacer-top spacer-bottom"
-    >
-      quality_gates.conditions.overall_code.description
-    </p>
-    <table
-      className="data zebra"
-      data-test="quality-gates__conditions-overall"
-    >
-      <thead>
-        <tr>
-          <th
-            className="nowrap"
-            style={
-              Object {
-                "width": 300,
-              }
-            }
-          >
-            quality_gates.conditions.metric
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.operator
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.value
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 1,
-              "metric": "coverage",
-              "op": "LT",
-            }
-          }
-          key="1"
-          metric={
-            Object {
-              "id": "coverage",
-              "key": "coverage",
-              "name": "Coverage",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={true}
-        />
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 2,
-              "metric": "duplicated_lines",
-              "op": "LT",
-            }
-          }
-          key="2"
-          metric={
-            Object {
-              "id": "duplicated_lines",
-              "key": "duplicated_lines",
-              "name": "Duplicated_lines",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-      </tbody>
-    </table>
-  </div>
-</div>
-`;
-
-exports[`should render correctly with new code conditions 1`] = `
-<div
-  className="quality-gate-section"
->
-  <header
-    className="display-flex-center spacer-bottom"
-  >
-    <h3>
-      quality_gates.conditions
-    </h3>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.conditions.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/clean-as-you-code/",
-            "label": "quality_gates.conditions.help.link",
-          },
-        ]
-      }
-    />
-  </header>
-  <div
-    className="big-spacer-top"
-  >
-    <h4>
-      quality_gates.conditions.new_code.long
-    </h4>
-    <p
-      className="spacer-top spacer-bottom"
-    >
-      quality_gates.conditions.new_code.description
-    </p>
-    <table
-      className="data zebra"
-      data-test="quality-gates__conditions-new"
-    >
-      <thead>
-        <tr>
-          <th
-            className="nowrap"
-            style={
-              Object {
-                "width": 300,
-              }
-            }
-          >
-            quality_gates.conditions.metric
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.operator
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.value
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 3,
-              "metric": "new_coverage",
-              "op": "LT",
-            }
-          }
-          key="3"
-          metric={
-            Object {
-              "id": "new_coverage",
-              "key": "new_coverage",
-              "name": "New_coverage",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 4,
-              "metric": "new_duplicated_lines",
-              "op": "LT",
-            }
-          }
-          key="4"
-          metric={
-            Object {
-              "id": "new_duplicated_lines",
-              "key": "new_duplicated_lines",
-              "name": "New_duplicated_lines",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-      </tbody>
-    </table>
-  </div>
-  <div
-    className="big-spacer-top"
-  >
-    <h4>
-      quality_gates.conditions.overall_code.long
-    </h4>
-    <p
-      className="spacer-top spacer-bottom"
-    >
-      quality_gates.conditions.overall_code.description
-    </p>
-    <table
-      className="data zebra"
-      data-test="quality-gates__conditions-overall"
-    >
-      <thead>
-        <tr>
-          <th
-            className="nowrap"
-            style={
-              Object {
-                "width": 300,
-              }
-            }
-          >
-            quality_gates.conditions.metric
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.operator
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.value
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 1,
-              "metric": "coverage",
-              "op": "LT",
-            }
-          }
-          key="1"
-          metric={
-            Object {
-              "id": "coverage",
-              "key": "coverage",
-              "name": "Coverage",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-        <withMetricsContext(ConditionComponent)
-          canEdit={false}
-          condition={
-            Object {
-              "error": "10",
-              "id": 2,
-              "metric": "duplicated_lines",
-              "op": "LT",
-            }
-          }
-          key="2"
-          metric={
-            Object {
-              "id": "duplicated_lines",
-              "key": "duplicated_lines",
-              "name": "Duplicated_lines",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-      </tbody>
-    </table>
-  </div>
-</div>
-`;
-
-exports[`should render the add conditions button and modal 1`] = `
-<div
-  className="quality-gate-section"
->
-  <div
-    className="pull-right"
-  >
-    <ModalButton
-      modal={[Function]}
-    >
-      <Component />
-    </ModalButton>
-  </div>
-  <header
-    className="display-flex-center spacer-bottom"
-  >
-    <h3>
-      quality_gates.conditions
-    </h3>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.conditions.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/clean-as-you-code/",
-            "label": "quality_gates.conditions.help.link",
-          },
-        ]
-      }
-    />
-  </header>
-  <div
-    className="big-spacer-top"
-  >
-    <h4>
-      quality_gates.conditions.overall_code.long
-    </h4>
-    <p
-      className="spacer-top spacer-bottom"
-    >
-      quality_gates.conditions.overall_code.description
-    </p>
-    <table
-      className="data zebra"
-      data-test="quality-gates__conditions-overall"
-    >
-      <thead>
-        <tr>
-          <th
-            className="nowrap"
-            style={
-              Object {
-                "width": 300,
-              }
-            }
-          >
-            quality_gates.conditions.metric
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.operator
-          </th>
-          <th
-            className="nowrap"
-          >
-            quality_gates.conditions.value
-          </th>
-          <th
-            className="thin"
-          >
-            edit
-          </th>
-          <th
-            className="thin"
-          >
-            delete
-          </th>
-        </tr>
-      </thead>
-      <tbody>
-        <withMetricsContext(ConditionComponent)
-          canEdit={true}
-          condition={
-            Object {
-              "error": "10",
-              "id": 1,
-              "metric": "coverage",
-              "op": "LT",
-            }
-          }
-          key="1"
-          metric={
-            Object {
-              "id": "coverage",
-              "key": "coverage",
-              "name": "Coverage",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-        <withMetricsContext(ConditionComponent)
-          canEdit={true}
-          condition={
-            Object {
-              "error": "10",
-              "id": 2,
-              "metric": "duplicated_lines",
-              "op": "LT",
-            }
-          }
-          key="2"
-          metric={
-            Object {
-              "id": "duplicated_lines",
-              "key": "duplicated_lines",
-              "name": "Duplicated_lines",
-              "type": "PERCENT",
-            }
-          }
-          onRemoveCondition={[MockFunction]}
-          onSaveCondition={[MockFunction]}
-          qualityGate={
-            Object {
-              "id": "1",
-              "name": "qualitygate",
-            }
-          }
-          updated={false}
-        />
-      </tbody>
-    </table>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap
deleted file mode 100644 (file)
index f360773..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ConfirmModal
-  confirmButtonText="copy"
-  confirmDisable={true}
-  header="quality_gates.copy"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <MandatoryFieldsExplanation
-    className="modal-field"
-  />
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="quality-gate-form-name"
-    >
-      name
-      <MandatoryFieldMarker />
-    </label>
-    <input
-      autoFocus={true}
-      id="quality-gate-form-name"
-      maxLength={100}
-      onChange={[Function]}
-      required={true}
-      size={50}
-      type="text"
-      value="qualitygate"
-    />
-  </div>
-</ConfirmModal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CreateQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CreateQualityGateForm-test.tsx.snap
deleted file mode 100644 (file)
index f814166..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ConfirmModal
-  confirmButtonText="save"
-  confirmDisable={true}
-  header="quality_gates.create"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <MandatoryFieldsExplanation
-    className="modal-field"
-  />
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="quality-gate-form-name"
-    >
-      name
-      <MandatoryFieldMarker />
-    </label>
-    <input
-      autoFocus={true}
-      id="quality-gate-form-name"
-      maxLength={100}
-      onChange={[Function]}
-      required={true}
-      size={50}
-      type="text"
-      value=""
-    />
-  </div>
-</ConfirmModal>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap
deleted file mode 100644 (file)
index d99d750..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ConfirmButton
-  confirmButtonText="delete"
-  isDestructive={true}
-  modalBody="quality_gates.delete.confirm.message.qualitygate"
-  modalHeader="quality_gates.delete"
-  onConfirm={[Function]}
->
-  <Component />
-</ConfirmButton>
-`;
index 7354a115ce829930ff1cc41b823acdf296719e82..74843ff5fe9dcae4d20bd0f6ae7919ddad559ceb 100644 (file)
@@ -86,7 +86,7 @@ exports[`should render correctly: is default 1`] = `
       Array [
         Object {
           "error": "10",
-          "id": 1,
+          "id": "1",
           "metric": "coverage",
           "op": "LT",
         },
@@ -100,7 +100,7 @@ exports[`should render correctly: is default 1`] = `
         "conditions": Array [
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "coverage",
             "op": "LT",
           },
@@ -204,7 +204,7 @@ exports[`should render correctly: is not default 1`] = `
       Array [
         Object {
           "error": "10",
-          "id": 1,
+          "id": "1",
           "metric": "coverage",
           "op": "LT",
         },
@@ -218,7 +218,7 @@ exports[`should render correctly: is not default 1`] = `
         "conditions": Array [
           Object {
             "error": "10",
-            "id": 1,
+            "id": "1",
             "metric": "coverage",
             "op": "LT",
           },
@@ -259,7 +259,7 @@ exports[`should render correctly: is not default 1`] = `
             "conditions": Array [
               Object {
                 "error": "10",
-                "id": 1,
+                "id": "1",
                 "metric": "coverage",
                 "op": "LT",
               },
index 614efb96ed87856b85ee8839ff207d8205128f46..a1106a333c959da6be726a452526c05ad4790c51 100644 (file)
@@ -55,7 +55,7 @@ exports[`should render correctly: admin actions 1`] = `
               "conditions": Array [
                 Object {
                   "error": "10",
-                  "id": 1,
+                  "id": "1",
                   "metric": "coverage",
                   "op": "LT",
                 },
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/List-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/List-test.tsx.snap
deleted file mode 100644 (file)
index 9fad96d..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="list-group"
->
-  <Link
-    activeClassName="active"
-    className="list-group-item display-flex-center"
-    data-id="1"
-    key="1"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/quality_gates/show/1",
-      }
-    }
-  >
-    <span
-      className="flex-1"
-    >
-      qualitygate
-    </span>
-  </Link>
-  <Link
-    activeClassName="active"
-    className="list-group-item display-flex-center"
-    data-id="1"
-    key="1"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/quality_gates/show/1",
-      }
-    }
-  >
-    <span
-      className="flex-1"
-    >
-      qualitygate
-    </span>
-    <BuiltInQualityGateBadge
-      className="little-spacer-left"
-    />
-  </Link>
-  <Link
-    activeClassName="active"
-    className="list-group-item display-flex-center"
-    data-id="1"
-    key="1"
-    onlyActiveOnIndex={false}
-    style={Object {}}
-    to={
-      Object {
-        "pathname": "/quality_gates/show/1",
-      }
-    }
-  >
-    <span
-      className="flex-1"
-    >
-      qualitygate
-    </span>
-    <span
-      className="badge little-spacer-left"
-    >
-      default
-    </span>
-  </Link>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/ListHeader-test.tsx.snap
deleted file mode 100644 (file)
index 0913eca..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<header
-  className="page-header"
->
-  <div
-    className="display-flex-center"
-  >
-    <h1
-      className="page-title"
-    >
-      quality_gates.page
-    </h1>
-    <DocumentationTooltip
-      className="spacer-left"
-      content="quality_gates.help"
-      links={
-        Array [
-          Object {
-            "href": "/documentation/user-guide/quality-gates/",
-            "label": "learn_more",
-          },
-        ]
-      }
-    />
-  </div>
-</header>
-`;
-
-exports[`should render correctly 2`] = `
-<Fragment>
-  <Button
-    data-test="quality-gates__add"
-    onClick={[Function]}
-  >
-    create
-  </Button>
-</Fragment>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/MetricSelect-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/MetricSelect-test.tsx.snap
deleted file mode 100644 (file)
index 1d2d310..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<SelectLegacy
-  className="text-middle quality-gate-metric-select"
-  id="condition-metric"
-  onChange={[Function]}
-  options={
-    Array [
-      Object {
-        "domain": undefined,
-        "label": "Coverage",
-        "value": "coverage",
-      },
-    ]
-  }
-  placeholder="search.search_for_metrics"
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/RenameQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/RenameQualityGateForm-test.tsx.snap
deleted file mode 100644 (file)
index b0220d9..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<ConfirmModal
-  confirmButtonText="rename"
-  confirmDisable={true}
-  header="quality_gates.rename"
-  onClose={[MockFunction]}
-  onConfirm={[Function]}
-  size="small"
->
-  <MandatoryFieldsExplanation
-    className="modal-field"
-  />
-  <div
-    className="modal-field"
-  >
-    <label
-      htmlFor="quality-gate-form-name"
-    >
-      name
-      <MandatoryFieldMarker />
-    </label>
-    <input
-      autoFocus={true}
-      id="quality-gate-form-name"
-      maxLength={100}
-      onChange={[Function]}
-      required={true}
-      size={50}
-      type="text"
-      value="qualitygate"
-    />
-  </div>
-</ConfirmModal>
-`;
index 80cb8cd229219483b2c1e3201bb0ef05875f8339..e52cd274a8dab66459b42a0c801b78ec26d94f00 100644 (file)
@@ -346,8 +346,8 @@ export class TooltipInner extends React.Component<TooltipProps, State> {
     return (
       <div
         className={`${classNameSpace} ${currentPlacement}`}
-        onMouseEnter={this.handleOverlayMouseEnter}
-        onMouseLeave={this.handleOverlayMouseLeave}
+        onPointerEnter={this.handleOverlayMouseEnter}
+        onPointerLeave={this.handleOverlayMouseLeave}
         ref={this.tooltipNodeRef}
         style={style}>
         <div className={`${classNameSpace}-inner`}>{this.props.overlay}</div>
@@ -367,8 +367,8 @@ export class TooltipInner extends React.Component<TooltipProps, State> {
     return (
       <>
         {React.cloneElement(this.props.children, {
-          onMouseEnter: this.handleMouseEnter,
-          onMouseLeave: this.handleMouseLeave
+          onPointerEnter: this.handleMouseEnter,
+          onPointerLeave: this.handleMouseLeave
         })}
         {this.isVisible() && (
           <TooltipPortal>
index aa0450f088d7d41c5bc1ed2378cb182a9fc9a9f0..bd79b3c3ca883108992e88a8a6c55c46129cb16d 100644 (file)
@@ -56,26 +56,26 @@ it('should open & close', () => {
   const onHide = jest.fn();
   const wrapper = shallowRenderTooltipInner({ onHide, onShow });
 
-  wrapper.find('#tooltip').simulate('mouseenter');
+  wrapper.find('#tooltip').simulate('pointerenter');
   jest.runOnlyPendingTimers();
   wrapper.update();
   expect(wrapper.find('TooltipPortal').exists()).toBe(true);
   expect(onShow).toBeCalled();
 
-  wrapper.find('#tooltip').simulate('mouseleave');
+  wrapper.find('#tooltip').simulate('pointerleave');
   jest.runOnlyPendingTimers();
   wrapper.update();
   expect(wrapper.find('TooltipPortal').exists()).toBe(false);
   expect(onHide).toBeCalled();
 });
 
-it('should not open when mouse goes away quickly', () => {
+it('should not open when pointer goes away quickly', () => {
   const onShow = jest.fn();
   const onHide = jest.fn();
   const wrapper = shallowRenderTooltipInner({ onHide, onShow });
 
-  wrapper.find('#tooltip').simulate('mouseenter');
-  wrapper.find('#tooltip').simulate('mouseleave');
+  wrapper.find('#tooltip').simulate('pointerenter');
+  wrapper.find('#tooltip').simulate('pointerleave');
   jest.runOnlyPendingTimers();
   wrapper.update();
 
index 4bd6a2ea46de8f6a8f0f3493a75ab29b62e20f31..42636f0208024d495d9d7d2289d048ddca02e5e9 100644 (file)
@@ -123,8 +123,8 @@ exports[`ActionsDropdownItem should render correctly copy item 1`] = `
       >
         <li
           data-clipboard-text="my content to copy to clipboard"
-          onMouseEnter={[Function]}
-          onMouseLeave={[Function]}
+          onPointerEnter={[Function]}
+          onPointerLeave={[Function]}
         >
           <a
             className="foo"
index de3df03b6e5f3777e7f60c9525bf4a3ce8aae38a..50bceeb148baa68b3e65b51049efc00be6e31b72 100644 (file)
@@ -16,8 +16,8 @@ exports[`should render 1`] = `
 <Fragment>
   <div
     id="tooltip"
-    onMouseEnter={[Function]}
-    onMouseLeave={[Function]}
+    onPointerEnter={[Function]}
+    onPointerLeave={[Function]}
   />
 </Fragment>
 `;
@@ -26,8 +26,8 @@ exports[`should render 2`] = `
 <Fragment>
   <div
     id="tooltip"
-    onMouseEnter={[Function]}
-    onMouseLeave={[Function]}
+    onPointerEnter={[Function]}
+    onPointerLeave={[Function]}
   />
   <TooltipPortal>
     <ScreenPositionFixer
index e0a23d842bb322a0bf636eb9eb2c46f3f726a83e..811bf2380c6731210221ec082144a9e054597c9c 100644 (file)
@@ -48,7 +48,7 @@ describe('Button', () => {
     const preventDefault = jest.fn();
     const onClick = jest.fn();
     const button = shallowRender({ disabled: true, onClick, preventDefault: false }).find('button');
-    expect(button.props().disabled).toBeUndefined();
+    expect(button.props().disabled).toBe(true);
     expect(button.props().className).toContain('disabled');
     expect(button.props()['aria-disabled']).toBe(true);
     click(button, mockEvent({ preventDefault }));
index a1acfe858f0ffb53fa2f8d0b7502c8a78c621ea4..8c0aa493d2a45ba60b79b7dcf1bf722c9b6f6ea4 100644 (file)
@@ -76,6 +76,7 @@ export class Button extends React.PureComponent<ButtonProps> {
       <button
         {...props}
         aria-disabled={disabled}
+        disabled={disabled}
         className={classNames('button', className, { disabled })}
         id={this.props.id}
         onClick={this.handleClick}
index ddbc2c8e952c3bf5a8d2df942b6c7c1a30e26e67..fde809bb117f29766955e9f682d51dec3651b4db 100644 (file)
@@ -292,7 +292,7 @@ export function mockClusterSysInfo(overrides: Partial<any> = {}): SysInfoCluster
 export function mockCondition(overrides: Partial<Condition> = {}): Condition {
   return {
     error: '10',
-    id: 1,
+    id: '1',
     metric: 'coverage',
     op: 'LT',
     ...overrides
index 01544faf61e08567102fdaf5b0d316edf58e04ee..cbff79bdbc7b09bc53d46edd90f3575c7a45fc3b 100644 (file)
@@ -192,7 +192,7 @@ export interface ComponentMeasureEnhanced extends ComponentMeasureIntern {
 
 export interface Condition {
   error: string;
-  id: number;
+  id: string;
   metric: string;
   op?: string;
 }
index a2ce05c61bce1621210afdcae2b87bf2ee92c8db..43c6cbcfcb2d404b0c8a164a5ea37ebdd6736a5a 100644 (file)
@@ -1666,6 +1666,8 @@ quality_gates.conditions.help.link=See also: Clean as You Code
 quality_gates.projects=Projects
 quality_gates.projects.help=The Default gate is applied to all projects not explicitly assigned to a gate. Quality Gate administrators can assign projects to a non-default gate, or always make it follow the system default. Project administrators may choose any gate.
 quality_gates.add_condition=Add Condition
+quality_gates.condition.edit=Edit condition on {0}
+quality_gates.condition.delete=Delete condition on {0}
 quality_gates.condition_added=Successfully added condition.
 quality_gates.update_condition=Update Condition
 quality_gates.condition_updated=Successfully updated condition.