Browse Source

Add tests for untested components

tags/7.8
Wouter Admiraal 5 years ago
parent
commit
c7bfd7c962

+ 117
- 0
server/sonar-web/src/main/js/apps/overview/components/__tests__/OverviewApp-test.tsx View File

@@ -0,0 +1,117 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { shallow } from 'enzyme';
import { OverviewApp } from '../OverviewApp';
import { getMeasuresAndMeta } from '../../../../api/measures';
import { getAllTimeMachineData } from '../../../../api/time-machine';
import {
mockMainBranch,
mockComponent,
mockMetric,
mockMeasure
} from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';

jest.mock('../../../../api/measures', () => {
const { mockMeasure, mockMetric } = getMockHelpers();
return {
getMeasuresAndMeta: jest.fn().mockResolvedValue({
component: {
measures: [mockMeasure({ metric: 'ncloc' }), mockMeasure({ metric: 'coverage' })],
name: 'foo'
},
metrics: [mockMetric({ key: 'ncloc' }), mockMetric()]
})
};
});

jest.mock('../../../../helpers/dates', () => ({
parseDate: jest.fn(date => date)
}));

jest.mock('../../../../api/time-machine', () => ({
getAllTimeMachineData: jest.fn().mockResolvedValue({
measures: [
{
metric: 'sqale_index',
history: [{ date: '2019-01-01', value: '1.0' }]
},
{
metric: 'duplicated_lines_density',
history: [{ date: '2019-01-02', value: '1.0' }]
},
{
metric: 'ncloc',
history: [{ date: '2019-01-03', value: '10000' }]
},
{
metric: 'coverage',
history: [{ date: '2019-01-04', value: '95.5' }]
}
]
})
}));

it('should render correctly', async () => {
const wrapper = shallowRender();
expect(wrapper).toMatchSnapshot();

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
expect(getMeasuresAndMeta).toBeCalled();
expect(getAllTimeMachineData).toBeCalled();
});

it('should render correctly if no measures are found', async () => {
(getMeasuresAndMeta as jest.Mock).mockResolvedValue({
component: {
measures: [mockMeasure({ metric: 'coverage' })],
name: 'foo'
},
metrics: [mockMetric()]
});
const wrapper = shallowRender();

await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
});

function getMockHelpers() {
// We use this little "force-requiring" instead of an import statement in
// order to prevent a hoisting race condition while mocking. If we want to use
// a mock helper in a Jest mock, we have to require it like this. Otherwise,
// we get errors like:
// ReferenceError: testMocks_1 is not defined
return require.requireActual('../../../../helpers/testMocks');
}

function shallowRender(props: Partial<OverviewApp['props']> = {}) {
return shallow(
<OverviewApp
branchLike={mockMainBranch()}
component={mockComponent({ name: 'foo' })}
fetchMetrics={jest.fn()}
metrics={{ coverage: mockMetric() }}
onComponentChange={jest.fn()}
{...props}
/>
);
}

+ 729
- 0
server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/OverviewApp-test.tsx.snap View File

