@@ -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} |
@@ -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 />); | |||
} |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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 | |||
]) | |||
); | |||
} |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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(); | |||
}); |
@@ -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> | |||
`; |
@@ -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> | |||
`; |
@@ -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, | |||
}, | |||
} | |||
} | |||
/> | |||
`; |
@@ -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> | |||
`; |
@@ -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> | |||
`; |
@@ -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 | |||
})} |
@@ -18,7 +18,14 @@ | |||
* 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 | |||
}; | |||
} |