]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17004 SONAR-17011 Write RTL ITs
authorWouter Admiraal <wouter.admiraal@sonarsource.com>
Tue, 11 Oct 2022 12:12:17 +0000 (14:12 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 13 Oct 2022 20:03:19 +0000 (20:03 +0000)
15 files changed:
server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx
server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetric-test.tsx [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetricPopup-test.tsx [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-test.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-test.tsx [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphHistory-test.tsx [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsHistory-test.tsx [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetric-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetricPopup-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/EventInner-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsHistory-test.tsx.snap [deleted file]
server/sonar-web/src/main/js/components/controls/Checkbox.tsx
server/sonar-web/src/main/js/helpers/mocks/project-activity.ts

index 6f8559169b4166d9d43067e09f77e504916276a5..c15aaac724a7010f49bc445396f865fcdef89497 100644 (file)
@@ -67,11 +67,11 @@ export default class GraphsHeader extends React.PureComponent<Props> {
       <div className={classNames(className, 'position-relative')}>
         <div className="display-flex-end">
           <div className="display-flex-column">
-            <label className="text-bold little-spacer-bottom" htmlFor="graph-select">
+            <label className="text-bold little-spacer-bottom" id="graph-select-label">
               {translate('project_activity.graphs.choose_type')}
             </label>
             <Select
-              id="graph-select"
+              aria-labelledby="graph-select-label"
               className="input-medium"
               isSearchable={false}
               onChange={this.handleGraphChange}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx
new file mode 100644 (file)
index 0000000..786e404
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * 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 } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { UserEvent } from '@testing-library/user-event/dist/types/setup';
+import { times } from 'lodash';
+import * as React from 'react';
+import selectEvent from 'react-select-event';
+import { byLabelText, byPlaceholderText, byRole, byText } from 'testing-library-selector';
+import { parseDate } from '../../../helpers/dates';
+import {
+  mockAnalysisEvent,
+  mockHistoryItem,
+  mockMeasureHistory,
+  mockParsedAnalysis
+} from '../../../helpers/mocks/project-activity';
+import { mockMetric } from '../../../helpers/testMocks';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import { MetricKey } from '../../../types/metrics';
+import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { Metric } from '../../../types/types';
+import GraphsHeader from '../GraphsHeader';
+import GraphsHistory from '../GraphsHistory';
+import { generateSeries, getDisplayedHistoryMetrics, splitSeriesInGraphs } from '../utils';
+
+const ui = {
+  // Graph types.
+  graphTypeSelect: byLabelText('project_activity.graphs.choose_type'),
+
+  // Add metrics.
+  addMetricBtn: byRole('button', { name: 'project_activity.graphs.custom.add' }),
+  bugsCheckbox: byRole('checkbox', { name: MetricKey.bugs }),
+  newBugsCheckbox: byRole('checkbox', { name: MetricKey.new_bugs }),
+  burnedBudgetCheckbox: byRole('checkbox', { name: MetricKey.burned_budget }),
+  vulnerabilityCheckbox: byRole('checkbox', { name: MetricKey.vulnerabilities }),
+  hiddenOptionsAlert: byText('project_activity.graphs.custom.type_x_message', {
+    exact: false
+  }),
+  maxOptionsAlert: byText('project_activity.graphs.custom.add_metric_info'),
+  filterMetrics: byPlaceholderText('search.search_for_metrics'),
+
+  // Graphs.
+  graphs: byLabelText('project_activity.graphs.explanation_x', { exact: false }),
+  noDataText: byText('project_activity.graphs.custom.no_history'),
+
+  // Date filters.
+  fromDateInput: byLabelText('from_date'),
+  toDateInput: byLabelText('to_date'),
+  submitDatesBtn: byRole('button', { name: 'Submit dates' }),
+
+  // Data in table.
+  openInTableBtn: byRole('button', { name: 'project_activity.graphs.open_in_table' }),
+  closeDataTableBtn: byRole('button', { name: 'close' }),
+  dataTable: byRole('table'),
+  dataTableRows: byRole('row'),
+  dataTableColHeaders: byRole('columnheader'),
+  onlyFirst100Text: byText('project_activity.graphs.data_table.max_lines_warning.100'),
+  noDataTableText: byText('project_activity.graphs.data_table.no_data_warning_check_dates_x', {
+    exact: false
+  })
+};
+
+it('should correctly handle adding/removing custom metrics', async () => {
+  const user = userEvent.setup();
+  renderActivityGraph();
+
+  // Change graph type to "Custom".
+  await changeGraphType(GraphType.custom);
+
+  // Open the "Add metrics" dropdown button; select some metrics.
+  await toggleAddMetrics(user);
+
+  // We should not see DATA type or New Code metrics.
+  expect(ui.newBugsCheckbox.query()).not.toBeInTheDocument();
+  expect(ui.burnedBudgetCheckbox.query()).not.toBeInTheDocument();
+
+  // Select 3 Int types.
+  await clickOnMetric(user, MetricKey.bugs);
+  await clickOnMetric(user, MetricKey.code_smells);
+  await clickOnMetric(user, MetricKey.confirmed_issues);
+  // Select 1 Percent type.
+  await clickOnMetric(user, MetricKey.coverage);
+
+  // We should see 2 graphs, correctly labelled.
+  expect(ui.graphs.getAll()).toHaveLength(2);
+
+  // We cannot select anymore Int types. It should hide options, and show an alert.
+  expect(ui.vulnerabilityCheckbox.query()).not.toBeInTheDocument();
+  expect(ui.hiddenOptionsAlert.get()).toBeInTheDocument();
+
+  // Select 2 more Percent types.
+  await clickOnMetric(user, MetricKey.duplicated_lines_density);
+  await clickOnMetric(user, MetricKey.test_success_density);
+
+  // We cannot select anymore options. It should disable all remaining options, and
+  // show a different alert.
+  expect(ui.maxOptionsAlert.get()).toBeInTheDocument();
+  // See https://github.com/testing-library/jest-dom/issues/144 for why we cannot
+  // use isDisabled().
+  expect(ui.vulnerabilityCheckbox.get()).toHaveAttribute('aria-disabled', 'true');
+
+  // Disable a few options.
+  await clickOnMetric(user, MetricKey.bugs);
+  await clickOnMetric(user, MetricKey.code_smells);
+  await clickOnMetric(user, MetricKey.coverage);
+
+  // Search for option.
+  await searchForMetric(user, 'bug');
+  expect(ui.bugsCheckbox.get()).toBeInTheDocument();
+  expect(ui.vulnerabilityCheckbox.query()).not.toBeInTheDocument();
+  toggleAddMetrics(user);
+
+  // Disable final metrics by clicking on the legend items.
+  await removeMetric(user, MetricKey.confirmed_issues);
+  await removeMetric(user, MetricKey.duplicated_lines_density);
+  await removeMetric(user, MetricKey.test_success_density);
+
+  // Should show message that there's no data to be rendered.
+  expect(ui.noDataText.get()).toBeInTheDocument();
+});
+
+it('should render correctly when loading', async () => {
+  renderActivityGraph({ loading: true });
+  expect(await screen.findByLabelText('loading')).toBeInTheDocument();
+});
+
+it('shows the same data in a table', async () => {
+  const user = userEvent.setup();
+  renderActivityGraph();
+
+  await user.click(ui.openInTableBtn.get());
+  expect(ui.dataTable.get()).toBeInTheDocument();
+  expect(ui.dataTableColHeaders.getAll()).toHaveLength(5);
+  expect(ui.dataTableRows.getAll()).toHaveLength(101);
+  expect(screen.getByText('event.category.QUALITY_GATE', { exact: false })).toBeInTheDocument();
+  expect(screen.getByText('event.category.VERSION', { exact: false })).toBeInTheDocument();
+  expect(
+    screen.getByText('event.category.DEFINITION_CHANGE', { exact: false })
+  ).toBeInTheDocument();
+  expect(ui.onlyFirst100Text.get()).toBeInTheDocument();
+
+  // Change graph type and dates, check table updates correctly.
+  await user.click(ui.closeDataTableBtn.get());
+  await changeGraphType(GraphType.coverage);
+
+  await user.click(ui.openInTableBtn.get());
+  expect(ui.dataTable.get()).toBeInTheDocument();
+  expect(ui.dataTableColHeaders.getAll()).toHaveLength(4);
+  expect(ui.dataTableRows.getAll()).toHaveLength(101);
+});
+
+it('shows the same data in a table when filtered by date', async () => {
+  const user = userEvent.setup();
+  renderActivityGraph({
+    graphStartDate: parseDate('2017-01-01'),
+    graphEndDate: parseDate('2019-01-01')
+  });
+
+  await user.click(ui.openInTableBtn.get());
+  expect(ui.dataTable.get()).toBeInTheDocument();
+  expect(ui.dataTableColHeaders.getAll()).toHaveLength(5);
+  expect(ui.dataTableRows.getAll()).toHaveLength(2);
+  expect(ui.onlyFirst100Text.query()).not.toBeInTheDocument();
+});
+
+async function changeGraphType(type: GraphType) {
+  await selectEvent.select(ui.graphTypeSelect.get(), [`project_activity.graphs.${type}`]);
+}
+
+async function toggleAddMetrics(user: UserEvent) {
+  await user.click(ui.addMetricBtn.get());
+}
+
+async function clickOnMetric(user: UserEvent, name: MetricKey) {
+  await user.click(screen.getByRole('checkbox', { name }));
+}
+
+async function searchForMetric(user: UserEvent, text: string) {
+  await user.type(ui.filterMetrics.get(), text);
+}
+
+async function removeMetric(user: UserEvent, metric: MetricKey) {
+  await user.click(
+    screen.getByRole('button', { name: `project_activity.graphs.custom.remove_metric.${metric}` })
+  );
+}
+
+function renderActivityGraph(
+  graphsHistoryProps: Partial<GraphsHistory['props']> = {},
+  graphsHeaderProps: Partial<GraphsHeader['props']> = {}
+) {
+  const MAX_GRAPHS = 2;
+  const MAX_SERIES_PER_GRAPH = 3;
+  const HISTORY_COUNT = 100;
+
+  function ActivityGraph() {
+    const [selectedMetrics, setSelectedMetrics] = React.useState<string[]>([]);
+    const [graph, setGraph] = React.useState(GraphType.issues);
+    const [selectedDate, setSelectedDate] = React.useState<Date | undefined>(undefined);
+    const [fromDate, setFromDate] = React.useState<Date | undefined>(undefined);
+    const [toDate, setToDate] = React.useState<Date | undefined>(undefined);
+
+    const measuresHistory: MeasureHistory[] = [];
+    const metrics: Metric[] = [];
+    [
+      MetricKey.bugs,
+      MetricKey.code_smells,
+      MetricKey.confirmed_issues,
+      MetricKey.vulnerabilities,
+      MetricKey.blocker_violations,
+      MetricKey.lines_to_cover,
+      MetricKey.uncovered_lines,
+      MetricKey.coverage,
+      MetricKey.duplicated_lines_density,
+      MetricKey.test_success_density
+    ].forEach(metric => {
+      const history = times(HISTORY_COUNT, i => {
+        const date = parseDate('2016-01-01T00:00:00+0200');
+        date.setDate(date.getDate() + i);
+        return mockHistoryItem({ date, value: i.toString() });
+      });
+      history.push(
+        mockHistoryItem({ date: parseDate('2018-10-27T12:21:15+0200') }),
+        mockHistoryItem({ date: parseDate('2020-10-27T16:33:50+0200') })
+      );
+      measuresHistory.push(mockMeasureHistory({ metric, history }));
+      metrics.push(
+        mockMetric({
+          key: metric,
+          name: metric,
+          type: metric.includes('_density') || metric === MetricKey.coverage ? 'PERCENT' : 'INT'
+        })
+      );
+    });
+
+    // The following should be filtered out, and not be suggested as options.
+    metrics.push(
+      mockMetric({ key: MetricKey.new_bugs, name: MetricKey.new_bugs, type: 'INT' }),
+      mockMetric({ key: MetricKey.burned_budget, name: MetricKey.burned_budget, type: 'DATA' })
+    );
+
+    const series = generateSeries(
+      measuresHistory,
+      graph,
+      metrics,
+      getDisplayedHistoryMetrics(graph, selectedMetrics)
+    );
+    const graphs = splitSeriesInGraphs(series, MAX_GRAPHS, MAX_SERIES_PER_GRAPH);
+    const metricsTypeFilter =
+      graphs.length < MAX_GRAPHS
+        ? undefined
+        : graphs.filter(graph => graph.length < MAX_SERIES_PER_GRAPH).map(graph => graph[0].type);
+
+    const addCustomMetric = (metricKey: string) => {
+      setSelectedMetrics([...selectedMetrics, metricKey]);
+    };
+
+    const removeCustomMetric = (metricKey: string) => {
+      setSelectedMetrics(selectedMetrics.filter(m => m !== metricKey));
+    };
+
+    const updateGraph = (graphType: string) => {
+      setGraph(graphType as GraphType);
+    };
+
+    const updateSelectedDate = (date?: Date) => {
+      setSelectedDate(date);
+    };
+
+    const updateFromToDates = (from?: Date, to?: Date) => {
+      setFromDate(from);
+      setToDate(to);
+    };
+
+    return (
+      <>
+        <GraphsHeader
+          addCustomMetric={addCustomMetric}
+          graph={graph}
+          metrics={metrics}
+          metricsTypeFilter={metricsTypeFilter}
+          removeCustomMetric={removeCustomMetric}
+          selectedMetrics={selectedMetrics}
+          updateGraph={updateGraph}
+          {...graphsHeaderProps}
+        />
+        <GraphsHistory
+          analyses={[
+            mockParsedAnalysis({
+              date: parseDate('2018-10-27T12:21:15+0200'),
+              events: [
+                mockAnalysisEvent({ key: '1' }),
+                mockAnalysisEvent({
+                  key: '2',
+                  category: 'VERSION',
+                  description: undefined,
+                  qualityGate: undefined
+                }),
+                mockAnalysisEvent({
+                  key: '3',
+                  category: 'DEFINITION_CHANGE',
+                  definitionChange: {
+                    projects: [{ changeType: 'ADDED', key: 'foo', name: 'Foo' }]
+                  },
+                  qualityGate: undefined
+                })
+              ]
+            })
+          ]}
+          graph={graph}
+          graphEndDate={toDate}
+          graphStartDate={fromDate}
+          graphs={graphs}
+          loading={false}
+          measuresHistory={[]}
+          removeCustomMetric={removeCustomMetric}
+          selectedDate={selectedDate}
+          series={series}
+          updateGraphZoom={updateFromToDates}
+          updateSelectedDate={updateSelectedDate}
+          {...graphsHistoryProps}
+        />
+      </>
+    );
+  }
+
+  return renderComponent(<ActivityGraph />);
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetric-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetric-test.tsx
deleted file mode 100644 (file)
index b1f1d66..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 { mockMetric } from '../../../helpers/testMocks';
-import AddGraphMetric from '../AddGraphMetric';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-function shallowRender(props: Partial<AddGraphMetric['props']> = {}) {
-  return shallow<AddGraphMetric>(
-    <AddGraphMetric
-      addMetric={jest.fn()}
-      metrics={[mockMetric()]}
-      removeMetric={jest.fn()}
-      selectedMetrics={[]}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetricPopup-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/AddGraphMetricPopup-test.tsx
deleted file mode 100644 (file)
index 20dbb07..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 MultiSelect from '../../common/MultiSelect';
-import AddGraphMetricPopup, { AddGraphMetricPopupProps } from '../AddGraphMetricPopup';
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot();
-});
-
-it('should render correctly whith 6+ selected elements', () => {
-  const selectedElements = ['1', '2', '3', '4', '5', '6'];
-  expect(shallowRender({ selectedElements })).toMatchSnapshot();
-});
-
-it('should render correctly with type filter', () => {
-  const metricsTypeFilter = ['filter1', 'filter2'];
-  expect(shallowRender({ metricsTypeFilter })).toMatchSnapshot();
-});
-
-it('should prevent selection of unknown element', () => {
-  const elements = ['1', '2', '3'];
-  const onSelect = jest.fn();
-  const wrapper = shallowRender({ elements, onSelect });
-  wrapper
-    .find(MultiSelect)
-    .props()
-    .onSelect('unknown');
-
-  expect(onSelect).not.toHaveBeenCalled();
-});
-
-function shallowRender(overrides: Partial<AddGraphMetricPopupProps> = {}) {
-  return shallow(
-    <AddGraphMetricPopup
-      elements={[]}
-      filterSelected={jest.fn()}
-      onSearch={jest.fn()}
-      onSelect={jest.fn()}
-      onUnselect={jest.fn()}
-      renderLabel={element => element}
-      selectedElements={[]}
-      {...overrides}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/DataTableModal-test.tsx
new file mode 100644 (file)
index 0000000..d9ec3fd
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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 } from '@testing-library/react';
+import { times } from 'lodash';
+import * as React from 'react';
+import { parseDate } from '../../../helpers/dates';
+import { mockHistoryItem, mockMeasureHistory } from '../../../helpers/mocks/project-activity';
+import { mockMetric } from '../../../helpers/testMocks';
+import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import { MetricKey } from '../../../types/metrics';
+import { GraphType, MeasureHistory } from '../../../types/project-activity';
+import { Metric } from '../../../types/types';
+import DataTableModal, { DataTableModalProps } from '../DataTableModal';
+import { generateSeries, getDisplayedHistoryMetrics } from '../utils';
+
+it('should render correctly if there are no series', () => {
+  renderDataTableModal({ series: [] });
+  expect(
+    screen.getByText('project_activity.graphs.data_table.no_data_warning')
+  ).toBeInTheDocument();
+});
+
+it('should render correctly if there is too much data', () => {
+  renderDataTableModal({ series: mockSeries(101) });
+  expect(
+    screen.getByText('project_activity.graphs.data_table.max_lines_warning.100')
+  ).toBeInTheDocument();
+});
+
+it('should render correctly if there is no data and we have a start date', () => {
+  renderDataTableModal({ graphStartDate: parseDate('3022-01-01') });
+  expect(
+    screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_x', {
+      exact: false
+    })
+  ).toBeInTheDocument();
+});
+
+it('should render correctly if there is no data and we have an end date', () => {
+  renderDataTableModal({ graphEndDate: parseDate('2015-01-01') });
+  expect(
+    screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_y', {
+      exact: false
+    })
+  ).toBeInTheDocument();
+});
+
+it('should render correctly if there is no data and we have a date range', () => {
+  renderDataTableModal({
+    graphEndDate: parseDate('2015-01-01'),
+    graphStartDate: parseDate('2014-01-01')
+  });
+  expect(
+    screen.getByText('project_activity.graphs.data_table.no_data_warning_check_dates_x_y', {
+      exact: false
+    })
+  ).toBeInTheDocument();
+});
+
+function renderDataTableModal(props: Partial<DataTableModalProps> = {}) {
+  return renderComponent(
+    <DataTableModal analyses={[]} series={mockSeries()} onClose={jest.fn()} {...props} />
+  );
+}
+
+function mockSeries(n = 10) {
+  const measuresHistory: MeasureHistory[] = [];
+  const metrics: Metric[] = [];
+  [MetricKey.bugs, MetricKey.code_smells, MetricKey.vulnerabilities].forEach(metric => {
+    const history = times(n, i => {
+      const date = parseDate('2016-01-01T00:00:00+0200');
+      date.setDate(date.getDate() + 365 * i);
+      return mockHistoryItem({ date, value: i.toString() });
+    });
+    measuresHistory.push(mockMeasureHistory({ metric, history }));
+    metrics.push(
+      mockMetric({
+        key: metric,
+        name: metric,
+        type: 'INT'
+      })
+    );
+  });
+
+  return generateSeries(
+    measuresHistory,
+    GraphType.issues,
+    metrics,
+    getDisplayedHistoryMetrics(GraphType.issues, [
+      MetricKey.bugs,
+      MetricKey.code_smells,
+      MetricKey.vulnerabilities
+    ])
+  );
+}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-test.tsx
deleted file mode 100644 (file)
index 950e389..0000000
+++ /dev/null
@@ -1,75 +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 { mockAnalysisEvent } from '../../../helpers/mocks/project-activity';
-import { BranchLike } from '../../../types/branch-like';
-import EventInner, { EventInnerProps } from '../EventInner';
-
-jest.mock('../../../app/components/componentContext/ComponentContext', () => {
-  const { mockBranch } = jest.requireActual('../../../helpers/mocks/branch-like');
-  return {
-    ComponentContext: {
-      Consumer: ({
-        children
-      }: {
-        children: (props: { branchLike: BranchLike }) => React.ReactNode;
-      }) => {
-        return children({ branchLike: mockBranch() });
-      }
-    }
-  };
-});
-
-it('should render correctly', () => {
-  expect(shallowRender()).toMatchSnapshot('default');
-  expect(
-    shallowRender({
-      event: mockAnalysisEvent({
-        category: 'VERSION',
-        description: undefined,
-        qualityGate: undefined
-      })
-    })
-  ).toMatchSnapshot('no description');
-  expect(shallowRender({ event: mockAnalysisEvent() })).toMatchSnapshot('rich quality gate');
-  expect(
-    shallowRender({
-      event: mockAnalysisEvent({
-        category: 'DEFINITION_CHANGE',
-        definitionChange: {
-          projects: [{ changeType: 'ADDED', key: 'foo', name: 'Foo' }]
-        },
-        qualityGate: undefined
-      })
-    })
-      .find('Consumer')
-      .dive()
-  ).toMatchSnapshot('definition change');
-});
-
-function shallowRender(props: Partial<EventInnerProps> = {}) {
-  return shallow(
-    <EventInner
-      event={mockAnalysisEvent({ category: 'VERSION', qualityGate: undefined })}
-      {...props}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphHistory-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphHistory-test.tsx
deleted file mode 100644 (file)
index 7cd02bd..0000000
+++ /dev/null
@@ -1,63 +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 { parseDate } from '../../../helpers/dates';
-import GraphHistory from '../GraphHistory';
-import { DEFAULT_GRAPH } from '../utils';
-
-const SERIES = [
-  {
-    name: 'bugs',
-    translatedName: 'metric.bugs.name',
-    data: [
-      { x: parseDate('2016-10-27T16:33:50+0200'), y: 5 },
-      { x: parseDate('2016-10-27T12:21:15+0200'), y: 16 },
-      { x: parseDate('2016-10-26T12:17:29+0200'), y: 12 }
-    ],
-    type: 'INT'
-  }
-];
-
-it('should correctly render a graph', () => {
-  expect(shallowRender()).toMatchSnapshot();
-  expect(shallowRender({ isCustom: true })).toMatchSnapshot('custom');
-});
-
-function shallowRender(overrides: Partial<GraphHistory['props']> = {}) {
-  return shallow(
-    <GraphHistory
-      analyses={[]}
-      ariaLabel="foo"
-      graph={DEFAULT_GRAPH}
-      leakPeriodDate={parseDate('2017-05-16T13:50:02+0200')}
-      isCustom={false}
-      measuresHistory={[]}
-      metricsType="INT"
-      removeCustomMetric={jest.fn()}
-      showAreas={true}
-      series={SERIES}
-      updateGraphZoom={jest.fn()}
-      updateSelectedDate={jest.fn()}
-      updateTooltip={jest.fn()}
-      {...overrides}
-    />
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsHistory-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsHistory-test.tsx
deleted file mode 100644 (file)
index 960820a..0000000
+++ /dev/null
@@ -1,118 +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 { parseDate } from '../../../helpers/dates';
-import GraphsHistory from '../GraphsHistory';
-import { DEFAULT_GRAPH } from '../utils';
-
-const ANALYSES = [
-  {
-    key: 'A1',
-    date: parseDate('2016-10-27T16:33:50+0200'),
-    events: [
-      {
-        key: 'E1',
-        category: 'VERSION',
-        name: '6.5-SNAPSHOT'
-      }
-    ]
-  },
-  {
-    key: 'A2',
-    date: parseDate('2016-10-27T12:21:15+0200'),
-    events: []
-  },
-  {
-    key: 'A3',
-    date: parseDate('2016-10-26T12:17:29+0200'),
-    events: [
-      {
-        key: 'E2',
-        category: 'OTHER',
-        name: 'foo'
-      },
-      {
-        key: 'E3',
-        category: 'VERSION',
-        name: '6.4'
-      }
-    ]
-  }
-];
-
-const SERIES = [
-  {
-    name: 'bugs',
-    translatedName: 'metric.bugs.name',
-    data: [
-      { x: parseDate('2016-10-27T16:33:50+0200'), y: 5 },
-      { x: parseDate('2016-10-27T12:21:15+0200'), y: 16 },
-      { x: parseDate('2016-10-26T12:17:29+0200'), y: 12 }
-    ],
-    type: 'INT'
-  }
-];
-
-const DEFAULT_PROPS: GraphsHistory['props'] = {
-  analyses: ANALYSES,
-  graph: DEFAULT_GRAPH,
-  graphs: [SERIES],
-  leakPeriodDate: parseDate('2017-05-16T13:50:02+0200'),
-  loading: false,
-  measuresHistory: [],
-  removeCustomMetric: () => {},
-  series: SERIES,
-  updateGraphZoom: () => {},
-  updateSelectedDate: () => {}
-};
-
-it('should correctly render a graph', () => {
-  expect(shallow(<GraphsHistory {...DEFAULT_PROPS} />)).toMatchSnapshot();
-});
-
-it('should correctly render multiple graphs', () => {
-  expect(shallow(<GraphsHistory {...DEFAULT_PROPS} graphs={[SERIES, SERIES]} />)).toMatchSnapshot();
-});
-
-it('should show a loading view instead of the graph', () => {
-  expect(
-    shallow(<GraphsHistory {...DEFAULT_PROPS} loading={true} />).find('DeferredSpinner')
-  ).toHaveLength(1);
-});
-
-it('should show that there is no history data', () => {
-  expect(shallow(<GraphsHistory {...DEFAULT_PROPS} series={[]} />)).toMatchSnapshot();
-  expect(
-    shallow(
-      <GraphsHistory
-        {...DEFAULT_PROPS}
-        series={[
-          {
-            name: 'bugs',
-            translatedName: 'metric.bugs.name',
-            data: [{ x: parseDate('2016-10-27T16:33:50+0200'), y: undefined }],
-            type: 'INT'
-          }
-        ]}
-      />
-    )
-  ).toMatchSnapshot();
-});
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetric-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetric-test.tsx.snap
deleted file mode 100644 (file)
index ef568c5..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Dropdown
-  className="display-inline-block"
-  closeOnClick={false}
-  closeOnClickOutside={true}
-  overlay={
-    <AddGraphMetricPopup
-      elements={
-        Array [
-          "coverage",
-        ]
-      }
-      filterSelected={[Function]}
-      onSearch={[Function]}
-      onSelect={[Function]}
-      onUnselect={[Function]}
-      renderLabel={[Function]}
-      selectedElements={Array []}
-    />
-  }
->
-  <Button
-    className="spacer-left"
-  >
-    <span
-      className="text-ellipsis text-middle"
-    >
-      project_activity.graphs.custom.add
-    </span>
-    <DropdownIcon
-      className="text-top little-spacer-left"
-    />
-  </Button>
-</Dropdown>
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetricPopup-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/AddGraphMetricPopup-test.tsx.snap
deleted file mode 100644 (file)
index 3070ede..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<div
-  className="menu abs-width-300"
->
-  <MultiSelect
-    allowNewElements={false}
-    allowSelection={true}
-    elements={Array []}
-    filterSelected={[MockFunction]}
-    footerNode=""
-    legend="project_activity.graphs.custom.select_metric"
-    listSize={0}
-    onSearch={[MockFunction]}
-    onSelect={[Function]}
-    onUnselect={[MockFunction]}
-    placeholder="search.search_for_metrics"
-    renderLabel={[Function]}
-    selectedElements={Array []}
-    validateSearchInput={[Function]}
-  />
-</div>
-`;
-
-exports[`should render correctly whith 6+ selected elements 1`] = `
-<div
-  className="menu abs-width-300"
->
-  <MultiSelect
-    allowNewElements={false}
-    allowSelection={false}
-    elements={Array []}
-    filterSelected={[MockFunction]}
-    footerNode={
-      <Alert
-        className="spacer-left spacer-right spacer-top"
-        variant="info"
-      >
-        project_activity.graphs.custom.add_metric_info
-      </Alert>
-    }
-    legend="project_activity.graphs.custom.select_metric"
-    listSize={0}
-    onSearch={[MockFunction]}
-    onSelect={[Function]}
-    onUnselect={[MockFunction]}
-    placeholder="search.search_for_metrics"
-    renderLabel={[Function]}
-    selectedElements={
-      Array [
-        "1",
-        "2",
-        "3",
-        "4",
-        "5",
-        "6",
-      ]
-    }
-    validateSearchInput={[Function]}
-  />
-</div>
-`;
-
-exports[`should render correctly with type filter 1`] = `
-<div
-  className="menu abs-width-300"
->
-  <MultiSelect
-    allowNewElements={false}
-    allowSelection={true}
-    elements={Array []}
-    filterSelected={[MockFunction]}
-    footerNode={
-      <Alert
-        className="spacer-left spacer-right spacer-top"
-        variant="info"
-      >
-        project_activity.graphs.custom.type_x_message.metric.type.filter1, metric.type.filter2
-      </Alert>
-    }
-    legend="project_activity.graphs.custom.select_metric"
-    listSize={0}
-    onSearch={[MockFunction]}
-    onSelect={[Function]}
-    onUnselect={[MockFunction]}
-    placeholder="search.search_for_metrics"
-    renderLabel={[Function]}
-    selectedElements={Array []}
-    validateSearchInput={[Function]}
-  />
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/EventInner-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/EventInner-test.tsx.snap
deleted file mode 100644 (file)
index 639a2bb..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly: default 1`] = `
-<Tooltip
-  overlay="Lorem ipsum dolor sit amet"
->
-  <span
-    className="text-middle"
-  >
-    <span
-      className="note little-spacer-right"
-    >
-      event.category.VERSION
-      :
-    </span>
-    <strong
-      className="spacer-right"
-    >
-      Lorem ipsum
-    </strong>
-  </span>
-</Tooltip>
-`;
-
-exports[`should render correctly: definition change 1`] = `
-<DefinitionChangeEventInner
-  branchLike={
-    Object {
-      "analysisDate": "2018-01-01",
-      "excludedFromPurge": true,
-      "isMain": false,
-      "name": "branch-6.7",
-    }
-  }
-  event={
-    Object {
-      "category": "DEFINITION_CHANGE",
-      "definitionChange": Object {
-        "projects": Array [
-          Object {
-            "changeType": "ADDED",
-            "key": "foo",
-            "name": "Foo",
-          },
-        ],
-      },
-      "description": "Lorem ipsum dolor sit amet",
-      "key": "E11",
-      "name": "Lorem ipsum",
-      "qualityGate": undefined,
-    }
-  }
-/>
-`;
-
-exports[`should render correctly: no description 1`] = `
-<Tooltip
-  overlay={null}
->
-  <span
-    className="text-middle"
-  >
-    <span
-      className="note little-spacer-right"
-    >
-      event.category.VERSION
-      :
-    </span>
-    <strong
-      className="spacer-right"
-    >
-      Lorem ipsum
-    </strong>
-  </span>
-</Tooltip>
-`;
-
-exports[`should render correctly: rich quality gate 1`] = `
-<RichQualityGateEventInner
-  event={
-    Object {
-      "category": "QUALITY_GATE",
-      "description": "Lorem ipsum dolor sit amet",
-      "key": "E11",
-      "name": "Lorem ipsum",
-      "qualityGate": Object {
-        "failing": Array [
-          Object {
-            "branch": "master",
-            "key": "foo",
-            "name": "Foo",
-          },
-          Object {
-            "branch": "feature/bar",
-            "key": "bar",
-            "name": "Bar",
-          },
-        ],
-        "status": "ERROR",
-        "stillFailing": true,
-      },
-    }
-  }
-/>
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphHistory-test.tsx.snap
deleted file mode 100644 (file)
index f1443c6..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly render a graph 1`] = `
-<div
-  className="activity-graph-container flex-grow display-flex-column display-flex-stretch display-flex-justify-center"
->
-  <GraphsLegendStatic
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-27T14:33:50.000Z,
-              "y": 5,
-            },
-            Object {
-              "x": 2016-10-27T10:21:15.000Z,
-              "y": 16,
-            },
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": 12,
-            },
-          ],
-          "name": "bugs",
-          "translatedName": "metric.bugs.name",
-          "type": "INT",
-        },
-      ]
-    }
-  />
-  <div
-    className="flex-1"
-  >
-    <AutoSizer>
-      <Component />
-    </AutoSizer>
-  </div>
-  <div
-    className="little-spacer-top big-spacer-bottom"
-  >
-    <div
-      className="display-flex-justify-end little-padded-right"
-    >
-      <ModalButton
-        modal={[Function]}
-      >
-        <Component />
-      </ModalButton>
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should correctly render a graph: custom 1`] = `
-<div
-  className="activity-graph-container flex-grow display-flex-column display-flex-stretch display-flex-justify-center"
->
-  <GraphsLegendCustom
-    removeMetric={[MockFunction]}
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-27T14:33:50.000Z,
-              "y": 5,
-            },
-            Object {
-              "x": 2016-10-27T10:21:15.000Z,
-              "y": 16,
-            },
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": 12,
-            },
-          ],
-          "name": "bugs",
-          "translatedName": "metric.bugs.name",
-          "type": "INT",
-        },
-      ]
-    }
-  />
-  <div
-    className="flex-1"
-  >
-    <AutoSizer>
-      <Component />
-    </AutoSizer>
-  </div>
-  <div
-    className="little-spacer-top big-spacer-bottom"
-  >
-    <div
-      className="display-flex-justify-end little-padded-right"
-    >
-      <ModalButton
-        modal={[Function]}
-      >
-        <Component />
-      </ModalButton>
-    </div>
-  </div>
-</div>
-`;
diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsHistory-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsHistory-test.tsx.snap
deleted file mode 100644 (file)
index 1bb0661..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly render a graph 1`] = `
-<div
-  className="display-flex-justify-center display-flex-column display-flex-stretch flex-grow"
->
-  <GraphHistory
-    analyses={
-      Array [
-        Object {
-          "date": 2016-10-27T14:33:50.000Z,
-          "events": Array [
-            Object {
-              "category": "VERSION",
-              "key": "E1",
-              "name": "6.5-SNAPSHOT",
-            },
-          ],
-          "key": "A1",
-        },
-        Object {
-          "date": 2016-10-27T10:21:15.000Z,
-          "events": Array [],
-          "key": "A2",
-        },
-        Object {
-          "date": 2016-10-26T10:17:29.000Z,
-          "events": Array [
-            Object {
-              "category": "OTHER",
-              "key": "E2",
-              "name": "foo",
-            },
-            Object {
-              "category": "VERSION",
-              "key": "E3",
-              "name": "6.4",
-            },
-          ],
-          "key": "A3",
-        },
-      ]
-    }
-    ariaLabel="project_activity.graphs.explanation_x.metric.bugs.name"
-    graph="issues"
-    isCustom={false}
-    key="0"
-    leakPeriodDate={2017-05-16T11:50:02.000Z}
-    measuresHistory={Array []}
-    metricsType="INT"
-    removeCustomMetric={[Function]}
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-27T14:33:50.000Z,
-              "y": 5,
-            },
-            Object {
-              "x": 2016-10-27T10:21:15.000Z,
-              "y": 16,
-            },
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": 12,
-            },
-          ],
-          "name": "bugs",
-          "translatedName": "metric.bugs.name",
-          "type": "INT",
-        },
-      ]
-    }
-    showAreas={false}
-    updateGraphZoom={[Function]}
-    updateSelectedDate={[Function]}
-    updateTooltip={[Function]}
-  />
-</div>
-`;
-
-exports[`should correctly render multiple graphs 1`] = `
-<div
-  className="display-flex-justify-center display-flex-column display-flex-stretch flex-grow"
->
-  <GraphHistory
-    analyses={
-      Array [
-        Object {
-          "date": 2016-10-27T14:33:50.000Z,
-          "events": Array [
-            Object {
-              "category": "VERSION",
-              "key": "E1",
-              "name": "6.5-SNAPSHOT",
-            },
-          ],
-          "key": "A1",
-        },
-        Object {
-          "date": 2016-10-27T10:21:15.000Z,
-          "events": Array [],
-          "key": "A2",
-        },
-        Object {
-          "date": 2016-10-26T10:17:29.000Z,
-          "events": Array [
-            Object {
-              "category": "OTHER",
-              "key": "E2",
-              "name": "foo",
-            },
-            Object {
-              "category": "VERSION",
-              "key": "E3",
-              "name": "6.4",
-            },
-          ],
-          "key": "A3",
-        },
-      ]
-    }
-    ariaLabel="project_activity.graphs.explanation_x.metric.bugs.name"
-    graph="issues"
-    isCustom={false}
-    key="0"
-    leakPeriodDate={2017-05-16T11:50:02.000Z}
-    measuresHistory={Array []}
-    metricsType="INT"
-    removeCustomMetric={[Function]}
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-27T14:33:50.000Z,
-              "y": 5,
-            },
-            Object {
-              "x": 2016-10-27T10:21:15.000Z,
-              "y": 16,
-            },
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": 12,
-            },
-          ],
-          "name": "bugs",
-          "translatedName": "metric.bugs.name",
-          "type": "INT",
-        },
-      ]
-    }
-    showAreas={false}
-    updateGraphZoom={[Function]}
-    updateSelectedDate={[Function]}
-    updateTooltip={[Function]}
-  />
-  <GraphHistory
-    analyses={
-      Array [
-        Object {
-          "date": 2016-10-27T14:33:50.000Z,
-          "events": Array [
-            Object {
-              "category": "VERSION",
-              "key": "E1",
-              "name": "6.5-SNAPSHOT",
-            },
-          ],
-          "key": "A1",
-        },
-        Object {
-          "date": 2016-10-27T10:21:15.000Z,
-          "events": Array [],
-          "key": "A2",
-        },
-        Object {
-          "date": 2016-10-26T10:17:29.000Z,
-          "events": Array [
-            Object {
-              "category": "OTHER",
-              "key": "E2",
-              "name": "foo",
-            },
-            Object {
-              "category": "VERSION",
-              "key": "E3",
-              "name": "6.4",
-            },
-          ],
-          "key": "A3",
-        },
-      ]
-    }
-    ariaLabel="project_activity.graphs.explanation_x.metric.bugs.name"
-    graph="issues"
-    isCustom={false}
-    key="1"
-    leakPeriodDate={2017-05-16T11:50:02.000Z}
-    measuresHistory={Array []}
-    metricsType="INT"
-    removeCustomMetric={[Function]}
-    series={
-      Array [
-        Object {
-          "data": Array [
-            Object {
-              "x": 2016-10-27T14:33:50.000Z,
-              "y": 5,
-            },
-            Object {
-              "x": 2016-10-27T10:21:15.000Z,
-              "y": 16,
-            },
-            Object {
-              "x": 2016-10-26T10:17:29.000Z,
-              "y": 12,
-            },
-          ],
-          "name": "bugs",
-          "translatedName": "metric.bugs.name",
-          "type": "INT",
-        },
-      ]
-    }
-    showAreas={false}
-    updateGraphZoom={[Function]}
-    updateSelectedDate={[Function]}
-    updateTooltip={[Function]}
-  />
-</div>
-`;
-
-exports[`should show that there is no history data 1`] = `
-<div
-  className="activity-graph-container flex-grow display-flex-column display-flex-stretch display-flex-justify-center"
->
-  <div
-    className="display-flex-center display-flex-justify-center"
-  >
-    <img
-      alt=""
-      className="spacer-right"
-      height={52}
-      src="/images/activity-chart.svg"
-    />
-    <div
-      className="big-spacer-left big text-muted"
-      style={
-        Object {
-          "maxWidth": 300,
-        }
-      }
-    >
-      component_measures.no_history
-    </div>
-  </div>
-</div>
-`;
-
-exports[`should show that there is no history data 2`] = `
-<div
-  className="activity-graph-container flex-grow display-flex-column display-flex-stretch display-flex-justify-center"
->
-  <div
-    className="display-flex-center display-flex-justify-center"
-  >
-    <img
-      alt=""
-      className="spacer-right"
-      height={52}
-      src="/images/activity-chart.svg"
-    />
-    <div
-      className="big-spacer-left big text-muted"
-      style={
-        Object {
-          "maxWidth": 300,
-        }
-      }
-    >
-      component_measures.no_history
-    </div>
-  </div>
-</div>
-`;
index c02a75414c3e3a861be380f7545702ea1ba38989..7573eb1c1ac3e7593f5d73fcf792435bb4cad39b 100644 (file)
@@ -75,6 +75,7 @@ export default class Checkbox extends React.PureComponent<Props> {
         <a
           aria-checked={thirdState ? 'mixed' : checked}
           aria-label={label}
+          aria-disabled={disabled}
           className={classNames('link-checkbox', this.props.className, {
             disabled
           })}
index 439bf4a576d5cbee128b629969940805ecf3b6e1..c8c366bdea391ffdbd0f869bb88ce3baf41a58df 100644 (file)
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-import { Analysis, AnalysisEvent, ParsedAnalysis } from '../../types/project-activity';
+import {
+  Analysis,
+  AnalysisEvent,
+  HistoryItem,
+  MeasureHistory,
+  ParsedAnalysis
+} from '../../types/project-activity';
+import { parseDate } from '../dates';
 
 export function mockAnalysis(overrides: Partial<Analysis> = {}): Analysis {
   return {
@@ -65,3 +72,23 @@ export function mockAnalysisEvent(overrides: Partial<AnalysisEvent> = {}): Analy
     ...overrides
   };
 }
+
+export function mockMeasureHistory(overrides: Partial<MeasureHistory> = {}): MeasureHistory {
+  return {
+    metric: 'code_smells',
+    history: [
+      mockHistoryItem(),
+      mockHistoryItem({ date: parseDate('2018-10-27T12:21:15+0200'), value: '1749' }),
+      mockHistoryItem({ date: parseDate('2020-10-27T16:33:50+0200'), value: '500' })
+    ],
+    ...overrides
+  };
+}
+
+export function mockHistoryItem(overrides: Partial<HistoryItem> = {}): HistoryItem {
+  return {
+    date: parseDate('2016-10-26T12:17:29+0200'),
+    value: '2286',
+    ...overrides
+  };
+}