@@ -0,0 +1,729 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<div
className="text-center"
>
<i
className="spinner spinner-margin"
/>
</div>
`;

exports[`should render correctly 2`] = `
<div
className="page page-limited"
>
<div
className="overview page-with-sidebar"
>
<A11ySkipTarget
anchor="overview_main"
/>
<div
className="overview-main page-main"
>
<QualityGate
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
<div
className="overview-domains-list"
>
<enhance(undefined)}
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
historyStartDate="2019-01-01"
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
<enhance(undefined)}
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
historyStartDate="2019-01-01"
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
<enhance(undefined)}
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
historyStartDate="2019-01-01"
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
<enhance(undefined)}
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
historyStartDate="2019-01-01"
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
/>
</div>
</div>
<div
className="overview-sidebar page-sidebar-fixed"
>
<Connect(Meta)
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "ncloc",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
metrics={
Object {
"coverage": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
}
}
onComponentChange={[MockFunction]}
/>
</div>
</div>
</div>
`;

exports[`should render correctly if no measures are found 1`] = `
<div
className="page page-limited"
>
<div
className="overview page-with-sidebar"
>
<A11ySkipTarget
anchor="overview_main"
/>
<div
className="overview-main page-main"
>
<h3>
overview.project.empty
</h3>
</div>
<div
className="overview-sidebar page-sidebar-fixed"
>
<Connect(Meta)
branchLike={
Object {
"analysisDate": "2018-01-01",
"isMain": true,
"name": "master",
}
}
component={
Object {
"breadcrumbs": Array [],
"key": "my-project",
"name": "foo",
"organization": "foo",
"qualifier": "TRK",
"qualityGate": Object {
"isDefault": true,
"key": "30",
"name": "Sonar way",
},
"qualityProfiles": Array [
Object {
"deleted": false,
"key": "my-qp",
"language": "ts",
"name": "Sonar way",
},
],
"tags": Array [],
}
}
history={
Object {
"coverage": Array [
Object {
"date": "2019-01-04",
"value": "95.5",
},
],
"duplicated_lines_density": Array [
Object {
"date": "2019-01-02",
"value": "1.0",
},
],
"ncloc": Array [
Object {
"date": "2019-01-03",
"value": "10000",
},
],
"sqale_index": Array [
Object {
"date": "2019-01-01",
"value": "1.0",
},
],
}
}
measures={
Array [
Object {
"bestValue": true,
"metric": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
"periods": Array [
Object {
"bestValue": true,
"index": 1,
"value": "1.0",
},
],
"value": "1.0",
},
]
}
metrics={
Object {
"coverage": Object {
"id": "coverage",
"key": "coverage",
"name": "Coverage",
"type": "PERCENT",
},
}
}
onComponentChange={[MockFunction]}
/>
</div>
</div>
</div>
`;

+ 34
- 0
server/sonar-web/src/main/js/apps/portfolio/__tests__/utils-test.ts View File

@@ -0,0 +1,34 @@
/*
* SonarQube
* Copyright (C) 2009-2019 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 { convertMeasures } from '../utils';
import { mockMeasure } from '../../../helpers/testMocks';

describe('convertMeasures', () => {
it('should correctly transform a list of metrics to a dictionary', () => {
const metrics = [
mockMeasure({ metric: 'bugs', value: '1' }),
mockMeasure({ metric: 'vulnerabilities', value: undefined })
];
expect(convertMeasures(metrics)).toEqual({
bugs: '1',
vulnerabilities: undefined
});
});
});

+ 73
- 0
server/sonar-web/src/main/js/apps/projects/__tests__/utils-test.ts View File

@@ -18,6 +18,25 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as utils from '../utils';
import { searchProjects } from '../../../api/components';
import { mockOrganization, mockComponent } from '../../../helpers/testMocks';

jest.mock('../../../api/components', () => ({
searchProjects: jest.fn().mockResolvedValue({ components: [], facets: [], paging: { total: 10 } })
}));

jest.mock('../../../api/measures', () => ({
getMeasuresForProjects: jest
.fn()
.mockResolvedValue([
{ component: 'foo', metric: 'new_coverage', periods: [{ index: 1, value: '10' }] },
{ component: 'bar', metric: 'languages', value: '20' }
])
}));

jest.mock('../../../api/organizations', () => ({
getOrganizations: jest.fn().mockResolvedValue({})
}));

describe('localizeSorting', () => {
it('localizes default sorting', () => {
@@ -69,3 +88,57 @@ describe('formatDuration', () => {
expect(utils.formatDuration(1000)).toEqual('duration.seconds');
});
});

describe('fetchProjects', () => {
it('correctly converts the passed arguments to the desired query format', async () => {
await utils.fetchProjects({ view: 'visualizations' }, true, mockOrganization());
expect(searchProjects).toBeCalledWith({
f: 'analysisDate,leakPeriodDate',
facets: utils.FACETS.join(),
filter: 'isFavorite',
organization: 'foo',
p: undefined,
ps: 99
});

await utils.fetchProjects({ view: 'leak' }, false, mockOrganization({ key: 'bar' }), 3);
expect(searchProjects).toBeCalledWith({
f: 'analysisDate,leakPeriodDate',
facets: utils.LEAK_FACETS.join(),
organization: 'bar',
p: 3,
ps: 50
});
});

it('correctly treats result data', async () => {
const components = [mockComponent({ key: 'foo' }), mockComponent({ key: 'bar' })];
const organization = mockOrganization();
(searchProjects as jest.Mock).mockResolvedValue({
components,
facets: [
{ property: 'new_coverage', values: [{ val: 'NO_DATA', count: 0 }] },
{ property: 'languages', values: [{ val: 'css', count: 10 }, { val: 'js', count: 2 }] }
],
paging: { total: 2 }
});
await utils.fetchProjects({ view: 'visualizations' }, true, organization).then(r => {
expect(r).toEqual({
facets: {
new_coverage: { NO_DATA: 0 },
languages: { css: 10, js: 2 }
},
projects: components.map((component: any) => {
component.organization = organization;
if (component.key === 'foo') {
component.measures = { new_coverage: '10' };
} else {
component.measures = { languages: '20' };
}
return component;
}),
total: 2
});
});
});
});

+ 3
- 3
server/sonar-web/src/main/js/apps/projects/utils.ts View File

@@ -125,7 +125,7 @@ const METRICS_BY_VISUALIZATION: T.Dict<string[]> = {
duplications: ['ncloc', 'duplicated_lines_density', 'duplicated_blocks']
};

const FACETS = [
export const FACETS = [
'reliability_rating',
'security_rating',
'sqale_rating',
@@ -137,7 +137,7 @@ const FACETS = [
'tags'
];

const LEAK_FACETS = [
export const LEAK_FACETS = [
'new_reliability_rating',
'new_security_rating',
'new_maintainability_rating',
@@ -232,7 +232,7 @@ function convertToQueryData(
) {
const data: RequestData = { ...defaultData, organization };
const filter = convertToFilter(query, isFavorite);
const sort = convertToSorting(query as any);
const sort = convertToSorting(query);

if (filter) {
data.filter = filter;

+ 3
- 2
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx View File

@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import { groupBy, pick, sortBy } from 'lodash';
import { Location } from 'history';
import ProfilesListRow from './ProfilesListRow';
import ProfilesListHeader from './ProfilesListHeader';
import DocTooltip from '../../../components/docs/DocTooltip';
@@ -27,8 +28,8 @@ import { Profile } from '../types';
import { Alert } from '../../../components/ui/Alert';

interface Props {
languages: Array<{ key: string; name: string }>;
location: { query: T.Dict<string> };
languages: T.Language[];
location: Pick<Location, 'query'>;
organization: string | null;
profiles: Profile[];
updateProfiles: () => Promise<void>;

+ 51
- 0
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/ProfilesList-test.tsx View File

@@ -0,0 +1,51 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { shallow } from 'enzyme';
import ProfilesList from '../ProfilesList';
import { mockLanguage, mockLocation, mockQualityProfile } from '../../../../helpers/testMocks';

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();

expect(
shallowRender({ location: mockLocation({ query: { language: 'css' } }) })
).toMatchSnapshot();

expect(
shallowRender({ location: mockLocation({ query: { language: 'unknown' } }) })
).toMatchSnapshot();
});

function shallowRender(props: Partial<ProfilesList['props']> = {}) {
return shallow(
<ProfilesList
languages={[mockLanguage(), mockLanguage({ key: 'js', name: 'JS' })]}
location={mockLocation()}
organization="foo"
profiles={[
mockQualityProfile(),
mockQualityProfile({ language: 'css', languageName: 'CSS' })
]}
updateProfiles={jest.fn()}
{...props}
/>
);
}

+ 279
- 0
server/sonar-web/src/main/js/apps/quality-profiles/home/__tests__/__snapshots__/ProfilesList-test.tsx.snap View File

@@ -0,0 +1,279 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<div>
<withRouter(ProfilesListHeader)
languages={
Array [
Object {
"key": "css",
"name": "CSS",
},
Object {
"key": "js",
"name": "JS",
},
]
}
organization="foo"
/>
<div
className="boxed-group boxed-group-inner quality-profiles-table"
key="css"
>
<table
className="data zebra zebra-hover"
data-language="css"
>
<thead>
<tr>
<th>
CSS
,
quality_profiles.x_profiles.1
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.projects
<DocTooltip
className="table-cell-doc"
doc={Promise {}}
/>
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.rules
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.updated
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.used
</th>
<th>
 
</th>
</tr>
</thead>
<tbody>
<ProfilesListRow
key="key"
organization="foo"
profile={
Object {
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "key",
"language": "css",
"languageName": "CSS",
"name": "name",
"organization": "foo",
"projectCount": 3,
}
}
updateProfiles={[MockFunction]}
/>
</tbody>
</table>
</div>
<div
className="boxed-group boxed-group-inner quality-profiles-table"
key="js"
>
<table
className="data zebra zebra-hover"
data-language="js"
>
<thead>
<tr>
<th>
JS
,
quality_profiles.x_profiles.1
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.projects
<DocTooltip
className="table-cell-doc"
doc={Promise {}}
/>
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.rules
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.updated
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.used
</th>
<th>
 
</th>
</tr>
</thead>
<tbody>
<ProfilesListRow
key="key"
organization="foo"
profile={
Object {
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "key",
"language": "js",
"languageName": "JavaScript",
"name": "name",
"organization": "foo",
"projectCount": 3,
}
}
updateProfiles={[MockFunction]}
/>
</tbody>
</table>
</div>
</div>
`;

