if (r.measures.length === 0) {
return [];
}
- return r.measures[0].history.map(analysis => ({
+ return r.measures[0].history.filter(analysis => analysis.value != null).map(analysis => ({
date: moment(analysis.date).toDate(),
value: analysis.value
}));
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 React from 'react';
+import { shallow } from 'enzyme';
+import ProjectActivityGraphs from '../ProjectActivityGraphs';
+
+const ANALYSES = [
+ {
+ key: 'A1',
+ date: '2016-10-27T16:33:50+0200',
+ events: [
+ {
+ key: 'E1',
+ category: 'VERSION',
+ name: '6.5-SNAPSHOT'
+ }
+ ]
+ },
+ {
+ key: 'A2',
+ date: '2016-10-27T12:21:15+0200',
+ events: []
+ },
+ {
+ key: 'A3',
+ date: '2016-10-26T12:17:29+0200',
+ events: [
+ {
+ key: 'E2',
+ category: 'VERSION',
+ name: '6.4'
+ },
+ {
+ key: 'E3',
+ category: 'OTHER',
+ name: 'foo'
+ }
+ ]
+ }
+];
+
+const DEFAULT_PROPS = {
+ analyses: ANALYSES,
+ leakPeriodDate: '2017-05-16T13:50:02+0200',
+ loading: false,
+ measuresHistory: [
+ {
+ metric: 'code_smells',
+ history: [
+ { date: new Date('2016-10-26T12:17:29+0200'), value: '2286' },
+ { date: new Date('2016-10-27T12:21:15+0200'), value: '1749' },
+ { date: new Date('2016-10-27T16:33:50+0200'), value: '500' }
+ ]
+ }
+ ],
+ metricsType: 'INT',
+ project: 'org.sonarsource.sonarqube:sonarqube',
+ query: { category: '', graph: 'overview', project: 'org.sonarsource.sonarqube:sonarqube' },
+ updateQuery: () => {}
+};
+
+it('should render correctly the graph and legends', () => {
+ expect(shallow(<ProjectActivityGraphs {...DEFAULT_PROPS} />)).toMatchSnapshot();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly the graph and legends 1`] = `
+<div
+ className="project-activity-layout-page-main-inner boxed-group boxed-group-inner"
+>
+ <ProjectActivityGraphsHeader
+ graph="overview"
+ updateQuery={[Function]}
+ />
+ <StaticGraphs
+ analyses={
+ Array [
+ Object {
+ "date": "2016-10-27T16:33:50+0200",
+ "events": Array [
+ Object {
+ "category": "VERSION",
+ "key": "E1",
+ "name": "6.5-SNAPSHOT",
+ },
+ ],
+ "key": "A1",
+ },
+ Object {
+ "date": "2016-10-27T12:21:15+0200",
+ "events": Array [],
+ "key": "A2",
+ },
+ Object {
+ "date": "2016-10-26T12:17:29+0200",
+ "events": Array [
+ Object {
+ "category": "VERSION",
+ "key": "E2",
+ "name": "6.4",
+ },
+ Object {
+ "category": "OTHER",
+ "key": "E3",
+ "name": "foo",
+ },
+ ],
+ "key": "A3",
+ },
+ ]
+ }
+ eventFilter=""
+ leakPeriodDate="2017-05-16T13:50:02+0200"
+ loading={false}
+ measuresHistory={
+ Array [
+ Object {
+ "history": Array [
+ Object {
+ "date": 2016-10-26T10:17:29.000Z,
+ "value": "2286",
+ },
+ Object {
+ "date": 2016-10-27T10:21:15.000Z,
+ "value": "1749",
+ },
+ Object {
+ "date": 2016-10-27T14:33:50.000Z,
+ "value": "500",
+ },
+ ],
+ "metric": "code_smells",
+ },
+ ]
+ }
+ metricsType="INT"
+ project="org.sonarsource.sonarqube:sonarqube"
+ seriesOrder={
+ Array [
+ "bugs",
+ "code_smells",
+ "vulnerabilities",
+ ]
+ }
+ showAreas={false}
+ />
+</div>
+`;
};
renderLines = (xScale: Scale, yScale: Scale) => {
- const lineGenerator = d3Line().x(d => xScale(d.x)).y(d => yScale(d.y));
+ const lineGenerator = d3Line()
+ .defined(d => d.y || d.y === 0)
+ .x(d => xScale(d.x))
+ .y(d => yScale(d.y));
if (this.props.basisCurve) {
lineGenerator.curve(curveBasis);
}
};
renderAreas = (xScale: Scale, yScale: Scale) => {
- const areaGenerator = area().x(d => xScale(d.x)).y1(d => yScale(d.y)).y0(yScale(0));
+ const areaGenerator = area()
+ .defined(d => d.y || d.y === 0)
+ .x(d => xScale(d.x))
+ .y1(d => yScale(d.y))
+ .y0(yScale(0));
if (this.props.basisCurve) {
areaGenerator.curve(curveBasis);
}
.x(d => xScale(d.x))
.y0(yScale.range()[0])
.y1(d => yScale(d.y))
+ .defined(d => d.y != null)
.curve(curveBasis);
let data = this.props.data;
if (!this.props.displayPoints) {
return null;
}
- const points = this.props.data.map((point, index) => {
+ const points = this.props.data.filter(point => point.y != null).map((point, index) => {
const x = xScale(point.x);
const y = yScale(point.y);
return <circle key={index} className="line-chart-point" r="3" cx={x} cy={y} />;
},
renderLine(xScale, yScale) {
- const p = d3Line().x(d => xScale(d.x)).y(d => yScale(d.y)).curve(curveBasis);
+ const p = d3Line()
+ .x(d => xScale(d.x))
+ .y(d => yScale(d.y))
+ .defined(d => d.y != null)
+ .curve(curveBasis);
return <path className="line-chart-path" d={p(this.props.data)} />;
},