]> source.dussan.org Git - sonarqube.git/commitdiff
[NO JIRA] Setup react testing library
authorMathieu Suen <mathieu.suen@sonarsource.com>
Mon, 21 Feb 2022 13:27:12 +0000 (14:27 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 7 Mar 2022 20:02:55 +0000 (20:02 +0000)
server/sonar-web/.eslintrc
server/sonar-web/build.gradle
server/sonar-web/config/jest/SetupReactTestingLibrary.js [new file with mode: 0644]
server/sonar-web/config/polyfills.js
server/sonar-web/jest.config.js
server/sonar-web/package.json
server/sonar-web/src/main/js/app/utils/startReactApp.tsx
server/sonar-web/src/main/js/helpers/mocks/metrics.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx [new file with mode: 0644]
server/sonar-web/yarn.lock

index 75d7196137b04597e184057d6bbc43131d98ba5c..9ba34dede11be4317a1bacd6a8a5a402d15b10a7 100644 (file)
@@ -7,5 +7,22 @@
   },
   "parserOptions": {
     "warnOnUnsupportedTypeScriptVersion": false
-  }
+  },
+  "plugins": ["testing-library"],
+  "overrides": [
+    {
+      "files": [
+        "**/__tests__/**/*-it.{ts,tsx}"
+      ],
+      "extends": [
+        "plugin:testing-library/react"
+      ],
+      "rules": {
+        "testing-library/await-async-query": "error",
+        "testing-library/no-await-sync-query": "error",
+        "testing-library/no-debugging-utils": "error",
+        "testing-library/no-dom-import": "error"
+      }
+    }
+  ]
 }