exports[`should render correctly 2`] = `
<div>
<withRouter(ProfilesListHeader)
currentFilter="css"
languages={
Array [
Object {
"key": "css",
"name": "CSS",
},
Object {
"key": "js",
"name": "JS",
},
]
}
organization="foo"
/>
<div
className="boxed-group boxed-group-inner quality-profiles-table"
key="css"
>
<table
className="data zebra zebra-hover"
data-language="css"
>
<thead>
<tr>
<th>
CSS
,
quality_profiles.x_profiles.1
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.projects
<DocTooltip
className="table-cell-doc"
doc={Promise {}}
/>
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.rules
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.updated
</th>
<th
className="text-right nowrap"
>
quality_profiles.list.used
</th>
<th>
 
</th>
</tr>
</thead>
<tbody>
<ProfilesListRow
key="key"
organization="foo"
profile={
Object {
"activeDeprecatedRuleCount": 2,
"activeRuleCount": 10,
"childrenCount": 0,
"depth": 1,
"isBuiltIn": false,
"isDefault": false,
"isInherited": false,
"key": "key",
"language": "css",
"languageName": "CSS",
"name": "name",
"organization": "foo",
"projectCount": 3,
}
}
updateProfiles={[MockFunction]}
/>
</tbody>
</table>
</div>
</div>
`;

