Bladeren bron

Improve test coverage

tags/8.7.0.41497
Wouter Admiraal 3 jaren geleden
bovenliggende
commit
71df799f40

+ 6
- 21
server/sonar-web/src/main/js/app/components/App.tsx Bestand weergeven

@@ -21,29 +21,18 @@ import * as React from 'react';
import { connect } from 'react-redux';
import { lazyLoadComponent } from 'sonar-ui-common/components/lazyLoadComponent';
import { fetchLanguages } from '../../store/rootActions';
import { getAppState, getCurrentUser, getGlobalSettingValue, Store } from '../../store/rootReducer';
import { getGlobalSettingValue, Store } from '../../store/rootReducer';
import KeyboardShortcutsModal from './KeyboardShortcutsModal';

const PageTracker = lazyLoadComponent(() => import('./PageTracker'));

interface StateProps {
appState: T.AppState | undefined;
currentUser: T.CurrentUser | undefined;
interface Props {
fetchLanguages: () => void;
enableGravatar: boolean;
gravatarServerUrl: string;
}

interface DispatchProps {
fetchLanguages: () => Promise<void>;
}

interface OwnProps {
children: JSX.Element;
}

type Props = StateProps & DispatchProps & OwnProps;

class App extends React.PureComponent<Props> {
export class App extends React.PureComponent<Props> {
mounted = false;

componentDidMount() {
@@ -102,19 +91,15 @@ class App extends React.PureComponent<Props> {
}
}

const mapStateToProps = (state: Store): StateProps => {
const mapStateToProps = (state: Store) => {
const enableGravatar = getGlobalSettingValue(state, 'sonar.lf.enableGravatar');
const gravatarServerUrl = getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl');
return {
appState: getAppState(state),
currentUser: getCurrentUser(state),
enableGravatar: Boolean(enableGravatar && enableGravatar.value === 'true'),
gravatarServerUrl: (gravatarServerUrl && gravatarServerUrl.value) || ''
};
};

const mapDispatchToProps = ({
fetchLanguages
} as any) as DispatchProps;
const mapDispatchToProps = { fetchLanguages };

export default connect(mapStateToProps, mapDispatchToProps)(App);

+ 73
- 0
server/sonar-web/src/main/js/app/components/__tests__/App-test.tsx Bestand weergeven

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

import { shallow } from 'enzyme';
import * as React from 'react';
import { connect } from 'react-redux';
import { fetchLanguages as realFetchLanguages } from '../../../store/rootActions';
import { App } from '../App';

jest.mock('react-redux', () => ({
connect: jest.fn(() => (a: any) => a)
}));

jest.mock('../../../store/rootReducer', () => ({
getGlobalSettingValue: jest.fn((_, key: string) => ({
value: key === 'sonar.lf.enableGravatar' ? 'true' : 'http://gravatar.com'
}))
}));

it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot('default');
expect(
shallowRender({ enableGravatar: true, gravatarServerUrl: 'http://example.com' })
).toMatchSnapshot('with gravatar');
});

it('should correctly fetch available languages', () => {
const fetchLanguages = jest.fn();
shallowRender({ fetchLanguages });
expect(fetchLanguages).toBeCalled();
});

it('should correctly set the scrollbar width as a custom property', () => {
shallowRender();
expect(document.body.style.getPropertyValue('--sbw')).toBe('0px');
});

describe('redux', () => {
it('should correctly map state and dispatch props', () => {
const [mapStateToProps, mapDispatchToProps] = (connect as jest.Mock).mock.calls[0];

expect(mapStateToProps({})).toEqual({
enableGravatar: true,
gravatarServerUrl: 'http://gravatar.com'
});
expect(mapDispatchToProps).toEqual(
expect.objectContaining({ fetchLanguages: realFetchLanguages })
);
});
});

function shallowRender(props: Partial<App['props']> = {}) {
return shallow<App>(
<App fetchLanguages={jest.fn()} enableGravatar={false} gravatarServerUrl="" {...props} />
);
}

+ 20
- 0
server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/App-test.tsx.snap Bestand weergeven

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

exports[`should render correctly: default 1`] = `
<Fragment>
<LazyComponentWrapper />
<KeyboardShortcutsModal />
</Fragment>
`;

exports[`should render correctly: with gravatar 1`] = `
<Fragment>
<LazyComponentWrapper>
<link
href="http://example.com"
rel="preconnect"
/>
</LazyComponentWrapper>
<KeyboardShortcutsModal />
</Fragment>
`;

+ 4
- 4
server/sonar-web/src/main/js/apps/issues/components/App.tsx Bestand weergeven

@@ -92,7 +92,7 @@ interface Props {
branchLike?: BranchLike;
component?: T.Component;
currentUser: T.CurrentUser;
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => Promise<void>;
fetchBranchStatus: (branchLike: BranchLike, projectKey: string) => void;
fetchIssues: (query: T.RawQuery) => Promise<FetchIssuesPromise>;
location: Location;
onBranchesChange?: () => void;
@@ -859,7 +859,7 @@ export default class App extends React.PureComponent<Props, State> {
}
};

renderBulkChange(openIssue: T.Issue | undefined) {
renderBulkChange() {
const { component, currentUser } = this.props;
const { checkAll, bulkChangeModal, checked, issues, paging } = this.state;

@@ -867,7 +867,7 @@ export default class App extends React.PureComponent<Props, State> {
const thirdState = checked.length > 0 && !isAllChecked;
const isChecked = isAllChecked || thirdState;

if (!currentUser.isLoggedIn || openIssue) {
if (!currentUser.isLoggedIn) {
return null;
}

@@ -1062,7 +1062,7 @@ export default class App extends React.PureComponent<Props, State> {
<div className="layout-page-main-inner">
<A11ySkipTarget anchor="issues_main" />

{this.renderBulkChange(openIssue)}
{this.renderBulkChange()}
<PageActions
canSetHome={!this.props.component}
effortTotal={this.state.effortTotal}

+ 2
- 11
server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx Bestand weergeven

@@ -25,16 +25,10 @@ import { withRouter } from '../../../components/hoc/withRouter';
import { parseIssueFromResponse } from '../../../helpers/issues';
import { fetchBranchStatus } from '../../../store/rootActions';
import { getCurrentUser, Store } from '../../../store/rootReducer';
import { FetchIssuesPromise } from '../../../types/issues';

const IssuesAppContainer = lazyLoadComponent(() => import('./App'), 'IssuesAppContainer');

interface StateProps {
currentUser: T.CurrentUser;
fetchIssues: (query: T.RawQuery) => Promise<FetchIssuesPromise>;
}

const mapStateToProps = (state: Store): StateProps => ({
const mapStateToProps = (state: Store) => ({
currentUser: getCurrentUser(state),
fetchIssues
});
@@ -54,9 +48,6 @@ const fetchIssues = (query: T.RawQuery) => {
.catch(throwGlobalError);
};

// have to type cast this, because of async action
const mapDispatchToProps = {
fetchBranchStatus: fetchBranchStatus as any
};
const mapDispatchToProps = { fetchBranchStatus };

export default withRouter(connect(mapStateToProps, mapDispatchToProps)(IssuesAppContainer));

+ 111
- 3
server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.tsx Bestand weergeven

@@ -18,9 +18,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { shallow } from 'enzyme';
import * as key from 'keymaster';
import * as React from 'react';
import handleRequiredAuthentication from 'sonar-ui-common/helpers/handleRequiredAuthentication';
import { KeyCodes } from 'sonar-ui-common/helpers/keycodes';
import {
addSideBarClass,
addWhitePageClass,
removeSideBarClass,
removeWhitePageClass
} from 'sonar-ui-common/helpers/pages';
import { KEYCODE_MAP, keydown, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { mockPullRequest } from '../../../../helpers/mocks/branch-like';
import {
@@ -33,6 +40,7 @@ import {
mockRouter
} from '../../../../helpers/testMocks';
import {
disableLocationsNavigator,
enableLocationsNavigator,
selectNextFlow,
selectNextLocation,
@@ -40,6 +48,14 @@ import {
selectPreviousLocation
} from '../../actions';
import App from '../App';
import BulkChangeModal from '../BulkChangeModal';

jest.mock('sonar-ui-common/helpers/pages', () => ({
addSideBarClass: jest.fn(),
addWhitePageClass: jest.fn(),
removeSideBarClass: jest.fn(),
removeWhitePageClass: jest.fn()
}));

jest.mock('sonar-ui-common/helpers/handleRequiredAuthentication', () => ({
default: jest.fn()
@@ -54,10 +70,13 @@ jest.mock('keymaster', () => {
return true;
});
};
let scope = 'issues';

key.getScope = () => 'issues';
key.setScope = () => {};
key.deleteScope = () => {};
key.getScope = () => scope;
key.setScope = (newScope: string) => {
scope = newScope;
};
key.deleteScope = jest.fn();

return key;
});
@@ -73,12 +92,36 @@ const PAGING = { pageIndex: 1, pageSize: 100, total: 4 };

const referencedComponent = { key: 'foo-key', name: 'bar', uuid: 'foo-uuid' };

const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;

beforeEach(() => {
Object.defineProperty(window, 'addEventListener', {
value: jest.fn()
});
Object.defineProperty(window, 'removeEventListener', {
value: jest.fn()
});
});

afterEach(() => {
Object.defineProperty(window, 'addEventListener', {
value: originalAddEventListener
});
Object.defineProperty(window, 'removeEventListener', {
value: originalRemoveEventListener
});
});

it('should render a list of issue', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);
expect(wrapper.state().issues.length).toBe(4);
expect(wrapper.state().referencedComponentsById).toEqual({ 'foo-uuid': referencedComponent });
expect(wrapper.state().referencedComponentsByKey).toEqual({ 'foo-key': referencedComponent });

expect(addSideBarClass).toBeCalled();
expect(addWhitePageClass).toBeCalled();
});

it('should not render for anonymous user', () => {
@@ -150,6 +193,37 @@ it('should correctly bind key events for issue navigation', async () => {

keydown(KeyCodes.LeftArrow);
expect(push).toBeCalledTimes(2);
expect(window.addEventListener).toBeCalledTimes(2);
});

it('should correctly clean up on unmount', () => {
const wrapper = shallowRender();

wrapper.unmount();
expect(key.deleteScope).toBeCalled();
expect(removeSideBarClass).toBeCalled();
expect(removeWhitePageClass).toBeCalled();
expect(window.removeEventListener).toBeCalledTimes(2);
});

it('should be able to bulk change specific issues', async () => {
const wrapper = shallowRender({ currentUser: mockLoggedInUser() });
await waitAndUpdate(wrapper);

const instance = wrapper.instance();
expect(wrapper.state().checked.length).toBe(0);
instance.handleIssueCheck('foo');
instance.handleIssueCheck('bar');
expect(wrapper.state().checked.length).toBe(2);

instance.handleOpenBulkChange();
wrapper.update();
expect(wrapper.find(BulkChangeModal).exists()).toBe(true);
const { issues } = await wrapper
.find(BulkChangeModal)
.props()
.fetchIssues({});
expect(issues).toHaveLength(2);
});

it('should be able to uncheck all issue with global checkbox', async () => {
@@ -309,6 +383,10 @@ describe('keydown event handler', () => {
jest.resetAllMocks();
});

afterEach(() => {
key.setScope('issues');
});

it('should handle alt', () => {
instance.handleKeyDown(mockEvent({ keyCode: 18 }));
expect(instance.setState).toHaveBeenCalledWith(enableLocationsNavigator);
@@ -329,6 +407,36 @@ describe('keydown event handler', () => {
instance.handleKeyDown(mockEvent({ altKey: true, keyCode: 39 }));
expect(instance.setState).toHaveBeenCalledWith(selectNextFlow);
});
it('should ignore different scopes', () => {
key.setScope('notissues');
instance.handleKeyDown(mockEvent({ keyCode: 18 }));
expect(instance.setState).not.toHaveBeenCalled();
});
});

describe('keyup event handler', () => {
const wrapper = shallowRender();
const instance = wrapper.instance();
jest.spyOn(instance, 'setState');

beforeEach(() => {
jest.resetAllMocks();
});

afterEach(() => {
key.setScope('issues');
});

it('should handle alt', () => {
instance.handleKeyUp(mockEvent({ keyCode: 18 }));
expect(instance.setState).toHaveBeenCalledWith(disableLocationsNavigator);
});

it('should ignore different scopes', () => {
key.setScope('notissues');
instance.handleKeyUp(mockEvent({ keyCode: 18 }));
expect(instance.setState).not.toHaveBeenCalled();
});
});

it('should fetch more issues', async () => {

+ 59
- 0
server/sonar-web/src/main/js/apps/issues/components/__tests__/AppContainer-test.tsx Bestand weergeven

@@ -0,0 +1,59 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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 { connect } from 'react-redux';
import { searchIssues } from '../../../../api/issues';
import { mockCurrentUser } from '../../../../helpers/testMocks';
import { fetchBranchStatus } from '../../../../store/rootActions';
import '../AppContainer';

jest.mock('react-redux', () => ({
connect: jest.fn(() => (a: any) => a)
}));

jest.mock('../../../../api/issues', () => ({
searchIssues: jest.fn().mockResolvedValue({ issues: [{ some: 'issue' }], bar: 'baz' })
}));

jest.mock('../../../../helpers/issues', () => ({
parseIssueFromResponse: jest.fn(() => 'parsedIssue')
}));

jest.mock('../../../../store/rootReducer', () => {
const { mockCurrentUser } = jest.requireActual('../../../../helpers/testMocks');
return {
getCurrentUser: jest.fn(() => mockCurrentUser())
};
});

describe('redux', () => {
it('should correctly map state and dispatch props', async () => {
const [mapStateToProps, mapDispatchToProps] = (connect as jest.Mock).mock.calls[0];
const { currentUser, fetchIssues } = mapStateToProps({});

expect(currentUser).toEqual(mockCurrentUser());
expect(mapDispatchToProps).toEqual(expect.objectContaining({ fetchBranchStatus }));

const result = await fetchIssues({ foo: 'bar' });
expect(searchIssues).toBeCalledWith(
expect.objectContaining({ foo: 'bar', additionalFields: '_all' })
);
expect(result).toEqual({ issues: ['parsedIssue'], bar: 'baz' });
});
});

+ 1
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx Bestand weergeven

@@ -44,7 +44,7 @@ interface State {
qualityGates: T.QualityGate[];
}

class App extends React.PureComponent<WithRouterProps, State> {
class App extends React.PureComponent<Pick<WithRouterProps, 'params' | 'router'>, State> {
mounted = false;
state: State = { canCreate: false, loading: true, qualityGates: [] };


+ 8
- 12
server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx Bestand weergeven

@@ -34,27 +34,23 @@ interface State {
name: string;
}

class CreateQualityGateForm extends React.PureComponent<Props, State> {
export class CreateQualityGateForm extends React.PureComponent<Props, State> {
state: State = { name: '' };

handleNameChange = (event: React.SyntheticEvent<HTMLInputElement>) => {
this.setState({ name: event.currentTarget.value });
};

handleCreate = () => {
handleCreate = async () => {
const { name } = this.state;

if (!name) {
return undefined;
}
if (name) {
const qualityGate = await createQualityGate({ name });

await this.props.onCreate();

return createQualityGate({ name })
.then(qualityGate => {
return this.props.onCreate().then(() => qualityGate);
})
.then(qualityGate => {
this.props.router.push(getQualityGateUrl(String(qualityGate.id)));
});
this.props.router.push(getQualityGateUrl(String(qualityGate.id)));
}
};

render() {

+ 92
- 0
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App.tsx Bestand weergeven

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

import { shallow } from 'enzyme';
import * as React from 'react';
import {
addSideBarClass,
addWhitePageClass,
removeSideBarClass,
removeWhitePageClass
} from 'sonar-ui-common/helpers/pages';
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper';
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates';
import { mockRouter } from '../../../../helpers/testMocks';
import App from '../App';

jest.mock('sonar-ui-common/helpers/pages', () => ({
addSideBarClass: jest.fn(),
addWhitePageClass: jest.fn(),
removeSideBarClass: jest.fn(),
removeWhitePageClass: jest.fn()
}));

jest.mock('../../../../api/quality-gates', () => {
const { mockQualityGate } = jest.requireActual('../../../../helpers/mocks/quality-gates');
return {
fetchQualityGates: jest.fn().mockResolvedValue({
actions: { create: true },
qualitygates: [
mockQualityGate(),
mockQualityGate({ id: '2', name: 'qualitygate 2', isDefault: true })
]
})
};
});

it('should render correctly', async () => {
const wrapper = shallowRender();
const replace = jest.fn(() => wrapper.setProps({ params: { id: '2' } }));
wrapper.setProps({ router: mockRouter({ replace }) });

expect(wrapper).toMatchSnapshot('default');
expect(wrapper.find(ScreenPositionHelper).dive()).toMatchSnapshot('ScreenPositionHelper');

await waitAndUpdate(wrapper);

// No ID parameter passed, it should redirect to the default gate.
expect(replace).toBeCalledWith({ pathname: '/quality_gates/show/2' });
expect(wrapper).toMatchSnapshot('default gate');

// Pass an ID, show a specific gate.
wrapper.setProps({ params: { id: '1' } });
expect(wrapper).toMatchSnapshot('specific gate');

expect(addSideBarClass).toBeCalled();
expect(addWhitePageClass).toBeCalled();

wrapper.unmount();
expect(removeSideBarClass).toBeCalled();
expect(removeWhitePageClass).toBeCalled();
});

it('should handle set default correctly', async () => {
const wrapper = shallowRender();
await waitAndUpdate(wrapper);

expect(wrapper.state().qualityGates?.find(gate => gate.isDefault)?.id).toBe('2');
wrapper.instance().handleSetDefault(mockQualityGate({ id: '1' }));
expect(wrapper.state().qualityGates?.find(gate => gate.isDefault)?.id).toBe('1');
});

function shallowRender(props: Partial<App['props']> = {}) {
return shallow<App>(<App params={{}} router={mockRouter()} {...props} />);
}

+ 48
- 4
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CreateQualityGateForm-test.tsx Bestand weergeven

@@ -17,12 +17,56 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { shallow } from 'enzyme';
import * as React from 'react';
import CreateQualityGateForm from '../CreateQualityGateForm';
import ConfirmModal from 'sonar-ui-common/components/controls/ConfirmModal';
import { change, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
import { createQualityGate } from '../../../../api/quality-gates';
import { mockRouter } from '../../../../helpers/testMocks';
import { getQualityGateUrl } from '../../../../helpers/urls';
import { CreateQualityGateForm } from '../CreateQualityGateForm';

jest.mock('../../../../api/quality-gates', () => ({
createQualityGate: jest.fn().mockResolvedValue({ id: '1', name: 'newValue' })
}));

it('should render correctly', () => {
expect(
shallow(<CreateQualityGateForm onClose={jest.fn()} onCreate={jest.fn()} />)
).toMatchSnapshot();
expect(shallowRender()).toMatchSnapshot();
});

it('should correctly handle create', async () => {
const onCreate = jest.fn().mockResolvedValue(undefined);
const push = jest.fn();
const wrapper = shallowRender({ onCreate, router: mockRouter({ push }) });

wrapper
.find(ConfirmModal)
.props()
.onConfirm();
expect(createQualityGate).not.toHaveBeenCalled();

change(wrapper.find('#quality-gate-form-name'), 'newValue');
expect(wrapper.state().name).toBe('newValue');

wrapper
.find(ConfirmModal)
.props()
.onConfirm();
expect(createQualityGate).toHaveBeenCalledWith({ name: 'newValue' });

await waitAndUpdate(wrapper);
expect(onCreate).toHaveBeenCalled();
expect(push).toHaveBeenCalledWith(getQualityGateUrl('1'));
});

function shallowRender(props: Partial<CreateQualityGateForm['props']> = {}) {
return shallow<CreateQualityGateForm>(
<CreateQualityGateForm
onClose={jest.fn()}
onCreate={jest.fn()}
router={mockRouter()}
{...props}
/>
);
}

+ 144
- 0
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/App.tsx.snap Bestand weergeven

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

exports[`should render correctly: ScreenPositionHelper 1`] = `
<div
className="layout-page-side-outer"
>
<div
className="layout-page-side"
style={
Object {
"top": 0,
}
}
>
<div
className="layout-page-side-inner"
>
<div
className="layout-page-filters"
>
<ListHeader
canCreate={false}
refreshQualityGates={[Function]}
/>
<DeferredSpinner
loading={true}
>
<List
qualityGates={Array []}
/>
</DeferredSpinner>
</div>
</div>
</div>
</div>
`;

exports[`should render correctly: default 1`] = `
<Fragment>
<Helmet
defaultTitle="quality_gates.page"
defer={false}
encodeSpecialCharacters={true}
titleTemplate="%s - quality_gates.page"
/>
<div
className="layout-page"
id="quality-gates-page"
>
<Suggestions
suggestions="quality_gates"
/>
<ScreenPositionHelper
className="layout-page-side-outer"
>
<Component />
</ScreenPositionHelper>
</div>
</Fragment>
`;

exports[`should render correctly: default gate 1`] = `
<Fragment>
<Helmet
defaultTitle="quality_gates.page"
defer={false}
encodeSpecialCharacters={true}
titleTemplate="%s - quality_gates.page"
/>
<div
className="layout-page"
id="quality-gates-page"
>
<Suggestions
suggestions="quality_gates"
/>
<ScreenPositionHelper
className="layout-page-side-outer"
>
<Component />
</ScreenPositionHelper>
<Connect(Details)
id="2"
onSetDefault={[Function]}
qualityGates={
Array [
Object {
"id": "1",
"name": "qualitygate",
},
Object {
"id": "2",
"isDefault": true,
"name": "qualitygate 2",
},
]
}
refreshQualityGates={[Function]}
/>
</div>
</Fragment>
`;

exports[`should render correctly: specific gate 1`] = `
<Fragment>
<Helmet
defaultTitle="quality_gates.page"
defer={false}
encodeSpecialCharacters={true}
titleTemplate="%s - quality_gates.page"
/>
<div
className="layout-page"
id="quality-gates-page"
>
<Suggestions
suggestions="quality_gates"
/>
<ScreenPositionHelper
className="layout-page-side-outer"
>
<Component />
</ScreenPositionHelper>
<Connect(Details)
id="1"
onSetDefault={[Function]}
qualityGates={
Array [
Object {
"id": "1",
"name": "qualitygate",
},
Object {
"id": "2",
"isDefault": true,
"name": "qualitygate 2",
},
]
}
refreshQualityGates={[Function]}
/>
</div>
</Fragment>
`;

+ 32
- 3
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CreateQualityGateForm-test.tsx.snap Bestand weergeven

@@ -1,8 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`should render correctly 1`] = `
<CreateQualityGateForm
<ConfirmModal
confirmButtonText="save"
confirmDisable={true}
header="quality_gates.create"
onClose={[MockFunction]}
onCreate={[MockFunction]}
/>
onConfirm={[Function]}
size="small"
>
<div
className="modal-field"
>
<label
htmlFor="quality-gate-form-name"
>
name
<em
className="mandatory"
>
*
</em>
</label>
<input
autoFocus={true}
id="quality-gate-form-name"
maxLength={100}
onChange={[Function]}
required={true}
size={50}
type="text"
value=""
/>
</div>
</ConfirmModal>
`;

+ 46
- 0
server/sonar-web/src/main/js/apps/quality-profiles/components/__tests__/AppContainer-test.tsx Bestand weergeven

@@ -0,0 +1,46 @@
/*
* SonarQube
* Copyright (C) 2009-2021 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 { connect } from 'react-redux';
import '../AppContainer';

jest.mock('react-redux', () => ({
connect: jest.fn(() => (a: any) => a)
}));

jest.mock('../../../../store/rootReducer', () => {
return {
getLanguages: jest.fn(() => [
{ key: 'css', name: 'CSS' },
{ key: 'js', name: 'JS' }
])
};
});

describe('redux', () => {
it('should correctly map state and dispatch props', () => {
const [mapStateToProps] = (connect as jest.Mock).mock.calls[0];
const { languages } = mapStateToProps({});

expect(languages).toEqual([
{ key: 'css', name: 'CSS' },
{ key: 'js', name: 'JS' }
]);
});
});

Laden…
Annuleren
Opslaan