@@ -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} | |||
/> | |||
); | |||
} |
@@ -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> | |||
`; |
@@ -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 | |||
}); | |||
}); | |||
}); |
@@ -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 | |||
}); | |||
}); | |||
}); | |||
}); |
@@ -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; |
@@ -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>; |
@@ -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} | |||
/> | |||
); | |||
} |
@@ -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> | |||
`; |
@@ -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' }} |
@@ -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} />); | |||
} |
@@ -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 />`; |
@@ -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 */ |
@@ -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 | |||
}; | |||
} |