exports[`should render correctly 3`] = `
<div>
<withRouter(ProfilesListHeader)
currentFilter="unknown"
languages={
Array [
Object {
"key": "css",
"name": "CSS",
},
Object {
"key": "js",
"name": "JS",
},
]
}
organization="foo"
/>
<Alert
className="spacer-top"
variant="warning"
>
no_results
</Alert>
</div>
`;

+ 8
- 8
server/sonar-web/src/main/js/components/icons-components/TestStatusIcon.tsx View File

@@ -39,9 +39,9 @@ export default function TestStatusIcon(props: Props) {
return Icon ? <Icon className={props.className} /> : null;
}

function OkTestStatusIcon({ className, size }: IconProps) {
function OkTestStatusIcon({ className }: IconProps) {
return (
<Icon className={className} size={size}>
<Icon className={className}>
<path
d="M12.03 6.734a.49.49 0 0 0-.14-.36l-.71-.702a.48.48 0 0 0-.352-.15.474.474 0 0 0-.35.15l-3.19 3.18-1.765-1.766a.479.479 0 0 0-.35-.15.479.479 0 0 0-.353.15l-.71.703a.482.482 0 0 0-.14.358c0 .14.046.258.14.352l2.828 2.828c.098.1.216.15.35.15.142 0 .26-.05.36-.15l4.243-4.242a.475.475 0 0 0 .14-.352l-.001.001zM14 8c0 1.09-.268 2.092-.805 3.012a5.96 5.96 0 0 1-2.183 2.183A5.863 5.863 0 0 1 8 14a5.863 5.863 0 0 1-3.012-.805 5.96 5.96 0 0 1-2.183-2.183A5.863 5.863 0 0 1 2 8c0-1.09.268-2.092.805-3.012a5.96 5.96 0 0 1 2.183-2.183A5.863 5.863 0 0 1 8 2c1.09 0 2.092.268 3.012.805a5.96 5.96 0 0 1 2.183 2.183C13.732 5.908 14 6.91 14 8z"
style={{ fill: theme.green }}
@@ -50,9 +50,9 @@ function OkTestStatusIcon({ className, size }: IconProps) {
);
}

function FailureTestStatusIcon({ className, size }: IconProps) {
function FailureTestStatusIcon({ className }: IconProps) {
return (
<Icon className={className} size={size}>
<Icon className={className}>
<path
d="M8 14c-3.311 0-6-2.689-6-6s2.689-6 6-6 6 2.689 6 6-2.689 6-6 6zM7 9h2V4H7v5zm0 3h2v-2H7v2z"
style={{ fill: theme.orange, fillRule: 'nonzero' }}
@@ -61,9 +61,9 @@ function FailureTestStatusIcon({ className, size }: IconProps) {
);
}

function ErrorTestStatusIcon({ className, size }: IconProps) {
function ErrorTestStatusIcon({ className }: IconProps) {
return (
<Icon className={className} size={size}>
<Icon className={className}>
<path
d="M10.977 9.766a.497.497 0 0 0-.149-.352L9.414 8l1.414-1.414a.497.497 0 0 0 0-.711l-.703-.703a.497.497 0 0 0-.71 0L8 6.586 6.586 5.172a.497.497 0 0 0-.711 0l-.703.703a.497.497 0 0 0 0 .71L6.586 8 5.172 9.414a.497.497 0 0 0 0 .711l.703.703a.497.497 0 0 0 .71 0L8 9.414l1.414 1.414a.497.497 0 0 0 .711 0l.703-.703a.515.515 0 0 0 .149-.36zM14 8c0 3.313-2.688 6-6 6-3.313 0-6-2.688-6-6 0-3.313 2.688-6 6-6 3.313 0 6 2.688 6 6z"
style={{ fill: theme.red, fillRule: 'nonzero' }}
@@ -72,9 +72,9 @@ function ErrorTestStatusIcon({ className, size }: IconProps) {
);
}

function SkippedTestStatusIcon({ className, size }: IconProps) {
function SkippedTestStatusIcon({ className }: IconProps) {
return (
<Icon className={className} size={size}>
<Icon className={className}>
<path
d="M11.5 8.5v-1c0-.273-.227-.5-.5-.5H5c-.273 0-.5.227-.5.5v1c0 .273.227.5.5.5h6c.273 0 .5-.227.5-.5zM14 8c0 3.313-2.688 6-6 6-3.313 0-6-2.688-6-6 0-3.313 2.688-6 6-6 3.313 0 6 2.688 6 6z"
style={{ fill: theme.gray71, fillRule: 'nonzero' }}

+ 33
- 0
server/sonar-web/src/main/js/components/icons-components/__tests__/TestStatusIcon-test.tsx View File

@@ -0,0 +1,33 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
import { shallow } from 'enzyme';
import TestStatusIcon from '../TestStatusIcon';

it('should render correctly', () => {
expect(shallowRender('OK')).toMatchSnapshot();
expect(shallowRender('failure')).toMatchSnapshot();
expect(shallowRender('skipped')).toMatchSnapshot();
expect(shallowRender('Error')).toMatchSnapshot();
});

function shallowRender(status: string) {
return shallow(<TestStatusIcon status={status} />);
}

+ 9
- 0
server/sonar-web/src/main/js/components/icons-components/__tests__/__snapshots__/TestStatusIcon-test.tsx.snap View File

@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `<OkTestStatusIcon />`;

exports[`should render correctly 2`] = `<FailureTestStatusIcon />`;

exports[`should render correctly 3`] = `<SkippedTestStatusIcon />`;

exports[`should render correctly 4`] = `<ErrorTestStatusIcon />`;

+ 7
- 4
server/sonar-web/src/main/js/helpers/measures.ts View File

@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { translate, translateWithParameters, getCurrentLocale } from './l10n';
import { isDefined } from './types';

const HOURS_IN_DAY = 8;

@@ -54,10 +55,12 @@ export function enhanceMeasuresWithMetrics(
measures: T.Measure[],
metrics: T.Metric[]
): T.MeasureEnhanced[] {
return measures.map(measure => {
const metric = metrics.find(metric => metric.key === measure.metric) as T.Metric;
return { ...measure, metric };
});
return measures
.map(measure => {
const metric = metrics.find(metric => metric.key === measure.metric);
return metric && { ...measure, metric };
})
.filter(isDefined);
}

/** Get period value of a measure */

+ 18
- 0
server/sonar-web/src/main/js/helpers/testMocks.ts View File

@@ -218,6 +218,16 @@ export function mockLocation(overrides: Partial<Location> = {}): Location {
};
}

export function mockMetric(overrides: Partial<T.Metric> = {}): T.Metric {
return {
id: 'coverage',
key: 'coverage',
name: 'Coverage',
type: 'PERCENT',
...overrides
};
}

export function mockMeasure(overrides: Partial<T.Measure> = {}): T.Measure {
return {
bestValue: true,
@@ -394,3 +404,11 @@ export function mockMainBranch(overrides: Partial<T.MainBranch> = {}): T.MainBra
...overrides
};
}

export function mockLanguage(overrides: Partial<T.Language> = {}): T.Language {
return {
key: 'css',
name: 'CSS',
...overrides
};
}

Loading…
Cancel
Save