aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWouter Admiraal <wouter.admiraal@sonarsource.com>2019-03-08 10:40:24 +0100
committersonartech <sonartech@sonarsource.com>2019-03-29 09:44:57 +0100
commitc23117124c41e0ad019db3b2c354e55eb3e891fd (patch)
tree32e64bfdd8961f24fc49012874cb02898e439257
parentc19e3ba3d999c51e3d7ef1d4b9f7ec3129a9a12f (diff)
downloadsonarqube-c23117124c41e0ad019db3b2c354e55eb3e891fd.tar.gz
sonarqube-c23117124c41e0ad019db3b2c354e55eb3e891fd.zip
SONAR-10994 Connect ReviewApp component to new branch store
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/LargeQualityGateBadge.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/ReviewApp.tsx31
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/ReviewApp-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/ReviewApp-test.tsx.snap424
4 files changed, 485 insertions, 14 deletions
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/LargeQualityGateBadge.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/LargeQualityGateBadge.tsx
index 78bd963a29b..550a137af4b 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/LargeQualityGateBadge.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/LargeQualityGateBadge.tsx
@@ -30,11 +30,11 @@ import { transparentWhite } from '../../../app/theme';
interface Props {
component: T.Component;
- level?: string;
+ level?: T.Status;
}
export default function LargeQualityGateBadge({ component, level }: Props) {
- const success = level !== 'ERROR';
+ const success = level === 'OK';
let path;
if (isSonarCloud()) {
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/ReviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/ReviewApp.tsx
index a0e47c2853e..f1d413efed9 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/ReviewApp.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/ReviewApp.tsx
@@ -19,6 +19,7 @@
*/
import * as React from 'react';
import * as classNames from 'classnames';
+import { connect } from 'react-redux';
import AfterMergeEstimate from './AfterMergeEstimate';
import LargeQualityGateBadge from './LargeQualityGateBadge';
import IssueLabel from './IssueLabel';
@@ -31,23 +32,25 @@ import { getMeasures } from '../../../api/measures';
import { getQualityGateProjectStatus } from '../../../api/quality-gates';
import { PR_METRICS, IssueType, MeasurementType } from '../utils';
import { getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branches';
-import { translate } from '../../../helpers/l10n';
import { extractStatusConditionsFromProjectStatus } from '../../../helpers/qualityGates';
+import { registerBranchStatus } from '../../../store/rootActions';
+import { translate } from '../../../helpers/l10n';
import '../styles.css';
interface Props {
- branchLike?: T.PullRequest | T.ShortLivingBranch;
+ branchLike: T.PullRequest | T.ShortLivingBranch;
component: T.Component;
+ registerBranchStatus: (branchLike: T.BranchLike, component: string, status: T.Status) => void;
}
interface State {
conditions: T.QualityGateStatusCondition[];
loading: boolean;
measures: T.Measure[];
- status?: string;
+ status?: T.Status;
}
-export default class ReviewApp extends React.Component<Props, State> {
+export class ReviewApp extends React.Component<Props, State> {
mounted = false;
state: State = {
@@ -89,14 +92,17 @@ export default class ReviewApp extends React.Component<Props, State> {
}),
getQualityGateProjectStatus(data)
]).then(
- ([measures, status]) => {
- if (this.mounted && measures && status) {
+ ([measures, qualityGateStatus]) => {
+ if (this.mounted && measures && qualityGateStatus) {
+ const { status } = qualityGateStatus.projectStatus;
this.setState({
- conditions: extractStatusConditionsFromProjectStatus(status),
+ conditions: extractStatusConditionsFromProjectStatus(qualityGateStatus),
loading: false,
measures,
- status: status.projectStatus.status
+ status
});
+
+ this.props.registerBranchStatus(branchLike, component.key, status);
}
},
() => {
@@ -109,7 +115,7 @@ export default class ReviewApp extends React.Component<Props, State> {
render() {
const { branchLike, component } = this.props;
- const { loading, measures, conditions, status } = this.state;
+ const { conditions = [], loading, measures, status } = this.state;
const erroredConditions = conditions.filter(condition => condition.level === 'ERROR');
return (
@@ -192,3 +198,10 @@ export default class ReviewApp extends React.Component<Props, State> {
);
}
}
+
+const mapDispatchToProps = { registerBranchStatus };
+
+export default connect(
+ null,
+ mapDispatchToProps
+)(ReviewApp);
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/ReviewApp-test.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/ReviewApp-test.tsx
index 53e9cbeff46..de6cd3d4a9d 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/ReviewApp-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/ReviewApp-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import ReviewApp from '../ReviewApp';
+import { ReviewApp } from '../ReviewApp';
import { getMeasures } from '../../../../api/measures';
import { getQualityGateProjectStatus } from '../../../../api/quality-gates';
import { mockComponent, mockPullRequest } from '../../../../helpers/testMocks';
@@ -49,8 +49,9 @@ beforeEach(() => {
it('should render correctly for a passed QG', async () => {
const { mockQualityGateProjectStatus } = getMockHelpers();
(getQualityGateProjectStatus as jest.Mock).mockResolvedValue(mockQualityGateProjectStatus());
+ const registerBranchStatus = jest.fn();
+ const wrapper = shallowRender({ registerBranchStatus });
- const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper).toMatchSnapshot();
@@ -58,6 +59,7 @@ it('should render correctly for a passed QG', async () => {
expect(getMeasures).toBeCalled();
expect(getQualityGateProjectStatus).toBeCalled();
+ expect(registerBranchStatus).toBeCalled();
});
it('should render correctly for a failed QG', async () => {
@@ -93,6 +95,33 @@ it('should render correctly for a failed QG', async () => {
expect(wrapper.find('QualityGateConditions').exists()).toBe(true);
});
+it('should correctly refresh data if certain props change', () => {
+ const wrapper = shallowRender();
+
+ jest.clearAllMocks();
+ wrapper.setProps({
+ component: mockComponent({ key: 'foo' })
+ });
+ expect(getMeasures).toBeCalled();
+ expect(getQualityGateProjectStatus).toBeCalled();
+
+ jest.clearAllMocks();
+ wrapper.setProps({
+ branchLike: mockPullRequest({ key: '1002' })
+ });
+ expect(getMeasures).toBeCalled();
+ expect(getQualityGateProjectStatus).toBeCalled();
+});
+
+it('should correctly handle a WS failure', async () => {
+ (getMeasures as jest.Mock).mockRejectedValue({});
+ (getQualityGateProjectStatus as jest.Mock).mockRejectedValue({});
+ 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
@@ -104,6 +133,11 @@ function getMockHelpers() {
function shallowRender(props: Partial<ReviewApp['props']> = {}) {
return shallow(
- <ReviewApp branchLike={mockPullRequest()} component={mockComponent()} {...props} />
+ <ReviewApp
+ branchLike={mockPullRequest()}
+ component={mockComponent()}
+ registerBranchStatus={jest.fn()}
+ {...props}
+ />
);
}
diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/ReviewApp-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/ReviewApp-test.tsx.snap
index 248765d7dee..a850b2f999b 100644
--- a/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/ReviewApp-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/__tests__/__snapshots__/ReviewApp-test.tsx.snap
@@ -1,5 +1,429 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`should correctly handle a WS failure 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="pr-overview"
+ >
+ <div
+ className="pr-overview-quality-gate big-spacer-right"
+ >
+ <h3
+ className="spacer-bottom small"
+ >
+ overview.quality_gate
+ <DocTooltip
+ className="spacer-left"
+ doc={Promise {}}
+ />
+ </h3>
+ <LargeQualityGateBadge
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 [],
+ }
+ }
+ />
+ </div>
+ <div
+ className="pr-overview-measurements flex-1"
+ >
+ <h3
+ className="spacer-bottom small"
+ >
+ overview.metrics
+ </h3>
+ <div
+ className="pr-overview-measurements-row display-flex-row"
+ key="BUG"
+ >
+ <div
+ className="pr-overview-measurements-value flex-1 small display-flex-center"
+ >
+ <IssueLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ className="overview-domain-measure-value"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="BUG"
+ />
+ </div>
+ <div
+ className="pr-overview-measurements-rating display-flex-center"
+ >
+ <IssueRating
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="BUG"
+ />
+ </div>
+ </div>
+ <div
+ className="pr-overview-measurements-row display-flex-row"
+ key="VULNERABILITY"
+ >
+ <div
+ className="pr-overview-measurements-value flex-1 small display-flex-center"
+ >
+ <IssueLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ className="overview-domain-measure-value"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="VULNERABILITY"
+ />
+ </div>
+ <div
+ className="pr-overview-measurements-rating display-flex-center"
+ >
+ <IssueRating
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="VULNERABILITY"
+ />
+ </div>
+ </div>
+ <div
+ className="pr-overview-measurements-row display-flex-row"
+ key="CODE_SMELL"
+ >
+ <div
+ className="pr-overview-measurements-value flex-1 small display-flex-center"
+ >
+ <IssueLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ className="overview-domain-measure-value"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="CODE_SMELL"
+ />
+ </div>
+ <div
+ className="pr-overview-measurements-rating display-flex-center"
+ >
+ <IssueRating
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="CODE_SMELL"
+ />
+ </div>
+ </div>
+ <div
+ className="pr-overview-measurements-row display-flex-row"
+ key="COVERAGE"
+ >
+ <div
+ className="pr-overview-measurements-value flex-1 small display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ className="overview-domain-measure-value"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="COVERAGE"
+ />
+ </div>
+ <div
+ className="pr-overview-measurements-estimate display-flex-center"
+ >
+ <AfterMergeEstimate
+ measures={Array []}
+ type="COVERAGE"
+ />
+ </div>
+ </div>
+ <div
+ className="pr-overview-measurements-row display-flex-row"
+ key="DUPLICATION"
+ >
+ <div
+ className="pr-overview-measurements-value flex-1 small display-flex-center"
+ >
+ <MeasurementLabel
+ branchLike={
+ Object {
+ "analysisDate": "2018-01-01",
+ "base": "master",
+ "branch": "feature/foo/bar",
+ "key": "1001",
+ "title": "Foo Bar feature",
+ }
+ }
+ className="overview-domain-measure-value"
+ component={
+ Object {
+ "breadcrumbs": Array [],
+ "key": "my-project",
+ "name": "MyProject",
+ "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 []}
+ type="DUPLICATION"
+ />
+ </div>
+ <div
+ className="pr-overview-measurements-estimate display-flex-center"
+ >
+ <AfterMergeEstimate
+ measures={Array []}
+ type="DUPLICATION"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+`;
+
exports[`should render correctly for a failed QG 1`] = `
<div
className="page page-limited"