index 4cff9991eb307b8376798cc0d9464f2bb8d4a362..f3b56c5223615b55fc9e62a5e5291fb2a30bf9c9 100644 (file)
@@ -2,7 +2,7 @@ sonarqube {
   properties {
     property "sonar.projectName", "${projectTitle} :: Web"
     property "sonar.sources", "src/main/js"
-    property "sonar.exclusions", "src/main/js/**/__tests__/**,src/main/js/**/__mocks__/**,src/main/js/@types/**,src/main/js/helpers/mocks/**,src/main/js/helpers/testUtils.ts,src/main/js/helpers/testMocks.ts"
+    property "sonar.exclusions", "src/main/js/**/__tests__/**,src/main/js/**/__mocks__/**,src/main/js/@types/**,src/main/js/helpers/mocks/**,src/main/js/helpers/testUtils.ts,src/main/js/helpers/testMocks.ts,src/main/js/helpers/testReactTestingUtils.tsx"
     property "sonar.tests", "src/main/js"
     property "sonar.test.inclusions", "src/main/js/**/__tests__/**"
     property "sonar.coverage.exclusions", "src/main/js/api/**,src/main/js/**/routes.ts,src/main/js/app/index.ts,src/main/js/app/utils/startReactApp.tsx,src/main/js/components/icons/**"
diff --git a/server/sonar-web/config/jest/SetupReactTestingLibrary.js b/server/sonar-web/config/jest/SetupReactTestingLibrary.js
new file mode 100644 (file)
index 0000000..7f2008b
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * 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 '@testing-library/jest-dom';
index ff7139a45936219aa617e102bb97084c41342cf8..878b843b7afd1a6e4c72c0f7f32630e6bdbf74df 100644 (file)
@@ -18,5 +18,4 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import 'core-js/stable';
-import 'regenerator-runtime/runtime';
 import 'whatwg-fetch';
index 7feb2548c0acdb7c70b0cffe1517e48b4dc06abf..9a61829902a80c8f53ed4e2bffa79bc003de5afc 100644 (file)
@@ -20,6 +20,7 @@ module.exports = {
     '<rootDir>/config/jest/SetupEnzyme.js',
     '<rootDir>/config/jest/SetupTestEnvironment.ts'
   ],
+  setupFilesAfterEnv: ['<rootDir>/config/jest/SetupReactTestingLibrary.js'],
   snapshotSerializers: ['enzyme-to-json/serializer', 'jest-emotion'],
   testEnvironment: 'jsdom',
   testPathIgnorePatterns: ['<rootDir>/config', '<rootDir>/node_modules', '<rootDir>/scripts'],
index bad8168c8fd84892d1f5bf61c9a953cf4b584b77..f36a67ee9e7291c3cc8f8ac27ea70389a0ab2b61 100644 (file)
     "@babel/preset-env": "7.16.11",
     "@babel/preset-react": "7.16.7",
     "@emotion/jest": "11.7.1",
+    "@testing-library/dom": "8.11.3",
+    "@testing-library/jest-dom": "5.16.2",
+    "@testing-library/react": "12.1.2",
+    "@testing-library/user-event": "14.0.0-beta.11",
     "@types/classnames": "2.3.0",
     "@types/clipboard": "2.0.1",
     "@types/d3-array": "1.2.4",
     "eslint-plugin-promise": "4.2.1",
     "eslint-plugin-react": "7.28.0",
     "eslint-plugin-react-hooks": "4.3.0",
+    "eslint-plugin-testing-library": "5.0.6",
     "fs-extra": "10.0.0",
     "glob": "7.2.0",
     "glob-promise": "3.4.0",
index 8acb13b44787ed6ea77fc65e31d527e20f19d3fd..0fa4217844bf810f8147707cf3b61603829a5540 100644 (file)
@@ -86,7 +86,7 @@ function handleUpdate(this: { state: { location: Location } }) {
 }
 
 // this is not an official api
-const RouteWithChildRoutes = Route as React.ComponentClass<
+export const RouteWithChildRoutes = Route as React.ComponentClass<
   RouteProps & { childRoutes: RouteConfig }
 >;
 
diff --git a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts
new file mode 100644 (file)
index 0000000..57a8cc8
--- /dev/null
@@ -0,0 +1,1498 @@
+/*
+ * 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.
+ */
+
+export const DEFAULT_METRICS = {
+  new_technical_debt: {
+    id: 'AXJMbIl_PAOIsUIE3guE',
+    key: 'new_technical_debt',
+    type: 'WORK_DUR',
+    name: 'Added Technical Debt',
+    description: 'Added technical debt',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  blocker_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtt',
+    key: 'blocker_violations',
+    type: 'INT',
+    name: 'Blocker Issues',
+    description: 'Blocker issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  bugs: {
+    id: 'AXJMbIl_PAOIsUIE3gt_',
+    key: 'bugs',
+    type: 'INT',
+    name: 'Bugs',
+    description: 'Bugs',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  classes: {
+    id: 'AXJMbImPPAOIsUIE3gu5',
+    key: 'classes',
+    type: 'INT',
+    name: 'Classes',
+    description: 'Classes',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  code_smells: {
+    id: 'AXJMbIl_PAOIsUIE3gt9',
+    key: 'code_smells',
+    type: 'INT',
+    name: 'Code Smells',
+    description: 'Code Smells',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  cognitive_complexity: {
+    id: 'AXJMbIl9PAOIsUIE3gtZ',
+    key: 'cognitive_complexity',
+    type: 'INT',
+    name: 'Cognitive Complexity',
+    description: 'Cognitive complexity',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  comment_lines: {
+    id: 'AXJMbImPPAOIsUIE3gup',
+    key: 'comment_lines',
+    type: 'INT',
+    name: 'Comment Lines',
+    description: 'Number of comment lines',
+    domain: 'Size',
+    direction: 1,
+    qualitative: false,
+    hidden: false
+  },
+  comment_lines_data: {
+    id: 'AXJMbImPPAOIsUIE3guV',
+    key: 'comment_lines_data',
+    type: 'DATA',
+    name: 'comment_lines_data',
+    domain: 'Size',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  comment_lines_density: {
+    id: 'AXJMbImPPAOIsUIE3guq',
+    key: 'comment_lines_density',
+    type: 'PERCENT',
+    name: 'Comments (%)',
+    description: 'Comments balanced by ncloc + comment lines',
+    domain: 'Size',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  class_complexity: {
+    id: 'AXJMbImPPAOIsUIE3guw',
+    key: 'class_complexity',
+    type: 'FLOAT',
+    name: 'Complexity / Class',
+    description: 'Complexity average by class',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: true,
+    hidden: true,
+    decimalScale: 1
+  },
+  file_complexity: {
+    id: 'AXJMbImPPAOIsUIE3guu',
+    key: 'file_complexity',
+    type: 'FLOAT',
+    name: 'Complexity / File',
+    description: 'Complexity average by file',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: true,
+    hidden: true,
+    decimalScale: 1
+  },
+  function_complexity: {
+    id: 'AXJMbImPPAOIsUIE3guy',
+    key: 'function_complexity',
+    type: 'FLOAT',
+    name: 'Complexity / Function',
+    description: 'Complexity average by function',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: true,
+    hidden: true,
+    decimalScale: 1
+  },
+  complexity_in_classes: {
+    id: 'AXJMbImPPAOIsUIE3guv',
+    key: 'complexity_in_classes',
+    type: 'INT',
+    name: 'Complexity in Classes',
+    description: 'Cyclomatic complexity in classes',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  complexity_in_functions: {
+    id: 'AXJMbImPPAOIsUIE3gux',
+    key: 'complexity_in_functions',
+    type: 'INT',
+    name: 'Complexity in Functions',
+    description: 'Cyclomatic complexity in functions',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  branch_coverage: {
+    id: 'AXJMbIl9PAOIsUIE3gs-',
+    key: 'branch_coverage',
+    type: 'PERCENT',
+    name: 'Condition Coverage',
+    description: 'Condition coverage',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_branch_coverage: {
+    id: 'AXJMbIl9PAOIsUIE3gs_',
+    key: 'new_branch_coverage',
+    type: 'PERCENT',
+    name: 'Condition Coverage on New Code',
+    description: 'Condition coverage of new/changed code',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  conditions_to_cover: {
+    id: 'AXJMbIl9PAOIsUIE3gqt',
+    key: 'conditions_to_cover',
+    type: 'INT',
+    name: 'Conditions to Cover',
+    description: 'Conditions to cover',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  new_conditions_to_cover: {
+    id: 'AXJMbIl9PAOIsUIE3gs7',
+    key: 'new_conditions_to_cover',
+    type: 'INT',
+    name: 'Conditions to Cover on New Code',
+    description: 'Conditions to cover on new code',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  confirmed_issues: {
+    id: 'AXJMbIl_PAOIsUIE3gt8',
+    key: 'confirmed_issues',
+    type: 'INT',
+    name: 'Confirmed Issues',
+    description: 'Confirmed issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  coverage: {
+    id: 'AXJMbIl9PAOIsUIE3gtg',
+    key: 'coverage',
+    type: 'PERCENT',
+    name: 'Coverage',
+    description: 'Coverage by tests',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_coverage: {
+    id: 'AXJMbIl_PAOIsUIE3gth',
+    key: 'new_coverage',
+    type: 'PERCENT',
+    name: 'Coverage on New Code',
+    description: 'Coverage of new/changed code',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  critical_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtu',
+    key: 'critical_violations',
+    type: 'INT',
+    name: 'Critical Issues',
+    description: 'Critical issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  complexity: {
+    id: 'AXJMbImPPAOIsUIE3gut',
+    key: 'complexity',
+    type: 'INT',
+    name: 'Cyclomatic Complexity',
+    description: 'Cyclomatic complexity',
+    domain: 'Complexity',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  last_commit_date: {
+    id: 'AXJMbImPPAOIsUIE3gua',
+    key: 'last_commit_date',
+    type: 'MILLISEC',
+    name: 'Date of Last Commit',
+    domain: 'SCM',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  development_cost: {
+    id: 'AXJMbIl_PAOIsUIE3guI',
+    key: 'development_cost',
+    type: 'STRING',
+    name: 'Development Cost',
+    description: 'Development cost',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_development_cost: {
+    id: 'AXJMbIl_PAOIsUIE3guJ',
+    key: 'new_development_cost',
+    type: 'FLOAT',
+    name: 'Development Cost on New Code',
+    description: 'Development cost on new code',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: true,
+    decimalScale: 1
+  },
+  directories: {
+    id: 'AXJMbImPPAOIsUIE3gu9',
+    key: 'directories',
+    type: 'INT',
+    name: 'Directories',
+    description: 'Directories',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  duplicated_blocks: {
+    id: 'AXJMbIl9PAOIsUIE3gsu',
+    key: 'duplicated_blocks',
+    type: 'INT',
+    name: 'Duplicated Blocks',
+    description: 'Duplicated blocks',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_duplicated_blocks: {
+    id: 'AXJMbIl_PAOIsUIE3gto',
+    key: 'new_duplicated_blocks',
+    type: 'INT',
+    name: 'Duplicated Blocks on New Code',
+    description: 'Duplicated blocks on new code',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  duplicated_files: {
+    id: 'AXJMbImPPAOIsUIE3gvA',
+    key: 'duplicated_files',
+    type: 'INT',
+    name: 'Duplicated Files',
+    description: 'Duplicated files',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  duplicated_lines: {
+    id: 'AXJMbIl9PAOIsUIE3gss',
+    key: 'duplicated_lines',
+    type: 'INT',
+    name: 'Duplicated Lines',
+    description: 'Duplicated lines',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  duplicated_lines_density: {
+    id: 'AXJMbIl_PAOIsUIE3gtp',
+    key: 'duplicated_lines_density',
+    type: 'PERCENT',
+    name: 'Duplicated Lines (%)',
+    description: 'Duplicated lines balanced by statements',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_duplicated_lines_density: {
+    id: 'AXJMbIl_PAOIsUIE3gtq',
+    key: 'new_duplicated_lines_density',
+    type: 'PERCENT',
+    name: 'Duplicated Lines (%) on New Code',
+    description: 'Duplicated lines (%) on new code balanced by statements',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_duplicated_lines: {
+    id: 'AXJMbIl9PAOIsUIE3gst',
+    key: 'new_duplicated_lines',
+    type: 'INT',
+    name: 'Duplicated Lines on New Code',
+    description: 'Duplicated Lines on New Code',
+    domain: 'Duplications',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  duplications_data: {
+    id: 'AXJMbIl_PAOIsUIE3gtr',
+    key: 'duplications_data',
+    type: 'DATA',
+    name: 'Duplication Details',
+    description: 'Duplications details',
+    domain: 'Duplications',
+    direction: 0,
+    qualitative: false,
+    hidden: false
+  },
+  effort_to_reach_maintainability_rating_a: {
+    id: 'AXJMbIl_PAOIsUIE3guM',
+    key: 'effort_to_reach_maintainability_rating_a',
+    type: 'WORK_DUR',
+    name: 'Effort to Reach Maintainability Rating A',
+    description: 'Effort to reach maintainability rating A',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  executable_lines_data: {
+    id: 'AXJMbImPPAOIsUIE3guW',
+    key: 'executable_lines_data',
+    type: 'DATA',
+    name: 'executable_lines_data',
+    domain: 'Coverage',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  false_positive_issues: {
+    id: 'AXJMbIl_PAOIsUIE3gt4',
+    key: 'false_positive_issues',
+    type: 'INT',
+    name: 'False Positive Issues',
+    description: 'False positive issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  file_complexity_distribution: {
+    id: 'AXJMbIl9PAOIsUIE3gtY',
+    key: 'file_complexity_distribution',
+    type: 'DISTRIB',
+    name: 'File Distribution / Complexity',
+    description: 'Files distribution /complexity',
+    domain: 'Complexity',
+    direction: 0,
+    qualitative: true,
+    hidden: true
+  },
+  files: {
+    id: 'AXJMbImPPAOIsUIE3gu6',
+    key: 'files',
+    type: 'INT',
+    name: 'Files',
+    description: 'Number of files',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  function_complexity_distribution: {
+    id: 'AXJMbIl9PAOIsUIE3gtX',
+    key: 'function_complexity_distribution',
+    type: 'DISTRIB',
+    name: 'Function Distribution / Complexity',
+    description: 'Functions distribution /complexity',
+    domain: 'Complexity',
+    direction: 0,
+    qualitative: true,
+    hidden: true
+  },
+  functions: {
+    id: 'AXJMbImPPAOIsUIE3gu-',
+    key: 'functions',
+    type: 'INT',
+    name: 'Functions',
+    description: 'Functions',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  generated_lines: {
+    id: 'AXJMbImPPAOIsUIE3gu0',
+    key: 'generated_lines',
+    type: 'INT',
+    name: 'Generated Lines',
+    description: 'Number of generated lines',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  generated_ncloc: {
+    id: 'AXJMbImPPAOIsUIE3gu4',
+    key: 'generated_ncloc',
+    type: 'INT',
+    name: 'Generated Lines of Code',
+    description: 'Generated non Commenting Lines of Code',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  info_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtx',
+    key: 'info_violations',
+    type: 'INT',
+    name: 'Info Issues',
+    description: 'Info issues',
+    domain: 'Issues',
+    direction: 0,
+    qualitative: true,
+    hidden: false
+  },
+  violations: {
+    id: 'AXJMbImPPAOIsUIE3gul',
+    key: 'violations',
+    type: 'INT',
+    name: 'Issues',
+    description: 'Issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  last_change_on_maintainability_rating: {
+    id: 'AXJMbImPPAOIsUIE3gud',
+    key: 'last_change_on_maintainability_rating',
+    type: 'DATA',
+    name: 'Last Change on Maintainability Rating',
+    domain: 'Maintainability',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  last_change_on_releasability_rating: {
+    id: 'AXJMbImPPAOIsUIE3gue',
+    key: 'last_change_on_releasability_rating',
+    type: 'DATA',
+    name: 'Last Change on Releasability Rating',
+    domain: 'Releasability',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  last_change_on_reliability_rating: {
+    id: 'AXJMbImPPAOIsUIE3guf',
+    key: 'last_change_on_reliability_rating',
+    type: 'DATA',
+    name: 'Last Change on Reliability Rating',
+    domain: 'Reliability',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  last_change_on_security_rating: {
+    id: 'AXJMbImPPAOIsUIE3gug',
+    key: 'last_change_on_security_rating',
+    type: 'DATA',
+    name: 'Last Change on Security Rating',
+    domain: 'Security',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  last_change_on_security_review_rating: {
+    id: 'AXJMbIl9PAOIsUIE3gs4',
+    key: 'last_change_on_security_review_rating',
+    type: 'DATA',
+    name: 'Last Change on Security Review Rating',
+    domain: 'Security',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  line_coverage: {
+    id: 'AXJMbIl_PAOIsUIE3gtl',
+    key: 'line_coverage',
+    type: 'PERCENT',
+    name: 'Line Coverage',
+    description: 'Line coverage',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_line_coverage: {
+    id: 'AXJMbIl_PAOIsUIE3gtm',
+    key: 'new_line_coverage',
+    type: 'PERCENT',
+    name: 'Line Coverage on New Code',
+    description: 'Line coverage of added/changed code',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  lines: {
+    id: 'AXJMbImPPAOIsUIE3guz',
+    key: 'lines',
+    type: 'INT',
+    name: 'Lines',
+    description: 'Lines',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  ncloc: {
+    id: 'AXJMbImPPAOIsUIE3gu1',
+    key: 'ncloc',
+    type: 'INT',
+    name: 'Lines of Code',
+    description: 'Non commenting lines of code',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  ncloc_language_distribution: {
+    id: 'AXJMbImPPAOIsUIE3gu3',
+    key: 'ncloc_language_distribution',
+    type: 'DATA',
+    name: 'Lines of Code Per Language',
+    description: 'Non Commenting Lines of Code Distributed By Language',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  lines_to_cover: {
+    id: 'AXJMbImPPAOIsUIE3gu_',
+    key: 'lines_to_cover',
+    type: 'INT',
+    name: 'Lines to Cover',
+    description: 'Lines to cover',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  new_lines_to_cover: {
+    id: 'AXJMbIl_PAOIsUIE3gti',
+    key: 'new_lines_to_cover',
+    type: 'INT',
+    name: 'Lines to Cover on New Code',
+    description: 'Lines to cover on new code',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  leak_projects: {
+    id: 'AXJMbImPPAOIsUIE3gvE',
+    key: 'leak_projects',
+    type: 'DATA',
+    name: 'List of technical projects with their leaks',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  sqale_rating: {
+    id: 'AXJMbIl_PAOIsUIE3guF',
+    key: 'sqale_rating',
+    type: 'RATING',
+    name: 'Maintainability Rating',
+    description: 'A-to-E rating based on the technical debt ratio',
+    domain: 'Maintainability',
+    direction: 0,
+    qualitative: true,
+    hidden: false
+  },
+  maintainability_rating_distribution: {
+    id: 'AX6QkqP7zEziun0YBqmh',
+    key: 'maintainability_rating_distribution',
+    type: 'DATA',
+    name: 'Maintainability Rating Distribution',
+    description: 'Maintainability rating distribution',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_maintainability_rating_distribution: {
+    id: 'AX6QkqP8zEziun0YBqml',
+    key: 'new_maintainability_rating_distribution',
+    type: 'DATA',
+    name: 'Maintainability Rating Distribution on New Code',
+    description: 'Maintainability rating distribution on new code',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_maintainability_rating: {
+    id: 'AXJMbIl_PAOIsUIE3guH',
+    key: 'new_maintainability_rating',
+    type: 'RATING',
+    name: 'Maintainability Rating on New Code',
+    description: 'Maintainability rating on new code',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  major_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtv',
+    key: 'major_violations',
+    type: 'INT',
+    name: 'Major Issues',
+    description: 'Major issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  minor_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtw',
+    key: 'minor_violations',
+    type: 'INT',
+    name: 'Minor Issues',
+    description: 'Minor issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  ncloc_data: {
+    id: 'AXJMbImPPAOIsUIE3guU',
+    key: 'ncloc_data',
+    type: 'DATA',
+    name: 'ncloc_data',
+    domain: 'Size',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  new_blocker_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gtz',
+    key: 'new_blocker_violations',
+    type: 'INT',
+    name: 'New Blocker Issues',
+    description: 'New Blocker issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_bugs: {
+    id: 'AXJMbIl_PAOIsUIE3guA',
+    key: 'new_bugs',
+    type: 'INT',
+    name: 'New Bugs',
+    description: 'New Bugs',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_code_smells: {
+    id: 'AXJMbIl_PAOIsUIE3gt-',
+    key: 'new_code_smells',
+    type: 'INT',
+    name: 'New Code Smells',
+    description: 'New Code Smells',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_critical_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gt0',
+    key: 'new_critical_violations',
+    type: 'INT',
+    name: 'New Critical Issues',
+    description: 'New Critical issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_info_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gt3',
+    key: 'new_info_violations',
+    type: 'INT',
+    name: 'New Info Issues',
+    description: 'New Info issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gty',
+    key: 'new_violations',
+    type: 'INT',
+    name: 'New Issues',
+    description: 'New issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_lines: {
+    id: 'AXJMbImPPAOIsUIE3gu2',
+    key: 'new_lines',
+    type: 'INT',
+    name: 'New Lines',
+    description: 'New lines',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  new_major_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gt1',
+    key: 'new_major_violations',
+    type: 'INT',
+    name: 'New Major Issues',
+    description: 'New Major issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_minor_violations: {
+    id: 'AXJMbIl_PAOIsUIE3gt2',
+    key: 'new_minor_violations',
+    type: 'INT',
+    name: 'New Minor Issues',
+    description: 'New Minor issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_security_hotspots: {
+    id: 'AXJMbIl9PAOIsUIE3gsw',
+    key: 'new_security_hotspots',
+    type: 'INT',
+    name: 'New Security Hotspots',
+    description: 'New Security Hotspots',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_vulnerabilities: {
+    id: 'AXJMbIl_PAOIsUIE3guC',
+    key: 'new_vulnerabilities',
+    type: 'INT',
+    name: 'New Vulnerabilities',
+    description: 'New Vulnerabilities',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  unanalyzed_c: {
+    id: 'AXTb6RMqLLQlB5osv3xN',
+    key: 'unanalyzed_c',
+    type: 'INT',
+    name: 'Number of unanalyzed c files',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  unanalyzed_cpp: {
+    id: 'AXTb6RMtLLQlB5osv3xO',
+    key: 'unanalyzed_cpp',
+    type: 'INT',
+    name: 'Number of unanalyzed c++ files',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  open_issues: {
+    id: 'AXJMbIl_PAOIsUIE3gt6',
+    key: 'open_issues',
+    type: 'INT',
+    name: 'Open Issues',
+    description: 'Open issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  quality_profiles: {
+    id: 'AXJMbImPPAOIsUIE3guZ',
+    key: 'quality_profiles',
+    type: 'DATA',
+    name: 'Profiles',
+    description: 'Details of quality profiles used during analysis',
+    domain: 'General',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  projects: {
+    id: 'AXJMbImPPAOIsUIE3guo',
+    key: 'projects',
+    type: 'INT',
+    name: 'Project branches',
+    description: 'Number of project branches',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  public_api: {
+    id: 'AXJMbImPPAOIsUIE3gun',
+    key: 'public_api',
+    type: 'INT',
+    name: 'Public API',
+    description: 'Public API',
+    domain: 'Documentation',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  public_documented_api_density: {
+    id: 'AXJMbImPPAOIsUIE3gur',
+    key: 'public_documented_api_density',
+    type: 'PERCENT',
+    name: 'Public Documented API (%)',
+    description: 'Public documented classes and functions balanced by ncloc',
+    domain: 'Documentation',
+    direction: 1,
+    qualitative: true,
+    hidden: true,
+    decimalScale: 1
+  },
+  public_undocumented_api: {
+    id: 'AXJMbImPPAOIsUIE3gus',
+    key: 'public_undocumented_api',
+    type: 'INT',
+    name: 'Public Undocumented API',
+    description: 'Public undocumented classes, functions and variables',
+    domain: 'Documentation',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  quality_gate_details: {
+    id: 'AXJMbImPPAOIsUIE3guY',
+    key: 'quality_gate_details',
+    type: 'DATA',
+    name: 'Quality Gate Details',
+    description: 'The project detailed status with regard to its quality gate',
+    domain: 'General',
+    direction: 0,
+    qualitative: false,
+    hidden: false
+  },
+  alert_status: {
+    id: 'AXJMbImPPAOIsUIE3guX',
+    key: 'alert_status',
+    type: 'LEVEL',
+    name: 'Quality Gate Status',
+    description: 'The project status with regard to its quality gate.',
+    domain: 'Releasability',
+    direction: 1,
+    qualitative: true,
+    hidden: false
+  },
+  releasability_rating: {
+    id: 'AXJMbImPPAOIsUIE3guc',
+    key: 'releasability_rating',
+    type: 'RATING',
+    name: 'Releasability rating',
+    domain: 'Releasability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  releasability_rating_distribution: {
+    id: 'AX6QkqP7zEziun0YBqmg',
+    key: 'releasability_rating_distribution',
+    type: 'DATA',
+    name: 'Releasability Rating Distribution',
+    description: 'Releasability rating distribution',
+    domain: 'Releasability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  reliability_rating: {
+    id: 'AXJMbIl_PAOIsUIE3guP',
+    key: 'reliability_rating',
+    type: 'RATING',
+    name: 'Reliability Rating',
+    description: 'Reliability rating',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  reliability_rating_distribution: {
+    id: 'AX6QkqP7zEziun0YBqmi',
+    key: 'reliability_rating_distribution',
+    type: 'DATA',
+    name: 'Reliability Rating Distribution',
+    description: 'Maintainability rating distribution',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_reliability_rating_distribution: {
+    id: 'AX6QkqP8zEziun0YBqmm',
+    key: 'new_reliability_rating_distribution',
+    type: 'DATA',
+    name: 'Reliability Rating Distribution on New Code',
+    description: 'Maintainability rating distribution on new code',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_reliability_rating: {
+    id: 'AXJMbIl_PAOIsUIE3guQ',
+    key: 'new_reliability_rating',
+    type: 'RATING',
+    name: 'Reliability Rating on New Code',
+    description: 'Reliability rating on new code',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  reliability_remediation_effort: {
+    id: 'AXJMbIl_PAOIsUIE3guN',
+    key: 'reliability_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Reliability Remediation Effort',
+    description: 'Reliability Remediation Effort',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_reliability_remediation_effort: {
+    id: 'AXJMbIl_PAOIsUIE3guO',
+    key: 'new_reliability_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Reliability Remediation Effort on New Code',
+    description: 'Reliability remediation effort on new code',
+    domain: 'Reliability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  reopened_issues: {
+    id: 'AXJMbIl_PAOIsUIE3gt7',
+    key: 'reopened_issues',
+    type: 'INT',
+    name: 'Reopened Issues',
+    description: 'Reopened issues',
+    domain: 'Issues',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_hotspots: {
+    id: 'AXJMbIl9PAOIsUIE3gsv',
+    key: 'security_hotspots',
+    type: 'INT',
+    name: 'Security Hotspots',
+    description: 'Security Hotspots',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  security_hotspots_reviewed: {
+    id: 'AXJMbIl9PAOIsUIE3gs0',
+    key: 'security_hotspots_reviewed',
+    type: 'PERCENT',
+    name: 'Security Hotspots Reviewed',
+    description: 'Percentage of Security Hotspots Reviewed',
+    domain: 'SecurityReview',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_security_hotspots_reviewed: {
+    id: 'AXJMbIl9PAOIsUIE3gs1',
+    key: 'new_security_hotspots_reviewed',
+    type: 'PERCENT',
+    name: 'Security Hotspots Reviewed on New Code',
+    description: 'Percentage of Security Hotspots Reviewed on New Code',
+    domain: 'SecurityReview',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  security_rating: {
+    id: 'AXJMbIl_PAOIsUIE3guS',
+    key: 'security_rating',
+    type: 'RATING',
+    name: 'Security Rating',
+    description: 'Security rating',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_rating_distribution: {
+    id: 'AX6QkqP7zEziun0YBqmj',
+    key: 'security_rating_distribution',
+    type: 'DATA',
+    name: 'Security Rating Distribution',
+    description: 'Security rating distribution',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_security_rating_distribution: {
+    id: 'AX6QkqP8zEziun0YBqmn',
+    key: 'new_security_rating_distribution',
+    type: 'DATA',
+    name: 'Security Rating Distribution on New Code',
+    description: 'Security rating distribution on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_security_rating: {
+    id: 'AXJMbImPPAOIsUIE3guT',
+    key: 'new_security_rating',
+    type: 'RATING',
+    name: 'Security Rating on New Code',
+    description: 'Security rating on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_remediation_effort: {
+    id: 'AXJMbIl_PAOIsUIE3guG',
+    key: 'security_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Security Remediation Effort',
+    description: 'Security remediation effort',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  new_security_remediation_effort: {
+    id: 'AXJMbIl_PAOIsUIE3guR',
+    key: 'new_security_remediation_effort',
+    type: 'WORK_DUR',
+    name: 'Security Remediation Effort on New Code',
+    description: 'Security remediation effort on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_review_rating: {
+    id: 'AXJMbIl9PAOIsUIE3gsx',
+    key: 'security_review_rating',
+    type: 'RATING',
+    name: 'Security Review Rating',
+    description: 'Security Review Rating',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_review_rating_distribution: {
+    id: 'AX6QkqP8zEziun0YBqmk',
+    key: 'security_review_rating_distribution',
+    type: 'DATA',
+    name: 'Security Review Rating Distribution',
+    description: 'Security review rating distribution',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_security_review_rating_distribution: {
+    id: 'AX6QkqP8zEziun0YBqmo',
+    key: 'new_security_review_rating_distribution',
+    type: 'DATA',
+    name: 'Security Review Rating Distribution on New Code',
+    description: 'Security review rating distribution on new code',
+    domain: 'Security',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  new_security_review_rating: {
+    id: 'AXJMbIl9PAOIsUIE3gtA',
+    key: 'new_security_review_rating',
+    type: 'RATING',
+    name: 'Security Review Rating on New Code',
+    description: 'Security Review Rating on New Code',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  security_hotspots_reviewed_status: {
+    id: 'AXJMbIl9PAOIsUIE3gs2',
+    key: 'security_hotspots_reviewed_status',
+    type: 'INT',
+    name: 'Security Review Reviewed Status',
+    description: 'Security Review Reviewed Status',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  new_security_hotspots_reviewed_status: {
+    id: 'AXJMbIl9PAOIsUIE3gtB',
+    key: 'new_security_hotspots_reviewed_status',
+    type: 'INT',
+    name: 'Security Review Reviewed Status on New Code',
+    description: 'Security Review Reviewed Status on New Code',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  security_hotspots_to_review_status: {
+    id: 'AXJMbIl9PAOIsUIE3gs3',
+    key: 'security_hotspots_to_review_status',
+    type: 'INT',
+    name: 'Security Review To Review Status',
+    description: 'Security Review To Review Status',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  new_security_hotspots_to_review_status: {
+    id: 'AXJMbIl9PAOIsUIE3gs5',
+    key: 'new_security_hotspots_to_review_status',
+    type: 'INT',
+    name: 'Security Review To Review Status on New Code',
+    description: 'Security Review To Review Status on New Code',
+    domain: 'SecurityReview',
+    direction: -1,
+    qualitative: false,
+    hidden: true
+  },
+  skipped_tests: {
+    id: 'AXJMbIl9PAOIsUIE3gtd',
+    key: 'skipped_tests',
+    type: 'INT',
+    name: 'Skipped Unit Tests',
+    description: 'Number of skipped unit tests',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  statements: {
+    id: 'AXJMbImPPAOIsUIE3gum',
+    key: 'statements',
+    type: 'INT',
+    name: 'Statements',
+    description: 'Number of statements',
+    domain: 'Size',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  sqale_index: {
+    id: 'AXJMbIl_PAOIsUIE3guD',
+    key: 'sqale_index',
+    type: 'WORK_DUR',
+    name: 'Technical Debt',
+    description:
+      'Total effort (in hours) to fix all the issues on the component and therefore to comply to all the requirements.',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  sqale_debt_ratio: {
+    id: 'AXJMbIl_PAOIsUIE3guK',
+    key: 'sqale_debt_ratio',
+    type: 'PERCENT',
+    name: 'Technical Debt Ratio',
+    description:
+      'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  new_sqale_debt_ratio: {
+    id: 'AXJMbIl_PAOIsUIE3guL',
+    key: 'new_sqale_debt_ratio',
+    type: 'PERCENT',
+    name: 'Technical Debt Ratio on New Code',
+    description: 'Technical Debt Ratio of new/changed code.',
+    domain: 'Maintainability',
+    direction: -1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  maintainability_rating_effort: {
+    id: 'AXJMbImPPAOIsUIE3gvD',
+    key: 'maintainability_rating_effort',
+    type: 'DATA',
+    name: 'Total number of projects having worst maintainability rating',
+    domain: 'Maintainability',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  reliability_rating_effort: {
+    id: 'AXJMbImPPAOIsUIE3gvC',
+    key: 'reliability_rating_effort',
+    type: 'DATA',
+    name: 'Total number of projects having worst reliability rating',
+    domain: 'Reliability',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  security_rating_effort: {
+    id: 'AXJMbImPPAOIsUIE3gvB',
+    key: 'security_rating_effort',
+    type: 'DATA',
+    name: 'Total number of projects having worst security rating',
+    domain: 'Security',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  security_review_rating_effort: {
+    id: 'AXJMbIl9PAOIsUIE3gs6',
+    key: 'security_review_rating_effort',
+    type: 'DATA',
+    name: 'Total number of projects having worst security review rating',
+    domain: 'Security',
+    direction: 0,
+    qualitative: false,
+    hidden: true
+  },
+  releasability_effort: {
+    id: 'AXJMbImPPAOIsUIE3gub',
+    key: 'releasability_effort',
+    type: 'INT',
+    name: 'Total number of projects not production ready',
+    domain: 'Releasability',
+    direction: -1,
+    qualitative: true,
+    hidden: true
+  },
+  uncovered_conditions: {
+    id: 'AXJMbIl9PAOIsUIE3gs8',
+    key: 'uncovered_conditions',
+    type: 'INT',
+    name: 'Uncovered Conditions',
+    description: 'Uncovered conditions',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  new_uncovered_conditions: {
+    id: 'AXJMbIl9PAOIsUIE3gs9',
+    key: 'new_uncovered_conditions',
+    type: 'INT',
+    name: 'Uncovered Conditions on New Code',
+    description: 'Uncovered conditions on new code',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  uncovered_lines: {
+    id: 'AXJMbIl_PAOIsUIE3gtj',
+    key: 'uncovered_lines',
+    type: 'INT',
+    name: 'Uncovered Lines',
+    description: 'Uncovered lines',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  new_uncovered_lines: {
+    id: 'AXJMbIl_PAOIsUIE3gtk',
+    key: 'new_uncovered_lines',
+    type: 'INT',
+    name: 'Uncovered Lines on New Code',
+    description: 'Uncovered lines on new code',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  test_execution_time: {
+    id: 'AXJMbIl9PAOIsUIE3gtb',
+    key: 'test_execution_time',
+    type: 'MILLISEC',
+    name: 'Unit Test Duration',
+    description: 'Execution duration of unit tests',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  test_errors: {
+    id: 'AXJMbIl9PAOIsUIE3gtc',
+    key: 'test_errors',
+    type: 'INT',
+    name: 'Unit Test Errors',
+    description: 'Number of unit test errors',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  test_failures: {
+    id: 'AXJMbIl9PAOIsUIE3gte',
+    key: 'test_failures',
+    type: 'INT',
+    name: 'Unit Test Failures',
+    description: 'Number of unit test failures',
+    domain: 'Coverage',
+    direction: -1,
+    qualitative: true,
+    hidden: false
+  },
+  tests: {
+    id: 'AXJMbIl9PAOIsUIE3gta',
+    key: 'tests',
+    type: 'INT',
+    name: 'Unit Tests',
+    description: 'Number of unit tests',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: false,
+    hidden: false
+  },
+  test_success_density: {
+    id: 'AXJMbIl9PAOIsUIE3gtf',
+    key: 'test_success_density',
+    type: 'PERCENT',
+    name: 'Unit Test Success (%)',
+    description: 'Density of successful unit tests',
+    domain: 'Coverage',
+    direction: 1,
+    qualitative: true,
+    hidden: false,
+    decimalScale: 1
+  },
+  vulnerabilities: {
+    id: 'AXJMbIl_PAOIsUIE3guB',
+    key: 'vulnerabilities',
+    type: 'INT',
+    name: 'Vulnerabilities',
+    description: 'Vulnerabilities',
+    domain: 'Security',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  },
+  wont_fix_issues: {
+    id: 'AXJMbIl_PAOIsUIE3gt5',
+    key: 'wont_fix_issues',
+    type: 'INT',
+    name: "Won't Fix Issues",
+    description: "Won't fix issues",
+    domain: 'Issues',
+    direction: -1,
+    qualitative: false,
+    hidden: false
+  }
+};
diff --git a/server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx b/server/sonar-web/src/main/js/helpers/testReactTestingUtils.tsx
new file mode 100644 (file)
index 0000000..fbc4f8a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 { render, RenderResult } from '@testing-library/react';
+import { History } from 'history';
+import * as React from 'react';
+import { HelmetProvider } from 'react-helmet-async';
+import { IntlProvider } from 'react-intl';
+import { Provider } from 'react-redux';
+import { createMemoryHistory, RouteConfig, Router } from 'react-router';
+import { Store } from 'redux';
+import AppStateContextProvider from '../app/components/app-state/AppStateContextProvider';
+import { MetricsContext } from '../app/components/metrics/MetricsContext';
+import getStore from '../app/utils/getStore';
+import { RouteWithChildRoutes } from '../app/utils/startReactApp';
+import { Store as State } from '../store/rootReducer';
+import { AppState, Dict, Metric } from '../types/types';
+import { DEFAULT_METRICS } from './mocks/metrics';
+import { mockAppState } from './testMocks';
+
+interface RenderContext {
+  metrics?: Dict<Metric>;
+  store?: Store<State, any>;
+  history?: History;
+  appState?: AppState;
+}
+
+export function renderApp(
+  indexPath: string,
+  routes: RouteConfig,
+  {
+    metrics = DEFAULT_METRICS,
+    store = getStore(),
+    appState = mockAppState(),
+    history = createMemoryHistory()
+  }: RenderContext = {}
+): RenderResult {
+  history.push(`/${indexPath}`);
+  return render(
+    <HelmetProvider context={{}}>
+      <IntlProvider defaultLocale="en" locale="en">
+        <MetricsContext.Provider value={metrics}>
+          <Provider store={store}>
+            <AppStateContextProvider appState={appState}>
+              <Router history={history}>
+                <RouteWithChildRoutes path={indexPath} childRoutes={routes} />
+              </Router>
+            </AppStateContextProvider>
+          </Provider>
+        </MetricsContext.Provider>
+      </IntlProvider>
+    </HelmetProvider>
+  );
+}
index e7e24aeba37be319e624ccf529ec9b10a87b2e5f..bf629a6ddb2991ac54acb19676c70738ebce3268 100644 (file)
@@ -24,7 +24,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7":
+"@babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.7":
   version: 7.16.7
   resolution: "@babel/code-frame@npm:7.16.7"
   dependencies:
@@ -2509,6 +2509,63 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@testing-library/dom@npm:8.11.3, @testing-library/dom@npm:^8.0.0":
+  version: 8.11.3
+  resolution: "@testing-library/dom@npm:8.11.3"
+  dependencies:
+    "@babel/code-frame": ^7.10.4
+    "@babel/runtime": ^7.12.5
+    "@types/aria-query": ^4.2.0
+    aria-query: ^5.0.0
+    chalk: ^4.1.0
+    dom-accessibility-api: ^0.5.9
+    lz-string: ^1.4.4
+    pretty-format: ^27.0.2
+  checksum: 2245d254b6058590e25de86fb7b3c75e4a31096901a191f80d3efb9fa7e1e273043416f370c8770feb9f3ccc73a1550a877a3b003b593f1728ae828fcb52cd62
+  languageName: node
+  linkType: hard
+
+"@testing-library/jest-dom@npm:5.16.2":
+  version: 5.16.2
+  resolution: "@testing-library/jest-dom@npm:5.16.2"
+  dependencies:
+    "@babel/runtime": ^7.9.2
+    "@types/testing-library__jest-dom": ^5.9.1
+    aria-query: ^5.0.0
+    chalk: ^3.0.0
+    css: ^3.0.0
+    css.escape: ^1.5.1
+    dom-accessibility-api: ^0.5.6
+    lodash: ^4.17.15
+    redent: ^3.0.0
+  checksum: e4569df67c4c4998d2c60c6cf00ce2f1ac10c9397e0970320728c8be8f4e2c17a0e801705ce8a7384f7f5629b598a6f58db91d4401dde02044f5625405ca0988
+  languageName: node
+  linkType: hard
+
+"@testing-library/react@npm:12.1.2":
+  version: 12.1.2
+  resolution: "@testing-library/react@npm:12.1.2"
+  dependencies:
+    "@babel/runtime": ^7.12.5
+    "@testing-library/dom": ^8.0.0
+  peerDependencies:
+    react: "*"
+    react-dom: "*"
+  checksum: 70b0f7f27c83fe1a33e7df01b1e64850fbab4050c403848d611d852cadaa25ccde58518773002ae569a1350b2282c2ccbcbe5eb6af8b29ab377ab2a8ab573b3b
+  languageName: node
+  linkType: hard
+
+"@testing-library/user-event@npm:14.0.0-beta.11":
+  version: 14.0.0-beta.11
+  resolution: "@testing-library/user-event@npm:14.0.0-beta.11"
+  dependencies:
+    "@babel/runtime": ^7.12.5
+  peerDependencies:
+    "@testing-library/dom": ">=7.21.4"
+  checksum: 92ed62c965b57420f607bc4214c45022bca55210864949fff3bcaadee6ce93a8b904f782385ddb77f8fc885b191b1da8f6557ab86bdd355a53c3a11177000ccb
+  languageName: node
+  linkType: hard
+
 "@tootallnate/once@npm:1":
   version: 1.1.2
   resolution: "@tootallnate/once@npm:1.1.2"
@@ -2516,6 +2573,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/aria-query@npm:^4.2.0":
+  version: 4.2.2
+  resolution: "@types/aria-query@npm:4.2.2"
+  checksum: 6f2ce11d91e2d665f3873258db19da752d91d85d3679eb5efcdf9c711d14492287e1e4eb52613b28e60375841a9e428594e745b68436c963d8bad4bf72188df3
+  languageName: node
+  linkType: hard
+
 "@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.14":
   version: 7.1.18
   resolution: "@types/babel__core@npm:7.1.18"
@@ -2815,7 +2879,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/jest@npm:27.4.0":
+"@types/jest@npm:*, @types/jest@npm:27.4.0":
   version: 27.4.0
   resolution: "@types/jest@npm:27.4.0"
   dependencies:
@@ -2832,7 +2896,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@types/json-schema@npm:^7.0.7":
+"@types/json-schema@npm:^7.0.7, @types/json-schema@npm:^7.0.9":
   version: 7.0.9
   resolution: "@types/json-schema@npm:7.0.9"
   checksum: 259d0e25f11a21ba5c708f7ea47196bd396e379fddb79c76f9f4f62c945879dc21657904914313ec2754e443c5018ea8372362f323f30e0792897fdb2098a705
@@ -3033,6 +3097,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/testing-library__jest-dom@npm:^5.9.1":
+  version: 5.14.2
+  resolution: "@types/testing-library__jest-dom@npm:5.14.2"
+  dependencies:
+    "@types/jest": "*"
+  checksum: e08715a565cc189112a6611485d779a0f1ceb546a9d4601b21aacff7596d7acf8b7c702e4c5f825677431ff601df3e635887dc8a5735da1a263cc857eb7c3833
+  languageName: node
+  linkType: hard
+
 "@types/trusted-types@npm:*":
   version: 1.0.4
   resolution: "@types/trusted-types@npm:1.0.4"
@@ -3135,6 +3208,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/scope-manager@npm:5.13.0":
+  version: 5.13.0
+  resolution: "@typescript-eslint/scope-manager@npm:5.13.0"
+  dependencies:
+    "@typescript-eslint/types": 5.13.0
+    "@typescript-eslint/visitor-keys": 5.13.0
+  checksum: 43fade6759e751387ee91f85033c036f122b5051f7ad7baf35fe5db68e2129afc1cc1c12c2b0b8a25eb206092ad1073d8e640b21f6b04824413f40751d8e0d42
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/types@npm:4.33.0":
   version: 4.33.0
   resolution: "@typescript-eslint/types@npm:4.33.0"
@@ -3142,6 +3225,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/types@npm:5.13.0":
+  version: 5.13.0
+  resolution: "@typescript-eslint/types@npm:5.13.0"
+  checksum: 2228935a9f7e80264a554ffadc458ee184259b56cd987bf10f12754183e032953fb93b7b31f8261dd0a40dbac4f341d4904ae7aa1f1aba9f2a92b1062f05c8dc
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/typescript-estree@npm:4.33.0":
   version: 4.33.0
   resolution: "@typescript-eslint/typescript-estree@npm:4.33.0"
@@ -3160,6 +3250,40 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/typescript-estree@npm:5.13.0":
+  version: 5.13.0
+  resolution: "@typescript-eslint/typescript-estree@npm:5.13.0"
+  dependencies:
+    "@typescript-eslint/types": 5.13.0
+    "@typescript-eslint/visitor-keys": 5.13.0
+    debug: ^4.3.2
+    globby: ^11.0.4
+    is-glob: ^4.0.3
+    semver: ^7.3.5
+    tsutils: ^3.21.0
+  peerDependenciesMeta:
+    typescript:
+      optional: true
+  checksum: bcf2f94eb4b8e0a5f47fa1e04478aa3f36c8d2b629300bf3d3a375f87e8046cd7f2364cd7df8fceb97855e7789721de5c66dafcf17cfd93552a93a7d7733dfdb
+  languageName: node
+  linkType: hard
+
+"@typescript-eslint/utils@npm:^5.13.0":
+  version: 5.13.0
+  resolution: "@typescript-eslint/utils@npm:5.13.0"
+  dependencies:
+    "@types/json-schema": ^7.0.9
+    "@typescript-eslint/scope-manager": 5.13.0
+    "@typescript-eslint/types": 5.13.0
+    "@typescript-eslint/typescript-estree": 5.13.0
+    eslint-scope: ^5.1.1
+    eslint-utils: ^3.0.0
+  peerDependencies:
+    eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+  checksum: cb93cddc83bd5f9cee7fc72ab64c509b285392a005fb1315522374991f18a1cb8f233ee0d1e828cc18570c3fe27e81cc28471c36142284bd39351b8a3f8a83bd
+  languageName: node
+  linkType: hard
+
 "@typescript-eslint/visitor-keys@npm:4.33.0":
   version: 4.33.0
   resolution: "@typescript-eslint/visitor-keys@npm:4.33.0"
@@ -3170,6 +3294,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@typescript-eslint/visitor-keys@npm:5.13.0":
+  version: 5.13.0
+  resolution: "@typescript-eslint/visitor-keys@npm:5.13.0"
+  dependencies:
+    "@typescript-eslint/types": 5.13.0
+    eslint-visitor-keys: ^3.0.0
+  checksum: 3987217053e22a86f9105efe6250ca028ef437483b79d0dad45850edacfc273835b82178e77e5012a3c045df18561fef3eb4417cc26c328c901fbaa0da09e922
+  languageName: node
+  linkType: hard
+
 "SonarQube@workspace:.":
   version: 0.0.0-use.local
   resolution: "SonarQube@workspace:."
@@ -3185,6 +3319,10 @@ __metadata:
     "@emotion/jest": 11.7.1
     "@emotion/react": 11.7.1
     "@emotion/styled": 11.6.0
+    "@testing-library/dom": 8.11.3
+    "@testing-library/jest-dom": 5.16.2
+    "@testing-library/react": 12.1.2
+    "@testing-library/user-event": 14.0.0-beta.11
     "@types/classnames": 2.3.0
     "@types/clipboard": 2.0.1
     "@types/d3-array": 1.2.4
@@ -3244,6 +3382,7 @@ __metadata:
     eslint-plugin-promise: 4.2.1
     eslint-plugin-react: 7.28.0
     eslint-plugin-react-hooks: 4.3.0
+    eslint-plugin-testing-library: 5.0.6
     formik: 1.2.0
     fs-extra: 10.0.0
     glob: 7.2.0
@@ -3562,6 +3701,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"aria-query@npm:^5.0.0":
+  version: 5.0.0
+  resolution: "aria-query@npm:5.0.0"
+  checksum: c41f98866c5a304561ee8cae55856711cddad6f3f85d8cb43cc5f79667078d9b8979ce32d244c1ff364e6463a4d0b6865804a33ccc717fed701b281cf7dc6296
+  languageName: node
+  linkType: hard
+
 "array-filter@npm:^1.0.0":
   version: 1.0.0
   resolution: "array-filter@npm:1.0.0"
@@ -4107,7 +4253,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"chalk@npm:3.0.0":
+"chalk@npm:3.0.0, chalk@npm:^3.0.0":
   version: 3.0.0
   resolution: "chalk@npm:3.0.0"
   dependencies:
@@ -4530,6 +4676,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"css.escape@npm:^1.5.1":
+  version: 1.5.1
+  resolution: "css.escape@npm:1.5.1"
+  checksum: f6d38088d870a961794a2580b2b2af1027731bb43261cfdce14f19238a88664b351cc8978abc20f06cc6bbde725699dec8deb6fe9816b139fc3f2af28719e774
+  languageName: node
+  linkType: hard
+
 "css@npm:^2.2.1":
   version: 2.2.4
   resolution: "css@npm:2.2.4"
@@ -4827,7 +4980,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"debug@npm:^4.0.1, debug@npm:^4.3.1":
+"debug@npm:^4.0.1, debug@npm:^4.3.1, debug@npm:^4.3.2":
   version: 4.3.3
   resolution: "debug@npm:4.3.3"
   dependencies:
@@ -4993,6 +5146,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"dom-accessibility-api@npm:^0.5.6, dom-accessibility-api@npm:^0.5.9":
+  version: 0.5.11
+  resolution: "dom-accessibility-api@npm:0.5.11"
+  checksum: 6928436f384e34f6c9279a887c7417fd0bf3c881b491f60a44b24eec37ce7318124f1440fcd4110b4cffc6dd0668548fde2837627eb76e3b75f840884c6bd7df
+  languageName: node
+  linkType: hard
+
 "dom-helpers@npm:^5.0.1, dom-helpers@npm:^5.1.3":
   version: 5.2.1
   resolution: "dom-helpers@npm:5.2.1"
@@ -5775,6 +5935,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-plugin-testing-library@npm:5.0.6":
+  version: 5.0.6
+  resolution: "eslint-plugin-testing-library@npm:5.0.6"
+  dependencies:
+    "@typescript-eslint/utils": ^5.13.0
+  peerDependencies:
+    eslint: ^7.5.0 || ^8.0.0
+  checksum: 8c9db0f535f807c7b2b23474c216a7239dbe21c5147e4d694f4a49f0e61c85a4ec8c2e77bc16ccb0a2c19e599f519bbf8108370d4721c4f17400bed170ec74aa
+  languageName: node
+  linkType: hard
+
 "eslint-scope@npm:^5.1.1":
   version: 5.1.1
   resolution: "eslint-scope@npm:5.1.1"
@@ -5819,6 +5990,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"eslint-visitor-keys@npm:^3.0.0":
+  version: 3.3.0
+  resolution: "eslint-visitor-keys@npm:3.3.0"
+  checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808
+  languageName: node
+  linkType: hard
+
 "eslint@npm:7.17.0":
   version: 7.17.0
   resolution: "eslint@npm:7.17.0"
@@ -6520,7 +6698,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"globby@npm:^11.0.3":
+"globby@npm:^11.0.3, globby@npm:^11.0.4":
   version: 11.1.0
   resolution: "globby@npm:11.1.0"
   dependencies:
@@ -8489,7 +8667,7 @@ __metadata:
   languageName: node
   linkType: hard
 
-"lodash@npm:4.17.21, lodash@npm:^4.15.0, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.19, lodash@npm:^4.17.21, lodash@npm:^4.7.0":
+"lodash@npm:4.17.21, lodash@npm:^4.15.0, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.21, lodash@npm:^4.7.0":
   version: 4.17.21
   resolution: "lodash@npm:4.17.21"
   checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
@@ -8530,6 +8708,15 @@ __metadata:
   languageName: node
   linkType: hard
 
+"lz-string@npm:^1.4.4":
+  version: 1.4.4
+  resolution: "lz-string@npm:1.4.4"
+  bin:
+    lz-string: bin/bin.js
+  checksum: 54e31238a61a84d8f664d9860a9fba7310c5b97a52c444f80543069bc084815eff40b8d4474ae1d93992fdf6c252dca37cf27f6adbeb4dbc3df2f3ac773d0e61
+  languageName: node
+  linkType: hard
+
 "make-dir@npm:^2.1.0":
   version: 2.1.0
   resolution: "make-dir@npm:2.1.0"
@@ -8729,6 +8916,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"min-indent@npm:^1.0.0":
+  version: 1.0.1
+  resolution: "min-indent@npm:1.0.1"
+  checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1
+  languageName: node
+  linkType: hard
+
 "minimatch@npm:^3.0.4":
   version: 3.0.4
   resolution: "minimatch@npm:3.0.4"
@@ -9686,6 +9880,17 @@ __metadata:
   languageName: node
   linkType: hard
 
+"pretty-format@npm:^27.0.2":
+  version: 27.5.1
+  resolution: "pretty-format@npm:27.5.1"
+  dependencies:
+    ansi-regex: ^5.0.1
+    ansi-styles: ^5.0.0
+    react-is: ^17.0.1
+  checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088
+  languageName: node
+  linkType: hard
+
 "private@npm:^0.1.8":
   version: 0.1.8
   resolution: "private@npm:0.1.8"
@@ -10177,6 +10382,16 @@ __metadata:
   languageName: node
   linkType: hard
 
+"redent@npm:^3.0.0":
+  version: 3.0.0
+  resolution: "redent@npm:3.0.0"
+  dependencies:
+    indent-string: ^4.0.0
+    strip-indent: ^3.0.0
+  checksum: fa1ef20404a2d399235e83cc80bd55a956642e37dd197b4b612ba7327bf87fa32745aeb4a1634b2bab25467164ab4ed9c15be2c307923dd08b0fe7c52431ae6b
+  languageName: node
+  linkType: hard
+
 "redux-thunk@npm:2.4.1":
   version: 2.4.1
   resolution: "redux-thunk@npm:2.4.1"
@@ -11349,6 +11564,15 @@ resolve@^1.3.2:
   languageName: node
   linkType: hard
 
+"strip-indent@npm:^3.0.0":
+  version: 3.0.0
+  resolution: "strip-indent@npm:3.0.0"
+  dependencies:
+    min-indent: ^1.0.0
+  checksum: 18f045d57d9d0d90cd16f72b2313d6364fd2cb4bf85b9f593523ad431c8720011a4d5f08b6591c9d580f446e78855c5334a30fb91aa1560f5d9f95ed1b4a0530
+  languageName: node
+  linkType: hard
+
 "strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1":
   version: 3.1.1
   resolution: "strip-json-comments@npm:3.1.1"