From: guillaume-peoch-sonarsource Date: Wed, 22 Feb 2023 16:43:10 +0000 (+0100) Subject: SONAR-18536 Migrate enzyme to RTL for Project Overview X-Git-Tag: 10.0.0.68432~171 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e2874ce9c4a4fc154e51b8e26a80ec2281eb7628;p=sonarqube.git SONAR-18536 Migrate enzyme to RTL for Project Overview --- diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx index 6c021598d32..db2be496150 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchOverview.tsx @@ -33,7 +33,6 @@ import { getBranchLikeDisplayName, getBranchLikeQuery, isMainBranch, - isSameBranchLike, } from '../../../helpers/branch-like'; import { parseDate, toNotSoISOString } from '../../../helpers/dates'; import { enhanceConditionWithMeasure, enhanceMeasuresWithMetrics } from '../../../helpers/measures'; @@ -98,16 +97,6 @@ export default class BranchOverview extends React.PureComponent { this.loadHistory(); } - componentDidUpdate(prevProps: Props) { - if ( - this.props.component.key !== prevProps.component.key || - !isSameBranchLike(this.props.branch, prevProps.branch) - ) { - this.loadStatus(); - this.loadHistory(); - } - } - componentWillUnmount() { this.mounted = false; } diff --git a/server/sonar-web/src/main/js/apps/overview/branches/LeakPeriodInfo.tsx b/server/sonar-web/src/main/js/apps/overview/branches/LeakPeriodInfo.tsx index fe9b79e2126..533cf15b074 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/LeakPeriodInfo.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/LeakPeriodInfo.tsx @@ -31,9 +31,8 @@ export interface LeakPeriodInfoProps { export function LeakPeriodInfo({ leakPeriod }: LeakPeriodInfoProps) { if (isApplicationPeriod(leakPeriod)) { return ; - } else { - return ; } + return ; } export default React.memo(LeakPeriodInfo); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx deleted file mode 100644 index 26540ecf008..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ActivityPanel-test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 GraphsHistory from '../../../../components/activity-graph/GraphsHistory'; -import { parseDate } from '../../../../helpers/dates'; -import { mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockAnalysis, mockAnalysisEvent } from '../../../../helpers/mocks/project-activity'; -import { mockMeasure, mockMetric } from '../../../../helpers/testMocks'; -import { GraphType } from '../../../../types/project-activity'; -import { ActivityPanel, ActivityPanelProps } from '../ActivityPanel'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ loading: true, analyses: undefined })).toMatchSnapshot(); -}); - -it('should correctly pass the leak period start date', () => { - // Leak period start is more recent than the oldest historic measure. - let { leakPeriodDate } = shallowRender({ - leakPeriodDate: parseDate('2017-08-27T16:33:50+0200'), - }) - .find(GraphsHistory) - .props(); - - expect(leakPeriodDate!.getTime()).toBe(1503844430000); /* 2017-08-27T16:33:50+0200 */ - - // Leak period start is older than the oldest historic measure. - ({ leakPeriodDate } = shallowRender({ leakPeriodDate: parseDate('2015-08-27T16:33:50+0200') }) - .find(GraphsHistory) - .props()); - - expect(leakPeriodDate!.getTime()).toBe(1477578830000); /* 2016-10-27T16:33:50+0200 */ -}); - -function shallowRender(props: Partial = {}) { - return shallow( - ({ - ...m, - history: [{ date: parseDate('2016-10-27T16:33:50+0200'), value: '20' }], - }))} - metrics={[mockMetric({ key: 'bugs' })]} - onGraphChange={jest.fn()} - {...props} - /> - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx deleted file mode 100644 index 147732263e6..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Analysis-test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockAnalysis } from '../../../../helpers/mocks/project-activity'; -import { ComponentQualifier } from '../../../../types/component'; -import { ProjectAnalysisEventCategory } from '../../../../types/project-activity'; -import { Analysis, AnalysisProps } from '../Analysis'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ qualifier: ComponentQualifier.Application })).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ApplicationLeakPeriodInfo-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ApplicationLeakPeriodInfo-test.tsx deleted file mode 100644 index 23593980132..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ApplicationLeakPeriodInfo-test.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockApplicationPeriod } from '../../../../helpers/mocks/application'; -import { - ApplicationLeakPeriodInfo, - ApplicationLeakPeriodInfoProps, -} from '../ApplicationLeakPeriodInfo'; - -jest.mock('../../../../components/intl/DateFromNow'); - -it('renders correctly', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('DateFromNow').dive()).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx new file mode 100644 index 00000000000..428ef513c29 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx @@ -0,0 +1,379 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 selectEvent from 'react-select-event'; +import { getMeasuresWithPeriodAndMetrics } from '../../../../api/measures'; +import { getProjectActivity } from '../../../../api/projectActivity'; +import { + getApplicationQualityGate, + getQualityGateProjectStatus, +} from '../../../../api/quality-gates'; +import CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider'; +import { getActivityGraph, saveActivityGraph } from '../../../../components/activity-graph/utils'; +import { isDiffMetric } from '../../../../helpers/measures'; +import { mockMainBranch } from '../../../../helpers/mocks/branch-like'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { mockAnalysis } from '../../../../helpers/mocks/project-activity'; +import { + mockQualityGateApplicationStatus, + mockQualityGateProjectStatus, +} from '../../../../helpers/mocks/quality-gates'; +import { mockLoggedInUser, mockPeriod } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { ComponentQualifier } from '../../../../types/component'; +import { MetricKey } from '../../../../types/metrics'; +import { GraphType } from '../../../../types/project-activity'; +import { CaycStatus, Measure, Metric } from '../../../../types/types'; +import BranchOverview, { BRANCH_OVERVIEW_ACTIVITY_GRAPH, NO_CI_DETECTED } from '../BranchOverview'; + +jest.mock('../../../../api/measures', () => { + const { mockMeasure, mockMetric } = jest.requireActual('../../../../helpers/testMocks'); + return { + getMeasuresWithPeriodAndMetrics: jest.fn((_, metricKeys: string[]) => { + const metrics: Metric[] = []; + const measures: Measure[] = []; + metricKeys.forEach((key) => { + if (key === 'unknown_metric') { + return; + } + + let type; + if (/(coverage|duplication)$/.test(key)) { + type = 'PERCENT'; + } else if (/_rating$/.test(key)) { + type = 'RATING'; + } else { + type = 'INT'; + } + metrics.push(mockMetric({ key, id: key, name: key, type })); + measures.push( + mockMeasure({ + metric: key, + ...(isDiffMetric(key) ? { leak: '1' } : { period: undefined }), + }) + ); + }); + return Promise.resolve({ + component: { + measures, + name: 'foo', + }, + metrics, + }); + }), + }; +}); + +jest.mock('../../../../api/quality-gates', () => { + const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = jest.requireActual( + '../../../../helpers/mocks/quality-gates' + ); + const { MetricKey } = jest.requireActual('../../../../types/metrics'); + return { + getQualityGateProjectStatus: jest.fn().mockResolvedValue( + mockQualityGateProjectStatus({ + status: 'ERROR', + conditions: [ + { + actualValue: '2', + comparator: 'GT', + errorThreshold: '1', + metricKey: MetricKey.new_reliability_rating, + periodIndex: 1, + status: 'ERROR', + }, + { + actualValue: '5', + comparator: 'GT', + errorThreshold: '2.0', + metricKey: MetricKey.bugs, + periodIndex: 0, + status: 'ERROR', + }, + { + actualValue: '2', + comparator: 'GT', + errorThreshold: '1.0', + metricKey: 'unknown_metric', + periodIndex: 0, + status: 'ERROR', + }, + ], + }) + ), + getApplicationQualityGate: jest.fn().mockResolvedValue(mockQualityGateApplicationStatus()), + }; +}); + +jest.mock('../../../../api/time-machine', () => { + const { MetricKey } = jest.requireActual('../../../../types/metrics'); + return { + getAllTimeMachineData: jest.fn().mockResolvedValue({ + measures: [ + { metric: MetricKey.bugs, history: [{ date: '2019-01-05', value: '2.0' }] }, + { metric: MetricKey.vulnerabilities, history: [{ date: '2019-01-05', value: '0' }] }, + { metric: MetricKey.sqale_index, history: [{ date: '2019-01-01', value: '1.0' }] }, + { + metric: MetricKey.duplicated_lines_density, + history: [{ date: '2019-01-02', value: '1.0' }], + }, + { metric: MetricKey.ncloc, history: [{ date: '2019-01-03', value: '10000' }] }, + { metric: MetricKey.coverage, history: [{ date: '2019-01-04', value: '95.5' }] }, + ], + }), + }; +}); + +jest.mock('../../../../api/projectActivity', () => { + const { mockAnalysis } = jest.requireActual('../../../../helpers/mocks/project-activity'); + return { + getProjectActivity: jest.fn().mockResolvedValue({ + analyses: [ + mockAnalysis({ detectedCI: 'Cirrus CI' }), + mockAnalysis(), + mockAnalysis(), + mockAnalysis(), + mockAnalysis(), + ], + }), + }; +}); + +jest.mock('../../../../api/application', () => ({ + getApplicationDetails: jest.fn().mockResolvedValue({ + branches: [], + key: 'key-1', + name: 'app', + projects: [ + { + branch: 'foo', + key: 'KEY-P1', + name: 'P1', + }, + ], + visibility: 'Private', + }), + getApplicationLeak: jest.fn().mockResolvedValue([ + { + date: '2017-01-05', + project: 'foo', + projectName: 'Foo', + }, + ]), +})); + +jest.mock('../../../../components/activity-graph/utils', () => { + const { MetricKey } = jest.requireActual('../../../../types/metrics'); + const { GraphType } = jest.requireActual('../../../../types/project-activity'); + const original = jest.requireActual('../../../../components/activity-graph/utils'); + return { + ...original, + getActivityGraph: jest.fn(() => ({ graph: GraphType.coverage })), + saveActivityGraph: jest.fn(), + getHistoryMetrics: jest.fn(() => [MetricKey.lines_to_cover, MetricKey.uncovered_lines]), + }; +}); + +beforeEach(jest.clearAllMocks); + +describe('project overview', () => { + it('should show a successful QG', async () => { + const user = userEvent.setup(); + jest + .mocked(getQualityGateProjectStatus) + .mockResolvedValueOnce(mockQualityGateProjectStatus({ status: 'OK' })); + renderBranchOverview(); + + // QG panel + expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); + expect(screen.getByText('overview.quality_gate_all_conditions_passed')).toBeInTheDocument(); + expect( + screen.queryByText('overview.quality_gate.conditions.cayc.warning') + ).not.toBeInTheDocument(); + + //Measures panel + expect(screen.getByText('metric.new_vulnerabilities.name')).toBeInTheDocument(); + + // go to overall + await user.click(screen.getByText('overview.overall_code')); + + expect(screen.getByText('metric.vulnerabilities.name')).toBeInTheDocument(); + }); + + it('should show a successful non-compliant QG', async () => { + jest + .mocked(getQualityGateProjectStatus) + .mockResolvedValueOnce( + mockQualityGateProjectStatus({ status: 'OK', caycStatus: CaycStatus.NonCompliant }) + ); + + renderBranchOverview(); + + expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); + expect(screen.getByText('overview.quality_gate.conditions.cayc.warning')).toBeInTheDocument(); + }); + + it('should show a failed QG', async () => { + renderBranchOverview(); + + expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument(); + expect(screen.getByText('overview.X_conditions_failed.2')).toBeInTheDocument(); + }); + + it('should correctly show a project as empty', async () => { + jest.mocked(getMeasuresWithPeriodAndMetrics).mockResolvedValueOnce({ + component: { key: '', name: '', qualifier: ComponentQualifier.Project, measures: [] }, + metrics: [], + period: mockPeriod(), + }); + + renderBranchOverview(); + + expect(await screen.findByText('overview.project.main_branch_empty')).toBeInTheDocument(); + }); +}); + +describe('application overview', () => { + const component = mockComponent({ + breadcrumbs: [mockComponent({ key: 'foo', qualifier: ComponentQualifier.Application })], + qualifier: ComponentQualifier.Application, + }); + + it('should show failed conditions for every project', async () => { + renderBranchOverview({ component }); + expect(await screen.findByText('Foo')).toBeInTheDocument(); + expect(screen.getByText('Bar')).toBeInTheDocument(); + }); + + it("should show projects that don't have a compliant quality gate", async () => { + const appStatus = mockQualityGateApplicationStatus({ + projects: [ + { + key: '1', + name: 'first project', + conditions: [], + caycStatus: CaycStatus.NonCompliant, + status: 'OK', + }, + { + key: '2', + name: 'second', + conditions: [], + caycStatus: CaycStatus.Compliant, + status: 'OK', + }, + { + key: '3', + name: 'number 3', + conditions: [], + caycStatus: CaycStatus.NonCompliant, + status: 'OK', + }, + { + key: '4', + name: 'four', + conditions: [ + { + comparator: 'GT', + metric: MetricKey.bugs, + status: 'ERROR', + value: '3', + errorThreshold: '0', + }, + ], + caycStatus: CaycStatus.NonCompliant, + status: 'ERROR', + }, + ], + }); + jest.mocked(getApplicationQualityGate).mockResolvedValueOnce(appStatus); + + renderBranchOverview({ component }); + expect( + await screen.findByText('overview.quality_gate.application.non_cayc.projects_x.3') + ).toBeInTheDocument(); + expect(screen.getByText('first project')).toBeInTheDocument(); + expect(screen.queryByText('second')).not.toBeInTheDocument(); + expect(screen.getByText('number 3')).toBeInTheDocument(); + }); + + it('should correctly show an app as empty', async () => { + jest.mocked(getMeasuresWithPeriodAndMetrics).mockResolvedValueOnce({ + component: { key: '', name: '', qualifier: ComponentQualifier.Application, measures: [] }, + metrics: [], + period: mockPeriod(), + }); + + renderBranchOverview({ component }); + + expect(await screen.findByText('portfolio.app.empty')).toBeInTheDocument(); + }); +}); + +it.each([ + ['no analysis', [], true], + ['1 analysis, no CI data', [mockAnalysis()], false], + ['1 analysis, no CI detected', [mockAnalysis({ detectedCI: NO_CI_DETECTED })], false], + ['1 analysis, CI detected', [mockAnalysis({ detectedCI: 'Cirrus CI' })], true], +])( + "should correctly flag a project that wasn't analyzed using a CI (%s)", + async (_, analyses, expected) => { + (getProjectActivity as jest.Mock).mockResolvedValueOnce({ analyses }); + + renderBranchOverview(); + + // wait for loading + await screen.findByText('overview.quality_gate'); + + expect(screen.queryByText('overview.project.next_steps.set_up_ci') === null).toBe(expected); + } +); + +it('should correctly handle graph type storage', async () => { + renderBranchOverview(); + expect(getActivityGraph).toHaveBeenCalledWith(BRANCH_OVERVIEW_ACTIVITY_GRAPH, 'foo'); + + const select = await screen.findByLabelText('project_activity.graphs.choose_type'); + await selectEvent.select(select, `project_activity.graphs.${GraphType.issues}`); + + expect(saveActivityGraph).toHaveBeenCalledWith( + BRANCH_OVERVIEW_ACTIVITY_GRAPH, + 'foo', + GraphType.issues + ); +}); + +function renderBranchOverview(props: Partial = {}) { + renderComponent( + + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx deleted file mode 100644 index 428ef513c29..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-test.tsx +++ /dev/null @@ -1,379 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 selectEvent from 'react-select-event'; -import { getMeasuresWithPeriodAndMetrics } from '../../../../api/measures'; -import { getProjectActivity } from '../../../../api/projectActivity'; -import { - getApplicationQualityGate, - getQualityGateProjectStatus, -} from '../../../../api/quality-gates'; -import CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider'; -import { getActivityGraph, saveActivityGraph } from '../../../../components/activity-graph/utils'; -import { isDiffMetric } from '../../../../helpers/measures'; -import { mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockAnalysis } from '../../../../helpers/mocks/project-activity'; -import { - mockQualityGateApplicationStatus, - mockQualityGateProjectStatus, -} from '../../../../helpers/mocks/quality-gates'; -import { mockLoggedInUser, mockPeriod } from '../../../../helpers/testMocks'; -import { renderComponent } from '../../../../helpers/testReactTestingUtils'; -import { ComponentQualifier } from '../../../../types/component'; -import { MetricKey } from '../../../../types/metrics'; -import { GraphType } from '../../../../types/project-activity'; -import { CaycStatus, Measure, Metric } from '../../../../types/types'; -import BranchOverview, { BRANCH_OVERVIEW_ACTIVITY_GRAPH, NO_CI_DETECTED } from '../BranchOverview'; - -jest.mock('../../../../api/measures', () => { - const { mockMeasure, mockMetric } = jest.requireActual('../../../../helpers/testMocks'); - return { - getMeasuresWithPeriodAndMetrics: jest.fn((_, metricKeys: string[]) => { - const metrics: Metric[] = []; - const measures: Measure[] = []; - metricKeys.forEach((key) => { - if (key === 'unknown_metric') { - return; - } - - let type; - if (/(coverage|duplication)$/.test(key)) { - type = 'PERCENT'; - } else if (/_rating$/.test(key)) { - type = 'RATING'; - } else { - type = 'INT'; - } - metrics.push(mockMetric({ key, id: key, name: key, type })); - measures.push( - mockMeasure({ - metric: key, - ...(isDiffMetric(key) ? { leak: '1' } : { period: undefined }), - }) - ); - }); - return Promise.resolve({ - component: { - measures, - name: 'foo', - }, - metrics, - }); - }), - }; -}); - -jest.mock('../../../../api/quality-gates', () => { - const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = jest.requireActual( - '../../../../helpers/mocks/quality-gates' - ); - const { MetricKey } = jest.requireActual('../../../../types/metrics'); - return { - getQualityGateProjectStatus: jest.fn().mockResolvedValue( - mockQualityGateProjectStatus({ - status: 'ERROR', - conditions: [ - { - actualValue: '2', - comparator: 'GT', - errorThreshold: '1', - metricKey: MetricKey.new_reliability_rating, - periodIndex: 1, - status: 'ERROR', - }, - { - actualValue: '5', - comparator: 'GT', - errorThreshold: '2.0', - metricKey: MetricKey.bugs, - periodIndex: 0, - status: 'ERROR', - }, - { - actualValue: '2', - comparator: 'GT', - errorThreshold: '1.0', - metricKey: 'unknown_metric', - periodIndex: 0, - status: 'ERROR', - }, - ], - }) - ), - getApplicationQualityGate: jest.fn().mockResolvedValue(mockQualityGateApplicationStatus()), - }; -}); - -jest.mock('../../../../api/time-machine', () => { - const { MetricKey } = jest.requireActual('../../../../types/metrics'); - return { - getAllTimeMachineData: jest.fn().mockResolvedValue({ - measures: [ - { metric: MetricKey.bugs, history: [{ date: '2019-01-05', value: '2.0' }] }, - { metric: MetricKey.vulnerabilities, history: [{ date: '2019-01-05', value: '0' }] }, - { metric: MetricKey.sqale_index, history: [{ date: '2019-01-01', value: '1.0' }] }, - { - metric: MetricKey.duplicated_lines_density, - history: [{ date: '2019-01-02', value: '1.0' }], - }, - { metric: MetricKey.ncloc, history: [{ date: '2019-01-03', value: '10000' }] }, - { metric: MetricKey.coverage, history: [{ date: '2019-01-04', value: '95.5' }] }, - ], - }), - }; -}); - -jest.mock('../../../../api/projectActivity', () => { - const { mockAnalysis } = jest.requireActual('../../../../helpers/mocks/project-activity'); - return { - getProjectActivity: jest.fn().mockResolvedValue({ - analyses: [ - mockAnalysis({ detectedCI: 'Cirrus CI' }), - mockAnalysis(), - mockAnalysis(), - mockAnalysis(), - mockAnalysis(), - ], - }), - }; -}); - -jest.mock('../../../../api/application', () => ({ - getApplicationDetails: jest.fn().mockResolvedValue({ - branches: [], - key: 'key-1', - name: 'app', - projects: [ - { - branch: 'foo', - key: 'KEY-P1', - name: 'P1', - }, - ], - visibility: 'Private', - }), - getApplicationLeak: jest.fn().mockResolvedValue([ - { - date: '2017-01-05', - project: 'foo', - projectName: 'Foo', - }, - ]), -})); - -jest.mock('../../../../components/activity-graph/utils', () => { - const { MetricKey } = jest.requireActual('../../../../types/metrics'); - const { GraphType } = jest.requireActual('../../../../types/project-activity'); - const original = jest.requireActual('../../../../components/activity-graph/utils'); - return { - ...original, - getActivityGraph: jest.fn(() => ({ graph: GraphType.coverage })), - saveActivityGraph: jest.fn(), - getHistoryMetrics: jest.fn(() => [MetricKey.lines_to_cover, MetricKey.uncovered_lines]), - }; -}); - -beforeEach(jest.clearAllMocks); - -describe('project overview', () => { - it('should show a successful QG', async () => { - const user = userEvent.setup(); - jest - .mocked(getQualityGateProjectStatus) - .mockResolvedValueOnce(mockQualityGateProjectStatus({ status: 'OK' })); - renderBranchOverview(); - - // QG panel - expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); - expect(screen.getByText('overview.quality_gate_all_conditions_passed')).toBeInTheDocument(); - expect( - screen.queryByText('overview.quality_gate.conditions.cayc.warning') - ).not.toBeInTheDocument(); - - //Measures panel - expect(screen.getByText('metric.new_vulnerabilities.name')).toBeInTheDocument(); - - // go to overall - await user.click(screen.getByText('overview.overall_code')); - - expect(screen.getByText('metric.vulnerabilities.name')).toBeInTheDocument(); - }); - - it('should show a successful non-compliant QG', async () => { - jest - .mocked(getQualityGateProjectStatus) - .mockResolvedValueOnce( - mockQualityGateProjectStatus({ status: 'OK', caycStatus: CaycStatus.NonCompliant }) - ); - - renderBranchOverview(); - - expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); - expect(screen.getByText('overview.quality_gate.conditions.cayc.warning')).toBeInTheDocument(); - }); - - it('should show a failed QG', async () => { - renderBranchOverview(); - - expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument(); - expect(screen.getByText('overview.X_conditions_failed.2')).toBeInTheDocument(); - }); - - it('should correctly show a project as empty', async () => { - jest.mocked(getMeasuresWithPeriodAndMetrics).mockResolvedValueOnce({ - component: { key: '', name: '', qualifier: ComponentQualifier.Project, measures: [] }, - metrics: [], - period: mockPeriod(), - }); - - renderBranchOverview(); - - expect(await screen.findByText('overview.project.main_branch_empty')).toBeInTheDocument(); - }); -}); - -describe('application overview', () => { - const component = mockComponent({ - breadcrumbs: [mockComponent({ key: 'foo', qualifier: ComponentQualifier.Application })], - qualifier: ComponentQualifier.Application, - }); - - it('should show failed conditions for every project', async () => { - renderBranchOverview({ component }); - expect(await screen.findByText('Foo')).toBeInTheDocument(); - expect(screen.getByText('Bar')).toBeInTheDocument(); - }); - - it("should show projects that don't have a compliant quality gate", async () => { - const appStatus = mockQualityGateApplicationStatus({ - projects: [ - { - key: '1', - name: 'first project', - conditions: [], - caycStatus: CaycStatus.NonCompliant, - status: 'OK', - }, - { - key: '2', - name: 'second', - conditions: [], - caycStatus: CaycStatus.Compliant, - status: 'OK', - }, - { - key: '3', - name: 'number 3', - conditions: [], - caycStatus: CaycStatus.NonCompliant, - status: 'OK', - }, - { - key: '4', - name: 'four', - conditions: [ - { - comparator: 'GT', - metric: MetricKey.bugs, - status: 'ERROR', - value: '3', - errorThreshold: '0', - }, - ], - caycStatus: CaycStatus.NonCompliant, - status: 'ERROR', - }, - ], - }); - jest.mocked(getApplicationQualityGate).mockResolvedValueOnce(appStatus); - - renderBranchOverview({ component }); - expect( - await screen.findByText('overview.quality_gate.application.non_cayc.projects_x.3') - ).toBeInTheDocument(); - expect(screen.getByText('first project')).toBeInTheDocument(); - expect(screen.queryByText('second')).not.toBeInTheDocument(); - expect(screen.getByText('number 3')).toBeInTheDocument(); - }); - - it('should correctly show an app as empty', async () => { - jest.mocked(getMeasuresWithPeriodAndMetrics).mockResolvedValueOnce({ - component: { key: '', name: '', qualifier: ComponentQualifier.Application, measures: [] }, - metrics: [], - period: mockPeriod(), - }); - - renderBranchOverview({ component }); - - expect(await screen.findByText('portfolio.app.empty')).toBeInTheDocument(); - }); -}); - -it.each([ - ['no analysis', [], true], - ['1 analysis, no CI data', [mockAnalysis()], false], - ['1 analysis, no CI detected', [mockAnalysis({ detectedCI: NO_CI_DETECTED })], false], - ['1 analysis, CI detected', [mockAnalysis({ detectedCI: 'Cirrus CI' })], true], -])( - "should correctly flag a project that wasn't analyzed using a CI (%s)", - async (_, analyses, expected) => { - (getProjectActivity as jest.Mock).mockResolvedValueOnce({ analyses }); - - renderBranchOverview(); - - // wait for loading - await screen.findByText('overview.quality_gate'); - - expect(screen.queryByText('overview.project.next_steps.set_up_ci') === null).toBe(expected); - } -); - -it('should correctly handle graph type storage', async () => { - renderBranchOverview(); - expect(getActivityGraph).toHaveBeenCalledWith(BRANCH_OVERVIEW_ACTIVITY_GRAPH, 'foo'); - - const select = await screen.findByLabelText('project_activity.graphs.choose_type'); - await selectEvent.select(select, `project_activity.graphs.${GraphType.issues}`); - - expect(saveActivityGraph).toHaveBeenCalledWith( - BRANCH_OVERVIEW_ACTIVITY_GRAPH, - 'foo', - GraphType.issues - ); -}); - -function renderBranchOverview(props: Partial = {}) { - renderComponent( - - - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx deleted file mode 100644 index 298186fa98e..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/DrilldownMeasureValue-test.tsx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks'; -import { MetricKey } from '../../../../types/metrics'; -import { DrilldownMeasureValue, DrilldownMeasureValueProps } from '../DrilldownMeasureValue'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ metric: MetricKey.bugs })).toMatchSnapshot('measure not found'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx deleted file mode 100644 index ac63c170394..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/Event-test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { AnalysisEvent, ProjectAnalysisEventCategory } from '../../../../types/project-activity'; -import { Event } from '../Event'; - -it('should render an event correctly', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); - -it('should render a version correctly', () => { - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); - -it('should render rich quality gate event', () => { - const event: AnalysisEvent = { - category: ProjectAnalysisEventCategory.QualityGate, - key: 'foo1234', - name: '', - qualityGate: { - failing: [{ branch: 'master', key: 'foo', name: 'Foo' }], - status: 'ERROR', - stillFailing: true, - }, - }; - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/FirstAnalysisNextStepsNotif-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/FirstAnalysisNextStepsNotif-test.tsx deleted file mode 100644 index fe803e7c12f..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/FirstAnalysisNextStepsNotif-test.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockProjectAlmBindingResponse } from '../../../../helpers/mocks/alm-settings'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks'; -import { ComponentQualifier } from '../../../../types/component'; -import { - FirstAnalysisNextStepsNotif, - FirstAnalysisNextStepsNotifProps, -} from '../FirstAnalysisNextStepsNotif'; - -it('should render correctly', () => { - expect(shallowRender({ currentUser: mockCurrentUser() }).type()).toBeNull(); - expect( - shallowRender({ - component: mockComponent({ qualifier: ComponentQualifier.Application }), - }).type() - ).toBeNull(); - expect(shallowRender({ detectedCIOnLastAnalysis: false })).toMatchSnapshot( - 'show prompt to configure CI' - ); - expect( - shallowRender({ - projectBinding: undefined, - }) - ).toMatchSnapshot('show prompt to configure PR decoration, regular user'); - expect( - shallowRender({ - component: mockComponent({ configuration: { showSettings: true } }), - projectBinding: undefined, - }) - ).toMatchSnapshot('show prompt to configure PR decoration, project admin'); - expect( - shallowRender({ - projectBinding: undefined, - detectedCIOnLastAnalysis: false, - }) - ).toMatchSnapshot('show prompt to configure PR decoration + CI, regular user'); - expect( - shallowRender({ - component: mockComponent({ configuration: { showSettings: true } }), - projectBinding: undefined, - detectedCIOnLastAnalysis: false, - }) - ).toMatchSnapshot('show prompt to configure PR decoration + CI, project admin'); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/LeakPeriodInfo-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/LeakPeriodInfo-test.tsx deleted file mode 100644 index c8905e7d195..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/LeakPeriodInfo-test.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockApplicationPeriod } from '../../../../helpers/mocks/application'; -import { mockPeriod } from '../../../../helpers/testMocks'; -import { LeakPeriodInfo, LeakPeriodInfoProps } from '../LeakPeriodInfo'; - -it('renders correctly for projects', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('renders correctly for applications', () => { - expect(shallowRender({ leakPeriod: mockApplicationPeriod() })).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx deleted file mode 100644 index 9516e0b727e..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/MeasuresPanel-test.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 BoxedTabs from '../../../../components/controls/BoxedTabs'; -import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { - mockLocation, - mockMeasureEnhanced, - mockMetric, - mockPeriod, -} from '../../../../helpers/testMocks'; -import { ComponentQualifier } from '../../../../types/component'; -import { MetricKey } from '../../../../types/metrics'; -import { MeasuresPanel, MeasuresPanelProps, MeasuresPanelTabs } from '../MeasuresPanel'; - -jest.mock('react', () => { - return { - ...jest.requireActual('react'), - useEffect: jest.fn().mockImplementation((f) => f()), - }; -}); - -it('should render correctly for projects', () => { - const wrapper = shallowRender(); - expect(wrapper).toMatchSnapshot('default'); - wrapper.find(BoxedTabs).prop('onSelect')(MeasuresPanelTabs.Overall); - expect(wrapper).toMatchSnapshot('overall'); -}); - -it('should render correctly for applications', () => { - const wrapper = shallowRender({ - component: mockComponent({ qualifier: ComponentQualifier.Application }), - }); - expect(wrapper).toMatchSnapshot('default'); - wrapper.find(BoxedTabs).prop('onSelect')(MeasuresPanelTabs.Overall); - expect(wrapper).toMatchSnapshot('overall'); -}); - -it('should render correctly if there is no new code measures', () => { - const wrapper = shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }), - ], - }); - wrapper.find(BoxedTabs).prop('onSelect')(MeasuresPanelTabs.New); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render correctly if branch is misconfigured', () => { - const wrapper = shallowRender({ - branch: mockBranch({ name: 'own-reference' }), - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }), - ], - period: mockPeriod({ date: undefined, mode: 'REFERENCE_BRANCH', parameter: 'own-reference' }), - }); - wrapper.find(BoxedTabs).prop('onSelect')(MeasuresPanelTabs.New); - expect(wrapper).toMatchSnapshot('hide settings'); - - wrapper.setProps({ component: mockComponent({ configuration: { showSettings: true } }) }); - expect(wrapper).toMatchSnapshot('show settings'); -}); - -it('should render correctly if there is no coverage', () => { - expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_bugs }) }), - ], - }) - ).toMatchSnapshot(); -}); - -it('should render correctly if the data is still loading', () => { - expect(shallowRender({ loading: true })).toMatchSnapshot(); -}); - -it('should render correctly when code scope is overall code', () => { - expect( - shallowRender({ - location: mockLocation({ pathname: '/dashboard', query: { code_scope: 'overall' } }), - }) - ).toMatchSnapshot(); -}); - -it('should render correctly when code scope is new code', () => { - expect( - shallowRender({ - location: mockLocation({ pathname: '/dashboard', query: { code_scope: 'new' } }), - }) - ).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx deleted file mode 100644 index 71962f7de3e..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/NoCodeWarning-test.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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, mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks'; -import { ComponentQualifier } from '../../../../types/component'; -import { MetricKey } from '../../../../types/metrics'; -import { NoCodeWarning } from '../NoCodeWarning'; - -it('should render correctly if the project has no lines of code', () => { - const wrapper = shallowRender(); - expect(wrapper.children().text()).toBe('overview.project.main_branch_no_lines_of_code'); - - wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) }); - expect(wrapper.children().text()).toBe('overview.project.branch_X_no_lines_of_code.branch-foo'); - - wrapper.setProps({ branchLike: undefined }); - expect(wrapper.children().text()).toBe('overview.project.no_lines_of_code'); -}); - -it('should correctly if the project is empty', () => { - const wrapper = shallowRender({ measures: [] }); - expect(wrapper.children().text()).toBe('overview.project.main_branch_empty'); - - wrapper.setProps({ branchLike: mockBranch({ name: 'branch-foo' }) }); - expect(wrapper.children().text()).toBe('overview.project.branch_X_empty.branch-foo'); - - wrapper.setProps({ branchLike: undefined }); - expect(wrapper.children().text()).toBe('overview.project.empty'); -}); - -it('should render correctly if the application is empty or has no lines of code', () => { - const wrapper = shallowRender({ - component: mockComponent({ qualifier: ComponentQualifier.Application }), - measures: [mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.projects }) })], - }); - expect(wrapper.children().text()).toBe('portfolio.app.no_lines_of_code'); - - wrapper.setProps({ measures: [] }); - expect(wrapper.children().text()).toBe('portfolio.app.empty'); -}); - -function shallowRender(props = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx index eb6c942fd33..fe635fe2114 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/ProjectLeakPeriodInfo-test.tsx @@ -17,11 +17,12 @@ * 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 { differenceInDays } from 'date-fns'; -import { shallow } from 'enzyme'; import * as React from 'react'; import { IntlShape } from 'react-intl'; import { mockPeriod } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { Period } from '../../../../types/types'; import { ProjectLeakPeriodInfo } from '../ProjectLeakPeriodInfo'; @@ -30,44 +31,67 @@ jest.mock('date-fns', () => { return { ...actual, differenceInDays: jest.fn().mockReturnValue(10) }; }); -it('should render correctly for 10 days', () => { - expect(shallowRender({ mode: 'days', parameter: '10' })).toMatchSnapshot(); +it('should render correctly for 10 days', async () => { + renderProjectLeakPeriodInfo({ mode: 'days', parameter: '10' }); + expect(await screen.findByText('overview.period.days.10')).toBeInTheDocument(); }); -it('should render correctly for a specific date', () => { - expect(shallowRender({ mode: 'date', parameter: '2013-01-01' })).toMatchSnapshot(); +it('should render correctly for a specific date', async () => { + renderProjectLeakPeriodInfo({ mode: 'date', parameter: '2013-01-01' }); + expect(await screen.findByText('overview.period.date.formatted.2013-01-01')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*ago/)).toBeInTheDocument(); }); -it('should render correctly for a specific version', () => { - expect(shallowRender({ mode: 'version', parameter: '0.1' })).toMatchSnapshot(); +it('should render correctly for a specific version', async () => { + renderProjectLeakPeriodInfo({ mode: 'version', parameter: '0.1' }); + expect(await screen.findByText('overview.period.version.0.1')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*ago/)).toBeInTheDocument(); }); -it('should render correctly for "previous_version"', () => { - expect(shallowRender({ mode: 'previous_version' })).toMatchSnapshot(); +it('should render correctly for "previous_version"', async () => { + renderProjectLeakPeriodInfo({ mode: 'previous_version' }); + expect(await screen.findByText('overview.period.previous_version_only_date')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*ago/)).toBeInTheDocument(); }); -it('should render correctly for "previous_analysis"', () => { - expect(shallowRender({ mode: 'previous_analysis' })).toMatchSnapshot(); +it('should render correctly for "previous_analysis"', async () => { + renderProjectLeakPeriodInfo({ mode: 'previous_analysis' }); + expect(await screen.findByText('overview.period.previous_analysis.')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.previous_analysis_x\..*ago/)).toBeInTheDocument(); }); -it('should render correctly for "REFERENCE_BRANCH"', () => { - expect(shallowRender({ mode: 'REFERENCE_BRANCH', parameter: 'master' })).toMatchSnapshot(); +it('should render correctly for "REFERENCE_BRANCH"', async () => { + renderProjectLeakPeriodInfo({ + mode: 'REFERENCE_BRANCH', + parameter: 'master', + }); + expect(await screen.findByText('overview.period.reference_branch.master')).toBeInTheDocument(); }); -it('should render correctly for "manual_baseline"', () => { - expect(shallowRender({ mode: 'manual_baseline' })).toMatchSnapshot(); - expect(shallowRender({ mode: 'manual_baseline', parameter: '1.1.2' })).toMatchSnapshot(); +it('should render correctly for "manual_baseline"', async () => { + const rtl = renderProjectLeakPeriodInfo({ mode: 'manual_baseline' }); + + expect( + await screen.findByText(/overview\.period\.manual_baseline\.formattedTime\..*/) + ).toBeInTheDocument(); + rtl.unmount(); + renderProjectLeakPeriodInfo({ mode: 'manual_baseline', parameter: '1.1.2' }); + expect(await screen.findByText('overview.period.manual_baseline.1.1.2')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*ago/)).toBeInTheDocument(); }); -it('should render a more precise date', () => { +it('should render a more precise date', async () => { (differenceInDays as jest.Mock).mockReturnValueOnce(0); - expect( - shallowRender({ date: '2018-08-17T00:00:00+0200', mode: 'previous_version' }) - ).toMatchSnapshot(); + renderProjectLeakPeriodInfo({ + date: '2018-08-17T00:00:00+0200', + mode: 'previous_version', + }); + expect(await screen.findByText('overview.period.previous_version_only_date')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*ago/)).toBeInTheDocument(); }); -function shallowRender(period: Partial = {}) { - return shallow( +function renderProjectLeakPeriodInfo(period: Partial = {}) { + return renderComponent( { - expect(shallowRender()).toMatchSnapshot(); - expect( - shallowRender({ qgStatuses: [mockQualityGateStatus({ status: 'OK', failedConditions: [] })] }) - ).toMatchSnapshot(); - - const wrapper = shallowRender({ - qgStatuses: [mockQualityGateStatus({ ignoredConditions: true })], - }); - expect(wrapper).toMatchSnapshot(); -}); - -it('should render correctly for applications', () => { - expect( - shallowRender({ - component: mockComponent({ qualifier: ComponentQualifier.Application }), - qgStatuses: [ - mockQualityGateStatus(), - mockQualityGateStatus({ - failedConditions: [ - mockQualityGateStatusConditionEnhanced(), - mockQualityGateStatusConditionEnhanced({ - measure: mockMeasureEnhanced({ - metric: mockMetric({ key: MetricKey.new_code_smells }), - }), - metric: MetricKey.new_code_smells, - }), - ], - }), - ], - }) - ).toMatchSnapshot(); - - const wrapper = shallowRender({ - component: mockComponent({ qualifier: ComponentQualifier.Application }), - qgStatuses: [ - mockQualityGateStatus(), - mockQualityGateStatus({ - status: 'OK', - failedConditions: [], - }), - ], - }); - expect(wrapper).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx deleted file mode 100644 index 1345e86bd6a..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/QualityGatePanelSection-test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockMainBranch } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { - mockQualityGateStatus, - mockQualityGateStatusConditionEnhanced, -} from '../../../../helpers/mocks/quality-gates'; -import { ComponentQualifier } from '../../../../types/component'; -import { MetricKey } from '../../../../types/metrics'; -import { CaycStatus } from '../../../../types/types'; -import { QualityGatePanelSection, QualityGatePanelSectionProps } from '../QualityGatePanelSection'; - -it('should render correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect( - shallowRender({ - qgStatus: mockQualityGateStatus({ - failedConditions: [], - status: 'OK', - caycStatus: CaycStatus.Compliant, - }), - }).type() - ).toBeNull(); - expect( - shallowRender({ component: mockComponent({ qualifier: ComponentQualifier.Application }) }) - ).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap deleted file mode 100644 index 5ed1dbc5711..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ActivityPanel-test.tsx.snap +++ /dev/null @@ -1,307 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
-

- overview.activity -

-
-
-
-
- - -
-
- -
-
-
-
- -
    - -
-
-
-
-
-
-
-`; - -exports[`should render correctly 2`] = ` -
-

- overview.activity -

-
-
-
-
- - -
-
- -
-
-
-
- -

- no_results -

-
-
-
-
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap deleted file mode 100644 index c457027703b..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Analysis-test.tsx.snap +++ /dev/null @@ -1,81 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
  • -
    - - - -
    -
    - - -
    -
  • -`; - -exports[`should render correctly 2`] = ` -
  • -
    - - - -
    -
    - - -
    -
  • -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap deleted file mode 100644 index 8a0e03c64df..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ApplicationLeakPeriodInfo-test.tsx.snap +++ /dev/null @@ -1,19 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
    - - - - -
    -`; - -exports[`renders correctly 2`] = `"overview.started_x.2017-10-01"`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap deleted file mode 100644 index ffa69935ea3..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/DrilldownMeasureValue-test.tsx.snap +++ /dev/null @@ -1,48 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: default 1`] = ` -
    - - - 1 - - - - tests - -
    -`; - -exports[`should render correctly: measure not found 1`] = ` -
    - - - - - - bugs - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap deleted file mode 100644 index 575f912e98b..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/Event-test.tsx.snap +++ /dev/null @@ -1,53 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render a version correctly 1`] = ` - - 6.5-SNAPSHOT - -`; - -exports[`should render an event correctly 1`] = ` -
    - - event.category.OTHER - : - - - - test - -
    -`; - -exports[`should render rich quality gate event 1`] = ` -
    - - event.category.QUALITY_GATE - : - - - , - } - } - /> -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/FirstAnalysisNextStepsNotif-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/FirstAnalysisNextStepsNotif-test.tsx.snap deleted file mode 100644 index 2b604303996..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/FirstAnalysisNextStepsNotif-test.tsx.snap +++ /dev/null @@ -1,124 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: show prompt to configure CI 1`] = ` - - - overview.project.next_steps.links.set_up_ci - , - } - } - /> - -`; - -exports[`should render correctly: show prompt to configure PR decoration + CI, project admin 1`] = ` - - - overview.project.next_steps.links.set_up_ci - , - "link_project_settings": - overview.project.next_steps.links.project_settings - , - } - } - /> - -`; - -exports[`should render correctly: show prompt to configure PR decoration + CI, regular user 1`] = ` - - - overview.project.next_steps.links.set_up_ci - , - } - } - /> - -`; - -exports[`should render correctly: show prompt to configure PR decoration, project admin 1`] = ` - - - overview.project.next_steps.links.project_settings - , - } - } - /> - -`; - -exports[`should render correctly: show prompt to configure PR decoration, regular user 1`] = ` - - overview.project.next_steps.set_up_pr_deco - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap deleted file mode 100644 index 06c90039f64..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/LeakPeriodInfo-test.tsx.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly for applications 1`] = ` - -`; - -exports[`renders correctly for projects 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap deleted file mode 100644 index 3c2c3e2d22d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/MeasuresPanel-test.tsx.snap +++ /dev/null @@ -1,5914 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for applications: default 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    -
    - -
    -
    -
    - -`; - -exports[`should render correctly for applications: overall 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - -`; - -exports[`should render correctly for projects: default 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    -
    - -
    -
    -
    - -`; - -exports[`should render correctly for projects: overall 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - -`; - -exports[`should render correctly if branch is misconfigured: hide settings 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - -
    - -`; - -exports[`should render correctly if branch is misconfigured: show settings 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - -
    - -`; - -exports[`should render correctly if the data is still loading 1`] = ` -
    -
    -

    - overview.measures -

    - -
    -
    - -
    -
    -`; - -exports[`should render correctly if there is no coverage 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    -
    -
    - -`; - -exports[`should render correctly if there is no new code measures 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - -
    - -`; - -exports[`should render correctly when code scope is new code 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    -
    - -
    -
    -
    - -`; - -exports[`should render correctly when code scope is overall code 1`] = ` -
    -
    -

    - overview.measures -

    - -
    - - - overview.new_code - -
    , - }, - { - "key": "overall", - "label":
    - - overview.overall_code - -
    , - }, - ] - } - /> -
    - - - - -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap deleted file mode 100644 index 1323291149c..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/ProjectLeakPeriodInfo-test.tsx.snap +++ /dev/null @@ -1,131 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render a more precise date 1`] = ` - -
    - overview.period.previous_version_only_date -
    - - - -
    -`; - -exports[`should render correctly for "REFERENCE_BRANCH" 1`] = ` -
    - overview.period.reference_branch.master - -
    -`; - -exports[`should render correctly for "manual_baseline" 1`] = ` - -
    - overview.period.manual_baseline.formattedTime.2019-04-23T02:12:32+0100 -
    - - - -
    -`; - -exports[`should render correctly for "manual_baseline" 2`] = ` - -
    - overview.period.manual_baseline.1.1.2 -
    - - - -
    -`; - -exports[`should render correctly for "previous_analysis" 1`] = ` - -
    - overview.period.previous_analysis. -
    - - - -
    -`; - -exports[`should render correctly for "previous_version" 1`] = ` - -
    - overview.period.previous_version_only_date -
    - - - -
    -`; - -exports[`should render correctly for 10 days 1`] = ` -
    - overview.period.days.10 - -
    -`; - -exports[`should render correctly for a specific date 1`] = ` - -
    - overview.period.date.formatted.2013-01-01 -
    - - - -
    -`; - -exports[`should render correctly for a specific version 1`] = ` - -
    - overview.period.version.0.1 -
    - - - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap deleted file mode 100644 index 293440a0cfb..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanel-test.tsx.snap +++ /dev/null @@ -1,770 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for applications 1`] = ` -
    -
    -

    - overview.quality_gate - -

    - - overview.quality_gate.help -
    - } - /> -
    -
    -
    -
    - metric.level.ERROR -
    - - overview.X_conditions_failed.3 - -
    -
    - - -
    -
    - - -`; - -exports[`should render correctly for applications 2`] = ` -
    -
    -

    - overview.quality_gate - -

    - - overview.quality_gate.help -
    - } - /> -
    -
    -
    -
    - metric.level.ERROR -
    - - overview.X_conditions_failed.1 - -
    -
    - - -
    -
    - - -`; - -exports[`should render correctly for projects 1`] = ` -
    -
    -

    - overview.quality_gate - -

    - - overview.quality_gate.help -
    - } - /> -
    -
    -
    -
    - metric.level.ERROR -
    - - overview.X_conditions_failed.1 - -
    -
    - -
    -
    - - -`; - -exports[`should render correctly for projects 2`] = ` -
    -
    -

    - overview.quality_gate - -

    - - overview.quality_gate.help -
    - } - /> -
    -
    -
    -
    - metric.level.OK -
    - - overview.quality_gate_all_conditions_passed - -
    -
    - - -`; - -exports[`should render correctly for projects 3`] = ` -
    -
    -

    - overview.quality_gate - -

    - - overview.quality_gate.help -
    - } - /> -
    - - - overview.quality_gate.ignored_conditions - - - -
    -
    -
    - metric.level.ERROR -
    - - overview.X_conditions_failed.1 - -
    -
    - -
    -
    - - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap deleted file mode 100644 index 75b980c3018..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/__snapshots__/QualityGatePanelSection-test.tsx.snap +++ /dev/null @@ -1,429 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` -
    -
    - -
    -
    - quality_gates.conditions.new_code_x.1 -
    - -
    - quality_gates.conditions.overall_code_x.1 -
    - -
    -`; - -exports[`should render correctly 2`] = ` -
    - -
    -
    - - - Foo - -
    -
    -
    -
    - quality_gates.conditions.new_code_x.1 -
    - -
    - quality_gates.conditions.overall_code_x.1 -
    - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx index 8c6efe0b26c..ad04df2512f 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx @@ -33,7 +33,7 @@ import BranchOverview from '../branches/BranchOverview'; import PullRequestOverview from '../pullRequests/PullRequestOverview'; import EmptyOverview from './EmptyOverview'; -interface Props extends WithAvailableFeaturesProps { +interface AppProps extends WithAvailableFeaturesProps { branchLike?: BranchLike; branchLikes: BranchLike[]; component: Component; @@ -42,49 +42,43 @@ interface Props extends WithAvailableFeaturesProps { projectBinding?: ProjectAlmBindingResponse; } -export class App extends React.PureComponent { - isPortfolio = () => { - return isPortfolioLike(this.props.component.qualifier); - }; +export function App(props: AppProps) { + const { branchLike, branchLikes, component, projectBinding, isPending, isInProgress } = props; + const branchSupportEnabled = props.hasFeature(Feature.BranchSupport); - render() { - const { branchLike, branchLikes, component, projectBinding } = this.props; - const branchSupportEnabled = this.props.hasFeature(Feature.BranchSupport); - - if (this.isPortfolio()) { - return null; - } + if (isPortfolioLike(component.qualifier)) { + return null; + } - return isPullRequest(branchLike) ? ( -
    - - -
    - ) : ( -
    - + return isPullRequest(branchLike) ? ( +
    + + +
    + ) : ( +
    + - {!component.analysisDate && ( - - )} + {!component.analysisDate && ( + + )} - {component.analysisDate && ( - - )} -
    - ); - } + {component.analysisDate && ( + + )} +
    + ); } export default withComponentContext(withAvailableFeatures(App)); diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx index 0f06690a0f9..df91fada466 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx @@ -18,12 +18,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { FormattedMessage } from 'react-intl'; import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext'; import TutorialSelection from '../../../components/tutorials/TutorialSelection'; import { Alert } from '../../../components/ui/Alert'; import { getBranchLikeDisplayName, isBranch, isMainBranch } from '../../../helpers/branch-like'; -import { translate } from '../../../helpers/l10n'; +import { translate, translateWithParameters } from '../../../helpers/l10n'; import { ProjectAlmBindingResponse } from '../../../types/alm-settings'; import { BranchLike } from '../../../types/branch-like'; import { ComponentQualifier } from '../../../types/component'; @@ -45,7 +44,9 @@ export function EmptyOverview(props: EmptyOverviewProps) { if (component.qualifier === ComponentQualifier.Application) { return (
    - {translate('provisioning.no_analysis.application')} + + {translate('provisioning.no_analysis.application')} +
    ); } else if (!isBranch(branchLike)) { @@ -62,25 +63,15 @@ export function EmptyOverview(props: EmptyOverviewProps) { let warning; if (isLoggedIn(currentUser) && showWarning && hasBadBranchConfig) { - warning = ( - + warning = translateWithParameters( + 'provisioning.no_analysis_on_main_branch.bad_configuration', + getBranchLikeDisplayName(branchLike), + translate('branches.main_branch') ); } else { - warning = ( - + warning = translateWithParameters( + 'provisioning.no_analysis_on_main_branch', + getBranchLikeDisplayName(branchLike) ); } @@ -88,7 +79,11 @@ export function EmptyOverview(props: EmptyOverviewProps) {
    {isLoggedIn(currentUser) ? ( <> - {showWarning && {warning}} + {showWarning && ( + + {warning} + + )} {showTutorial && ( ) : ( - {warning} + + {warning} + )}
    ); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx index e72a1a7e7a4..bb669487c1c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx @@ -17,36 +17,66 @@ * 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 { screen } from '@testing-library/react'; import * as React from 'react'; -import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; -import BranchOverview from '../../branches/BranchOverview'; -import PullRequestOverview from '../../pullRequests/PullRequestOverview'; +import CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider'; +import { mockBranch, mockMainBranch } from '../../../../helpers/mocks/branch-like'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { mockCurrentUser } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { ComponentQualifier } from '../../../../types/component'; import { App } from '../App'; -const component = { - key: 'foo', - analysisDate: '2016-01-01', - breadcrumbs: [], - name: 'Foo', - qualifier: 'TRK', - version: '0.0.1', -}; - -it('should render BranchOverview', () => { - expect(getWrapper().find(BranchOverview).exists()).toBe(true); - expect(getWrapper({ branchLike: mockPullRequest() }).find(PullRequestOverview).exists()).toBe( - true - ); +it('should render Empty Overview for Application with no analysis', async () => { + renderApp({ component: mockComponent({ qualifier: ComponentQualifier.Application }) }); + + expect( + await screen.findByRole('alert', { name: 'provisioning.no_analysis.application' }) + ).toBeInTheDocument(); +}); + +it('should render Empty Overview on main branch with no analysis', async () => { + renderApp({}, mockCurrentUser()); + + expect( + await screen.findByRole('alert', { name: 'provisioning.no_analysis_on_main_branch.master' }) + ).toBeInTheDocument(); +}); + +it('should render Empty Overview on main branch with multiple branches with bad configuration', async () => { + renderApp({ branchLikes: [mockBranch(), mockBranch()] }); + + expect( + await screen.findByRole('alert', { + name: 'provisioning.no_analysis_on_main_branch.bad_configuration.master.branches.main_branch', + }) + ).toBeInTheDocument(); +}); + +it('should not render for portfolios and subportfolios', () => { + const rtl = renderApp({ + component: mockComponent({ qualifier: ComponentQualifier.Portfolio }), + }); + expect(rtl.container).toBeEmptyDOMElement(); + + rtl.unmount(); + + renderApp({ + component: mockComponent({ qualifier: ComponentQualifier.Portfolio }), + }); + expect(rtl.container).toBeEmptyDOMElement(); }); -function getWrapper(props = {}) { - return shallow( - +function renderApp(props = {}, userProps = {}) { + return renderComponent( + + + ); } diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx deleted file mode 100644 index 7ce107ebb02..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockProjectGithubBindingResponse } from '../../../../helpers/mocks/alm-settings'; -import { mockBranch, mockMainBranch, mockPullRequest } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockCurrentUser, mockLoggedInUser } from '../../../../helpers/testMocks'; -import { ComponentQualifier } from '../../../../types/component'; -import { EmptyOverview, EmptyOverviewProps } from '../EmptyOverview'; - -it('renders correctly', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ hasAnalyses: true })).toMatchSnapshot(); - expect(shallowRender({ currentUser: mockCurrentUser() })).toMatchSnapshot(); - expect(shallowRender({ projectBinding: mockProjectGithubBindingResponse() })).toMatchSnapshot(); -}); - -it('should render another message when there are branches', () => { - expect(shallowRender({ branchLikes: [mockMainBranch(), mockBranch()] })).toMatchSnapshot(); - expect( - shallowRender({ - branchLikes: [mockMainBranch(), mockBranch(), mockBranch({ name: 'branch-7.8' })], - }) - ).toMatchSnapshot(); -}); - -it('should not render warning message for pull requests', () => { - expect(shallowRender({ branchLike: mockPullRequest() }).type()).toBeNull(); -}); - -it('should not render the tutorial for applications', () => { - expect( - shallowRender({ component: mockComponent({ qualifier: ComponentQualifier.Application }) }) - ).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx index 8a4474d9e92..f09ee72491c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/IssueLabel-test.tsx @@ -17,74 +17,65 @@ * 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 { screen } from '@testing-library/react'; import * as React from 'react'; import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; import { mockComponent } from '../../../../helpers/mocks/component'; import { mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { IssueType } from '../../../../types/issues'; import { MetricKey } from '../../../../types/metrics'; import { IssueLabel, IssueLabelProps } from '../IssueLabel'; -it('should render correctly for bugs', () => { +it('should render correctly for bugs', async () => { const measures = [ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.bugs }) }), mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_bugs }) }), ]; - expect(shallowRender({ measures })).toMatchSnapshot(); - expect(shallowRender({ measures, useDiffMetric: true })).toMatchSnapshot(); -}); -it('should render correctly for code smells', () => { - const type = IssueType.CodeSmell; - const measures = [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.code_smells }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_code_smells }) }), - ]; - expect(shallowRender({ measures, type })).toMatchSnapshot(); - expect(shallowRender({ measures, type, useDiffMetric: true })).toMatchSnapshot(); -}); + const rtl = renderIssueLabel({ measures }); + expect( + await screen.findByRole('link', { + name: 'overview.see_list_of_x_y_issues.1.0.metric.bugs.name', + }) + ).toBeInTheDocument(); -it('should render correctly for vulnerabilities', () => { - const type = IssueType.Vulnerability; - const measures = [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.vulnerabilities }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_vulnerabilities }) }), - ]; - expect(shallowRender({ measures, type })).toMatchSnapshot(); - expect(shallowRender({ measures, type, useDiffMetric: true })).toMatchSnapshot(); + rtl.unmount(); + + renderIssueLabel({ measures, useDiffMetric: true }); + + expect( + await screen.findByRole('link', { + name: 'overview.see_list_of_x_y_issues.1.0.metric.new_bugs.name', + }) + ).toBeInTheDocument(); }); -it('should render correctly for hotspots', () => { +it('should render correctly for hotspots with tooltip', async () => { const helpTooltip = 'tooltip text'; const type = IssueType.SecurityHotspot; const measures = [ mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.security_hotspots }) }), mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_security_hotspots }) }), ]; + + renderIssueLabel({ + helpTooltip, + measures, + type, + }); + expect( - shallowRender({ - helpTooltip, - measures, - type, - }) - ).toMatchSnapshot(); - expect( - shallowRender({ - helpTooltip, - measures, - type, - useDiffMetric: true, + await screen.findByRole('link', { + name: 'overview.see_list_of_x_y_issues.1.0.metric.security_hotspots.name', }) - ).toMatchSnapshot(); -}); + ).toBeInTheDocument(); -it('should render correctly if no values are present', () => { - expect(shallowRender()).toMatchSnapshot(); + expect(await screen.findByText('tooltip text')).toBeInTheDocument(); }); -function shallowRender(props: Partial = {}) { - return shallow( +function renderIssueLabel(props: Partial = {}) { + return renderComponent( { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ useDiffMetric: true })).toMatchSnapshot(); -}); - -it('should render correctly for code smells', () => { - expect(shallowRender({ type: IssueType.CodeSmell })).toMatchSnapshot(); - expect(shallowRender({ type: IssueType.CodeSmell, useDiffMetric: true })).toMatchSnapshot(); -}); +it('should render correctly for vulnerabilities', async () => { + renderIssueRating({ type: IssueType.Vulnerability }); + expect(await screen.findByText('metric_domain.Security')).toBeInTheDocument(); -it('should render correctly for vulnerabilities', () => { - expect(shallowRender({ type: IssueType.Vulnerability })).toMatchSnapshot(); - expect(shallowRender({ type: IssueType.Vulnerability, useDiffMetric: true })).toMatchSnapshot(); + renderIssueRating({ type: IssueType.Vulnerability, useDiffMetric: true }); + const labels = await screen.findAllByText('metric_domain.Security'); + expect(labels).toHaveLength(2); + const tooltips = await screen.findAllByText('metric.security_rating.tooltip.A'); + expect(tooltips).toHaveLength(2); }); -it('should render correctly if no values are present', () => { - expect( - shallowRender({ - measures: [mockMeasureEnhanced({ metric: mockMetric({ key: 'NONE' }) })], - }) - ).toMatchSnapshot(); +it('should render correctly if no values are present', async () => { + renderIssueRating({ + measures: [mockMeasureEnhanced({ metric: mockMetric({ key: 'NONE' }) })], + }); + expect(await screen.findByText('metric_domain.Reliability')).toBeInTheDocument(); }); -function shallowRender(props: Partial = {}) { - return shallow( +function renderIssueRating(props: Partial = {}) { + return renderComponent( { return { ...actual, differenceInDays: jest.fn().mockReturnValue(10) }; }); -it('10 days', () => { - expect(getWrapper({ mode: 'days', parameter: '10' })).toMatchSnapshot(); +it('10 days', async () => { + renderLeakPeriodLegend({ mode: 'days', parameter: '10' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.days.10') + ).toBeInTheDocument(); }); -it('date', () => { - expect(getWrapper({ mode: 'date', parameter: '2013-01-01' })).toMatchSnapshot(); +it('date', async () => { + renderLeakPeriodLegend({ mode: 'date', parameter: '2013-01-01' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.date.formatted.2013-01-01') + ).toBeInTheDocument(); + expect(await screen.findByText('overview.started_x.9 years ago')).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_on_x\..*/)).toBeInTheDocument(); }); -it('version', () => { - expect(findLegend(getWrapper({ mode: 'version', parameter: '0.1' }))).toMatchSnapshot(); +it('version', async () => { + renderLeakPeriodLegend({ mode: 'version', parameter: '0.1' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.version.0.1') + ).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*/)).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_on_x\..*/)).toBeInTheDocument(); }); -it('previous_version', () => { - expect(findLegend(getWrapper({ mode: 'previous_version' }))).toMatchSnapshot(); +it('previous_version', async () => { + renderLeakPeriodLegend({ mode: 'previous_version' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.previous_version_only_date') + ).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*/)).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_on_x\..*/)).toBeInTheDocument(); }); -it('previous_analysis', () => { - expect(findLegend(getWrapper({ mode: 'previous_analysis' }))).toMatchSnapshot(); +it('previous_analysis', async () => { + renderLeakPeriodLegend({ mode: 'previous_analysis' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.previous_analysis.') + ).toBeInTheDocument(); + expect(await screen.findByText(/overview\.previous_analysis_x\..*/)).toBeInTheDocument(); + expect(await screen.findByText(/overview\.previous_analysis_x\..*/)).toBeInTheDocument(); }); -it('manual_baseline', () => { - expect(findLegend(getWrapper({ mode: 'manual_baseline' }))).toMatchSnapshot(); - expect(findLegend(getWrapper({ mode: 'manual_baseline', parameter: '1.1.2' }))).toMatchSnapshot(); +it('manual_baseline', async () => { + const rtl = renderLeakPeriodLegend({ mode: 'manual_baseline' }); + + expect( + await screen.findByText( + /overview\.new_code_period_x\.overview\.period\.manual_baseline\.formattedTime\..*/ + ) + ).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*/)).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_on_x\..*/)).toBeInTheDocument(); + + rtl.unmount(); + renderLeakPeriodLegend({ mode: 'manual_baseline', parameter: '1.1.2' }); + + expect( + await screen.findByText('overview.new_code_period_x.overview.period.manual_baseline.1.1.2') + ).toBeInTheDocument(); + expect( + await screen.findByText('overview.new_code_period_x.overview.period.manual_baseline.1.1.2') + ).toBeInTheDocument(); }); -it('should render a more precise date', () => { +it('should render a more precise date', async () => { (differenceInDays as jest.Mock).mockReturnValueOnce(0); + + renderLeakPeriodLegend({ date: '2018-08-17T00:00:00+0200', mode: 'previous_version' }); + expect( - getWrapper({ date: '2018-08-17T00:00:00+0200', mode: 'previous_version' }) - ).toMatchSnapshot(); + await screen.findByText('overview.new_code_period_x.overview.period.previous_version_only_date') + ).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_x\..*/)).toBeInTheDocument(); + expect(await screen.findByText(/overview\.started_on_x\..*/)).toBeInTheDocument(); }); -function getWrapper(period: Partial = {}) { - return shallow( +function renderLeakPeriodLegend(period: Partial = {}) { + return renderComponent( = {}) { /> ); } - -function findLegend(wrapper: any) { - return wrapper.find('.overview-legend'); -} diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/MeasurementLabel-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/MeasurementLabel-test.tsx index efc2a98f639..ac51384db5a 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/MeasurementLabel-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/MeasurementLabel-test.tsx @@ -17,78 +17,91 @@ * 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 { screen } from '@testing-library/react'; import * as React from 'react'; import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; import { mockComponent } from '../../../../helpers/mocks/component'; import { mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; import { MetricKey } from '../../../../types/metrics'; import { MeasurementType } from '../../utils'; import MeasurementLabel from '../MeasurementLabel'; -it('should render correctly for coverage', () => { - expect(shallowRender()).toMatchSnapshot(); - expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.lines_to_cover }) }), - ], - }) - ).toMatchSnapshot(); - expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_coverage }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_lines_to_cover }) }), - ], - useDiffMetric: true, - }) - ).toMatchSnapshot(); +it('should render correctly for coverage', async () => { + renderMeasurementLabel(); + expect(await screen.findByText('metric.coverage.name')).toBeInTheDocument(); + + renderMeasurementLabel({ + measures: [ + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.coverage }) }), + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.lines_to_cover }) }), + ], + }); + expect(await screen.findByText('metric.coverage.name')).toBeInTheDocument(); + expect(await screen.findByText('overview.coverage_on_X_lines')).toBeInTheDocument(); + + renderMeasurementLabel({ + measures: [ + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_coverage }) }), + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_lines_to_cover }) }), + ], + useDiffMetric: true, + }); + expect(screen.getByRole('link', { name: /.*new_coverage.*/ })).toBeInTheDocument(); + expect(await screen.findByText('overview.coverage_on_X_lines')).toBeInTheDocument(); + expect(await screen.findByText('overview.coverage_on_X_new_lines')).toBeInTheDocument(); }); -it('should render correctly for duplications', () => { +it('should render correctly for duplications', async () => { + renderMeasurementLabel({ + measures: [ + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.duplicated_lines_density }) }), + ], + type: MeasurementType.Duplication, + }); expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.duplicated_lines_density }) }), - ], - type: MeasurementType.Duplication, + screen.getByRole('link', { + name: 'overview.see_more_details_on_x_of_y.1.0%.metric.duplicated_lines_density.name', }) - ).toMatchSnapshot(); - expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.duplicated_lines_density }) }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.ncloc }) }), - ], - type: MeasurementType.Duplication, - }) - ).toMatchSnapshot(); + ).toBeInTheDocument(); + expect(await screen.findByText('metric.duplicated_lines_density.short_name')).toBeInTheDocument(); + + renderMeasurementLabel({ + measures: [ + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.duplicated_lines_density }) }), + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.ncloc }) }), + ], + type: MeasurementType.Duplication, + }); + expect(await screen.findByText('metric.duplicated_lines_density.short_name')).toBeInTheDocument(); + expect(await screen.findByText('overview.duplications_on_X_lines')).toBeInTheDocument(); + + renderMeasurementLabel({ + measures: [ + mockMeasureEnhanced({ + metric: mockMetric({ key: MetricKey.new_duplicated_lines_density }), + }), + mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_lines }) }), + ], + type: MeasurementType.Duplication, + useDiffMetric: true, + }); + expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ - metric: mockMetric({ key: MetricKey.new_duplicated_lines_density }), - }), - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.new_lines }) }), - ], - type: MeasurementType.Duplication, - useDiffMetric: true, + screen.getByRole('link', { + name: 'overview.see_more_details_on_x_of_y.1.0%.metric.new_duplicated_lines_density.name', }) - ).toMatchSnapshot(); -}); - -it('should render correctly with no value', () => { - expect(shallowRender({ measures: [] })).toMatchSnapshot(); + ).toBeInTheDocument(); + expect(await screen.findByText('overview.duplications_on_X_new_lines')).toBeInTheDocument(); }); -it('should render correctly when centered', () => { - expect(shallowRender({ centered: true })).toMatchSnapshot(); +it('should render correctly with no value', async () => { + renderMeasurementLabel({ measures: [] }); + expect(await screen.findByText('metric.coverage.name')).toBeInTheDocument(); }); -function shallowRender(props: Partial = {}) { - return shallow( +function renderMeasurementLabel(props: Partial = {}) { + return renderComponent( { - expect(shallowRender({ condition })).toMatchSnapshot(); +])('should render correclty', async (condition) => { + renderQualityGateCondition({ condition }); + expect( + await screen.findByText(`metric.${condition.measure.metric.name}.name`) + ).toBeInTheDocument(); + + expect( + await screen.findByText(`quality_gates.operator.${condition.op}`, { exact: false }) + ).toBeInTheDocument(); + // if (condition.measure.metric.type === 'RATING') { + // expect(await screen.findByText('.rating', { exact: false })).toBeInTheDocument(); + // } }); -it('should work with branch', () => { +it('should work with branch', async () => { const condition = quickMock(MetricKey.new_maintainability_rating); - expect(shallowRender({ branchLike: mockBranch(), condition })).toMatchSnapshot(); + renderQualityGateCondition({ branchLike: mockBranch(), condition }); + + expect(await screen.findByText('metric.new_maintainability_rating.name')).toBeInTheDocument(); + expect( + await screen.findByText('quality_gates.operator.GT.rating', { exact: false }) + ).toBeInTheDocument(); }); -function shallowRender(props: Partial) { - return shallow( +function renderQualityGateCondition(props: Partial) { + return renderComponent( { - const wrapper = shallowRender(); - expect(wrapper.find('QualityGateCondition').length).toBe(10); +const ALL_CONDITIONS = 10; +const HALF_CONDITIONS = 5; + +it('should render correctly', async () => { + renderQualityGateConditions(); + expect(await screen.findAllByText(/.*metric..+.name.*/)).toHaveLength(ALL_CONDITIONS); + + expect(await screen.findAllByText('quality_gates.operator', { exact: false })).toHaveLength( + ALL_CONDITIONS + ); }); -it('should be collapsible', () => { - const wrapper = shallowRender({ collapsible: true }); - expect(wrapper.find('QualityGateCondition').length).toBe(5); - click(wrapper.find('ButtonLink')); - expect(wrapper.find('QualityGateCondition').length).toBe(10); +it('should be collapsible', async () => { + renderQualityGateConditions({ collapsible: true }); + const user = userEvent.setup(); + + expect(await screen.findAllByText(/.*metric..+.name.*/)).toHaveLength(HALF_CONDITIONS); + expect(await screen.findAllByText('quality_gates.operator', { exact: false })).toHaveLength( + HALF_CONDITIONS + ); + + await user.click(screen.getByRole('button', { name: 'overview.X_more_failed_conditions.5' })); + + expect(await screen.findAllByText(/.*metric..+.name.*/)).toHaveLength(ALL_CONDITIONS); + expect(await screen.findAllByText('quality_gates.operator', { exact: false })).toHaveLength( + ALL_CONDITIONS + ); }); -function shallowRender(props: Partial = {}) { +function renderQualityGateConditions(props: Partial = {}) { const conditions: QualityGateStatusConditionEnhanced[] = []; - for (let i = 10; i > 0; --i) { - conditions.push(mockQualityGateStatusConditionEnhanced()); + for (let i = ALL_CONDITIONS; i > 0; --i) { + conditions.push( + mockQualityGateStatusConditionEnhanced({ + measure: mockMeasureEnhanced({ metric: mockMetric({ key: i.toString() }) }), + }) + ); } - return shallow( + return renderComponent( ); } diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromition-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromition-test.tsx deleted file mode 100644 index 21e482eb61f..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromition-test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockQualityGateStatusCondition } from '../../../../helpers/mocks/quality-gates'; -import { mockCurrentUser } from '../../../../helpers/testMocks'; -import { MetricKey } from '../../../../types/metrics'; -import { SonarLintPromotion, SonarLintPromotionProps } from '../SonarLintPromotion'; - -it('should render correctly', () => { - expect(shallowRender().type()).toBeNull(); - expect( - shallowRender({ currentUser: mockCurrentUser({ usingSonarLintConnectedMode: true }) }).type() - ).toBeNull(); - expect( - shallowRender({ - qgConditions: [ - mockQualityGateStatusCondition({ metric: MetricKey.new_bugs, level: 'ERROR' }), - ], - }) - ).toMatchSnapshot('has failed condition'); -}); - -it.each( - [ - MetricKey.new_blocker_violations, - MetricKey.new_critical_violations, - MetricKey.new_info_violations, - MetricKey.new_violations, - MetricKey.new_major_violations, - MetricKey.new_minor_violations, - MetricKey.new_code_smells, - MetricKey.new_bugs, - MetricKey.new_vulnerabilities, - MetricKey.new_security_rating, - MetricKey.new_maintainability_rating, - MetricKey.new_reliability_rating, - ].map(Array.of) -)('should show message for %s', (metric) => { - const wrapper = shallowRender({ - qgConditions: [mockQualityGateStatusCondition({ metric: metric as string })], - }); - expect(wrapper.type()).not.toBeNull(); -}); - -function shallowRender(props: Partial = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromotion-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromotion-test.tsx new file mode 100644 index 00000000000..0e31004d2f4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarLintPromotion-test.tsx @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 { mockQualityGateStatusCondition } from '../../../../helpers/mocks/quality-gates'; +import { mockCurrentUser } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { MetricKey } from '../../../../types/metrics'; +import { SonarLintPromotion, SonarLintPromotionProps } from '../SonarLintPromotion'; + +it('should render correctly', () => { + renderSonarLintPromotion(); + expect( + screen.queryByText('overview.fix_failed_conditions_with_sonarlint') + ).not.toBeInTheDocument(); + + renderSonarLintPromotion({ currentUser: mockCurrentUser({ usingSonarLintConnectedMode: true }) }); + expect( + screen.queryByText('overview.fix_failed_conditions_with_sonarlint') + ).not.toBeInTheDocument(); +}); + +it.each( + [ + MetricKey.new_blocker_violations, + MetricKey.new_critical_violations, + MetricKey.new_info_violations, + MetricKey.new_violations, + MetricKey.new_major_violations, + MetricKey.new_minor_violations, + MetricKey.new_code_smells, + MetricKey.new_bugs, + MetricKey.new_vulnerabilities, + MetricKey.new_security_rating, + MetricKey.new_maintainability_rating, + MetricKey.new_reliability_rating, + ].map(Array.of) +)('should show message for %s', async (metric) => { + renderSonarLintPromotion({ + qgConditions: [mockQualityGateStatusCondition({ metric: metric as string })], + }); + + expect( + await screen.findByText('overview.fix_failed_conditions_with_sonarlint') + ).toBeInTheDocument(); +}); + +function renderSonarLintPromotion(props: Partial = {}) { + return renderComponent(); +} diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap deleted file mode 100644 index ef723cf1b24..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap +++ /dev/null @@ -1,179 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
    - -
    -`; - -exports[`renders correctly 2`] = ` -
    -`; - -exports[`renders correctly 3`] = ` -
    - - - -
    -`; - -exports[`renders correctly 4`] = ` -
    - -
    -`; - -exports[`should not render the tutorial for applications 1`] = ` -
    - - provisioning.no_analysis.application - -
    -`; - -exports[`should render another message when there are branches 1`] = ` -
    - - - -
    -`; - -exports[`should render another message when there are branches 2`] = ` -
    - - - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap deleted file mode 100644 index 9780158f073..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueLabel-test.tsx.snap +++ /dev/null @@ -1,198 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for bugs 1`] = ` - - - 1 - - - metric.bugs.name - -`; - -exports[`should render correctly for bugs 2`] = ` - - - 1 - - - metric.new_bugs.name - -`; - -exports[`should render correctly for code smells 1`] = ` - - - 1 - - - metric.code_smells.name - -`; - -exports[`should render correctly for code smells 2`] = ` - - - 1 - - - metric.new_code_smells.name - -`; - -exports[`should render correctly for hotspots 1`] = ` - - - 1 - - - metric.security_hotspots.name - - -`; - -exports[`should render correctly for hotspots 2`] = ` - - - 1 - - - metric.new_security_hotspots.name - - -`; - -exports[`should render correctly for vulnerabilities 1`] = ` - - - 1 - - - metric.vulnerabilities.name - -`; - -exports[`should render correctly for vulnerabilities 2`] = ` - - - 1 - - - metric.new_vulnerabilities.name - -`; - -exports[`should render correctly if no values are present 1`] = ` - - - - metric.bugs.name - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueRating-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueRating-test.tsx.snap deleted file mode 100644 index 9a3ff0faa92..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/IssueRating-test.tsx.snap +++ /dev/null @@ -1,256 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for bugs 1`] = ` - - - metric_domain.Reliability - - - } - > - - - - - - - -`; - -exports[`should render correctly for bugs 2`] = ` - - - metric_domain.Reliability - - - } - > - - - - - - - -`; - -exports[`should render correctly for code smells 1`] = ` - - - metric_domain.Maintainability - - - } - > - - - - - - - -`; - -exports[`should render correctly for code smells 2`] = ` - - - metric_domain.Maintainability - - - } - > - - - - - - - -`; - -exports[`should render correctly for vulnerabilities 1`] = ` - - - metric_domain.Security - - - } - > - - - - - - - -`; - -exports[`should render correctly for vulnerabilities 2`] = ` - - - metric_domain.Security - - - } - > - - - - - - - -`; - -exports[`should render correctly if no values are present 1`] = ` - - - metric_domain.Reliability - -
    - -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.tsx.snap deleted file mode 100644 index 5a16ef23f03..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/LeakPeriodLegend-test.tsx.snap +++ /dev/null @@ -1,128 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`10 days 1`] = ` -
    - overview.new_code_period_x.overview.period.days.10 -
    -`; - -exports[`date 1`] = ` - - [Function] - - } -> -
    - overview.new_code_period_x.overview.period.date.formatted.2013-01-01 -
    - - - -
    -
    -`; - -exports[`manual_baseline 1`] = ` -
    - overview.new_code_period_x.overview.period.manual_baseline.formattedTime.2013-09-22T00:00:00+0200 -
    - - - -
    -`; - -exports[`manual_baseline 2`] = ` -
    - overview.new_code_period_x.overview.period.manual_baseline.1.1.2 -
    - - - -
    -`; - -exports[`previous_analysis 1`] = ` -
    - overview.new_code_period_x.overview.period.previous_analysis. -
    - - - -
    -`; - -exports[`previous_version 1`] = ` -
    - overview.new_code_period_x.overview.period.previous_version_only_date -
    - - - -
    -`; - -exports[`should render a more precise date 1`] = ` - - [Function] - - } -> -
    - overview.new_code_period_x.overview.period.previous_version_only_date -
    - - - -
    -
    -`; - -exports[`version 1`] = ` -
    - overview.new_code_period_x.overview.period.version.0.1 -
    - - - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/MeasurementLabel-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/MeasurementLabel-test.tsx.snap deleted file mode 100644 index 407684f3a3d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/MeasurementLabel-test.tsx.snap +++ /dev/null @@ -1,419 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for coverage 1`] = ` -
    - - - -
    - - - 1.0% - - - - metric.coverage.name - -
    -
    -`; - -exports[`should render correctly for coverage 2`] = ` -
    - - - -
    - - - 1.0% - - - - - 1 - , - } - } - /> - -
    -
    -`; - -exports[`should render correctly for coverage 3`] = ` -
    - - - -
    - - - 1.0% - - - - - 1 - , - } - } - /> - -
    -
    -`; - -exports[`should render correctly for duplications 1`] = ` -
    - - - -
    - - - 1.0% - - - - metric.duplicated_lines_density.short_name - -
    -
    -`; - -exports[`should render correctly for duplications 2`] = ` -
    - - - -
    - - - 1.0% - - - - - 1 - , - } - } - /> - -
    -
    -`; - -exports[`should render correctly for duplications 3`] = ` -
    - - - -
    - - - 1.0% - - - - - 1 - , - } - } - /> - -
    -
    -`; - -exports[`should render correctly when centered 1`] = ` -
    -
    - - - - - 1.0% - -
    -
    - metric.coverage.name -
    -
    -`; - -exports[`should render correctly with no value 1`] = ` -
    - - - metric.coverage.name - -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/QualityGateCondition-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/QualityGateCondition-test.tsx.snap deleted file mode 100644 index 32cc7f8bcb1..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/QualityGateCondition-test.tsx.snap +++ /dev/null @@ -1,477 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correclty 1`] = ` -
  • - -
    -
    - -
    -
    - - - metric.open_issues.name - - - quality_gates.operator.GT - - 1 - -
    -
    -
    -
  • -`; - -exports[`should render correclty 2`] = ` -
  • - -
    -
    - -
    -
    - - - metric.reliability_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 3`] = ` -
  • - -
    -
    - -
    -
    - - - metric.security_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 4`] = ` -
  • - -
    -
    - -
    -
    - - - metric.sqale_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 5`] = ` -
  • - -
    -
    - -
    -
    - - - metric.new_reliability_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 6`] = ` -
  • - -
    -
    - -
    -
    - - - metric.new_security_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 7`] = ` -
  • - -
    -
    - -
    -
    - - - metric.new_maintainability_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 8`] = ` -
  • - -
    -
    - -
    -
    - - - metric.security_hotspots_reviewed.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should render correclty 9`] = ` -
  • - -
    -
    - -
    -
    - - - metric.new_security_hotspots_reviewed.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; - -exports[`should work with branch 1`] = ` -
  • - -
    -
    - -
    -
    - - - metric.new_maintainability_rating.name - - - quality_gates.operator.GT.rating - - A - -
    -
    -
    -
  • -`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarLintPromition-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarLintPromition-test.tsx.snap deleted file mode 100644 index bdabd1b0678..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarLintPromition-test.tsx.snap +++ /dev/null @@ -1,28 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly: has failed condition 1`] = ` -
    - - - SonarLint - - - , - } - } - /> -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/AfterMergeEstimate-test.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/AfterMergeEstimate-test.tsx deleted file mode 100644 index 4ad0ae90ab2..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/AfterMergeEstimate-test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockMeasureEnhanced, mockMetric } from '../../../../helpers/testMocks'; -import { MetricKey } from '../../../../types/metrics'; -import { MeasurementType } from '../../utils'; -import { AfterMergeEstimate, AfterMergeEstimateProps } from '../AfterMergeEstimate'; - -it('should render correctly for coverage', () => { - expect(shallowRender()).toMatchSnapshot(); -}); - -it('should render correctly for duplications', () => { - expect( - shallowRender({ - measures: [ - mockMeasureEnhanced({ metric: mockMetric({ key: MetricKey.duplicated_lines_density }) }), - ], - type: MeasurementType.Duplication, - }) - ).toMatchSnapshot(); -}); - -it('should render correctly with no value', () => { - expect(shallowRender({ measures: [] })).toMatchSnapshot(); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/LargeQualityGateBadge-test.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/LargeQualityGateBadge-test.tsx deleted file mode 100644 index d38dee5239f..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/LargeQualityGateBadge-test.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { mockComponent } from '../../../../helpers/mocks/component'; -import { LargeQualityGateBadge } from '../LargeQualityGateBadge'; - -it('should render correctly for SQ', () => { - expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ level: 'OK' })).toMatchSnapshot(); -}); - -function shallowRender(props = {}) { - return shallow(); -} diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx new file mode 100644 index 00000000000..1be518dd553 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-it.tsx @@ -0,0 +1,177 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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 CurrentUserContextProvider from '../../../../app/components/current-user/CurrentUserContextProvider'; +import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; +import { mockComponent } from '../../../../helpers/mocks/component'; +import { mockQualityGateStatusCondition } from '../../../../helpers/mocks/quality-gates'; +import { mockLoggedInUser, mockMetric, mockPeriod } from '../../../../helpers/testMocks'; +import { renderComponent } from '../../../../helpers/testReactTestingUtils'; +import { ComponentQualifier } from '../../../../types/component'; +import { MetricKey } from '../../../../types/metrics'; +import { PullRequestOverview } from '../PullRequestOverview'; + +jest.mock('../../../../api/measures', () => { + return { + ...jest.requireActual('../../../../types/metrics'), + getMeasuresWithMetrics: jest.fn().mockResolvedValue({ + component: { + key: '', + name: '', + qualifier: ComponentQualifier.Project, + measures: [ + mockQualityGateStatusCondition({ + error: '1.0', + metric: MetricKey.new_coverage, + period: 1, + }), + mockQualityGateStatusCondition({ + error: '1.0', + metric: MetricKey.duplicated_lines, + period: 1, + }), + mockQualityGateStatusCondition({ + error: '3', + metric: MetricKey.new_bugs, + period: 1, + }), + ], + }, + metrics: [ + mockMetric({ key: MetricKey.new_coverage }), + mockMetric({ + key: MetricKey.duplicated_lines, + }), + mockMetric({ + key: MetricKey.new_bugs, + type: 'INT', + }), + ], + period: mockPeriod(), + }), + }; +}); + +jest.mock('../../../../api/quality-gates', () => { + const { mockQualityGateProjectStatus, mockQualityGateApplicationStatus } = jest.requireActual( + '../../../../helpers/mocks/quality-gates' + ); + const { MetricKey } = jest.requireActual('../../../../types/metrics'); + return { + getQualityGateProjectStatus: jest.fn().mockResolvedValue( + mockQualityGateProjectStatus({ + status: 'ERROR', + conditions: [ + { + actualValue: '2', + comparator: 'GT', + errorThreshold: '1', + metricKey: MetricKey.new_reliability_rating, + periodIndex: 1, + status: 'ERROR', + }, + { + actualValue: '5', + comparator: 'GT', + errorThreshold: '2.0', + metricKey: MetricKey.bugs, + periodIndex: 0, + status: 'ERROR', + }, + { + actualValue: '2', + comparator: 'GT', + errorThreshold: '1.0', + metricKey: 'unknown_metric', + periodIndex: 0, + status: 'ERROR', + }, + ], + }) + ), + getApplicationQualityGate: jest.fn().mockResolvedValue(mockQualityGateApplicationStatus()), + }; +}); + +it('should render correctly for a passed QG', async () => { + renderPullRequestOverview({ status: 'OK', conditions: [] }); + + expect(await screen.findByText('metric.level.OK')).toBeInTheDocument(); + expect(screen.queryByText('overview.failed_conditions')).not.toBeInTheDocument(); +}); + +it('should render correctly if conditions are ignored', async () => { + renderPullRequestOverview({ conditions: [], ignoredConditions: true }); + + expect(await screen.findByText('overview.quality_gate.ignored_conditions')).toBeInTheDocument(); +}); + +it('should render correctly for a failed QG', async () => { + renderPullRequestOverview({ + status: 'ERROR', + conditions: [ + mockQualityGateStatusCondition({ + error: '2.0', + metric: MetricKey.new_coverage, + period: 1, + }), + mockQualityGateStatusCondition({ + error: '1.0', + metric: MetricKey.duplicated_lines, + period: 1, + }), + mockQualityGateStatusCondition({ + error: '3', + metric: MetricKey.new_bugs, + period: 1, + }), + ], + }); + + expect(await screen.findByText('metric.level.ERROR')).toBeInTheDocument(); + + expect(await screen.findByText('overview.failed_conditions')).toBeInTheDocument(); + + expect(await screen.findByText('metric.new_coverage.name')).toBeInTheDocument(); + expect(await screen.findByText('quality_gates.operator.GT 2.0%')).toBeInTheDocument(); + + expect(await screen.findByText('metric.duplicated_lines.name')).toBeInTheDocument(); + expect(await screen.findByText('quality_gates.operator.GT 1.0%')).toBeInTheDocument(); + + expect(screen.getByText('quality_gates.operator.GT 3')).toBeInTheDocument(); +}); + +function renderPullRequestOverview(props: Partial = {}) { + renderComponent( + + + + ); +} diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-test.tsx deleted file mode 100644 index 33571956e0d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/PullRequestOverview-test.tsx +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2023 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 { getMeasuresWithMetrics } from '../../../../api/measures'; -import { mockPullRequest } from '../../../../helpers/mocks/branch-like'; -import { mockComponent } from '../../../../helpers/mocks/component'; -import { mockQualityGateStatusCondition } from '../../../../helpers/mocks/quality-gates'; -import { waitAndUpdate } from '../../../../helpers/testUtils'; -import { PR_METRICS } from '../../utils'; -import { PullRequestOverview } from '../PullRequestOverview'; - -jest.mock('../../../../api/measures', () => { - const { mockMeasure, mockMetric } = jest.requireActual('../../../../helpers/testMocks'); - return { - getMeasuresWithMetrics: jest.fn().mockResolvedValue({ - component: { - measures: [ - mockMeasure({ metric: 'new_bugs' }), - mockMeasure({ metric: 'new_vulnerabilities' }), - mockMeasure({ metric: 'new_code_smells' }), - mockMeasure({ metric: 'new_security_hotspots' }), - ], - }, - metrics: [ - mockMetric({ key: 'new_bugs', name: 'new_bugs', id: 'new_bugs' }), - mockMetric({ - key: 'new_vulnerabilities', - name: 'new_vulnerabilities', - id: 'new_vulnerabilities', - }), - mockMetric({ key: 'new_code_smells', name: 'new_code_smells', id: 'new_code_smells' }), - mockMetric({ - key: 'new_security_hotspots', - name: 'new_security_hotspots', - id: 'new_security_hotspots', - }), - ], - }), - }; -}); - -beforeEach(() => { - jest.clearAllMocks(); -}); - -it('should render correctly for a passed QG', async () => { - const fetchBranchStatus = jest.fn(); - - const wrapper = shallowRender({ fetchBranchStatus, status: 'OK' }); - - wrapper.setProps({ conditions: [] }); - - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); - - expect(wrapper.find('QualityGateConditions').exists()).toBe(false); - - expect(getMeasuresWithMetrics).toHaveBeenCalled(); - expect(fetchBranchStatus).toHaveBeenCalled(); -}); - -it('should render correctly if conditions are ignored', async () => { - const wrapper = shallowRender({ conditions: [], ignoredConditions: true }); - await waitAndUpdate(wrapper); - expect(wrapper.find('Alert').exists()).toBe(true); -}); - -it('should render correctly for a failed QG', async () => { - const wrapper = shallowRender({ - status: 'ERROR', - conditions: [ - mockQualityGateStatusCondition({ - error: '1.0', - level: 'OK', - metric: 'new_bugs', - period: 1, - }), - mockQualityGateStatusCondition({ - error: '1.0', - metric: 'new_code_smells', - period: 1, - }), - ], - }); - await waitAndUpdate(wrapper); - expect(wrapper).toMatchSnapshot(); -}); - -it('should correctly fetch all required metrics for a passing QG', async () => { - const wrapper = shallowRender({ conditions: [] }); - await waitAndUpdate(wrapper); - expect(getMeasuresWithMetrics).toHaveBeenCalledWith('my-project', PR_METRICS, expect.any(Object)); -}); - -it('should correctly fetch all required metrics for a failing QG', async () => { - const wrapper = shallowRender({ - conditions: [mockQualityGateStatusCondition({ level: 'ERROR', metric: 'foo' })], - }); - await waitAndUpdate(wrapper); - expect(getMeasuresWithMetrics).toHaveBeenCalledWith( - 'my-project', - [...PR_METRICS, 'foo'], - expect.any(Object) - ); -}); - -function shallowRender(props: Partial = {}) { - return shallow( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/AfterMergeEstimate-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/AfterMergeEstimate-test.tsx.snap deleted file mode 100644 index fd304d0e754..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/AfterMergeEstimate-test.tsx.snap +++ /dev/null @@ -1,37 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for coverage 1`] = ` -
    - - 1.0% - - - component_measures.facet_category.overall_category.estimated - -
    -`; - -exports[`should render correctly for duplications 1`] = ` -
    - - 1.0% - - - component_measures.facet_category.overall_category.estimated - -
    -`; - -exports[`should render correctly with no value 1`] = `""`; diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/LargeQualityGateBadge-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/LargeQualityGateBadge-test.tsx.snap deleted file mode 100644 index 04838bb893d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/LargeQualityGateBadge-test.tsx.snap +++ /dev/null @@ -1,93 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for SQ 1`] = ` -
    -
    - - overview.on_new_code_long - - - overview.quality_gate - , - } - } - /> - } - > - - -
    -
    - metric.level.ERROR -
    -
    -`; - -exports[`should render correctly for SQ 2`] = ` -
    -
    - - overview.on_new_code_long - - - overview.quality_gate - , - } - } - /> - } - > - - -
    -
    - metric.level.OK -
    -
    -`; diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap deleted file mode 100644 index 1a58b5506a1..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/PullRequestOverview-test.tsx.snap +++ /dev/null @@ -1,2653 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly for a failed QG 1`] = ` -
    -
    -
    -
    -

    - overview.quality_gate - - overview.quality_gate.help -

    - } - /> - - - -
    -
    -

    - overview.failed_conditions -

    - -
    -
    -

    - overview.measures -

    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    -
    -`; - -exports[`should render correctly for a passed QG 1`] = ` -
    -
    -
    -
    -

    - overview.quality_gate - - overview.quality_gate.help -

    - } - /> - - - -
    -
    -

    - overview.measures -

    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - -`; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 77c79ed4e49..7489c7bdc5c 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2215,8 +2215,8 @@ my_account.preferences.keyboard_shortcuts.disabled=Keyboard shortcuts are disabl provisioning.no_analysis=No analysis has been performed since creation. The only available section is the configuration. provisioning.no_analysis.delete=Either you should retry analysis or simply {link}. provisioning.no_analysis.delete_project=delete the project -provisioning.no_analysis_on_main_branch="{branchName}" branch has not been analyzed yet. -provisioning.no_analysis_on_main_branch.bad_configuration="{branchName}" branch has not been analyzed yet and you have multiple branches already. It looks like it is not your {branchType}, check your configuration. +provisioning.no_analysis_on_main_branch="{0}" branch has not been analyzed yet. +provisioning.no_analysis_on_main_branch.bad_configuration="{0}" branch has not been analyzed yet and you have multiple branches already. It looks like it is not your {1}, check your configuration. provisioning.only_provisioned=Only Provisioned provisioning.only_provisioned.tooltip=Provisioned projects are projects that have been created, but have not been analyzed yet. provisioning.no_analysis.application=No analysis has been performed since creation. Analyze a project to see information here.