diff options
author | Jeremy Davis <jeremy.davis@sonarsource.com> | 2020-12-10 17:55:59 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2020-12-22 20:09:36 +0000 |
commit | a8c060c66b6ed656cdfeb33593492fd09209847a (patch) | |
tree | 0227b434ed03dbfed4c782f2d7a454a55e6430db /server/sonar-web/src/main/js/apps | |
parent | 2c9a70a4bac47b14dec82cd9d4b7fce1e4905f8e (diff) | |
download | sonarqube-a8c060c66b6ed656cdfeb33593492fd09209847a.tar.gz sonarqube-a8c060c66b6ed656cdfeb33593492fd09209847a.zip |
SONAR-13999 Drop orgs from QualityGates
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
20 files changed, 237 insertions, 97 deletions
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx index 76e2d45004e..7270d953afa 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx @@ -38,17 +38,13 @@ import Details from './Details'; import List from './List'; import ListHeader from './ListHeader'; -interface Props extends WithRouterProps { - organization?: Pick<T.Organization, 'key'>; -} - interface State { canCreate: boolean; loading: boolean; qualityGates: T.QualityGate[]; } -class App extends React.PureComponent<Props, State> { +class App extends React.PureComponent<WithRouterProps, State> { mounted = false; state: State = { canCreate: false, loading: true, qualityGates: [] }; @@ -59,7 +55,7 @@ class App extends React.PureComponent<Props, State> { addSideBarClass(); } - componentDidUpdate(prevProps: Props) { + componentDidUpdate(prevProps: WithRouterProps) { if (prevProps.params.id !== undefined && this.props.params.id === undefined) { this.openDefault(this.state.qualityGates); } @@ -72,8 +68,7 @@ class App extends React.PureComponent<Props, State> { } fetchQualityGates = () => { - const { organization } = this.props; - return fetchQualityGates({ organization: organization && organization.key }).then( + return fetchQualityGates().then( ({ actions, qualitygates: qualityGates }) => { if (this.mounted) { this.setState({ canCreate: actions.create, loading: false, qualityGates }); @@ -113,7 +108,6 @@ class App extends React.PureComponent<Props, State> { const { id } = this.props.params; const { canCreate, qualityGates } = this.state; const defaultTitle = translate('quality_gates.page'); - const organization = this.props.organization && this.props.organization.key; return ( <> @@ -128,7 +122,6 @@ class App extends React.PureComponent<Props, State> { <div className="layout-page-filters"> <ListHeader canCreate={canCreate} - organization={organization} refreshQualityGates={this.fetchQualityGates} /> <DeferredSpinner loading={this.state.loading}> @@ -144,7 +137,6 @@ class App extends React.PureComponent<Props, State> { <Details id={id} onSetDefault={this.handleSetDefault} - organization={organization} qualityGates={this.state.qualityGates} refreshQualityGates={this.fetchQualityGates} /> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx index c8f16386178..89f1685552d 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx @@ -35,7 +35,6 @@ interface Props { condition: T.Condition; canEdit: boolean; metric: T.Metric; - organization?: string; onRemoveCondition: (Condition: T.Condition) => void; onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void; qualityGate: T.QualityGate; @@ -77,7 +76,7 @@ export default class Condition extends React.PureComponent<Props, State> { }; removeCondition = (condition: T.Condition) => { - deleteCondition({ id: condition.id, organization: this.props.organization }).then( + deleteCondition({ id: condition.id }).then( () => this.props.onRemoveCondition(condition), () => {} ); @@ -92,7 +91,7 @@ export default class Condition extends React.PureComponent<Props, State> { } render() { - const { condition, canEdit, metric, organization, qualityGate, updated } = this.props; + const { condition, canEdit, metric, qualityGate, updated } = this.props; return ( <tr className={classNames({ highlighted: updated })}> <td className="text-middle"> @@ -127,7 +126,6 @@ export default class Condition extends React.PureComponent<Props, State> { metric={metric} onAddCondition={this.handleUpdateCondition} onClose={this.handleUpdateClose} - organization={organization} qualityGate={qualityGate} /> )} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx index 2a9fb8a5184..bb7b800e444 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionModal.tsx @@ -36,7 +36,6 @@ interface Props { header: string; onAddCondition: (condition: T.Condition) => void; onClose: () => void; - organization?: string; qualityGate: T.QualityGate; } @@ -66,15 +65,15 @@ export default class ConditionModal extends React.PureComponent<Props, State> { handleFormSubmit = () => { if (this.state.metric) { - const { condition, qualityGate, organization } = this.props; + const { condition, qualityGate } = this.props; const newCondition: T.Omit<T.Condition, 'id'> = { metric: this.state.metric.key, op: this.getSinglePossibleOperator(this.state.metric) || this.state.op, error: this.state.error }; const submitPromise = condition - ? updateCondition({ organization, id: condition.id, ...newCondition }) - : createCondition({ gateId: qualityGate.id, organization, ...newCondition }); + ? updateCondition({ id: condition.id, ...newCondition }) + : createCondition({ gateId: qualityGate.id, ...newCondition }); return submitPromise.then(this.props.onAddCondition); } return Promise.reject(); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx index d90c53ebe2a..cb3f178d39b 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx @@ -38,7 +38,6 @@ interface Props { onAddCondition: (condition: T.Condition) => void; onRemoveCondition: (Condition: T.Condition) => void; onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void; - organization?: string; qualityGate: T.QualityGate; updatedConditionId?: number; } @@ -59,7 +58,6 @@ export class Conditions extends React.PureComponent<Props> { canEdit, onRemoveCondition, onSaveCondition, - organization, updatedConditionId } = this.props; return ( @@ -88,7 +86,6 @@ export class Conditions extends React.PureComponent<Props> { metric={metrics[condition.metric]} onRemoveCondition={onRemoveCondition} onSaveCondition={onSaveCondition} - organization={organization} qualityGate={qualityGate} updated={condition.id === updatedConditionId} /> @@ -150,7 +147,6 @@ export class Conditions extends React.PureComponent<Props> { metrics={availableMetrics} onAddCondition={this.props.onAddCondition} onClose={onClose} - organization={this.props.organization} qualityGate={this.props.qualityGate} /> )}> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx index dd727b4a490..11d03bbf83b 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/CopyQualityGateForm.tsx @@ -27,7 +27,6 @@ import { getQualityGateUrl } from '../../../helpers/urls'; interface Props { onClose: () => void; onCopy: () => Promise<void>; - organization?: string; qualityGate: T.QualityGate; router: Pick<Router, 'push'>; } @@ -36,7 +35,7 @@ interface State { name: string; } -class CopyQualityGateForm extends React.PureComponent<Props, State> { +export class CopyQualityGateForm extends React.PureComponent<Props, State> { constructor(props: Props) { super(props); this.state = { name: props.qualityGate.name }; @@ -47,14 +46,14 @@ class CopyQualityGateForm extends React.PureComponent<Props, State> { }; handleCopy = () => { - const { qualityGate, organization } = this.props; + const { qualityGate } = this.props; const { name } = this.state; if (!name) { return undefined; } - return copyQualityGate({ id: qualityGate.id, name, organization }).then(qualityGate => { + return copyQualityGate({ id: qualityGate.id, name }).then(qualityGate => { this.props.onCopy(); this.props.router.push(getQualityGateUrl(String(qualityGate.id))); }); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx index 53f964ee74c..d209517cfb8 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/CreateQualityGateForm.tsx @@ -27,7 +27,6 @@ import { getQualityGateUrl } from '../../../helpers/urls'; interface Props { onClose: () => void; onCreate: () => Promise<void>; - organization?: string; router: Pick<Router, 'push'>; } @@ -43,14 +42,13 @@ class CreateQualityGateForm extends React.PureComponent<Props, State> { }; handleCreate = () => { - const { organization } = this.props; const { name } = this.state; if (!name) { return undefined; } - return createQualityGate({ name, organization }) + return createQualityGate({ name }) .then(qualityGate => { return this.props.onCreate().then(() => qualityGate); }) diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx index 0bfaaaf6668..a3b76a64d01 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DeleteQualityGateForm.tsx @@ -27,15 +27,14 @@ import { getQualityGatesUrl } from '../../../helpers/urls'; interface Props { onDelete: () => Promise<void>; - organization?: string; qualityGate: T.QualityGate; router: Pick<Router, 'push'>; } -class DeleteQualityGateForm extends React.PureComponent<Props> { +export class DeleteQualityGateForm extends React.PureComponent<Props> { onDelete = () => { - const { organization, qualityGate } = this.props; - return deleteQualityGate({ id: qualityGate.id, organization }) + const { qualityGate } = this.props; + return deleteQualityGate({ id: qualityGate.id }) .then(this.props.onDelete) .then(() => { this.props.router.push(getQualityGatesUrl()); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx index c7967dcaab9..6ebbcea42a3 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Details.tsx @@ -33,7 +33,6 @@ import DetailsHeader from './DetailsHeader'; interface OwnProps { id: string; onSetDefault: (qualityGate: T.QualityGate) => void; - organization?: string; qualityGates: T.QualityGate[]; refreshQualityGates: () => Promise<void>; } @@ -75,9 +74,9 @@ export class Details extends React.PureComponent<Props, State> { } fetchDetails = () => { - const { id, organization } = this.props; + const { id } = this.props; this.setState({ loading: true }); - return fetchQualityGate({ id, organization }).then( + return fetchQualityGate({ id }).then( qualityGate => { if (this.mounted) { this.setState({ loading: false, qualityGate, updatedConditionId: undefined }); @@ -145,7 +144,7 @@ export class Details extends React.PureComponent<Props, State> { }; render() { - const { organization, metrics, refreshQualityGates } = this.props; + const { metrics, refreshQualityGates } = this.props; const { loading, qualityGate, updatedConditionId } = this.state; return ( @@ -156,7 +155,6 @@ export class Details extends React.PureComponent<Props, State> { <Helmet defer={false} title={qualityGate.name} /> <DetailsHeader onSetDefault={this.handleSetDefault} - organization={organization} qualityGate={qualityGate} refreshItem={this.fetchDetails} refreshList={refreshQualityGates} @@ -167,7 +165,6 @@ export class Details extends React.PureComponent<Props, State> { onAddCondition={this.handleAddCondition} onRemoveCondition={this.handleRemoveCondition} onSaveCondition={this.handleSaveCondition} - organization={organization} qualityGate={qualityGate} updatedConditionId={updatedConditionId} /> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx index 5966b0cb1bc..6d299df5a67 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx @@ -26,7 +26,6 @@ import Projects from './Projects'; export interface DetailsContentProps { isDefault?: boolean; metrics: T.Dict<T.Metric>; - organization?: string; onAddCondition: (condition: T.Condition) => void; onRemoveCondition: (Condition: T.Condition) => void; onSaveCondition: (newCondition: T.Condition, oldCondition: T.Condition) => void; @@ -35,7 +34,7 @@ export interface DetailsContentProps { } export function DetailsContent(props: DetailsContentProps) { - const { isDefault, metrics, organization, qualityGate, updatedConditionId } = props; + const { isDefault, metrics, qualityGate, updatedConditionId } = props; const conditions = qualityGate.conditions || []; const actions = qualityGate.actions || ({} as any); @@ -48,7 +47,6 @@ export function DetailsContent(props: DetailsContentProps) { onAddCondition={props.onAddCondition} onRemoveCondition={props.onRemoveCondition} onSaveCondition={props.onSaveCondition} - organization={organization} qualityGate={qualityGate} updatedConditionId={updatedConditionId} /> @@ -72,7 +70,6 @@ export function DetailsContent(props: DetailsContentProps) { canEdit={actions.associateProjects} // pass unique key to re-mount the component when the quality gate changes key={qualityGate.id} - organization={organization} qualityGate={qualityGate} /> )} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx index 854d8fd4ea9..769ac5d0cd9 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/DetailsHeader.tsx @@ -29,7 +29,6 @@ import RenameQualityGateForm from './RenameQualityGateForm'; interface Props { onSetDefault: () => void; - organization?: string; qualityGate: T.QualityGate; refreshItem: () => Promise<void>; refreshList: () => Promise<void>; @@ -45,11 +44,11 @@ export default class DetailsHeader extends React.PureComponent<Props> { }; handleSetAsDefaultClick = () => { - const { organization, qualityGate } = this.props; + const { qualityGate } = this.props; if (!qualityGate.isDefault) { // Optimistic update this.props.onSetDefault(); - setQualityGateAsDefault({ id: qualityGate.id, organization }).then( + setQualityGateAsDefault({ id: qualityGate.id }).then( this.handleActionRefresh, this.handleActionRefresh ); @@ -57,7 +56,7 @@ export default class DetailsHeader extends React.PureComponent<Props> { }; render() { - const { organization, qualityGate } = this.props; + const { qualityGate } = this.props; const actions = qualityGate.actions || ({} as any); return ( <div className="layout-page-header-panel layout-page-main-header issues-main-header"> @@ -75,7 +74,6 @@ export default class DetailsHeader extends React.PureComponent<Props> { <RenameQualityGateForm onClose={onClose} onRename={this.handleActionRefresh} - organization={organization} qualityGate={qualityGate} /> )}> @@ -92,7 +90,6 @@ export default class DetailsHeader extends React.PureComponent<Props> { <CopyQualityGateForm onClose={onClose} onCopy={this.handleActionRefresh} - organization={organization} qualityGate={qualityGate} /> )}> @@ -114,7 +111,6 @@ export default class DetailsHeader extends React.PureComponent<Props> { {actions.delete && ( <DeleteQualityGateForm onDelete={this.props.refreshList} - organization={organization} qualityGate={qualityGate} /> )} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx index 8fc6c24c0b3..40f2ae8b3db 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx @@ -27,21 +27,16 @@ import CreateQualityGateForm from './CreateQualityGateForm'; interface Props { canCreate: boolean; refreshQualityGates: () => Promise<void>; - organization?: string; } -export default function ListHeader({ canCreate, refreshQualityGates, organization }: Props) { +export default function ListHeader({ canCreate, refreshQualityGates }: Props) { return ( <header className="page-header"> {canCreate && ( <div className="page-actions"> <ModalButton modal={({ onClose }) => ( - <CreateQualityGateForm - onClose={onClose} - onCreate={refreshQualityGates} - organization={organization} - /> + <CreateQualityGateForm onClose={onClose} onCreate={refreshQualityGates} /> )}> {({ onClick }) => ( <Button data-test="quality-gates__add" onClick={onClick}> diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx index 170f62078e0..147e9ba7b42 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx @@ -32,7 +32,6 @@ import { interface Props { canEdit?: boolean; - organization?: string; qualityGate: T.QualityGate; } @@ -68,7 +67,6 @@ export default class Projects extends React.PureComponent<Props, State> { fetchProjects = (searchParams: SelectListSearchParams) => searchProjects({ gateName: this.props.qualityGate.name, - organization: this.props.organization, page: searchParams.page, pageSize: searchParams.pageSize, query: searchParams.query !== '' ? searchParams.query : undefined, @@ -100,7 +98,6 @@ export default class Projects extends React.PureComponent<Props, State> { handleSelect = (key: string) => associateGateWithProject({ gateId: this.props.qualityGate.id, - organization: this.props.organization, projectKey: key }).then(() => { if (this.mounted) { @@ -114,7 +111,6 @@ export default class Projects extends React.PureComponent<Props, State> { handleUnselect = (key: string) => dissociateGateWithProject({ gateId: this.props.qualityGate.id, - organization: this.props.organization, projectKey: key }).then(() => { if (this.mounted) { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx index 3d7f45ff74b..b52404ca962 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/RenameQualityGateForm.tsx @@ -25,7 +25,6 @@ import { renameQualityGate } from '../../../api/quality-gates'; interface Props { onClose: () => void; onRename: () => Promise<void>; - organization?: string; qualityGate: T.QualityGate; } @@ -44,16 +43,14 @@ export default class RenameQualityGateForm extends React.PureComponent<Props, St }; handleRename = () => { - const { qualityGate, organization } = this.props; + const { qualityGate } = this.props; const { name } = this.state; if (!name) { return undefined; } - return renameQualityGate({ id: qualityGate.id, name, organization }).then(() => - this.props.onRename() - ); + return renameQualityGate({ id: qualityGate.id, name }).then(() => this.props.onRename()); }; render() { diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx index ab6e843fb9f..5b7eb8ff9a4 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/ConditionModal-test.tsx @@ -19,11 +19,17 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { createCondition, updateCondition } from '../../../../api/quality-gates'; import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; -import { mockMetric } from '../../../../helpers/testMocks'; +import { mockCondition, mockMetric } from '../../../../helpers/testMocks'; import { MetricKey } from '../../../../types/metrics'; import ConditionModal from '../ConditionModal'; +jest.mock('../../../../api/quality-gates', () => ({ + createCondition: jest.fn().mockResolvedValue({}), + updateCondition: jest.fn().mockResolvedValue({}) +})); + it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot(); expect(shallowRender({ metric: mockMetric() })).toMatchSnapshot(); @@ -59,6 +65,26 @@ it('should correctly switch scope', () => { expect(wrapper).toMatchSnapshot(); }); +it('should handle submission', async () => { + const onAddCondition = jest.fn(); + const wrapper = shallowRender({ onAddCondition }); + + wrapper.setState({ metric: mockMetric() }); + + await wrapper.instance().handleFormSubmit(); + + expect(createCondition).toBeCalled(); + expect(updateCondition).not.toBeCalled(); + + jest.clearAllMocks(); + + wrapper.setProps({ condition: mockCondition() }); + await wrapper.instance().handleFormSubmit(); + + expect(createCondition).not.toBeCalled(); + expect(updateCondition).toBeCalled(); +}); + function shallowRender(props: Partial<ConditionModal['props']> = {}) { return shallow<ConditionModal>( <ConditionModal diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx index 492e8fa6b2f..5f7d9a900c4 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/CopyQualityGateForm-test.tsx @@ -19,13 +19,50 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { copyQualityGate } from '../../../../api/quality-gates'; import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; -import CopyQualityGateForm from '../CopyQualityGateForm'; +import { mockRouter } from '../../../../helpers/testMocks'; +import { CopyQualityGateForm } from '../CopyQualityGateForm'; + +jest.mock('../../../../api/quality-gates', () => ({ + copyQualityGate: jest.fn().mockResolvedValue({}) +})); it('should render correctly', () => { - expect( - shallow( - <CopyQualityGateForm onClose={jest.fn()} onCopy={jest.fn()} qualityGate={mockQualityGate()} /> - ) - ).toMatchSnapshot(); + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should handle copy', async () => { + const onCopy = jest.fn(); + const router = mockRouter(); + const qualityGate = mockQualityGate(); + const wrapper = shallowRender({ onCopy, qualityGate, router }); + + const name = 'name'; + wrapper.setState({ name }); + + await wrapper.instance().handleCopy(); + + expect(copyQualityGate).toBeCalledWith({ id: qualityGate.id, name }); + expect(onCopy).toBeCalled(); + expect(router.push).toBeCalled(); + + jest.clearAllMocks(); + + wrapper.setState({ name: '' }); + await wrapper.instance().handleCopy(); + + expect(copyQualityGate).not.toBeCalled(); }); + +function shallowRender(overrides: Partial<CopyQualityGateForm['props']> = {}) { + return shallow<CopyQualityGateForm>( + <CopyQualityGateForm + onClose={jest.fn()} + onCopy={jest.fn()} + qualityGate={mockQualityGate()} + router={mockRouter()} + {...overrides} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx new file mode 100644 index 00000000000..b31d51d749b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DeleteQualityGateForm-test.tsx @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2020 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 { deleteQualityGate } from '../../../../api/quality-gates'; +import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; +import { mockRouter } from '../../../../helpers/testMocks'; +import { DeleteQualityGateForm } from '../DeleteQualityGateForm'; + +jest.mock('../../../../api/quality-gates', () => ({ + deleteQualityGate: jest.fn().mockResolvedValue({}) +})); + +it('should render correctly', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should handle onDelete', async () => { + const onDelete = jest.fn(); + const router = mockRouter(); + const qualityGate = mockQualityGate(); + const wrapper = shallowRender({ onDelete, qualityGate, router }); + + await wrapper.instance().onDelete(); + + expect(deleteQualityGate).toBeCalledWith({ id: qualityGate.id }); + expect(onDelete).toBeCalled(); + expect(router.push).toBeCalled(); +}); + +function shallowRender(overrides: Partial<DeleteQualityGateForm['props']> = {}) { + return shallow<DeleteQualityGateForm>( + <DeleteQualityGateForm + onDelete={jest.fn()} + qualityGate={mockQualityGate()} + router={mockRouter()} + {...overrides} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx index f7a76c49793..47472ac1598 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx @@ -30,7 +30,6 @@ import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; import Projects from '../Projects'; const qualityGate = mockQualityGate(); -const organization = 'TEST'; jest.mock('../../../../api/quality-gates', () => ({ searchProjects: jest.fn().mockResolvedValue({ @@ -70,7 +69,6 @@ it('should render correctly', async () => { expect(searchProjects).toHaveBeenCalledWith( expect.objectContaining({ gateName: qualityGate.name, - organization, page: 1, pageSize: 100, query: undefined, @@ -110,7 +108,5 @@ it('should handle deselection properly', async () => { }); function shallowRender(props: Partial<Projects['props']> = {}) { - return shallow<Projects>( - <Projects organization={organization} qualityGate={qualityGate} {...props} /> - ); + return shallow<Projects>(<Projects qualityGate={qualityGate} {...props} />); } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx index 40eb1a513bf..b060388264b 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/RenameQualityGateForm-test.tsx @@ -19,17 +19,46 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; +import { renameQualityGate } from '../../../../api/quality-gates'; import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; import RenameQualityGateForm from '../RenameQualityGateForm'; +jest.mock('../../../../api/quality-gates', () => ({ + renameQualityGate: jest.fn().mockResolvedValue({}) +})); + it('should render correctly', () => { - expect( - shallow( - <RenameQualityGateForm - onClose={jest.fn()} - onRename={jest.fn()} - qualityGate={mockQualityGate()} - /> - ) - ).toMatchSnapshot(); + expect(shallowRender()).toMatchSnapshot(); +}); + +it('should handle rename', async () => { + const qualityGate = mockQualityGate(); + const wrapper = shallowRender({ qualityGate }); + + const name = 'new name'; + + wrapper.setState({ name }); + + await wrapper.instance().handleRename(); + + expect(renameQualityGate).toBeCalledWith({ ...qualityGate, name }); + + jest.clearAllMocks(); + + wrapper.setState({ name: '' }); + + await wrapper.instance().handleRename(); + + expect(renameQualityGate).not.toBeCalled(); }); + +function shallowRender(overrides: Partial<RenameQualityGateForm['props']> = {}) { + return shallow<RenameQualityGateForm>( + <RenameQualityGateForm + onClose={jest.fn()} + onRename={jest.fn()} + qualityGate={mockQualityGate()} + {...overrides} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap index e961412c207..556ab1bdd5e 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/CopyQualityGateForm-test.tsx.snap @@ -1,14 +1,37 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`should render correctly 1`] = ` -<CopyQualityGateForm +<ConfirmModal + confirmButtonText="copy" + confirmDisable={true} + header="quality_gates.copy" onClose={[MockFunction]} - onCopy={[MockFunction]} - qualityGate={ - Object { - "id": "1", - "name": "qualitygate", - } - } -/> + 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="qualitygate" + /> + </div> +</ConfirmModal> `; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap new file mode 100644 index 00000000000..d99d75037ab --- /dev/null +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DeleteQualityGateForm-test.tsx.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +<ConfirmButton + confirmButtonText="delete" + isDestructive={true} + modalBody="quality_gates.delete.confirm.message.qualitygate" + modalHeader="quality_gates.delete" + onConfirm={[Function]} +> + <Component /> +</ConfirmButton> +`; |