diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2022-11-24 10:01:37 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-11-28 11:29:35 +0000 |
commit | a8a5d01b4ada4c4be6a56325f3951fca1bbc3f85 (patch) | |
tree | e50df5d7790d21d8136b4d34e979f69ce48df373 /server/sonar-web/src/main/js/components/activity-graph | |
parent | 92ce215524cf11c0dee49d2f4b6981497f197020 (diff) | |
download | sonarqube-a8a5d01b4ada4c4be6a56325f3951fca1bbc3f85.tar.gz sonarqube-a8a5d01b4ada4c4be6a56325f3951fca1bbc3f85.zip |
SONAR-17667 Finish migration of Activity Graph tests to RTL
Diffstat (limited to 'server/sonar-web/src/main/js/components/activity-graph')
37 files changed, 578 insertions, 1944 deletions
diff --git a/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx b/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx index 0b0fabb17e4..05ff2dd5420 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/DataTableModal.tsx @@ -41,7 +41,7 @@ export interface DataTableModalProps { type DataTableEntry = { date: Date } & { [x: string]: string | undefined }; -const MAX_DATA_TABLE_ROWS = 100; +export const MAX_DATA_TABLE_ROWS = 100; export default function DataTableModal(props: DataTableModalProps) { const { analyses, series, graphEndDate, graphStartDate } = props; diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx index a8f54da826a..bf223af2c87 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendCustom.tsx @@ -32,36 +32,34 @@ export interface GraphsLegendCustomProps { export default function GraphsLegendCustom(props: GraphsLegendCustomProps) { const { series } = props; return ( - <div className="activity-graph-legends display-flex-center"> - <div className="flex-1"> - {series.map((serie, idx) => { - const hasData = hasDataValues(serie); - const legendItem = ( - <GraphsLegendItem - index={idx} - metric={serie.name} - name={serie.translatedName} - removeMetric={props.removeMetric} - showWarning={!hasData} - /> - ); - if (!hasData) { - return ( - <Tooltip - key={serie.name} - overlay={translate('project_activity.graphs.custom.metric_no_history')} - > - <span className="spacer-left spacer-right">{legendItem}</span> - </Tooltip> - ); - } + <ul className="activity-graph-legends"> + {series.map((serie, idx) => { + const hasData = hasDataValues(serie); + const legendItem = ( + <GraphsLegendItem + index={idx} + metric={serie.name} + name={serie.translatedName} + removeMetric={props.removeMetric} + showWarning={!hasData} + /> + ); + if (!hasData) { return ( - <span className="spacer-left spacer-right" key={serie.name}> - {legendItem} - </span> + <Tooltip + key={serie.name} + overlay={translate('project_activity.graphs.custom.metric_no_history')} + > + <li className="spacer-left spacer-right">{legendItem}</li> + </Tooltip> ); - })} - </div> - </div> + } + return ( + <li className="spacer-left spacer-right" key={serie.name}> + {legendItem} + </li> + ); + })} + </ul> ); } diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx deleted file mode 100644 index 06e81da93e4..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendNewCode.tsx +++ /dev/null @@ -1,35 +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 * as React from 'react'; -import Tooltip from '../../components/controls/Tooltip'; -import { translate } from '../../helpers/l10n'; - -export default function GraphsLegendNewCode() { - return ( - <Tooltip overlay={translate('project_activity.graphs.new_code_long')}> - <span - aria-label={translate('project_activity.graphs.new_code_long')} - className="activity-graph-new-code-legend display-flex-center pull-right note" - > - {translate('project_activity.graphs.new_code')} - </span> - </Tooltip> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx index 386fd4b59fe..e72d08b008c 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendStatic.tsx @@ -27,16 +27,17 @@ export interface GraphsLegendStaticProps { export default function GraphsLegendStatic({ series }: GraphsLegendStaticProps) { return ( - <div className="activity-graph-legends"> + <ul className="activity-graph-legends"> {series.map((serie, idx) => ( - <GraphsLegendItem - className="big-spacer-left big-spacer-right" - index={idx} - key={serie.name} - metric={serie.name} - name={serie.translatedName} - /> + <li key={serie.name}> + <GraphsLegendItem + className="big-spacer-left big-spacer-right" + index={idx} + metric={serie.name} + name={serie.translatedName} + /> + </li> ))} - </div> + </ul> ); } diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx index 9950dc79b32..13ee1ad4961 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltips.tsx @@ -20,7 +20,7 @@ import * as React from 'react'; import { Popup, PopupPlacement } from '../../components/ui/popups'; import { isDefined } from '../../helpers/types'; -import { AnalysisEvent, MeasureHistory, Serie } from '../../types/project-activity'; +import { AnalysisEvent, GraphType, MeasureHistory, Serie } from '../../types/project-activity'; import DateTimeFormatter from '../intl/DateTimeFormatter'; import GraphsTooltipsContent from './GraphsTooltipsContent'; import GraphsTooltipsContentCoverage from './GraphsTooltipsContentCoverage'; @@ -42,53 +42,60 @@ interface Props { } const TOOLTIP_WIDTH = 250; +const TOOLTIP_LEFT_MARGIN = 60; +const TOOLTIP_LEFT_FLIP_THRESHOLD = 50; export default class GraphsTooltips extends React.PureComponent<Props> { renderContent() { - const { tooltipIdx } = this.props; + const { tooltipIdx, series, graph, measuresHistory } = this.props; - return this.props.series.map((serie, idx) => { + return series.map((serie, idx) => { const point = serie.data[tooltipIdx]; if (!point || (!point.y && point.y !== 0)) { return null; } - if (this.props.graph === DEFAULT_GRAPH) { + + if (graph === DEFAULT_GRAPH) { return ( <GraphsTooltipsContentIssues index={idx} key={serie.name} - measuresHistory={this.props.measuresHistory} + measuresHistory={measuresHistory} name={serie.name} tooltipIdx={tooltipIdx} translatedName={serie.translatedName} value={this.props.formatValue(point.y)} /> ); - } else { - return ( - <GraphsTooltipsContent - index={idx} - key={serie.name} - name={serie.name} - translatedName={serie.translatedName} - value={this.props.formatValue(point.y)} - /> - ); } + + return ( + <GraphsTooltipsContent + index={idx} + key={serie.name} + name={serie.name} + translatedName={serie.translatedName} + value={this.props.formatValue(point.y)} + /> + ); }); } render() { - const { events, measuresHistory, tooltipIdx } = this.props; + const { events, measuresHistory, tooltipIdx, tooltipPos, graph, graphWidth, selectedDate } = + this.props; + const top = 30; - let left = this.props.tooltipPos + 60; + let left = tooltipPos + TOOLTIP_LEFT_MARGIN; let placement = PopupPlacement.RightTop; - if (left > this.props.graphWidth - TOOLTIP_WIDTH - 50) { + if (left > graphWidth - TOOLTIP_WIDTH - TOOLTIP_LEFT_FLIP_THRESHOLD) { left -= TOOLTIP_WIDTH; placement = PopupPlacement.LeftTop; } + const tooltipContent = this.renderContent().filter(isDefined); const addSeparator = tooltipContent.length > 0; + return ( <Popup className="disabled-pointer-events" @@ -97,21 +104,21 @@ export default class GraphsTooltips extends React.PureComponent<Props> { > <div className="activity-graph-tooltip"> <div className="activity-graph-tooltip-title spacer-bottom"> - <DateTimeFormatter date={this.props.selectedDate} /> + <DateTimeFormatter date={selectedDate} /> </div> <table className="width-100"> - {events && events.length > 0 && ( + {events?.length > 0 && ( <GraphsTooltipsContentEvents addSeparator={addSeparator} events={events} /> )} <tbody>{tooltipContent}</tbody> - {this.props.graph === 'coverage' && ( + {graph === GraphType.coverage && ( <GraphsTooltipsContentCoverage addSeparator={addSeparator} measuresHistory={measuresHistory} tooltipIdx={tooltipIdx} /> )} - {this.props.graph === 'duplications' && ( + {graph === GraphType.duplications && ( <GraphsTooltipsContentDuplication addSeparator={addSeparator} measuresHistory={measuresHistory} diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx index 6021f6e382c..faec9a9c928 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentCoverage.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import { translate } from '../../helpers/l10n'; import { formatMeasure } from '../../helpers/measures'; +import { MetricKey } from '../../types/metrics'; import { MeasureHistory } from '../../types/project-activity'; export interface GraphsTooltipsContentCoverageProps { @@ -28,13 +29,10 @@ export interface GraphsTooltipsContentCoverageProps { tooltipIdx: number; } -export default function GraphsTooltipsContentCoverage({ - addSeparator, - measuresHistory, - tooltipIdx, -}: GraphsTooltipsContentCoverageProps) { - const uncovered = measuresHistory.find((measure) => measure.metric === 'uncovered_lines'); - const coverage = measuresHistory.find((measure) => measure.metric === 'coverage'); +export default function GraphsTooltipsContentCoverage(props: GraphsTooltipsContentCoverageProps) { + const { addSeparator, measuresHistory, tooltipIdx } = props; + const uncovered = measuresHistory.find((measure) => measure.metric === MetricKey.uncovered_lines); + const coverage = measuresHistory.find((measure) => measure.metric === MetricKey.coverage); if (!uncovered || !uncovered.history[tooltipIdx] || !coverage || !coverage.history[tooltipIdx]) { return null; } diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx index e97d87d4f09..c134d96acfa 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentDuplication.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import { translate } from '../../helpers/l10n'; import { formatMeasure } from '../../helpers/measures'; +import { MetricKey } from '../../types/metrics'; import { MeasureHistory } from '../../types/project-activity'; export interface GraphsTooltipsContentDuplicationProps { @@ -28,13 +29,12 @@ export interface GraphsTooltipsContentDuplicationProps { tooltipIdx: number; } -export default function GraphsTooltipsContentDuplication({ - addSeparator, - measuresHistory, - tooltipIdx, -}: GraphsTooltipsContentDuplicationProps) { +export default function GraphsTooltipsContentDuplication( + props: GraphsTooltipsContentDuplicationProps +) { + const { addSeparator, measuresHistory, tooltipIdx } = props; const duplicationDensity = measuresHistory.find( - (measure) => measure.metric === 'duplicated_lines_density' + (measure) => measure.metric === MetricKey.duplicated_lines_density ); if (!duplicationDensity || !duplicationDensity.history[tooltipIdx]) { return null; diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentIssues.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentIssues.tsx index 3ca06bd94ba..134e9a6635e 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentIssues.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsTooltipsContentIssues.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import ChartLegendIcon from '../../components/icons/ChartLegendIcon'; import Rating from '../../components/ui/Rating'; +import { MetricKey } from '../../types/metrics'; import { MeasureHistory } from '../../types/project-activity'; import { Dict } from '../../types/types'; @@ -33,29 +34,28 @@ export interface GraphsTooltipsContentIssuesProps { } const METRIC_RATING: Dict<string> = { - bugs: 'reliability_rating', - vulnerabilities: 'security_rating', - code_smells: 'sqale_rating', + [MetricKey.bugs]: MetricKey.reliability_rating, + [MetricKey.vulnerabilities]: MetricKey.security_rating, + [MetricKey.code_smells]: MetricKey.sqale_rating, }; export default function GraphsTooltipsContentIssues(props: GraphsTooltipsContentIssuesProps) { - const rating = props.measuresHistory.find( - (measure) => measure.metric === METRIC_RATING[props.name] - ); - if (!rating || !rating.history[props.tooltipIdx]) { + const { index, measuresHistory, name, tooltipIdx, translatedName, value } = props; + const rating = measuresHistory.find((measure) => measure.metric === METRIC_RATING[name]); + if (!rating || !rating.history[tooltipIdx]) { return null; } - const ratingValue = rating.history[props.tooltipIdx].value; + const ratingValue = rating.history[tooltipIdx].value; return ( - <tr className="activity-graph-tooltip-issues-line" key={props.name}> + <tr className="activity-graph-tooltip-issues-line" key={name}> <td className="thin"> - <ChartLegendIcon className="spacer-right" index={props.index} /> + <ChartLegendIcon className="spacer-right" index={index} /> </td> <td className="text-right spacer-right"> - <span className="activity-graph-tooltip-value">{props.value}</span> + <span className="activity-graph-tooltip-value">{value}</span> {ratingValue && <Rating className="spacer-left" small={true} value={ratingValue} />} </td> - <td>{props.translatedName}</td> + <td>{translatedName}</td> </tr> ); } 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 index 42d90877818..684a1968baf 100644 --- 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 @@ -26,12 +26,7 @@ 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 { mockHistoryItem, mockMeasureHistory } from '../../../helpers/mocks/project-activity'; import { mockMetric } from '../../../helpers/testMocks'; import { renderComponent } from '../../../helpers/testReactTestingUtils'; import { MetricKey } from '../../../types/metrics'; @@ -41,63 +36,65 @@ 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, - }), -}; +const MAX_GRAPHS = 2; +const MAX_SERIES_PER_GRAPH = 3; +const HISTORY_COUNT = 10; +const START_DATE = '2016-01-01T00:00:00+0200'; -it('should correctly handle adding/removing custom metrics', async () => { +it('should render correctly when loading', async () => { + renderActivityGraph({ loading: true }); + expect(await screen.findByLabelText('loading')).toBeInTheDocument(); +}); + +it('should show the correct legend items', async () => { const user = userEvent.setup(); + const ui = getPageObject(user); + renderActivityGraph(); + + // Static legend items, which aren't interactive. + expect(ui.legendRemoveMetricBtn(MetricKey.bugs).query()).not.toBeInTheDocument(); + expect(ui.getLegendItem(MetricKey.bugs)).toBeInTheDocument(); + + // Switch to custom graph. + await ui.changeGraphType(GraphType.custom); + await ui.openAddMetrics(); + await ui.clickOnMetric(MetricKey.bugs); + await ui.clickOnMetric(MetricKey.test_failures); + await user.keyboard('{Escape}'); + + // These legend items are interactive (interaction tested below). + expect(ui.legendRemoveMetricBtn(MetricKey.bugs).get()).toBeInTheDocument(); + expect(ui.legendRemoveMetricBtn(MetricKey.test_failures).get()).toBeInTheDocument(); + + // Shows warning for metrics with no data. + const li = ui.getLegendItem(MetricKey.test_failures); + // eslint-disable-next-line jest/no-conditional-in-test + if (li) { + li.focus(); + } + expect(ui.noDataWarningTooltip.get()).toBeInTheDocument(); +}); + +it('should correctly handle adding/removing custom metrics', async () => { + const ui = getPageObject(userEvent.setup()); renderActivityGraph(); // Change graph type to "Custom". - await changeGraphType(GraphType.custom); + await ui.changeGraphType(GraphType.custom); // Open the "Add metrics" dropdown button; select some metrics. - await toggleAddMetrics(user); + await ui.openAddMetrics(); // 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); + await ui.clickOnMetric(MetricKey.bugs); + await ui.clickOnMetric(MetricKey.code_smells); + await ui.clickOnMetric(MetricKey.confirmed_issues); // Select 1 Percent type. - await clickOnMetric(user, MetricKey.coverage); + await ui.clickOnMetric(MetricKey.coverage); // We should see 2 graphs, correctly labelled. expect(ui.graphs.getAll()).toHaveLength(2); @@ -107,8 +104,8 @@ it('should correctly handle adding/removing custom metrics', async () => { expect(ui.hiddenOptionsAlert.get()).toBeInTheDocument(); // Select 2 more Percent types. - await clickOnMetric(user, MetricKey.duplicated_lines_density); - await clickOnMetric(user, MetricKey.test_success_density); + await ui.clickOnMetric(MetricKey.duplicated_lines_density); + await ui.clickOnMetric(MetricKey.test_success_density); // We cannot select anymore options. It should disable all remaining options, and // show a different alert. @@ -118,103 +115,139 @@ it('should correctly handle adding/removing custom metrics', async () => { 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); + await ui.clickOnMetric(MetricKey.bugs); + await ui.clickOnMetric(MetricKey.code_smells); + await ui.clickOnMetric(MetricKey.coverage); // Search for option. - await searchForMetric(user, 'bug'); + await ui.searchForMetric('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); + await ui.removeMetric(MetricKey.confirmed_issues); + await ui.removeMetric(MetricKey.duplicated_lines_density); + await ui.removeMetric(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(); -}); +describe('data table modal', () => { + it('shows the same data in a table', async () => { + const ui = getPageObject(userEvent.setup()); + renderActivityGraph(); -it('shows the same data in a table', async () => { - const user = userEvent.setup(); - renderActivityGraph(); + await ui.openDataTable(); + expect(ui.dataTable.get()).toBeInTheDocument(); + expect(ui.dataTableColHeaders.getAll()).toHaveLength(5); + expect(ui.dataTableRows.getAll()).toHaveLength(HISTORY_COUNT + 1); - 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); -}); + // Change graph type and dates, check table updates correctly. + await ui.closeDataTable(); + await ui.changeGraphType(GraphType.coverage); -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 ui.openDataTable(); + expect(ui.dataTable.get()).toBeInTheDocument(); + expect(ui.dataTableColHeaders.getAll()).toHaveLength(4); + expect(ui.dataTableRows.getAll()).toHaveLength(HISTORY_COUNT + 1); }); - 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 })); -} + it('shows the same data in a table when filtered by date', async () => { + const ui = getPageObject(userEvent.setup()); + renderActivityGraph({ + graphStartDate: parseDate('2017-01-01'), + graphEndDate: parseDate('2019-01-01'), + }); -async function searchForMetric(user: UserEvent, text: string) { - await user.type(ui.filterMetrics.get(), text); -} + await ui.openDataTable(); + expect(ui.dataTable.get()).toBeInTheDocument(); + expect(ui.dataTableColHeaders.getAll()).toHaveLength(5); + expect(ui.dataTableRows.getAll()).toHaveLength(2); + }); +}); -async function removeMetric(user: UserEvent, metric: MetricKey) { - await user.click( - screen.getByRole('button', { name: `project_activity.graphs.custom.remove_metric.${metric}` }) - ); +function getPageObject(user: UserEvent) { + const ui = { + // Graph types. + graphTypeSelect: byLabelText('project_activity.graphs.choose_type'), + + // Add/remove 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'), + legendRemoveMetricBtn: (key: string) => + byRole('button', { name: `project_activity.graphs.custom.remove_metric.${key}` }), + getLegendItem: (name: string) => { + // This is due to a limitation in testing library, where we cannot get a listitem + // role element by name. + return screen.getAllByRole('listitem').find((item) => item.textContent === name); + }, + noDataWarningTooltip: byLabelText('project_activity.graphs.custom.metric_no_history'), + + // 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'), + noDataTableText: byText('project_activity.graphs.data_table.no_data_warning_check_dates_x', { + exact: false, + }), + }; + + return { + ...ui, + async changeGraphType(type: GraphType) { + await selectEvent.select(ui.graphTypeSelect.get(), [`project_activity.graphs.${type}`]); + }, + async openAddMetrics() { + await user.click(ui.addMetricBtn.get()); + }, + async searchForMetric(text: string) { + await user.type(ui.filterMetrics.get(), text); + }, + async clickOnMetric(name: MetricKey) { + await user.click(screen.getByRole('checkbox', { name })); + }, + async removeMetric(metric: MetricKey) { + await user.click(ui.legendRemoveMetricBtn(metric).get()); + }, + async openDataTable() { + await user.click(ui.openInTableBtn.get()); + }, + async closeDataTable() { + await user.click(ui.closeDataTableBtn.get()); + }, + }; } 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 [graph, setGraph] = React.useState(graphsHistoryProps.graph || GraphType.issues); + const [selectedDate, setSelectedDate] = React.useState<Date | undefined>( + graphsHistoryProps.selectedDate + ); const [fromDate, setFromDate] = React.useState<Date | undefined>(undefined); const [toDate, setToDate] = React.useState<Date | undefined>(undefined); @@ -232,8 +265,8 @@ function renderActivityGraph( 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'); + const history = times(HISTORY_COUNT - 2, (i) => { + const date = parseDate(START_DATE); date.setDate(date.getDate() + i); return mockHistoryItem({ date, value: i.toString() }); }); @@ -245,7 +278,6 @@ function renderActivityGraph( metrics.push( mockMetric({ key: metric, - name: metric, type: metric.includes('_density') || metric === MetricKey.coverage ? 'PERCENT' : 'INT', }) ); @@ -253,8 +285,21 @@ function renderActivityGraph( // 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' }) + mockMetric({ key: MetricKey.new_bugs, type: 'INT' }), + mockMetric({ key: MetricKey.burned_budget, type: 'DATA' }) + ); + + // The following will not be filtered out, but has no values. + metrics.push(mockMetric({ key: MetricKey.test_failures, type: 'INT' })); + measuresHistory.push( + mockMeasureHistory({ + metric: MetricKey.test_failures, + history: times(HISTORY_COUNT, (i) => { + const date = parseDate(START_DATE); + date.setDate(date.getDate() + i); + return mockHistoryItem({ date, value: undefined }); + }), + }) ); const series = generateSeries( @@ -305,28 +350,7 @@ function renderActivityGraph( {...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, - }), - ], - }), - ]} + analyses={[]} graph={graph} graphEndDate={toDate} graphStartDate={fromDate} 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-it.tsx index b4d16fb678e..fb5dd3a5184 100644 --- 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-it.tsx @@ -22,13 +22,18 @@ 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 { + 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 DataTableModal, { DataTableModalProps } from '../DataTableModal'; +import DataTableModal, { DataTableModalProps, MAX_DATA_TABLE_ROWS } from '../DataTableModal'; import { generateSeries, getDisplayedHistoryMetrics } from '../utils'; it('should render correctly if there are no series', () => { @@ -38,10 +43,22 @@ it('should render correctly if there are no series', () => { ).toBeInTheDocument(); }); +it('should render correctly if there are events', () => { + renderDataTableModal({ + analyses: [ + mockParsedAnalysis({ + date: parseDate('2016-01-01T00:00:00+0200'), + events: [mockAnalysisEvent({ key: '1', category: 'QUALITY_GATE' })], + }), + ], + }); + expect(screen.getByText('event.category.QUALITY_GATE', { exact: false })).toBeInTheDocument(); +}); + it('should render correctly if there is too much data', () => { - renderDataTableModal({ series: mockSeries(101) }); + renderDataTableModal({ series: mockSeries(MAX_DATA_TABLE_ROWS + 1) }); expect( - screen.getByText('project_activity.graphs.data_table.max_lines_warning.100') + screen.getByText(`project_activity.graphs.data_table.max_lines_warning.${MAX_DATA_TABLE_ROWS}`) ).toBeInTheDocument(); }); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/DefinitionChangeEventInner-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/DefinitionChangeEventInner-test.tsx deleted file mode 100644 index cd609cbfeca..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/DefinitionChangeEventInner-test.tsx +++ /dev/null @@ -1,88 +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 { mockBranch } from '../../../helpers/mocks/branch-like'; -import { click } from '../../../helpers/testUtils'; -import { DefinitionChangeEvent, DefinitionChangeEventInner } from '../DefinitionChangeEventInner'; - -it('should render', () => { - const event: DefinitionChangeEvent = { - category: 'DEFINITION_CHANGE', - key: 'foo1234', - name: '', - definitionChange: { - projects: [ - { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' }, - { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }, - ], - }, - }; - const wrapper = shallow(<DefinitionChangeEventInner branchLike={undefined} event={event} />); - expect(wrapper).toMatchSnapshot(); - - click(wrapper.find('.project-activity-event-inner-more-link')); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render for a branch', () => { - const branch = mockBranch({ name: 'feature-x' }); - const event: DefinitionChangeEvent = { - category: 'DEFINITION_CHANGE', - key: 'foo1234', - name: '', - definitionChange: { - projects: [ - { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'feature-x' }, - { - changeType: 'BRANCH_CHANGED', - key: 'bar', - name: 'Bar', - oldBranch: 'master', - newBranch: 'feature-y', - }, - ], - }, - }; - const wrapper = shallow(<DefinitionChangeEventInner branchLike={branch} event={event} />); - click(wrapper.find('.project-activity-event-inner-more-link')); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render when readonly', () => { - const event: DefinitionChangeEvent = { - category: 'DEFINITION_CHANGE', - key: 'foo1234', - name: '', - definitionChange: { - projects: [ - { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master' }, - { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master' }, - ], - }, - }; - const wrapper = shallow( - <DefinitionChangeEventInner branchLike={undefined} event={event} readonly={true} /> - ); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false); -}); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx new file mode 100644 index 00000000000..ef0f1179e33 --- /dev/null +++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/EventInner-it.tsx @@ -0,0 +1,165 @@ +/* + * 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 * as React from 'react'; +import { byRole, byText } from 'testing-library-selector'; +import { mockAnalysisEvent } from '../../../helpers/mocks/project-activity'; +import { renderComponent } from '../../../helpers/testReactTestingUtils'; +import EventInner, { EventInnerProps } from '../EventInner'; + +const ui = { + showMoreBtn: byRole('button', { name: 'more' }), + showLessBtn: byRole('button', { name: 'hide' }), + projectLink: (name: string) => byRole('link', { name }), + + definitionChangeLabel: byText('event.category.DEFINITION_CHANGE', { exact: false }), + projectAddedTxt: byText('event.definition_change.added'), + projectRemovedTxt: byText('event.definition_change.removed'), + branchReplacedTxt: byText('event.definition_change.branch_replaced'), + + qualityGateLabel: byText('event.category.QUALITY_GATE', { exact: false }), + stillFailingTxt: byText('event.quality_gate.still_x'), + + versionLabel: byText('event.category.VERSION', { exact: false }), +}; + +describe('DEFINITION_CHANGE events', () => { + it('should render correctly for "DEFINITION_CHANGE" events', async () => { + const user = userEvent.setup(); + renderEventInner({ + event: mockAnalysisEvent({ + category: 'DEFINITION_CHANGE', + definitionChange: { + projects: [ + { changeType: 'ADDED', key: 'foo', name: 'Foo', branch: 'master-foo' }, + { changeType: 'REMOVED', key: 'bar', name: 'Bar', branch: 'master-bar' }, + { + changeType: 'BRANCH_CHANGED', + key: 'baz', + name: 'Baz', + oldBranch: 'old-branch', + newBranch: 'new-branch', + }, + ], + }, + }), + }); + + expect(ui.definitionChangeLabel.get()).toBeInTheDocument(); + + await user.click(ui.showMoreBtn.get()); + + // ADDED. + expect(ui.projectAddedTxt.get()).toBeInTheDocument(); + expect(ui.projectLink('Foo').get()).toBeInTheDocument(); + expect(screen.getByText('master-foo')).toBeInTheDocument(); + + // REMOVED. + expect(ui.projectRemovedTxt.get()).toBeInTheDocument(); + expect(ui.projectLink('Bar').get()).toBeInTheDocument(); + expect(screen.getByText('master-bar')).toBeInTheDocument(); + + // BRANCH_CHANGED + expect(ui.branchReplacedTxt.get()).toBeInTheDocument(); + expect(ui.projectLink('Baz').get()).toBeInTheDocument(); + expect(screen.getByText('old-branch')).toBeInTheDocument(); + expect(screen.getByText('new-branch')).toBeInTheDocument(); + }); +}); + +describe('QUALITY_GATE events', () => { + it('should render correctly for simple "QUALITY_GATE" events', () => { + renderEventInner({ + event: mockAnalysisEvent({ + category: 'QUALITY_GATE', + qualityGate: { status: 'ERROR', stillFailing: false, failing: [] }, + }), + }); + + expect(ui.qualityGateLabel.get()).toBeInTheDocument(); + }); + + it('should render correctly for "still failing" "QUALITY_GATE" events', () => { + renderEventInner({ + event: mockAnalysisEvent({ + category: 'QUALITY_GATE', + qualityGate: { status: 'ERROR', stillFailing: true, failing: [] }, + }), + }); + + expect(ui.qualityGateLabel.get()).toBeInTheDocument(); + expect(ui.stillFailingTxt.get()).toBeInTheDocument(); + }); + + it('should render correctly for application "QUALITY_GATE" events', async () => { + const user = userEvent.setup(); + renderEventInner({ + event: mockAnalysisEvent({ + category: 'QUALITY_GATE', + qualityGate: { + status: 'ERROR', + stillFailing: true, + failing: [ + { + key: 'foo', + name: 'Foo', + branch: 'master', + }, + { + key: 'bar', + name: 'Bar', + branch: 'feature/bar', + }, + ], + }, + }), + }); + + expect(ui.qualityGateLabel.get()).toBeInTheDocument(); + + await user.click(ui.showMoreBtn.get()); + expect(ui.projectLink('Foo').get()).toBeInTheDocument(); + expect(ui.projectLink('Bar').get()).toBeInTheDocument(); + + await user.click(ui.showLessBtn.get()); + expect(ui.projectLink('Foo').query()).not.toBeInTheDocument(); + expect(ui.projectLink('Bar').query()).not.toBeInTheDocument(); + }); +}); + +describe('VERSION events', () => { + it('should render correctly', () => { + renderEventInner({ + event: mockAnalysisEvent({ + category: 'VERSION', + name: '1.0', + }), + }); + + expect(ui.versionLabel.get()).toBeInTheDocument(); + expect(screen.getByText('1.0')).toBeInTheDocument(); + }); +}); + +function renderEventInner(props: Partial<EventInnerProps> = {}) { + return renderComponent(<EventInner event={mockAnalysisEvent()} {...props} />); +} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx deleted file mode 100644 index c54700cf5ea..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendCustom-test.tsx +++ /dev/null @@ -1,56 +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 GraphsLegendCustom, { GraphsLegendCustomProps } from '../GraphsLegendCustom'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); -}); - -function shallowRender(props: Partial<GraphsLegendCustomProps> = {}) { - return shallow<GraphsLegendCustomProps>( - <GraphsLegendCustom - removeMetric={jest.fn()} - series={[ - { - name: 'bugs', - translatedName: 'Bugs', - data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }], - type: 'INT', - }, - { - name: 'my_metric', - translatedName: 'My Metric', - data: [{ x: parseDate('2017-05-16T13:50:02+0200'), y: 1 }], - type: 'INT', - }, - { - name: 'foo', - translatedName: 'Foo', - data: [], - type: 'INT', - }, - ]} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendItem-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendItem-test.tsx deleted file mode 100644 index d2c9a3ea8d5..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendItem-test.tsx +++ /dev/null @@ -1,51 +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 { ClearButton } from '../../../components/controls/buttons'; -import { click } from '../../../helpers/testUtils'; -import GraphsLegendItem from '../GraphsLegendItem'; - -it('should render correctly a legend', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect( - shallowRender({ - className: 'myclass', - index: 1, - metric: 'foo', - name: 'Foo', - removeMetric: jest.fn(), - }) - ).toMatchSnapshot('with legend'); - expect(shallowRender({ showWarning: true })).toMatchSnapshot('with warning'); -}); - -it('should correctly handle clicks', () => { - const removeMetric = jest.fn(); - const wrapper = shallowRender({ removeMetric }); - click(wrapper.find(ClearButton)); - expect(removeMetric).toHaveBeenCalledWith('bugs'); -}); - -function shallowRender(props: Partial<GraphsLegendItem['props']> = {}) { - return shallow<GraphsLegendItem>( - <GraphsLegendItem index={2} metric="bugs" name="Bugs" {...props} /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx deleted file mode 100644 index 2e5d932fcd2..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendNewCode-test.tsx +++ /dev/null @@ -1,30 +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 GraphsLegendNewCode from '../GraphsLegendNewCode'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); -}); - -function shallowRender() { - return shallow(<GraphsLegendNewCode />); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx deleted file mode 100644 index 98403cb1eb0..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsLegendStatic-test.tsx +++ /dev/null @@ -1,38 +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 GraphsLegendStatic, { GraphsLegendStaticProps } from '../GraphsLegendStatic'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); -}); - -function shallowRender(props: Partial<GraphsLegendStaticProps> = {}) { - return shallow<GraphsLegendStaticProps>( - <GraphsLegendStatic - series={[ - { name: 'bugs', translatedName: 'Bugs' }, - { name: 'code_smells', translatedName: 'Code Smells' }, - ]} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx new file mode 100644 index 00000000000..0886532eed5 --- /dev/null +++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-it.tsx @@ -0,0 +1,127 @@ +/* + * 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 * as React from 'react'; +import { parseDate } from '../../../helpers/dates'; +import { + mockAnalysisEvent, + 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 GraphsTooltips from '../GraphsTooltips'; +import { generateSeries, getDisplayedHistoryMetrics } from '../utils'; + +it.each([ + [ + GraphType.issues, + [ + [MetricKey.bugs, 1, 'C'], + [MetricKey.code_smells, 0, 'A'], + [MetricKey.vulnerabilities, 2, 'E'], + ], + ], + [ + GraphType.coverage, + [ + ['metric.coverage.name', '75.0%'], + ['metric.uncovered_lines.name', 8], + ], + ], + [GraphType.duplications, [['metric.duplicated_lines_density.name', '3.0%']]], + [GraphType.custom, [[MetricKey.bugs, 1]]], +])( + 'renders correctly for graph of type %s', + (graph, metrics: Array<[string, number, string] | [string, number]>) => { + renderGraphsTooltips({ graph }); + + // Render events. + expect(screen.getByText('event.category.QUALITY_GATE', { exact: false })).toBeInTheDocument(); + + // Measures table. + metrics.forEach(([key, n, rating]) => { + expect( + screen.getByRole('row', { + // eslint-disable-next-line jest/no-conditional-in-test + name: rating ? `${n} metric.has_rating_X.${rating} ${key}` : `${n} ${key}`, + }) + ).toBeInTheDocument(); + }); + } +); + +function renderGraphsTooltips(props: Partial<GraphsTooltips['props']> = {}) { + const graph = (props.graph as GraphType) || GraphType.coverage; + const measuresHistory: MeasureHistory[] = []; + const date = props.selectedDate || parseDate('2016-01-01T00:00:00+0200'); + const metrics: Metric[] = []; + + [ + [MetricKey.bugs, '1'], + [MetricKey.reliability_rating, '3'], + [MetricKey.code_smells, '0'], + [MetricKey.sqale_rating, '1'], + [MetricKey.vulnerabilities, '2'], + [MetricKey.security_rating, '5'], + [MetricKey.lines_to_cover, '10'], + [MetricKey.uncovered_lines, '8'], + [MetricKey.coverage, '75'], + [MetricKey.duplicated_lines_density, '3'], + ].forEach(([metric, value]) => { + measuresHistory.push( + mockMeasureHistory({ + metric, + history: [mockHistoryItem({ date, value })], + }) + ); + metrics.push( + mockMetric({ + key: metric, + type: metric.includes('_density') || metric === MetricKey.coverage ? 'PERCENT' : 'INT', + }) + ); + }); + + const series = generateSeries( + measuresHistory, + graph, + metrics, + getDisplayedHistoryMetrics(graph, graph === GraphType.custom ? [MetricKey.bugs] : []) + ); + + return renderComponent( + <GraphsTooltips + events={[mockAnalysisEvent({ key: '1' })]} + graph={graph} + graphWidth={100} + measuresHistory={measuresHistory} + selectedDate={date} + series={series} + tooltipIdx={0} + tooltipPos={0} + formatValue={(n: number | string) => String(n)} + {...props} + /> + ); +} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-test.tsx deleted file mode 100644 index d76eceafecb..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltips-test.tsx +++ /dev/null @@ -1,111 +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 { mockEvent } from '../../../helpers/testUtils'; -import GraphsTooltips from '../GraphsTooltips'; -import { DEFAULT_GRAPH } from '../utils'; - -const SERIES_ISSUES = [ - { - name: 'bugs', - translatedName: 'Bugs', - data: [ - { - x: parseDate('2011-10-01T22:01:00.000Z'), - y: 3, - }, - { - x: parseDate('2011-10-25T10:27:41.000Z'), - y: 0, - }, - ], - type: 'INT', - }, - { - name: 'code_smells', - translatedName: 'Code Smells', - data: [ - { - x: parseDate('2011-10-01T22:01:00.000Z'), - y: 18, - }, - { - x: parseDate('2011-10-25T10:27:41.000Z'), - y: 15, - }, - ], - type: 'INT', - }, - { - name: 'vulnerabilities', - translatedName: 'Vulnerabilities', - data: [ - { - x: parseDate('2011-10-01T22:01:00.000Z'), - y: 0, - }, - { - x: parseDate('2011-10-25T10:27:41.000Z'), - y: 1, - }, - ], - type: 'INT', - }, -]; - -const DEFAULT_PROPS: GraphsTooltips['props'] = { - events: [], - formatValue: (val) => 'Formated.' + val, - graph: DEFAULT_GRAPH, - graphWidth: 500, - measuresHistory: [], - selectedDate: parseDate('2011-10-01T22:01:00.000Z'), - series: SERIES_ISSUES, - tooltipIdx: 0, - tooltipPos: 666, -}; - -it('should render correctly for issues graphs', () => { - expect(shallow(<GraphsTooltips {...DEFAULT_PROPS} />)).toMatchSnapshot(); - expect(shallow(<GraphsTooltips {...DEFAULT_PROPS} events={[mockEvent()]} />)).toMatchSnapshot( - 'with events' - ); -}); - -it('should render correctly for random graphs', () => { - expect( - shallow( - <GraphsTooltips - {...DEFAULT_PROPS} - graph="random" - selectedDate={parseDate('2011-10-25T10:27:41.000Z')} - tooltipIdx={1} - /> - ) - ).toMatchSnapshot(); -}); - -it('should not add separators if not needed', () => { - expect( - shallow(<GraphsTooltips {...DEFAULT_PROPS} graph="coverage" series={[]} />) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContent-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContent-test.tsx deleted file mode 100644 index ab5c3cb022c..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContent-test.tsx +++ /dev/null @@ -1,33 +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 GraphsTooltipsContent from '../GraphsTooltipsContent'; - -const DEFAULT_PROPS = { - index: 1, - name: 'code_smells', - translatedName: 'Code Smells', - value: '1.2k', -}; - -it('should render correctly', () => { - expect(shallow(<GraphsTooltipsContent {...DEFAULT_PROPS} />)).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentCoverage-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentCoverage-test.tsx deleted file mode 100644 index f7f1a6d1851..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentCoverage-test.tsx +++ /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 { parseDate } from '../../../helpers/dates'; -import GraphsTooltipsContentCoverage, { - GraphsTooltipsContentCoverageProps, -} from '../GraphsTooltipsContentCoverage'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ addSeparator: true })).toMatchSnapshot('with separator'); - expect(shallowRender({ tooltipIdx: -1 }).type()).toBeNull(); -}); - -function shallowRender(props: Partial<GraphsTooltipsContentCoverageProps> = {}) { - return shallow<GraphsTooltipsContentCoverageProps>( - <GraphsTooltipsContentCoverage - addSeparator={false} - measuresHistory={[ - { - metric: 'coverage', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z') }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '80.3' }, - ], - }, - { - metric: 'lines_to_cover', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z'), value: '60545' }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '65215' }, - ], - }, - { - metric: 'uncovered_lines', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z'), value: '40564' }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '10245' }, - ], - }, - ]} - tooltipIdx={1} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentDuplication-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentDuplication-test.tsx deleted file mode 100644 index 69d82091e3b..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentDuplication-test.tsx +++ /dev/null @@ -1,51 +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 GraphsTooltipsContentDuplication, { - GraphsTooltipsContentDuplicationProps, -} from '../GraphsTooltipsContentDuplication'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ addSeparator: true })).toMatchSnapshot('with separator'); - expect(shallowRender({ tooltipIdx: -1 }).type()).toBeNull(); - expect(shallowRender({ measuresHistory: [] }).type()).toBeNull(); -}); - -function shallowRender(props: Partial<GraphsTooltipsContentDuplicationProps> = {}) { - return shallow<GraphsTooltipsContentDuplicationProps>( - <GraphsTooltipsContentDuplication - addSeparator={false} - measuresHistory={[ - { - metric: 'duplicated_lines_density', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z') }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '10245' }, - ], - }, - ]} - tooltipIdx={1} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentEvents-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentEvents-test.tsx deleted file mode 100644 index 24f8075b0cd..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentEvents-test.tsx +++ /dev/null @@ -1,33 +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 GraphsTooltipsContentEvents from '../GraphsTooltipsContentEvents'; - -const EVENTS = [ - { key: '1', category: 'VERSION', name: '6.5' }, - { key: '2', category: 'OTHER', name: 'Foo' }, -]; - -it('should render correctly', () => { - expect( - shallow(<GraphsTooltipsContentEvents addSeparator={true} events={EVENTS} />) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentIssues-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentIssues-test.tsx deleted file mode 100644 index b3ab3a252cb..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/GraphsTooltipsContentIssues-test.tsx +++ /dev/null @@ -1,59 +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 GraphsTooltipsContentIssues, { - GraphsTooltipsContentIssuesProps, -} from '../GraphsTooltipsContentIssues'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ tooltipIdx: -1 }).type()).toBeNull(); -}); - -function shallowRender(props: Partial<GraphsTooltipsContentIssuesProps> = {}) { - return shallow<GraphsTooltipsContentIssuesProps>( - <GraphsTooltipsContentIssues - index={2} - measuresHistory={[ - { - metric: 'bugs', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z'), value: '500' }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '1.2k' }, - ], - }, - { - metric: 'reliability_rating', - history: [ - { date: parseDate('2011-10-01T22:01:00.000Z') }, - { date: parseDate('2011-10-25T10:27:41.000Z'), value: '5.0' }, - ], - }, - ]} - name="bugs" - tooltipIdx={1} - translatedName="Bugs" - value="1.2k" - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/RichQualityGateEventInner-test.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/RichQualityGateEventInner-test.tsx deleted file mode 100644 index 471c2ad61db..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/RichQualityGateEventInner-test.tsx +++ /dev/null @@ -1,60 +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 { click } from '../../../helpers/testUtils'; -import { RichQualityGateEvent, RichQualityGateEventInner } from '../RichQualityGateEventInner'; - -const event: RichQualityGateEvent = { - category: 'QUALITY_GATE', - key: 'foo1234', - name: '', - qualityGate: { - failing: [ - { branch: 'master', key: 'foo', name: 'Foo' }, - { branch: 'master', key: 'bar', name: 'Bar' }, - ], - status: 'ERROR', - stillFailing: true, - }, -}; - -it('should render', () => { - const wrapper = shallow(<RichQualityGateEventInner event={event} />); - expect(wrapper).toMatchSnapshot(); - - click(wrapper.find('.project-activity-event-inner-more-link')); - wrapper.update(); - expect(wrapper).toMatchSnapshot(); -}); - -it('should not expand', () => { - const wrapper = shallow( - <RichQualityGateEventInner - event={{ ...event, qualityGate: { ...event.qualityGate, failing: [] } }} - /> - ); - expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false); -}); - -it('should not expand when readonly', () => { - const wrapper = shallow(<RichQualityGateEventInner event={event} readonly={true} />); - expect(wrapper.find('.project-activity-event-inner-more-link').exists()).toBe(false); -}); diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/DefinitionChangeEventInner-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/DefinitionChangeEventInner-test.tsx.snap deleted file mode 100644 index ce770c6fcd3..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/DefinitionChangeEventInner-test.tsx.snap +++ /dev/null @@ -1,248 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render 1`] = ` -<Fragment> - <span - className="note" - > - event.category.DEFINITION_CHANGE - : - </span> - <div> - <ButtonLink - className="project-activity-event-inner-more-link" - onClick={[Function]} - stopPropagation={true} - > - more - <DropdownIcon - className="little-spacer-left" - turned={false} - /> - </ButtonLink> - </div> -</Fragment> -`; - -exports[`should render 2`] = ` -<Fragment> - <span - className="note" - > - event.category.DEFINITION_CHANGE - : - </span> - <div> - <ButtonLink - className="project-activity-event-inner-more-link" - onClick={[Function]} - stopPropagation={true} - > - hide - <DropdownIcon - className="little-spacer-left" - turned={true} - /> - </ButtonLink> - </div> - <ul - className="spacer-left spacer-top" - > - <li - className="display-flex-center spacer-top" - key="foo" - > - <div - className="text-ellipsis" - > - <FormattedMessage - defaultMessage="event.definition_change.added" - id="event.definition_change.added" - values={ - Object { - "branch": <span - className="nowrap" - title="master" - > - <BranchIcon - className="little-spacer-left text-text-top" - /> - master - </span>, - "project": <ForwardRef(Link) - onClick={[Function]} - title="Foo" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=foo&branch=master", - } - } - > - Foo - </ForwardRef(Link)>, - } - } - /> - </div> - </li> - <li - className="display-flex-center spacer-top" - key="bar" - > - <div - className="text-ellipsis" - > - <FormattedMessage - defaultMessage="event.definition_change.removed" - id="event.definition_change.removed" - values={ - Object { - "branch": <span - className="nowrap" - title="master" - > - <BranchIcon - className="little-spacer-left text-text-top" - /> - master - </span>, - "project": <ForwardRef(Link) - onClick={[Function]} - title="Bar" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=bar&branch=master", - } - } - > - Bar - </ForwardRef(Link)>, - } - } - /> - </div> - </li> - </ul> -</Fragment> -`; - -exports[`should render for a branch 1`] = ` -<Fragment> - <span - className="note" - > - event.category.DEFINITION_CHANGE - : - </span> - <div> - <ButtonLink - className="project-activity-event-inner-more-link" - onClick={[Function]} - stopPropagation={true} - > - hide - <DropdownIcon - className="little-spacer-left" - turned={true} - /> - </ButtonLink> - </div> - <ul - className="spacer-left spacer-top" - > - <li - className="display-flex-center spacer-top" - key="foo" - > - <div - className="text-ellipsis" - > - <FormattedMessage - defaultMessage="event.definition_change.branch_added" - id="event.definition_change.branch_added" - values={ - Object { - "branch": <span - className="nowrap" - title="feature-x" - > - <BranchIcon - className="little-spacer-left text-text-top" - /> - feature-x - </span>, - "project": <ForwardRef(Link) - onClick={[Function]} - title="Foo" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=foo&branch=feature-x", - } - } - > - Foo - </ForwardRef(Link)>, - } - } - /> - </div> - </li> - <li - className="display-flex-center spacer-top" - key="bar" - > - <FormattedMessage - defaultMessage="event.definition_change.branch_replaced" - id="event.definition_change.branch_replaced" - values={ - Object { - "newBranch": <span - className="nowrap" - title="feature-y" - > - <BranchIcon - className="little-spacer-left text-text-top" - /> - feature-y - </span>, - "oldBranch": <span - className="nowrap" - title="master" - > - <BranchIcon - className="little-spacer-left text-text-top" - /> - master - </span>, - "project": <ForwardRef(Link) - onClick={[Function]} - title="Bar" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=bar&branch=feature-y", - } - } - > - Bar - </ForwardRef(Link)>, - } - } - /> - </li> - </ul> -</Fragment> -`; - -exports[`should render when readonly 1`] = ` -<Fragment> - <span - className="note" - > - event.category.DEFINITION_CHANGE - </span> -</Fragment> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap deleted file mode 100644 index eb50e58ca57..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendCustom-test.tsx.snap +++ /dev/null @@ -1,52 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<div - className="activity-graph-legends display-flex-center" -> - <div - className="flex-1" - > - <span - className="spacer-left spacer-right" - key="bugs" - > - <GraphsLegendItem - index={0} - metric="bugs" - name="Bugs" - removeMetric={[MockFunction]} - showWarning={false} - /> - </span> - <span - className="spacer-left spacer-right" - key="my_metric" - > - <GraphsLegendItem - index={1} - metric="my_metric" - name="My Metric" - removeMetric={[MockFunction]} - showWarning={false} - /> - </span> - <Tooltip - key="foo" - overlay="project_activity.graphs.custom.metric_no_history" - > - <span - className="spacer-left spacer-right" - > - <GraphsLegendItem - index={2} - metric="foo" - name="Foo" - removeMetric={[MockFunction]} - showWarning={true} - /> - </span> - </Tooltip> - </div> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendItem-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendItem-test.tsx.snap deleted file mode 100644 index 37369e0d970..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendItem-test.tsx.snap +++ /dev/null @@ -1,58 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly a legend: default 1`] = ` -<span - className="" -> - <ChartLegendIcon - className="text-middle spacer-right" - index={2} - /> - <span - className="text-middle" - > - Bugs - </span> -</span> -`; - -exports[`should render correctly a legend: with legend 1`] = ` -<span - className="activity-graph-legend-actionable myclass" -> - <ChartLegendIcon - className="text-middle spacer-right" - index={1} - /> - <span - className="text-middle" - > - Foo - </span> - <ClearButton - aria-label="project_activity.graphs.custom.remove_metric.Foo" - className="button-tiny spacer-left text-middle" - iconProps={ - Object { - "size": 12, - } - } - onClick={[Function]} - /> -</span> -`; - -exports[`should render correctly a legend: with warning 1`] = ` -<span - className="" -> - <AlertWarnIcon - className="spacer-right" - /> - <span - className="text-middle" - > - Bugs - </span> -</span> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap deleted file mode 100644 index e6c7707ef39..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendNewCode-test.tsx.snap +++ /dev/null @@ -1,14 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<Tooltip - overlay="project_activity.graphs.new_code_long" -> - <span - aria-label="project_activity.graphs.new_code_long" - className="activity-graph-new-code-legend display-flex-center pull-right note" - > - project_activity.graphs.new_code - </span> -</Tooltip> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap deleted file mode 100644 index 00239dc81f1..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsLegendStatic-test.tsx.snap +++ /dev/null @@ -1,22 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<div - className="activity-graph-legends" -> - <GraphsLegendItem - className="big-spacer-left big-spacer-right" - index={0} - key="bugs" - metric="bugs" - name="Bugs" - /> - <GraphsLegendItem - className="big-spacer-left big-spacer-right" - index={1} - key="code_smells" - metric="code_smells" - name="Code Smells" - /> -</div> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltips-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltips-test.tsx.snap deleted file mode 100644 index c4f775ce431..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltips-test.tsx.snap +++ /dev/null @@ -1,226 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should not add separators if not needed 1`] = ` -<Popup - className="disabled-pointer-events" - placement="left-top" - style={ - Object { - "left": 476, - "top": 30, - "width": 250, - } - } -> - <div - className="activity-graph-tooltip" - > - <div - className="activity-graph-tooltip-title spacer-bottom" - > - <DateTimeFormatter - date={2011-10-01T22:01:00.000Z} - /> - </div> - <table - className="width-100" - > - <tbody /> - <GraphsTooltipsContentCoverage - addSeparator={false} - measuresHistory={Array []} - tooltipIdx={0} - /> - </table> - </div> -</Popup> -`; - -exports[`should render correctly for issues graphs 1`] = ` -<Popup - className="disabled-pointer-events" - placement="left-top" - style={ - Object { - "left": 476, - "top": 30, - "width": 250, - } - } -> - <div - className="activity-graph-tooltip" - > - <div - className="activity-graph-tooltip-title spacer-bottom" - > - <DateTimeFormatter - date={2011-10-01T22:01:00.000Z} - /> - </div> - <table - className="width-100" - > - <tbody> - <GraphsTooltipsContentIssues - index={0} - key="bugs" - measuresHistory={Array []} - name="bugs" - tooltipIdx={0} - translatedName="Bugs" - value="Formated.3" - /> - <GraphsTooltipsContentIssues - index={1} - key="code_smells" - measuresHistory={Array []} - name="code_smells" - tooltipIdx={0} - translatedName="Code Smells" - value="Formated.18" - /> - <GraphsTooltipsContentIssues - index={2} - key="vulnerabilities" - measuresHistory={Array []} - name="vulnerabilities" - tooltipIdx={0} - translatedName="Vulnerabilities" - value="Formated.0" - /> - </tbody> - </table> - </div> -</Popup> -`; - -exports[`should render correctly for issues graphs: with events 1`] = ` -<Popup - className="disabled-pointer-events" - placement="left-top" - style={ - Object { - "left": 476, - "top": 30, - "width": 250, - } - } -> - <div - className="activity-graph-tooltip" - > - <div - className="activity-graph-tooltip-title spacer-bottom" - > - <DateTimeFormatter - date={2011-10-01T22:01:00.000Z} - /> - </div> - <table - className="width-100" - > - <GraphsTooltipsContentEvents - addSeparator={true} - events={ - Array [ - Object { - "currentTarget": Object { - "blur": [Function], - }, - "preventDefault": [Function], - "stopImmediatePropagation": [Function], - "stopPropagation": [Function], - "target": Object { - "blur": [Function], - }, - }, - ] - } - /> - <tbody> - <GraphsTooltipsContentIssues - index={0} - key="bugs" - measuresHistory={Array []} - name="bugs" - tooltipIdx={0} - translatedName="Bugs" - value="Formated.3" - /> - <GraphsTooltipsContentIssues - index={1} - key="code_smells" - measuresHistory={Array []} - name="code_smells" - tooltipIdx={0} - translatedName="Code Smells" - value="Formated.18" - /> - <GraphsTooltipsContentIssues - index={2} - key="vulnerabilities" - measuresHistory={Array []} - name="vulnerabilities" - tooltipIdx={0} - translatedName="Vulnerabilities" - value="Formated.0" - /> - </tbody> - </table> - </div> -</Popup> -`; - -exports[`should render correctly for random graphs 1`] = ` -<Popup - className="disabled-pointer-events" - placement="left-top" - style={ - Object { - "left": 476, - "top": 30, - "width": 250, - } - } -> - <div - className="activity-graph-tooltip" - > - <div - className="activity-graph-tooltip-title spacer-bottom" - > - <DateTimeFormatter - date={2011-10-25T10:27:41.000Z} - /> - </div> - <table - className="width-100" - > - <tbody> - <GraphsTooltipsContent - index={0} - key="bugs" - name="bugs" - translatedName="Bugs" - value="Formated.0" - /> - <GraphsTooltipsContent - index={1} - key="code_smells" - name="code_smells" - translatedName="Code Smells" - value="Formated.15" - /> - <GraphsTooltipsContent - index={2} - key="vulnerabilities" - name="vulnerabilities" - translatedName="Vulnerabilities" - value="Formated.1" - /> - </tbody> - </table> - </div> -</Popup> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContent-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContent-test.tsx.snap deleted file mode 100644 index 4bfd687cf88..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContent-test.tsx.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -<tr - className="activity-graph-tooltip-line" - key="code_smells" -> - <td - className="thin" - > - <ChartLegendIcon - className="spacer-right" - index={1} - /> - </td> - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - > - 1.2k - </td> - <td> - Code Smells - </td> -</tr> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentCoverage-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentCoverage-test.tsx.snap deleted file mode 100644 index f83e91ef9f5..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentCoverage-test.tsx.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<tbody> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 10short_number_suffix.k - </td> - <td> - metric.uncovered_lines.name - </td> - </tr> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 80.3% - </td> - <td> - metric.coverage.name - </td> - </tr> -</tbody> -`; - -exports[`should render correctly: with separator 1`] = ` -<tbody> - <tr> - <td - className="activity-graph-tooltip-separator" - colSpan={3} - > - <hr /> - </td> - </tr> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 10short_number_suffix.k - </td> - <td> - metric.uncovered_lines.name - </td> - </tr> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 80.3% - </td> - <td> - metric.coverage.name - </td> - </tr> -</tbody> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentDuplication-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentDuplication-test.tsx.snap deleted file mode 100644 index 30fc8c8118a..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentDuplication-test.tsx.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<tbody> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 10,245.0% - </td> - <td> - metric.duplicated_lines_density.name - </td> - </tr> -</tbody> -`; - -exports[`should render correctly: with separator 1`] = ` -<tbody> - <tr> - <td - className="activity-graph-tooltip-separator" - colSpan={3} - > - <hr /> - </td> - </tr> - <tr - className="activity-graph-tooltip-line" - > - <td - className="activity-graph-tooltip-value text-right spacer-right thin" - colSpan={2} - > - 10,245.0% - </td> - <td> - metric.duplicated_lines_density.name - </td> - </tr> -</tbody> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentEvents-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentEvents-test.tsx.snap deleted file mode 100644 index c4297a01b3d..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentEvents-test.tsx.snap +++ /dev/null @@ -1,60 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -<tbody> - <tr> - <td - className="activity-graph-tooltip-separator" - colSpan={3} - > - <hr /> - </td> - </tr> - <tr - className="activity-graph-tooltip-line" - > - <td - colSpan={3} - > - <div - className="little-spacer-bottom" - key="1" - > - <EventInner - event={ - Object { - "category": "VERSION", - "key": "1", - "name": "6.5", - } - } - readonly={true} - /> - </div> - <div - className="little-spacer-bottom" - key="2" - > - <EventInner - event={ - Object { - "category": "OTHER", - "key": "2", - "name": "Foo", - } - } - readonly={true} - /> - </div> - </td> - </tr> - <tr> - <td - className="activity-graph-tooltip-separator" - colSpan={3} - > - <hr /> - </td> - </tr> -</tbody> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentIssues-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentIssues-test.tsx.snap deleted file mode 100644 index 43f9d71b1dc..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/GraphsTooltipsContentIssues-test.tsx.snap +++ /dev/null @@ -1,34 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -<tr - className="activity-graph-tooltip-issues-line" - key="bugs" -> - <td - className="thin" - > - <ChartLegendIcon - className="spacer-right" - index={2} - /> - </td> - <td - className="text-right spacer-right" - > - <span - className="activity-graph-tooltip-value" - > - 1.2k - </span> - <Rating - className="spacer-left" - small={true} - value="5.0" - /> - </td> - <td> - Bugs - </td> -</tr> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap b/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap deleted file mode 100644 index cd9373673f2..00000000000 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/__snapshots__/RichQualityGateEventInner-test.tsx.snap +++ /dev/null @@ -1,139 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render 1`] = ` -<Fragment> - <span - className="note spacer-right" - > - event.category.QUALITY_GATE - : - </span> - <FormattedMessage - defaultMessage="event.quality_gate.still_x" - id="event.quality_gate.still_x" - values={ - Object { - "status": <Level - level="ERROR" - small={true} - />, - } - } - /> - <div> - <ResetButtonLink - className="project-activity-event-inner-more-link" - onClick={[Function]} - stopPropagation={true} - > - more - <DropdownIcon - className="little-spacer-left" - turned={false} - /> - </ResetButtonLink> - </div> -</Fragment> -`; - -exports[`should render 2`] = ` -<Fragment> - <span - className="note spacer-right" - > - event.category.QUALITY_GATE - : - </span> - <FormattedMessage - defaultMessage="event.quality_gate.still_x" - id="event.quality_gate.still_x" - values={ - Object { - "status": <Level - level="ERROR" - small={true} - />, - } - } - /> - <div> - <ResetButtonLink - className="project-activity-event-inner-more-link" - onClick={[Function]} - stopPropagation={true} - > - hide - <DropdownIcon - className="little-spacer-left" - turned={true} - /> - </ResetButtonLink> - </div> - <ul - className="spacer-left spacer-top" - > - <li - className="display-flex-center spacer-top" - key="foo" - > - <Level - aria-label="quality_gates.status" - className="spacer-right" - level="ERROR" - small={true} - /> - <div - className="flex-1 text-ellipsis" - > - <ForwardRef(Link) - onClick={[Function]} - title="Foo" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=foo&branch=master", - } - } - > - <span - aria-label="project_x.Foo" - > - Foo - </span> - </ForwardRef(Link)> - </div> - </li> - <li - className="display-flex-center spacer-top" - key="bar" - > - <Level - aria-label="quality_gates.status" - className="spacer-right" - level="ERROR" - small={true} - /> - <div - className="flex-1 text-ellipsis" - > - <ForwardRef(Link) - onClick={[Function]} - title="Bar" - to={ - Object { - "pathname": "/dashboard", - "search": "?id=bar&branch=master", - } - } - > - <span - aria-label="project_x.Bar" - > - Bar - </span> - </ForwardRef(Link)> - </div> - </li> - </ul> -</Fragment> -`; diff --git a/server/sonar-web/src/main/js/components/activity-graph/styles.css b/server/sonar-web/src/main/js/components/activity-graph/styles.css index 73d9cda0f64..81e4f03e602 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/styles.css +++ b/server/sonar-web/src/main/js/components/activity-graph/styles.css @@ -54,9 +54,9 @@ } .activity-graph-legends { - flex-grow: 0; + display: flex; + justify-content: center; padding-bottom: calc(2 * var(--gridSize)); - text-align: center; } .activity-graph-legend-actionable { |