*/
import { request } from '../helpers/request';
-export function login(login: string, password: string): Promise<Response> {
+export function logIn(login: string, password: string): Promise<Response> {
return request('/api/authentication/login')
.setMethod('POST')
.setData({ login, password })
.then(basicCheckStatus);
}
-export function logout(): Promise<Response> {
+export function logOut(): Promise<Response> {
return request('/api/authentication/logout')
.setMethod('POST')
.submit()
} from '../../helpers/branch-like';
import { HttpStatus } from '../../helpers/request';
import { getPortfolioUrl } from '../../helpers/urls';
-import { registerBranchStatus } from '../../store/rootActions';
+import { registerBranchStatus } from '../../store/branches';
import {
ProjectAlmBindingConfigurationErrors,
ProjectAlmBindingResponse
import { isPullRequest, isSameBranchLike } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import { getCodeUrl, getProjectUrl } from '../../../helpers/urls';
-import { fetchBranchStatus } from '../../../store/rootActions';
+import { fetchBranchStatus } from '../../../store/branches';
import { BranchLike } from '../../../types/branch-like';
import { isPortfolioLike } from '../../../types/component';
import { Breadcrumb, Component, ComponentMeasure, Dict, Issue, Metric } from '../../../types/types';
removeSideBarClass,
removeWhitePageClass
} from '../../../helpers/pages';
-import { fetchBranchStatus } from '../../../store/rootActions';
+import { fetchBranchStatus } from '../../../store/branches';
import { BranchLike } from '../../../types/branch-like';
import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
import {
import { withRouter } from '../../../components/hoc/withRouter';
import { lazyLoadComponent } from '../../../components/lazyLoadComponent';
import { parseIssueFromResponse } from '../../../helpers/issues';
-import { fetchBranchStatus } from '../../../store/rootActions';
+import { fetchBranchStatus } from '../../../store/branches';
import { Store } from '../../../store/rootReducer';
import { FetchIssuesPromise } from '../../../types/issues';
import { RawQuery } from '../../../types/types';
*/
import { connect } from 'react-redux';
import { searchIssues } from '../../../../api/issues';
-import { fetchBranchStatus } from '../../../../store/rootActions';
+import { fetchBranchStatus } from '../../../../store/branches';
import '../AppContainer';
jest.mock('react-redux', () => ({
import { translate } from '../../../helpers/l10n';
import { enhanceConditionWithMeasure, enhanceMeasuresWithMetrics } from '../../../helpers/measures';
import { isDefined } from '../../../helpers/types';
-import { fetchBranchStatus } from '../../../store/rootActions';
+import { fetchBranchStatus } from '../../../store/branches';
import { getBranchStatusByBranchLike, Store } from '../../../store/rootReducer';
import { BranchLike, PullRequest } from '../../../types/branch-like';
import { IssueType } from '../../../types/issues';
import { KeyboardCodes, KeyboardKeys } from '../../helpers/keycodes';
import { scrollToElement } from '../../helpers/scrolling';
import { getStandards } from '../../helpers/security-standard';
-import { fetchBranchStatus } from '../../store/rootActions';
+import { fetchBranchStatus } from '../../store/branches';
import { BranchLike } from '../../types/branch-like';
import { SecurityStandard, Standards } from '../../types/security';
import {
*/
import { Location } from 'history';
import * as React from 'react';
-import { connect } from 'react-redux';
+import { logIn } from '../../../api/auth';
import { getIdentityProviders } from '../../../api/users';
+import addGlobalErrorMessage from '../../../app/utils/addGlobalErrorMessage';
import { getReturnUrl } from '../../../helpers/urls';
-import { doLogin } from '../../../store/rootActions';
import { IdentityProvider } from '../../../types/types';
import Login from './Login';
-interface OwnProps {
+interface Props {
location: Pick<Location, 'hash' | 'pathname' | 'query'> & {
query: { advanced?: string; return_to?: string };
};
}
-
-interface DispatchToProps {
- doLogin: (login: string, password: string) => Promise<void>;
-}
-
-type Props = OwnProps & DispatchToProps;
-
interface State {
identityProviders?: IdentityProvider[];
}
this.setState({ identityProviders });
}
},
- () => {}
+ () => {
+ /* already handled */
+ }
);
}
window.location.href = getReturnUrl(this.props.location);
};
- handleSubmit = (login: string, password: string) => {
- return this.props.doLogin(login, password).then(this.handleSuccessfulLogin, () => {});
+ handleSubmit = (id: string, password: string) => {
+ return logIn(id, password)
+ .then(this.handleSuccessfulLogin)
+ .catch(() => {
+ addGlobalErrorMessage('Authentication failed');
+ return Promise.reject();
+ });
};
render() {
}
}
-const mapStateToProps = null;
-const mapDispatchToProps = { doLogin: doLogin as any };
-
-export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer);
+export default LoginContainer;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { connect } from 'react-redux';
+import { logOut } from '../../../api/auth';
import GlobalMessagesContainer from '../../../app/components/GlobalMessagesContainer';
import RecentHistory from '../../../app/components/RecentHistory';
+import addGlobalErrorMessage from '../../../app/utils/addGlobalErrorMessage';
import { translate } from '../../../helpers/l10n';
import { getBaseUrl } from '../../../helpers/system';
-import { doLogout } from '../../../store/rootActions';
-interface Props {
- doLogout: () => Promise<void>;
-}
-
-export class Logout extends React.PureComponent<Props> {
+export class Logout extends React.PureComponent<{}> {
componentDidMount() {
- this.props.doLogout().then(
- () => {
+ logOut()
+ .then(() => {
RecentHistory.clear();
window.location.replace(getBaseUrl() + '/');
- },
- () => {}
- );
+ })
+ .catch(() => {
+ addGlobalErrorMessage('Logout failed');
+ });
}
render() {
}
}
-const mapStateToProps = () => ({});
-
-const mapDispatchToProps = { doLogout };
-
-export default connect(mapStateToProps, mapDispatchToProps)(Logout as any);
+export default Logout;
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { logIn } from '../../../../api/auth';
import { getIdentityProviders } from '../../../../api/users';
import { mockLocation } from '../../../../helpers/testMocks';
import { waitAndUpdate } from '../../../../helpers/testUtils';
};
});
+jest.mock('../../../../api/auth', () => ({
+ logIn: jest.fn().mockResolvedValue({})
+}));
+
beforeEach(jest.clearAllMocks);
it('should render correctly', async () => {
});
it('should handle submission', () => {
- const doLogin = jest.fn().mockResolvedValue(null);
- const wrapper = shallowRender({ doLogin });
+ (logIn as jest.Mock).mockResolvedValue(null);
+ const wrapper = shallowRender();
wrapper.instance().handleSubmit('user', 'pass');
- expect(doLogin).toBeCalledWith('user', 'pass');
+ expect(logIn).toBeCalledWith('user', 'pass');
});
function shallowRender(props: Partial<LoginContainer['props']> = {}) {
- return shallow<LoginContainer>(
- <LoginContainer doLogin={jest.fn()} location={mockLocation()} {...props} />
- );
+ return shallow<LoginContainer>(<LoginContainer location={mockLocation()} {...props} />);
}
*/
import { shallow } from 'enzyme';
import * as React from 'react';
+import { logOut } from '../../../../api/auth';
+import addGlobalErrorMessage from '../../../../app/utils/addGlobalErrorMessage';
import { waitAndUpdate } from '../../../../helpers/testUtils';
import { Logout } from '../Logout';
-const originalLocation = window.location;
+jest.mock('../../../../api/auth', () => ({
+ logOut: jest.fn().mockResolvedValue(true)
+}));
+
+jest.mock('../../../../app/utils/addGlobalErrorMessage', () => ({
+ __esModule: true,
+ default: jest.fn()
+}));
+const originalLocation = window.location;
beforeAll(() => {
const location = {
...window.location,
});
it('should logout correctly', async () => {
- const doLogout = jest.fn().mockResolvedValue(true);
+ (logOut as jest.Mock).mockResolvedValue(true);
- const wrapper = shallowRender({ doLogout });
+ const wrapper = shallowRender();
await waitAndUpdate(wrapper);
- expect(doLogout).toHaveBeenCalled();
+ expect(logOut).toHaveBeenCalled();
expect(window.location.replace).toHaveBeenCalledWith('/');
+ expect(addGlobalErrorMessage).not.toHaveBeenCalled();
});
it('should not redirect if logout fails', async () => {
- const doLogout = jest.fn().mockRejectedValue(false);
+ (logOut as jest.Mock).mockRejectedValue(false);
- const wrapper = shallowRender({ doLogout });
+ const wrapper = shallowRender();
await waitAndUpdate(wrapper);
- expect(doLogout).toHaveBeenCalled();
+ expect(logOut).toHaveBeenCalled();
expect(window.location.replace).not.toHaveBeenCalled();
+ expect(addGlobalErrorMessage).toHaveBeenCalled();
expect(wrapper).toMatchSnapshot();
});
-function shallowRender(props: Partial<Logout['props']> = {}) {
- return shallow(<Logout doLogout={jest.fn()} {...props} />);
+function shallowRender() {
+ return shallow(<Logout />);
}
import { getParents } from '../../api/components';
import { isPullRequest } from '../../helpers/branch-like';
import { scrollToElement } from '../../helpers/scrolling';
-import { fetchBranchStatus } from '../../store/rootActions';
+import { fetchBranchStatus } from '../../store/branches';
import { BranchLike } from '../../types/branch-like';
import { Issue, SourceViewerFile } from '../../types/types';
import SourceViewer from '../SourceViewer/SourceViewer';
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { getBrancheLikesAsTree, isSameBranchLike, sortBranches } from '../branch-like';
+import { mockBranch, mockMainBranch, mockPullRequest } from '../mocks/branch-like';
+
+describe('#getBrancheLikesAsTree', () => {
+ it('should correctly map branches and prs to tree object', () => {
+ const main = mockMainBranch({ name: 'master' });
+ const branch1 = mockBranch({ name: 'branch-1' });
+ const branch2 = mockBranch({ name: 'branch-2' });
+ const branch3 = mockBranch({ name: 'branch-3' });
+ const branch4 = mockBranch({ name: 'branch-4' });
+
+ const mainPr1 = mockPullRequest({ base: main.name, key: 'PR1' });
+ const mainPr2 = mockPullRequest({ base: main.name, key: 'PR2' });
+ const llb1Pr1 = mockPullRequest({ base: branch1.name, key: 'PR1' });
+ const llb1Pr2 = mockPullRequest({ base: branch1.name, key: 'PR2' });
+ const llb2Pr1 = mockPullRequest({ base: branch2.name, key: 'PR1' });
+ const llb2Pr2 = mockPullRequest({ base: branch2.name, key: 'PR1' });
+ const orphanPR1 = mockPullRequest({ isOrphan: true, key: 'PR1' });
+ const orphanPR2 = mockPullRequest({ isOrphan: true, key: 'PR2' });
+ const parentlessPR1 = mockPullRequest({ base: 'not_present_branch_1', key: 'PR1' });
+ const parentlessPR2 = mockPullRequest({ base: 'not_present_branch_2', key: 'PR2' });
+
+ expect(
+ getBrancheLikesAsTree([
+ branch2,
+ branch1,
+ main,
+ orphanPR2,
+ orphanPR1,
+ branch4,
+ branch3,
+ mainPr2,
+ mainPr1,
+ parentlessPR2,
+ parentlessPR1,
+ llb2Pr2,
+ llb2Pr1,
+ llb1Pr2,
+ llb1Pr1
+ ])
+ ).toEqual({
+ mainBranchTree: {
+ branch: main,
+ pullRequests: [mainPr1, mainPr2]
+ },
+ branchTree: [
+ { branch: branch1, pullRequests: [llb1Pr1, llb1Pr2] },
+ { branch: branch2, pullRequests: [llb2Pr1, llb2Pr1] },
+ { branch: branch3, pullRequests: [] },
+ { branch: branch4, pullRequests: [] }
+ ],
+ parentlessPullRequests: [parentlessPR1, parentlessPR2],
+ orphanPullRequests: [orphanPR1, orphanPR2]
+ });
+ });
+});
+
+describe('#sortBranches', () => {
+ it('should sort branches correctly', () => {
+ const main = mockMainBranch();
+ const foo = mockBranch({ name: 'shortFoo' });
+ const bar = mockBranch({ name: 'shortBar' });
+ const pre = mockBranch({ name: 'shortPre' });
+ const baz = mockBranch({ name: 'longBaz' });
+ const qux = mockBranch({ name: 'longQux' });
+ const qwe = mockBranch({ name: 'longQwe' });
+ const branchList = [foo, baz, pre, qux, main, qwe, bar];
+
+ const sortedBrancList = sortBranches(branchList);
+
+ expect(sortedBrancList).toEqual([main, baz, qux, qwe, bar, foo, pre]);
+ });
+});
+
+describe('#isSameBranchLike', () => {
+ it('compares different kinds', () => {
+ const main = mockMainBranch();
+ const foo = mockBranch({ name: 'foo' });
+ const foo1 = mockBranch({ name: 'foo-1' });
+ const pr = mockPullRequest();
+ expect(isSameBranchLike(main, pr)).toBe(false);
+ expect(isSameBranchLike(main, foo1)).toBe(false);
+ expect(isSameBranchLike(main, foo)).toBe(false);
+ expect(isSameBranchLike(pr, foo1)).toBe(false);
+ expect(isSameBranchLike(pr, foo)).toBe(false);
+ expect(isSameBranchLike(foo1, foo)).toBe(false);
+ });
+
+ it('compares pull requests', () => {
+ expect(
+ isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '1234' }))
+ ).toBe(true);
+ expect(
+ isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '5678' }))
+ ).toBe(false);
+ });
+
+ it('compares branches', () => {
+ expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
+ expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
+ expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
+ expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
+ });
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { getBrancheLikesAsTree, isSameBranchLike, sortBranches } from '../branch-like';
-import { mockBranch, mockMainBranch, mockPullRequest } from '../mocks/branch-like';
-
-describe('#getBrancheLikesAsTree', () => {
- it('should correctly map branches and prs to tree object', () => {
- const main = mockMainBranch({ name: 'master' });
- const branch1 = mockBranch({ name: 'branch-1' });
- const branch2 = mockBranch({ name: 'branch-2' });
- const branch3 = mockBranch({ name: 'branch-3' });
- const branch4 = mockBranch({ name: 'branch-4' });
-
- const mainPr1 = mockPullRequest({ base: main.name, key: 'PR1' });
- const mainPr2 = mockPullRequest({ base: main.name, key: 'PR2' });
- const llb1Pr1 = mockPullRequest({ base: branch1.name, key: 'PR1' });
- const llb1Pr2 = mockPullRequest({ base: branch1.name, key: 'PR2' });
- const llb2Pr1 = mockPullRequest({ base: branch2.name, key: 'PR1' });
- const llb2Pr2 = mockPullRequest({ base: branch2.name, key: 'PR1' });
- const orphanPR1 = mockPullRequest({ isOrphan: true, key: 'PR1' });
- const orphanPR2 = mockPullRequest({ isOrphan: true, key: 'PR2' });
- const parentlessPR1 = mockPullRequest({ base: 'not_present_branch_1', key: 'PR1' });
- const parentlessPR2 = mockPullRequest({ base: 'not_present_branch_2', key: 'PR2' });
-
- expect(
- getBrancheLikesAsTree([
- branch2,
- branch1,
- main,
- orphanPR2,
- orphanPR1,
- branch4,
- branch3,
- mainPr2,
- mainPr1,
- parentlessPR2,
- parentlessPR1,
- llb2Pr2,
- llb2Pr1,
- llb1Pr2,
- llb1Pr1
- ])
- ).toEqual({
- mainBranchTree: {
- branch: main,
- pullRequests: [mainPr1, mainPr2]
- },
- branchTree: [
- { branch: branch1, pullRequests: [llb1Pr1, llb1Pr2] },
- { branch: branch2, pullRequests: [llb2Pr1, llb2Pr1] },
- { branch: branch3, pullRequests: [] },
- { branch: branch4, pullRequests: [] }
- ],
- parentlessPullRequests: [parentlessPR1, parentlessPR2],
- orphanPullRequests: [orphanPR1, orphanPR2]
- });
- });
-});
-
-describe('#sortBranches', () => {
- it('should sort branches correctly', () => {
- const main = mockMainBranch();
- const foo = mockBranch({ name: 'shortFoo' });
- const bar = mockBranch({ name: 'shortBar' });
- const pre = mockBranch({ name: 'shortPre' });
- const baz = mockBranch({ name: 'longBaz' });
- const qux = mockBranch({ name: 'longQux' });
- const qwe = mockBranch({ name: 'longQwe' });
- const branchList = [foo, baz, pre, qux, main, qwe, bar];
-
- const sortedBrancList = sortBranches(branchList);
-
- expect(sortedBrancList).toEqual([main, baz, qux, qwe, bar, foo, pre]);
- });
-});
-
-describe('#isSameBranchLike', () => {
- it('compares different kinds', () => {
- const main = mockMainBranch();
- const foo = mockBranch({ name: 'foo' });
- const foo1 = mockBranch({ name: 'foo-1' });
- const pr = mockPullRequest();
- expect(isSameBranchLike(main, pr)).toBe(false);
- expect(isSameBranchLike(main, foo1)).toBe(false);
- expect(isSameBranchLike(main, foo)).toBe(false);
- expect(isSameBranchLike(pr, foo1)).toBe(false);
- expect(isSameBranchLike(pr, foo)).toBe(false);
- expect(isSameBranchLike(foo1, foo)).toBe(false);
- });
-
- it('compares pull requests', () => {
- expect(
- isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '1234' }))
- ).toBe(true);
- expect(
- isSameBranchLike(mockPullRequest({ key: '1234' }), mockPullRequest({ key: '5678' }))
- ).toBe(false);
- });
-
- it('compares branches', () => {
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'foo' }))).toBe(true);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
- expect(isSameBranchLike(mockBranch({ name: 'foo' }), mockBranch({ name: 'bar' }))).toBe(false);
- });
-});
import { QualityGateStatusCondition } from '../../types/quality-gates';
import { Status } from '../../types/types';
import reducer, {
+ fetchBranchStatus,
getBranchStatusByBranchLike,
+ registerBranchStatus,
registerBranchStatusAction,
State
} from '../branches';
return state;
}
+
+jest.mock('../../app/utils/addGlobalErrorMessage', () => ({
+ __esModule: true,
+ default: jest.fn()
+}));
+
+jest.mock('../../api/quality-gates', () => {
+ const { mockQualityGateProjectStatus } = jest.requireActual('../../helpers/mocks/quality-gates');
+ return {
+ getQualityGateProjectStatus: jest.fn().mockResolvedValue(
+ mockQualityGateProjectStatus({
+ conditions: [
+ {
+ actualValue: '10',
+ comparator: 'GT',
+ errorThreshold: '0',
+ metricKey: 'foo',
+ periodIndex: 1,
+ status: 'ERROR'
+ }
+ ]
+ })
+ )
+ };
+});
+
+describe('branch store actions', () => {
+ const branchLike = mockBranch();
+ const component = 'foo';
+ const status = 'OK';
+
+ it('correctly registers a new branch status', () => {
+ const dispatch = jest.fn();
+
+ registerBranchStatus(branchLike, component, status)(dispatch);
+ expect(dispatch).toBeCalledWith({
+ branchLike,
+ component,
+ status,
+ type: 'REGISTER_BRANCH_STATUS'
+ });
+ });
+
+ it('correctly fetches a branch status', async () => {
+ const dispatch = jest.fn();
+
+ fetchBranchStatus(branchLike, component)(dispatch);
+ await new Promise(setImmediate);
+
+ expect(dispatch).toBeCalledWith({
+ branchLike,
+ component,
+ status,
+ conditions: [
+ mockQualityGateStatusCondition({
+ period: 1
+ })
+ ],
+ ignoredConditions: false,
+ type: 'REGISTER_BRANCH_STATUS'
+ });
+ });
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { mockBranch } from '../../helpers/mocks/branch-like';
-import { mockQualityGateStatusCondition } from '../../helpers/mocks/quality-gates';
-import { registerBranchStatusAction } from '../branches';
-import { fetchBranchStatus, registerBranchStatus } from '../rootActions';
-
-jest.mock('../branches', () => ({
- ...jest.requireActual('../branches'),
- registerBranchStatusAction: jest.fn()
-}));
-
-jest.mock('../../api/quality-gates', () => {
- const { mockQualityGateProjectStatus } = jest.requireActual('../../helpers/mocks/quality-gates');
- return {
- getQualityGateProjectStatus: jest.fn().mockResolvedValue(
- mockQualityGateProjectStatus({
- conditions: [
- {
- actualValue: '10',
- comparator: 'GT',
- errorThreshold: '0',
- metricKey: 'foo',
- periodIndex: 1,
- status: 'ERROR'
- }
- ]
- })
- )
- };
-});
-
-describe('branch store actions', () => {
- const branchLike = mockBranch();
- const component = 'foo';
- const status = 'OK';
-
- it('correctly registers a new branch status', () => {
- const dispatch = jest.fn();
-
- registerBranchStatus(branchLike, component, status)(dispatch);
- expect(registerBranchStatusAction).toBeCalledWith(branchLike, component, status);
- expect(dispatch).toBeCalled();
- });
-
- it('correctly fetches a branch status', async () => {
- const dispatch = jest.fn();
-
- fetchBranchStatus(branchLike, component)(dispatch);
- await new Promise(setImmediate);
-
- expect(registerBranchStatusAction).toBeCalledWith(
- branchLike,
- component,
- status,
- [
- mockQualityGateStatusCondition({
- period: 1
- })
- ],
- false
- );
- expect(dispatch).toBeCalled();
- });
-});
import * as fromBranches from '../branches';
import { getBranchStatusByBranchLike, Store } from '../rootReducer';
-jest.mock('../branches', () => {
- return {
- ...jest.requireActual('../branches'),
- getBranchStatusByBranchLike: jest.fn()
- };
-});
-
it('correctly reduce state for branches', () => {
- const branches = {};
+ const spiedOn = jest.spyOn(fromBranches, 'getBranchStatusByBranchLike').mockReturnValueOnce({});
+
+ const branches = { byComponent: {} };
const component = 'foo';
const branchLike = mockPullRequest();
getBranchStatusByBranchLike({ branches } as Store, component, branchLike);
- expect(fromBranches.getBranchStatusByBranchLike).toBeCalledWith(branches, component, branchLike);
+ expect(spiedOn).toBeCalledWith(branches, component, branchLike);
});
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { getBranchLikeKey } from '../helpers/branch-like';
+import { Dispatch } from 'redux';
+import { getQualityGateProjectStatus } from '../api/quality-gates';
+import addGlobalErrorMessage from '../app/utils/addGlobalErrorMessage';
+import { getBranchLikeKey, getBranchLikeQuery } from '../helpers/branch-like';
+import { extractStatusConditionsFromProjectStatus } from '../helpers/qualityGates';
+import { ActionType } from '../types/actions';
import { BranchLike } from '../types/branch-like';
import { QualityGateStatusCondition } from '../types/quality-gates';
import { Dict, Status } from '../types/types';
-import { ActionType } from './utils/actions';
export interface BranchStatusData {
conditions?: QualityGateStatusCondition[];
};
}
-export default function(state: State = { byComponent: {} }, action: Action): State {
+export default function branchesReducer(state: State = { byComponent: {} }, action: Action): State {
if (action.type === Actions.RegisterBranchStatus) {
const { component, conditions, branchLike, ignoredConditions, status } = action;
const branchLikeKey = getBranchLikeKey(branchLike);
const branchLikeKey = getBranchLikeKey(branchLike);
return state.byComponent[component] && state.byComponent[component][branchLikeKey];
}
+
+export function fetchBranchStatus(branchLike: BranchLike, projectKey: string) {
+ return (dispatch: Dispatch) => {
+ getQualityGateProjectStatus({ projectKey, ...getBranchLikeQuery(branchLike) }).then(
+ projectStatus => {
+ const { ignoredConditions, status } = projectStatus;
+ const conditions = extractStatusConditionsFromProjectStatus(projectStatus);
+ dispatch(
+ registerBranchStatusAction(branchLike, projectKey, status, conditions, ignoredConditions)
+ );
+ },
+ () => {
+ addGlobalErrorMessage('Fetching Quality Gate status failed');
+ }
+ );
+ };
+}
+
+export function registerBranchStatus(branchLike: BranchLike, component: string, status: Status) {
+ return (dispatch: Dispatch) => {
+ dispatch(registerBranchStatusAction(branchLike, component, status));
+ };
+}
*/
import { uniqueId } from 'lodash';
import { Dispatch } from 'redux';
-import { ActionType } from './utils/actions';
+import { ActionType } from '../types/actions';
enum MessageLevel {
Error = 'ERROR',
level: MessageLevel;
}
+const MESSAGE_DISPLAY_TIME = 5000;
+
+/* Action creators */
+
function addGlobalMessageActionCreator(id: string, message: string, level: MessageLevel) {
return { type: 'ADD_GLOBAL_MESSAGE', message, level, id };
}
return { type: 'CLOSE_GLOBAL_MESSAGE', id };
}
-export function closeAllGlobalMessages() {
- return { type: 'CLOSE_ALL_GLOBAL_MESSAGES' };
-}
-
type Action =
| ActionType<typeof addGlobalMessageActionCreator, 'ADD_GLOBAL_MESSAGE'>
- | ActionType<typeof closeGlobalMessage, 'CLOSE_GLOBAL_MESSAGE'>
- | ActionType<typeof closeAllGlobalMessages, 'CLOSE_ALL_GLOBAL_MESSAGES'>;
+ | ActionType<typeof closeGlobalMessage, 'CLOSE_GLOBAL_MESSAGE'>;
function addGlobalMessage(message: string, level: MessageLevel) {
return (dispatch: Dispatch) => {
const id = uniqueId('global-message-');
dispatch(addGlobalMessageActionCreator(id, message, level));
- setTimeout(() => dispatch(closeGlobalMessage(id)), 5000);
+ setTimeout(() => dispatch(closeGlobalMessage(id)), MESSAGE_DISPLAY_TIME);
};
}
export type State = Message[];
-export default function(state: State = [], action: Action): State {
+export default function globalMessagesReducer(state: State = [], action: Action): State {
switch (action.type) {
case 'ADD_GLOBAL_MESSAGE':
return [{ id: action.id, message: action.message, level: action.level }];
case 'CLOSE_GLOBAL_MESSAGE':
return state.filter(message => message.id !== action.id);
- case 'CLOSE_ALL_GLOBAL_MESSAGES':
- return [];
default:
return state;
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { Dispatch } from 'redux';
-import * as auth from '../api/auth';
-import { getQualityGateProjectStatus } from '../api/quality-gates';
-import { getBranchLikeQuery } from '../helpers/branch-like';
-import { extractStatusConditionsFromProjectStatus } from '../helpers/qualityGates';
-import { BranchLike } from '../types/branch-like';
-import { Status } from '../types/types';
-import { registerBranchStatusAction } from './branches';
-import { addGlobalErrorMessage } from './globalMessages';
-
-export function fetchBranchStatus(branchLike: BranchLike, projectKey: string) {
- return (dispatch: Dispatch<any>) => {
- getQualityGateProjectStatus({ projectKey, ...getBranchLikeQuery(branchLike) }).then(
- projectStatus => {
- const { ignoredConditions, status } = projectStatus;
- const conditions = extractStatusConditionsFromProjectStatus(projectStatus);
- dispatch(
- registerBranchStatusAction(branchLike, projectKey, status, conditions, ignoredConditions)
- );
- },
- () => {
- dispatch(addGlobalErrorMessage('Fetching Quality Gate status failed'));
- }
- );
- };
-}
-
-export function doLogin(login: string, password: string) {
- return (dispatch: Dispatch<any>) =>
- auth.login(login, password).then(
- () => {
- /* everything is fine */
- },
- () => {
- dispatch(addGlobalErrorMessage('Authentication failed'));
- return Promise.reject();
- }
- );
-}
-
-export function doLogout() {
- return (dispatch: Dispatch<any>) =>
- auth.logout().then(
- () => {
- /* everything is fine */
- },
- () => {
- dispatch(addGlobalErrorMessage('Logout failed'));
- return Promise.reject();
- }
- );
-}
-
-export function registerBranchStatus(branchLike: BranchLike, component: string, status: Status) {
- return (dispatch: Dispatch) => {
- dispatch(registerBranchStatusAction(branchLike, component, status));
- };
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2022 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-type ActionCreator = (...args: any[]) => { type: string };
-
-export type ActionType<F extends ActionCreator, T> = Omit<ReturnType<F>, 'type'> & { type: T };
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+type ActionCreator = (...args: any[]) => { type: string };
+
+export type ActionType<F extends ActionCreator, T> = Omit<ReturnType<F>, 'type'> & { type: T };