aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js
diff options
context:
space:
mode:
authorStas Vilchik <stas.vilchik@sonarsource.com>2018-08-22 10:46:42 +0200
committerSonarTech <sonartech@sonarsource.com>2018-08-24 20:21:20 +0200
commitfede6d0a2378ce959e7cb1afdf221a92e22b8a6f (patch)
tree664177136e675521b5f11f3e20272b453a4a5ceb /server/sonar-web/src/main/js
parent07dd03a5bb3d8460412e4d09043568cb477838c0 (diff)
downloadsonarqube-fede6d0a2378ce959e7cb1afdf221a92e22b8a6f.tar.gz
sonarqube-fede6d0a2378ce959e7cb1afdf221a92e22b8a6f.zip
SONAR-11156 fix issues section of hotspot rules
Diffstat (limited to 'server/sonar-web/src/main/js')
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsIssues.tsx23
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsIssues-test.tsx63
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsIssues-test.tsx.snap233
4 files changed, 312 insertions, 9 deletions
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
index dcdc5b733dd..fabcfaf39ee 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
@@ -254,7 +254,7 @@ export default class RuleDetails extends React.PureComponent<Props, State> {
)}
{!ruleDetails.isTemplate && (
- <RuleDetailsIssues organization={organization} ruleKey={ruleDetails.key} />
+ <RuleDetailsIssues organization={organization} ruleDetails={ruleDetails} />
)}
</DeferredSpinner>
</div>
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsIssues.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsIssues.tsx
index 3bb6e1839eb..4925b83ccce 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsIssues.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsIssues.tsx
@@ -23,13 +23,14 @@ import { Link } from 'react-router';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import Tooltip from '../../../components/controls/Tooltip';
import { getFacet } from '../../../api/issues';
+import { RuleDetails } from '../../../app/types';
import { getIssuesUrl } from '../../../helpers/urls';
import { formatMeasure } from '../../../helpers/measures';
import { translate } from '../../../helpers/l10n';
interface Props {
organization: string | undefined;
- ruleKey: string;
+ ruleDetails: Pick<RuleDetails, 'key' | 'type'>;
}
interface Project {
@@ -59,7 +60,7 @@ export default class RuleDetailsIssues extends React.PureComponent<Props, State>
}
componentDidUpdate(prevProps: Props) {
- if (prevProps.ruleKey !== this.props.ruleKey) {
+ if (prevProps.ruleDetails !== this.props.ruleDetails) {
this.fetchIssues();
}
}
@@ -68,10 +69,19 @@ export default class RuleDetailsIssues extends React.PureComponent<Props, State>
this.mounted = false;
}
+ getBaseIssuesQuery = () => ({
+ resolved: 'false',
+ rules: this.props.ruleDetails.key,
+ types:
+ this.props.ruleDetails.type === 'SECURITY_HOTSPOT'
+ ? 'VULNERABILITY,SECURITY_HOTSPOT'
+ : undefined
+ });
+
fetchIssues = () => {
this.setState({ loading: true });
getFacet(
- { organization: this.props.organization, rules: this.props.ruleKey, resolved: false },
+ { ...this.getBaseIssuesQuery(), organization: this.props.organization },
'projects'
).then(
({ facet, response }) => {
@@ -100,10 +110,7 @@ export default class RuleDetailsIssues extends React.PureComponent<Props, State>
if (total === undefined) {
return null;
}
- const path = getIssuesUrl(
- { resolved: 'false', rules: this.props.ruleKey },
- this.props.organization
- );
+ const path = getIssuesUrl(this.getBaseIssuesQuery(), this.props.organization);
const totalItem = (
<span className="little-spacer-left">
@@ -124,7 +131,7 @@ export default class RuleDetailsIssues extends React.PureComponent<Props, State>
renderProject = (project: Project) => {
const path = getIssuesUrl(
- { projects: project.key, resolved: 'false', rules: this.props.ruleKey },
+ { ...this.getBaseIssuesQuery(), projects: project.key },
this.props.organization
);
return (
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsIssues-test.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsIssues-test.tsx
new file mode 100644
index 00000000000..fb79d0585ed
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/RuleDetailsIssues-test.tsx
@@ -0,0 +1,63 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import RuleDetailsIssues from '../RuleDetailsIssues';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+import { getFacet } from '../../../../api/issues';
+
+jest.mock('../../../../api/issues', () => ({
+ getFacet: jest.fn().mockResolvedValue({
+ facet: [{ count: 13, val: 'sample-key' }, { count: 5, val: 'example-key' }],
+ response: {
+ components: [{ key: 'sample-key', name: 'Sample' }, { key: 'example-key', name: 'Example' }],
+ paging: { total: 18 }
+ }
+ })
+}));
+
+beforeEach(() => {
+ (getFacet as jest.Mock).mockClear();
+});
+
+it('should fetch issues and render', async () => {
+ await check('BUG', undefined);
+});
+
+it('should handle hotspot rules', async () => {
+ await check('SECURITY_HOTSPOT', ['VULNERABILITY', 'SECURITY_HOTSPOT']);
+});
+
+async function check(ruleType: string, requestedTypes: string[] | undefined) {
+ const wrapper = shallow(
+ <RuleDetailsIssues organization="org" ruleDetails={{ key: 'foo', type: ruleType }} />
+ );
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(getFacet).toBeCalledWith(
+ {
+ organization: 'org',
+ resolved: 'false',
+ rules: 'foo',
+ types: requestedTypes && requestedTypes.join()
+ },
+ 'projects'
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsIssues-test.tsx.snap b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsIssues-test.tsx.snap
new file mode 100644
index 00000000000..a3b6fbe185a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/__tests__/__snapshots__/RuleDetailsIssues-test.tsx.snap
@@ -0,0 +1,233 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should fetch issues and render 1`] = `
+<div
+ className="js-rule-issues coding-rule-section"
+>
+ <div
+ className="coding-rule-section-separator"
+ />
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ >
+ <h3
+ className="coding-rules-detail-title"
+ >
+ coding_rules.issues
+ <span
+ className="little-spacer-left"
+ >
+ (
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "resolved": "false",
+ "rules": "foo",
+ "types": undefined,
+ },
+ }
+ }
+ >
+ 18
+ </Link>
+ )
+ </span>
+ </h3>
+ <table
+ className="coding-rules-detail-list coding-rules-most-violated-projects"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="coding-rules-detail-list-name"
+ colSpan={2}
+ >
+ coding_rules.most_violating_projects
+ </td>
+ </tr>
+ <tr
+ key="sample-key"
+ >
+ <td
+ className="coding-rules-detail-list-name"
+ >
+ Sample
+ </td>
+ <td
+ className="coding-rules-detail-list-parameters"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "projects": "sample-key",
+ "resolved": "false",
+ "rules": "foo",
+ "types": undefined,
+ },
+ }
+ }
+ >
+ 13
+ </Link>
+ </td>
+ </tr>
+ <tr
+ key="example-key"
+ >
+ <td
+ className="coding-rules-detail-list-name"
+ >
+ Example
+ </td>
+ <td
+ className="coding-rules-detail-list-parameters"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "projects": "example-key",
+ "resolved": "false",
+ "rules": "foo",
+ "types": undefined,
+ },
+ }
+ }
+ >
+ 5
+ </Link>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </DeferredSpinner>
+</div>
+`;
+
+exports[`should handle hotspot rules 1`] = `
+<div
+ className="js-rule-issues coding-rule-section"
+>
+ <div
+ className="coding-rule-section-separator"
+ />
+ <DeferredSpinner
+ loading={false}
+ timeout={100}
+ >
+ <h3
+ className="coding-rules-detail-title"
+ >
+ coding_rules.issues
+ <span
+ className="little-spacer-left"
+ >
+ (
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "resolved": "false",
+ "rules": "foo",
+ "types": "VULNERABILITY,SECURITY_HOTSPOT",
+ },
+ }
+ }
+ >
+ 18
+ </Link>
+ )
+ </span>
+ </h3>
+ <table
+ className="coding-rules-detail-list coding-rules-most-violated-projects"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="coding-rules-detail-list-name"
+ colSpan={2}
+ >
+ coding_rules.most_violating_projects
+ </td>
+ </tr>
+ <tr
+ key="sample-key"
+ >
+ <td
+ className="coding-rules-detail-list-name"
+ >
+ Sample
+ </td>
+ <td
+ className="coding-rules-detail-list-parameters"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "projects": "sample-key",
+ "resolved": "false",
+ "rules": "foo",
+ "types": "VULNERABILITY,SECURITY_HOTSPOT",
+ },
+ }
+ }
+ >
+ 13
+ </Link>
+ </td>
+ </tr>
+ <tr
+ key="example-key"
+ >
+ <td
+ className="coding-rules-detail-list-name"
+ >
+ Example
+ </td>
+ <td
+ className="coding-rules-detail-list-parameters"
+ >
+ <Link
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/organizations/org/issues",
+ "query": Object {
+ "projects": "example-key",
+ "resolved": "false",
+ "rules": "foo",
+ "types": "VULNERABILITY,SECURITY_HOTSPOT",
+ },
+ }
+ }
+ >
+ 5
+ </Link>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </DeferredSpinner>
+</div>
+`;