@@ -18,20 +18,28 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { cloneDeep, flatten, omit, remove } from 'lodash'; | |||
import { Project } from '../../apps/quality-gates/components/Projects'; | |||
import { mockQualityGate } from '../../helpers/mocks/quality-gates'; | |||
import { mockUserBase } from '../../helpers/mocks/users'; | |||
import { mockGroup } from '../../helpers/testMocks'; | |||
import { Condition, QualityGate } from '../../types/types'; | |||
import { | |||
addGroup, | |||
addUser, | |||
associateGateWithProject, | |||
copyQualityGate, | |||
createCondition, | |||
createQualityGate, | |||
deleteCondition, | |||
deleteQualityGate, | |||
dissociateGateWithProject, | |||
fetchQualityGate, | |||
fetchQualityGates, | |||
renameQualityGate, | |||
searchGroups, | |||
searchProjects, | |||
searchUsers, | |||
setQualityGateAsDefault, | |||
updateCondition | |||
} from '../quality-gates'; | |||
@@ -39,6 +47,7 @@ export class QualityGatesServiceMock { | |||
isAdmin = false; | |||
readOnlyList: QualityGate[]; | |||
list: QualityGate[]; | |||
projects: Project[]; | |||
constructor(list?: QualityGate[], defaultId = 'AWBWEMe2qGAMGEYPjJlm') { | |||
this.readOnlyList = list || [ | |||
@@ -117,6 +126,13 @@ export class QualityGatesServiceMock { | |||
this.list = cloneDeep(this.readOnlyList); | |||
this.projects = [ | |||
{ key: 'test1', name: 'test1', selected: false }, | |||
{ key: 'test2', name: 'test2', selected: false }, | |||
{ key: 'test3', name: 'test3', selected: true }, | |||
{ key: 'test4', name: 'test4', selected: true } | |||
]; | |||
(fetchQualityGate as jest.Mock).mockImplementation(this.showHandler); | |||
(fetchQualityGates as jest.Mock).mockImplementation(this.listHandler); | |||
(createQualityGate as jest.Mock).mockImplementation(this.createHandler); | |||
@@ -126,18 +142,16 @@ export class QualityGatesServiceMock { | |||
(createCondition as jest.Mock).mockImplementation(this.createConditionHandler); | |||
(updateCondition as jest.Mock).mockImplementation(this.updateConditionHandler); | |||
(deleteCondition as jest.Mock).mockImplementation(this.deleteConditionHandler); | |||
(searchProjects as jest.Mock).mockImplementation(this.searchProjectsHandler); | |||
(searchUsers as jest.Mock).mockImplementation(this.searchUsersHandler); | |||
(searchGroups as jest.Mock).mockImplementation(this.searchGroupsHandler); | |||
(associateGateWithProject as jest.Mock).mockImplementation(this.selectHandler); | |||
(dissociateGateWithProject as jest.Mock).mockImplementation(this.deSelectHandler); | |||
(setQualityGateAsDefault as jest.Mock).mockImplementation(this.setDefaultHandler); | |||
// To be implemented. | |||
(searchUsers as jest.Mock).mockResolvedValue({ users: [] }); | |||
(searchGroups as jest.Mock).mockResolvedValue({ groups: [] }); | |||
(searchProjects as jest.Mock).mockResolvedValue({ | |||
paging: { | |||
pageIndex: 1, | |||
pageSize: 100, | |||
total: 0 | |||
}, | |||
results: [] | |||
}); | |||
(addUser as jest.Mock).mockResolvedValue({}); | |||
(addGroup as jest.Mock).mockResolvedValue({}); | |||
} | |||
getCorruptedQualityGateName() { | |||
@@ -247,6 +261,18 @@ export class QualityGatesServiceMock { | |||
}); | |||
}; | |||
setDefaultHandler = ({ id }: { id: string }) => { | |||
this.list.forEach(q => { | |||
q.isDefault = false; | |||
}); | |||
const selectedQG = this.list.find(q => q.id === id); | |||
if (selectedQG === undefined) { | |||
return Promise.reject({ errors: [{ msg: `No quality gate has been found for id ${id}` }] }); | |||
} | |||
selectedQG.isDefault = true; | |||
return Promise.resolve(); | |||
}; | |||
createConditionHandler = ( | |||
data: { | |||
gateId: string; | |||
@@ -288,6 +314,63 @@ export class QualityGatesServiceMock { | |||
return Promise.resolve(); | |||
}; | |||
searchProjectsHandler = ({ | |||
selected, | |||
query | |||
}: { | |||
selected: string; | |||
query: string | undefined; | |||
}) => { | |||
let filteredProjects = this.projects; | |||
if (selected === 'selected') { | |||
filteredProjects = this.projects.filter(p => p.selected); | |||
} else if (selected === 'deselected') { | |||
filteredProjects = this.projects.filter(p => !p.selected); | |||
} | |||
if (query !== '' && query !== undefined) { | |||
filteredProjects = filteredProjects.filter(p => p.name.includes(query)); | |||
} | |||
const response = { | |||
paging: { pageIndex: 1, pageSize: 3, total: 55 }, | |||
results: filteredProjects | |||
}; | |||
return this.reply(response); | |||
}; | |||
searchUsersHandler = ({ selected }: { selected: string }) => { | |||
if (selected === 'selected') { | |||
return this.reply({ users: [] }); | |||
} | |||
return this.reply({ users: [mockUserBase()] }); | |||
}; | |||
searchGroupsHandler = ({ selected }: { selected: string }) => { | |||
if (selected === 'selected') { | |||
return this.reply({ groups: [] }); | |||
} | |||
return this.reply({ groups: [mockGroup()] }); | |||
}; | |||
selectHandler = ({ projectKey }: { projectKey: string }) => { | |||
const changedProject = this.projects.find(p => p.key === projectKey); | |||
if (changedProject) { | |||
changedProject.selected = true; | |||
} | |||
return Promise.resolve(); | |||
}; | |||
deSelectHandler = ({ projectKey }: { projectKey: string }) => { | |||
const changedProject = this.projects.find(p => p.key === projectKey); | |||
if (changedProject) { | |||
changedProject.selected = false; | |||
} | |||
return Promise.resolve(); | |||
}; | |||
reply<T>(response: T): Promise<T> { | |||
return Promise.resolve(cloneDeep(response)); | |||
} |
@@ -45,7 +45,10 @@ export default function PermissionItem(props: PermissionItemProps) { | |||
{isUser(item) && <div className="note">{item.login}</div>} | |||
</div> | |||
<DeleteButton onClick={() => props.onClickDelete(item)} /> | |||
<DeleteButton | |||
onClick={() => props.onClickDelete(item)} | |||
data-testid="permission-delete-button" | |||
/> | |||
</div> | |||
); | |||
} |
@@ -39,11 +39,18 @@ interface Props { | |||
interface State { | |||
needToReload: boolean; | |||
lastSearchParams?: SelectListSearchParams; | |||
projects: Array<{ key: string; name: string; selected: boolean }>; | |||
projects: Project[]; | |||
projectsTotalCount?: number; | |||
selectedProjects: string[]; | |||
} | |||
// exported for testing | |||
export interface Project { | |||
key: string; | |||
name: string; | |||
selected: boolean; | |||
} | |||
export default class Projects extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
@@ -87,7 +87,7 @@ export default function QualityGatePermissionsAddModalRenderer( | |||
export function customOptions(option: OptionWithValue) { | |||
return ( | |||
<span className="display-flex-center"> | |||
<span className="display-flex-center" data-testid="qg-add-permission-option"> | |||
{isUser(option) ? ( | |||
<Avatar hash={option.avatar} name={option.name} size={16} /> | |||
) : ( |
@@ -20,6 +20,7 @@ | |||
import { screen, waitFor, within } from '@testing-library/react'; | |||
import userEvent from '@testing-library/user-event'; | |||
import selectEvent from 'react-select-event'; | |||
import { searchProjects, searchUsers } from '../../../../api/quality-gates'; | |||
import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock'; | |||
import { mockAppState } from '../../../../helpers/testMocks'; | |||
import { renderApp } from '../../../../helpers/testReactTestingUtils'; | |||
@@ -66,7 +67,6 @@ it('should be able to create a quality gate then delete it', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
let createButton = await screen.findByRole('button', { name: 'create' }); | |||
// Using keyboard | |||
@@ -136,6 +136,18 @@ it('should be able to rename a quality gate', async () => { | |||
expect(await screen.findByRole('menuitem', { name: /New Name.*/ })).toBeInTheDocument(); | |||
}); | |||
it('should be able to set as default a quality gate', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily'); | |||
await user.click(notDefaultQualityGate); | |||
const setAsDefaultButton = screen.getByRole('button', { name: 'set_as_default' }); | |||
await user.click(setAsDefaultButton); | |||
expect(screen.getAllByRole('menuitem')[1]).toHaveTextContent('default'); | |||
}); | |||
it('should be able to add a condition', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
@@ -266,6 +278,202 @@ it('should explain condition on branch', async () => { | |||
).toBeInTheDocument(); | |||
}); | |||
describe('The Project section', () => { | |||
it('should render list of projects correctly in different tabs', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily'); | |||
await user.click(notDefaultQualityGate); | |||
// by default it shows "selected" values | |||
expect(screen.getAllByRole('radio')).toHaveLength(3); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(2); | |||
// change tabs to show deselected projects | |||
await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.without' })); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(2); | |||
// change tabs to show all projects | |||
await user.click(screen.getByRole('radio', { name: 'quality_gates.projects.all' })); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(4); | |||
}); | |||
it('should handle select and deselect correctly', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily'); | |||
await user.click(notDefaultQualityGate); | |||
const checkedProjects = screen.getAllByRole('checkbox')[0]; | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(2); | |||
await user.click(checkedProjects); | |||
const reloadButton = screen.getByRole('button', { name: 'reload' }); | |||
expect(reloadButton).toBeInTheDocument(); | |||
await user.click(reloadButton); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(1); | |||
// change tabs to show deselected projects | |||
await user.click(screen.getAllByRole('radio')[1]); | |||
const uncheckedProjects = screen.getAllByRole('checkbox')[0]; | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(3); | |||
await user.click(uncheckedProjects); | |||
expect(reloadButton).toBeInTheDocument(); | |||
await user.click(reloadButton); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(2); | |||
}); | |||
it('should handle the search of projects', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily'); | |||
await user.click(notDefaultQualityGate); | |||
const searchInput = screen.getByRole('searchbox', { name: 'search_verb' }); | |||
expect(searchInput).toBeInTheDocument(); | |||
await user.click(searchInput); | |||
await user.keyboard('test2{Enter}'); | |||
expect(screen.getAllByRole('checkbox')).toHaveLength(1); | |||
}); | |||
it('should display show more button if there are multiple pages of data', async () => { | |||
(searchProjects as jest.Mock).mockResolvedValueOnce({ | |||
paging: { pageIndex: 2, pageSize: 3, total: 55 }, | |||
results: [] | |||
}); | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const notDefaultQualityGate = await screen.findByText('SonarSource way - CFamily'); | |||
await user.click(notDefaultQualityGate); | |||
expect(screen.getByRole('button', { name: 'show_more' })).toBeInTheDocument(); | |||
}); | |||
}); | |||
describe('The Permissions section', () => { | |||
it('should not show button to grant permission when user is not admin', () => { | |||
renderQualityGateApp(); | |||
expect(screen.queryByText('quality_gates.permissions')).not.toBeInTheDocument(); | |||
}); | |||
it('should show button to grant permission when user is admin', async () => { | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const grantPermissionButton = await screen.findByRole('button', { | |||
name: 'quality_gates.permissions.grant' | |||
}); | |||
expect(screen.getByText('quality_gates.permissions')).toBeInTheDocument(); | |||
expect(grantPermissionButton).toBeInTheDocument(); | |||
}); | |||
it('should assign permission to a user and delete it later', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
expect(screen.queryByText('userlogin')).not.toBeInTheDocument(); | |||
// Granting permission to a user | |||
const grantPermissionButton = await screen.findByRole('button', { | |||
name: 'quality_gates.permissions.grant' | |||
}); | |||
await user.click(grantPermissionButton); | |||
const popup = screen.getByRole('dialog'); | |||
const searchUserInput = within(popup).getByRole('textbox'); | |||
expect(searchUserInput).toBeInTheDocument(); | |||
const addUserButton = screen.getByRole('button', { | |||
name: 'add_verb' | |||
}); | |||
expect(addUserButton).toBeDisabled(); | |||
await user.click(searchUserInput); | |||
expect(screen.getAllByTestId('qg-add-permission-option')).toHaveLength(2); | |||
await user.click(screen.getByText('userlogin')); | |||
expect(addUserButton).toBeEnabled(); | |||
await user.click(addUserButton); | |||
expect(screen.getByText('userlogin')).toBeInTheDocument(); | |||
// Cancel granting permission | |||
await user.click(grantPermissionButton); | |||
await user.click(searchUserInput); | |||
await user.keyboard('test{Enter}'); | |||
const cancelButton = screen.getByRole('button', { | |||
name: 'cancel' | |||
}); | |||
await user.click(cancelButton); | |||
expect(screen.getAllByRole('listitem')).toHaveLength(1); | |||
// Delete the user permission | |||
const deleteButton = screen.getByTestId('permission-delete-button'); | |||
await user.click(deleteButton); | |||
const deletePopup = screen.getByRole('dialog'); | |||
const dialogDeleteButton = within(deletePopup).getByRole('button', { name: 'remove' }); | |||
await user.click(dialogDeleteButton); | |||
expect(screen.queryByRole('listitem')).not.toBeInTheDocument(); | |||
}); | |||
it('should assign permission to a group and delete it later', async () => { | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
expect(screen.queryByText('userlogin')).not.toBeInTheDocument(); | |||
// Granting permission to a group | |||
const grantPermissionButton = await screen.findByRole('button', { | |||
name: 'quality_gates.permissions.grant' | |||
}); | |||
await user.click(grantPermissionButton); | |||
const popup = screen.getByRole('dialog'); | |||
const searchUserInput = within(popup).getByRole('textbox'); | |||
const addUserButton = screen.getByRole('button', { | |||
name: 'add_verb' | |||
}); | |||
await user.click(searchUserInput); | |||
expect(screen.getAllByTestId('qg-add-permission-option')).toHaveLength(2); | |||
await user.click(screen.getAllByTestId('qg-add-permission-option')[1]); | |||
await user.click(addUserButton); | |||
expect(screen.getByText('Foo')).toBeInTheDocument(); | |||
// Delete the group permission | |||
const deleteButton = screen.getByTestId('permission-delete-button'); | |||
await user.click(deleteButton); | |||
const deletePopup = screen.getByRole('dialog'); | |||
const dialogDeleteButton = within(deletePopup).getByRole('button', { name: 'remove' }); | |||
await user.click(dialogDeleteButton); | |||
expect(screen.queryByRole('listitem')).not.toBeInTheDocument(); | |||
}); | |||
it('should handle searchUser service failure', async () => { | |||
(searchUsers as jest.Mock).mockRejectedValue('error'); | |||
const user = userEvent.setup(); | |||
handler.setIsAdmin(true); | |||
renderQualityGateApp(); | |||
const grantPermissionButton = await screen.findByRole('button', { | |||
name: 'quality_gates.permissions.grant' | |||
}); | |||
await user.click(grantPermissionButton); | |||
const popup = screen.getByRole('dialog'); | |||
const searchUserInput = within(popup).getByRole('textbox'); | |||
await user.click(searchUserInput); | |||
expect(screen.getByText('no_results')).toBeInTheDocument(); | |||
}); | |||
}); | |||
function renderQualityGateApp(appState?: AppState) { | |||
renderApp('quality_gates', routes, { appState }); | |||
} |
@@ -1,91 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import ScreenPositionHelper from '../../../../components/common/ScreenPositionHelper'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { | |||
addSideBarClass, | |||
addWhitePageClass, | |||
removeSideBarClass, | |||
removeWhitePageClass | |||
} from '../../../../helpers/pages'; | |||
import { mockRouter } from '../../../../helpers/testMocks'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import App from '../App'; | |||
jest.mock('../../../../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} />); | |||
} |
@@ -1,124 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { fetchQualityGate } from '../../../../api/quality-gates'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockCondition } from '../../../../helpers/testMocks'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { addCondition, deleteCondition, replaceCondition } from '../../utils'; | |||
import Details from '../Details'; | |||
jest.mock('../../../../api/quality-gates', () => { | |||
const { mockQualityGate } = jest.requireActual('../../../../helpers/mocks/quality-gates'); | |||
return { | |||
fetchQualityGate: jest.fn().mockResolvedValue(mockQualityGate()) | |||
}; | |||
}); | |||
jest.mock('../../utils', () => ({ | |||
checkIfDefault: jest.fn(() => false), | |||
addCondition: jest.fn(qg => qg), | |||
deleteCondition: jest.fn(qg => qg), | |||
replaceCondition: jest.fn(qg => qg) | |||
})); | |||
beforeEach(jest.clearAllMocks); | |||
it('should render correctly', async () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper).toMatchSnapshot('loading'); | |||
await waitAndUpdate(wrapper); | |||
expect(fetchQualityGate).toBeCalledWith({ id: '1' }); | |||
expect(wrapper).toMatchSnapshot('loaded'); | |||
}); | |||
it('should refresh if the QG id changes', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
jest.clearAllMocks(); | |||
wrapper.setProps({ id: '2' }); | |||
expect(fetchQualityGate).toBeCalledWith({ id: '2' }); | |||
}); | |||
it('should correctly add/replace/remove conditions', async () => { | |||
const qualityGate = mockQualityGate(); | |||
(fetchQualityGate as jest.Mock).mockResolvedValue(qualityGate); | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
instance.handleAddCondition(mockCondition()); | |||
expect(wrapper.state().qualityGate).toBeUndefined(); | |||
instance.handleSaveCondition(mockCondition(), mockCondition()); | |||
expect(wrapper.state().qualityGate).toBeUndefined(); | |||
instance.handleRemoveCondition(mockCondition()); | |||
expect(wrapper.state().qualityGate).toBeUndefined(); | |||
await waitAndUpdate(wrapper); | |||
const newCondition = mockCondition({ metric: 'bugs', id: '2' }); | |||
instance.handleAddCondition(newCondition); | |||
expect(addCondition).toBeCalledWith(qualityGate, newCondition); | |||
const updatedCondition = mockCondition({ metric: 'new_bugs' }); | |||
instance.handleSaveCondition(newCondition, updatedCondition); | |||
expect(replaceCondition).toBeCalledWith(qualityGate, newCondition, updatedCondition); | |||
instance.handleRemoveCondition(newCondition); | |||
expect(deleteCondition).toBeCalledWith(qualityGate, newCondition); | |||
}); | |||
it('should correctly handle setting default', async () => { | |||
const qualityGate = mockQualityGate(); | |||
(fetchQualityGate as jest.Mock).mockResolvedValue(qualityGate); | |||
const onSetDefault = jest.fn(); | |||
const wrapper = shallowRender({ onSetDefault }); | |||
wrapper.instance().handleSetDefault(); | |||
expect(wrapper.state().qualityGate).toBeUndefined(); | |||
await waitAndUpdate(wrapper); | |||
wrapper.instance().handleSetDefault(); | |||
expect(wrapper.state().qualityGate).toEqual( | |||
expect.objectContaining({ | |||
id: qualityGate.id, | |||
actions: { delete: false, setAsDefault: false } | |||
}) | |||
); | |||
}); | |||
function shallowRender(props: Partial<Details['props']> = {}) { | |||
return shallow<Details>( | |||
<Details | |||
id="1" | |||
onSetDefault={jest.fn()} | |||
qualityGates={[mockQualityGate()]} | |||
refreshQualityGates={jest.fn()} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -1,49 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockCondition } from '../../../../helpers/testMocks'; | |||
import { DetailsContent, DetailsContentProps } from '../DetailsContent'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('is not default'); | |||
expect(shallowRender({ isDefault: true })).toMatchSnapshot('is default'); | |||
expect( | |||
shallowRender({ isDefault: true, qualityGate: mockQualityGate({ conditions: [] }) }) | |||
).toMatchSnapshot('is default, no conditions'); | |||
expect( | |||
shallowRender({ | |||
qualityGate: mockQualityGate({ actions: { delegate: true } }) | |||
}) | |||
).toMatchSnapshot('Admin'); | |||
}); | |||
function shallowRender(props: Partial<DetailsContentProps> = {}) { | |||
return shallow( | |||
<DetailsContent | |||
onAddCondition={jest.fn()} | |||
onRemoveCondition={jest.fn()} | |||
onSaveCondition={jest.fn()} | |||
qualityGate={mockQualityGate({ conditions: [mockCondition()] })} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -1,97 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { setQualityGateAsDefault } from '../../../../api/quality-gates'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockCondition } from '../../../../helpers/testMocks'; | |||
import { click, waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import DetailsHeader from '../DetailsHeader'; | |||
jest.mock('../../../../api/quality-gates', () => ({ | |||
setQualityGateAsDefault: jest.fn().mockResolvedValue(null) | |||
})); | |||
beforeEach(jest.clearAllMocks); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect( | |||
shallowRender({ | |||
qualityGate: mockQualityGate({ isBuiltIn: true, conditions: [mockCondition()] }) | |||
}) | |||
).toMatchSnapshot('built-in'); | |||
expect( | |||
shallowRender({ | |||
qualityGate: mockQualityGate({ | |||
conditions: [mockCondition()], | |||
actions: { | |||
copy: true, | |||
delete: true, | |||
rename: true, | |||
setAsDefault: true | |||
} | |||
}) | |||
}) | |||
).toMatchSnapshot('admin actions'); | |||
expect( | |||
shallowRender({ | |||
qualityGate: mockQualityGate({ actions: { setAsDefault: true }, conditions: [] }) | |||
}) | |||
).toMatchSnapshot('no conditions, cannot set as default'); | |||
}); | |||
it('should allow the QG to be set as the default', async () => { | |||
const onSetDefault = jest.fn(); | |||
const refreshItem = jest.fn(); | |||
const refreshList = jest.fn(); | |||
const qualityGate = mockQualityGate({ id: 'one', actions: { setAsDefault: true } }); | |||
const wrapper = shallowRender({ onSetDefault, qualityGate, refreshItem, refreshList }); | |||
click(wrapper.find('Button#quality-gate-toggle-default')); | |||
expect(setQualityGateAsDefault).toBeCalledWith({ id: 'one' }); | |||
expect(onSetDefault).toBeCalled(); | |||
await waitAndUpdate(wrapper); | |||
expect(refreshItem).toBeCalled(); | |||
expect(refreshList).toBeCalled(); | |||
jest.clearAllMocks(); | |||
wrapper.setProps({ qualityGate: mockQualityGate({ ...qualityGate, isDefault: true }) }); | |||
click(wrapper.find('Button#quality-gate-toggle-default')); | |||
expect(setQualityGateAsDefault).not.toBeCalled(); | |||
expect(onSetDefault).not.toBeCalled(); | |||
await waitAndUpdate(wrapper); | |||
expect(refreshItem).not.toBeCalled(); | |||
expect(refreshList).not.toBeCalled(); | |||
}); | |||
function shallowRender(props: Partial<DetailsHeader['props']> = {}) { | |||
return shallow<DetailsHeader>( | |||
<DetailsHeader | |||
onSetDefault={jest.fn()} | |||
qualityGate={mockQualityGate({ conditions: [mockCondition()] })} | |||
refreshItem={jest.fn().mockResolvedValue(null)} | |||
refreshList={jest.fn().mockResolvedValue(null)} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -1,32 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockUser } from '../../../../helpers/testMocks'; | |||
import PermissionItem, { PermissionItemProps } from '../PermissionItem'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('user'); | |||
expect(shallowRender({ item: { name: 'groupname' } })).toMatchSnapshot('group'); | |||
}); | |||
function shallowRender(overrides: Partial<PermissionItemProps> = {}) { | |||
return shallow(<PermissionItem onClickDelete={jest.fn()} item={mockUser()} {...overrides} />); | |||
} |
@@ -1,119 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { | |||
associateGateWithProject, | |||
dissociateGateWithProject, | |||
searchProjects | |||
} from '../../../../api/quality-gates'; | |||
import SelectList, { SelectListFilter } from '../../../../components/controls/SelectList'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockCondition } from '../../../../helpers/testMocks'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import Projects from '../Projects'; | |||
jest.mock('../../../../api/quality-gates', () => ({ | |||
searchProjects: jest.fn().mockResolvedValue({ | |||
paging: { pageIndex: 1, pageSize: 3, total: 55 }, | |||
results: [ | |||
{ id: 'test1', key: 'test1', name: 'test1', selected: false }, | |||
{ id: 'test2', key: 'test2', name: 'test2', selected: false }, | |||
{ id: 'test3', key: 'test3', name: 'test3', selected: true } | |||
] | |||
}), | |||
associateGateWithProject: jest.fn().mockResolvedValue({}), | |||
dissociateGateWithProject: jest.fn().mockResolvedValue({}) | |||
})); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render correctly', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper | |||
.find(SelectList) | |||
.props() | |||
.onSearch({ | |||
query: '', | |||
filter: SelectListFilter.Selected, | |||
page: 1, | |||
pageSize: 100 | |||
}); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.instance().mounted).toBe(true); | |||
expect(wrapper).toMatchSnapshot('default'); | |||
expect(wrapper.instance().renderElement('test1')).toMatchSnapshot('known project'); | |||
expect(wrapper.instance().renderElement('test_foo')).toMatchSnapshot('unknown project'); | |||
expect(shallowRender({ qualityGate: mockQualityGate({ conditions: [] }) })).toMatchSnapshot( | |||
'quality gate without conditions' | |||
); | |||
expect(searchProjects).toHaveBeenCalledWith( | |||
expect.objectContaining({ | |||
gateName: 'Foo', | |||
page: 1, | |||
pageSize: 100, | |||
query: undefined, | |||
selected: SelectListFilter.Selected | |||
}) | |||
); | |||
expect(wrapper.state().needToReload).toBe(false); | |||
wrapper.instance().componentWillUnmount(); | |||
expect(wrapper.instance().mounted).toBe(false); | |||
}); | |||
it('should handle selection properly', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper.instance().handleSelect('toto'); | |||
await waitAndUpdate(wrapper); | |||
expect(associateGateWithProject).toHaveBeenCalledWith( | |||
expect.objectContaining({ | |||
projectKey: 'toto' | |||
}) | |||
); | |||
expect(wrapper.state().needToReload).toBe(true); | |||
}); | |||
it('should handle deselection properly', async () => { | |||
const wrapper = shallowRender(); | |||
wrapper.instance().handleUnselect('tata'); | |||
await waitAndUpdate(wrapper); | |||
expect(dissociateGateWithProject).toHaveBeenCalledWith( | |||
expect.objectContaining({ | |||
projectKey: 'tata' | |||
}) | |||
); | |||
expect(wrapper.state().needToReload).toBe(true); | |||
}); | |||
function shallowRender(props: Partial<Projects['props']> = {}) { | |||
return shallow<Projects>( | |||
<Projects | |||
qualityGate={mockQualityGate({ name: 'Foo', conditions: [mockCondition()] })} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -1,247 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { | |||
addGroup, | |||
addUser, | |||
removeGroup, | |||
removeUser, | |||
searchGroups, | |||
searchUsers | |||
} from '../../../../api/quality-gates'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockUserBase } from '../../../../helpers/mocks/users'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import QualityGatePermissions from '../QualityGatePermissions'; | |||
jest.mock('../../../../api/quality-gates', () => ({ | |||
addUser: jest.fn().mockResolvedValue(undefined), | |||
removeUser: jest.fn().mockResolvedValue(undefined), | |||
searchUsers: jest.fn().mockResolvedValue({ users: [] }), | |||
addGroup: jest.fn().mockResolvedValue(undefined), | |||
removeGroup: jest.fn().mockResolvedValue(undefined), | |||
searchGroups: jest.fn().mockResolvedValue({ groups: [] }) | |||
})); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should fetch users and groups', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(searchUsers).toBeCalledWith({ gateName: 'qualitygate', selected: 'selected' }); | |||
expect(searchGroups).toBeCalledWith({ gateName: 'qualitygate', selected: 'selected' }); | |||
}); | |||
it('should handle errors when fetching users and groups', async () => { | |||
(searchUsers as jest.Mock).mockRejectedValueOnce('nope'); | |||
(searchGroups as jest.Mock).mockRejectedValueOnce('nope'); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().groups).toHaveLength(0); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
}); | |||
it('should fetch users and groups on update', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
(searchUsers as jest.Mock).mockClear(); | |||
wrapper.setProps({ qualityGate: mockQualityGate({ id: '2', name: 'qg2' }) }); | |||
expect(searchUsers).toBeCalledWith({ gateName: 'qg2', selected: 'selected' }); | |||
}); | |||
it('should handleCloseAddPermission', () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ showAddModal: true }); | |||
wrapper.instance().handleCloseAddPermission(); | |||
expect(wrapper.state().showAddModal).toBe(false); | |||
}); | |||
it('should handleClickAddPermission', () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ showAddModal: false }); | |||
wrapper.instance().handleClickAddPermission(); | |||
expect(wrapper.state().showAddModal).toBe(true); | |||
}); | |||
it('should handleSubmitAddPermission for a user', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
expect(wrapper.state().groups).toHaveLength(0); | |||
wrapper.instance().handleSubmitAddPermission(mockUserBase({ login: 'user1', name: 'User One' })); | |||
expect(wrapper.state().submitting).toBe(true); | |||
expect(addUser).toBeCalledWith({ gateName: 'qualitygate', login: 'user1' }); | |||
expect(addGroup).not.toBeCalled(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().submitting).toBe(false); | |||
expect(wrapper.state().showAddModal).toBe(false); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
expect(wrapper.state().groups).toHaveLength(0); | |||
}); | |||
it('should handleSubmitAddPermission for a group', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
expect(wrapper.state().groups).toHaveLength(0); | |||
wrapper.instance().handleSubmitAddPermission({ name: 'group' }); | |||
expect(wrapper.state().submitting).toBe(true); | |||
expect(addUser).not.toBeCalled(); | |||
expect(addGroup).toBeCalledWith({ gateName: 'qualitygate', groupName: 'group' }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().submitting).toBe(false); | |||
expect(wrapper.state().showAddModal).toBe(false); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
expect(wrapper.state().groups).toHaveLength(1); | |||
}); | |||
it('should handleSubmitAddPermission if it returns an error', async () => { | |||
(addUser as jest.Mock).mockRejectedValueOnce(undefined); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
wrapper.setState({ showAddModal: true }); | |||
wrapper.instance().handleSubmitAddPermission(mockUserBase({ login: 'user1', name: 'User One' })); | |||
expect(wrapper.state().submitting).toBe(true); | |||
expect(addUser).toBeCalledWith({ gateName: 'qualitygate', login: 'user1' }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().submitting).toBe(false); | |||
expect(wrapper.state().showAddModal).toBe(true); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
}); | |||
it('should handleCloseDeletePermission', () => { | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ permissionToDelete: mockUserBase() }); | |||
wrapper.instance().handleCloseDeletePermission(); | |||
expect(wrapper.state().permissionToDelete).toBeUndefined(); | |||
}); | |||
it('should handleClickDeletePermission', () => { | |||
const user = mockUserBase(); | |||
const wrapper = shallowRender(); | |||
wrapper.setState({ permissionToDelete: undefined }); | |||
wrapper.instance().handleClickDeletePermission(user); | |||
expect(wrapper.state().permissionToDelete).toBe(user); | |||
}); | |||
it('should handleConfirmDeletePermission for a user', async () => { | |||
const deleteThisUser = mockUserBase(); | |||
const deleteThisGroup = { name: 'deletableGroup' }; | |||
(searchUsers as jest.Mock).mockResolvedValueOnce({ users: [deleteThisUser] }); | |||
(searchGroups as jest.Mock).mockResolvedValueOnce({ groups: [deleteThisGroup] }); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
expect(wrapper.state().groups).toHaveLength(1); | |||
wrapper.instance().handleConfirmDeletePermission(deleteThisUser); | |||
expect(removeUser).toBeCalledWith({ gateName: 'qualitygate', login: deleteThisUser.login }); | |||
expect(removeGroup).not.toBeCalled(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().permissionToDelete).toBeUndefined(); | |||
expect(wrapper.state().users).toHaveLength(0); | |||
expect(wrapper.state().groups).toHaveLength(1); | |||
}); | |||
it('should handleConfirmDeletePermission for a group', async () => { | |||
const deleteThisUser = mockUserBase(); | |||
const deleteThisGroup = { name: 'deletableGroup' }; | |||
(searchUsers as jest.Mock).mockResolvedValueOnce({ users: [deleteThisUser] }); | |||
(searchGroups as jest.Mock).mockResolvedValueOnce({ groups: [deleteThisGroup] }); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
expect(wrapper.state().groups).toHaveLength(1); | |||
wrapper.instance().handleConfirmDeletePermission(deleteThisGroup); | |||
expect(removeUser).not.toBeCalled(); | |||
expect(removeGroup).toBeCalledWith({ gateName: 'qualitygate', groupName: deleteThisGroup.name }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().permissionToDelete).toBeUndefined(); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
expect(wrapper.state().groups).toHaveLength(0); | |||
}); | |||
it('should handleConfirmDeletePermission if it returns an error', async () => { | |||
const deleteThisUser = mockUserBase(); | |||
(searchUsers as jest.Mock).mockResolvedValueOnce({ users: [deleteThisUser] }); | |||
(removeUser as jest.Mock).mockRejectedValueOnce(undefined); | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
wrapper.instance().handleConfirmDeletePermission(deleteThisUser); | |||
expect(removeUser).toBeCalledWith({ gateName: 'qualitygate', login: deleteThisUser.login }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.state().permissionToDelete).toBeUndefined(); | |||
expect(wrapper.state().users).toHaveLength(1); | |||
}); | |||
function shallowRender(overrides: Partial<QualityGatePermissions['props']> = {}) { | |||
return shallow<QualityGatePermissions>( | |||
<QualityGatePermissions qualityGate={mockQualityGate()} {...overrides} /> | |||
); | |||
} |
@@ -1,93 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { searchGroups, searchUsers } from '../../../../api/quality-gates'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockUserBase } from '../../../../helpers/mocks/users'; | |||
import { mockEvent } from '../../../../helpers/testUtils'; | |||
import QualityGatePermissionsAddModal from '../QualityGatePermissionsAddModal'; | |||
import QualityGatePermissionsAddModalRenderer from '../QualityGatePermissionsAddModalRenderer'; | |||
jest.mock('../../../../api/quality-gates', () => ({ | |||
searchUsers: jest.fn().mockResolvedValue({ users: [] }), | |||
searchGroups: jest.fn().mockResolvedValue({ groups: [] }) | |||
})); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should fetch users and groups on mount', async () => { | |||
(searchUsers as jest.Mock).mockResolvedValue({ users: [mockUserBase()] }); | |||
(searchGroups as jest.Mock).mockResolvedValue({ groups: [{ name: 'group' }] }); | |||
const wrapper = shallowRender(); | |||
const query = 'Waldo'; | |||
const results = await new Promise(resolve => { | |||
wrapper.instance().handleSearch(query, resolve); | |||
}); | |||
expect(searchUsers).toBeCalledWith(expect.objectContaining({ q: query })); | |||
expect(searchGroups).toBeCalledWith(expect.objectContaining({ q: query })); | |||
expect(results).toHaveLength(2); | |||
}); | |||
it('should handleSelection', () => { | |||
const wrapper = shallowRender(); | |||
const selection = { ...mockUserBase(), value: 'value' }; | |||
wrapper | |||
.find(QualityGatePermissionsAddModalRenderer) | |||
.props() | |||
.onSelection(selection); | |||
expect(wrapper.state().selection).toBe(selection); | |||
}); | |||
it('should handleSubmit', () => { | |||
const onSubmit = jest.fn(); | |||
const wrapper = shallowRender({ onSubmit }); | |||
wrapper.instance().handleSubmit(mockEvent()); | |||
expect(onSubmit).not.toBeCalled(); | |||
const selection = mockUserBase(); | |||
wrapper.setState({ selection }); | |||
wrapper.instance().handleSubmit(mockEvent()); | |||
expect(onSubmit).toBeCalledWith(selection); | |||
}); | |||
function shallowRender(overrides: Partial<QualityGatePermissionsAddModal['props']> = {}) { | |||
return shallow<QualityGatePermissionsAddModal>( | |||
<QualityGatePermissionsAddModal | |||
onClose={jest.fn()} | |||
onSubmit={jest.fn()} | |||
submitting={false} | |||
qualityGate={mockQualityGate()} | |||
{...overrides} | |||
/> | |||
); | |||
} |
@@ -1,53 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockUserBase } from '../../../../helpers/mocks/users'; | |||
import QualityGatePermissionsAddModalRenderer, { | |||
customOptions, | |||
QualityGatePermissionsAddModalRendererProps | |||
} from '../QualityGatePermissionsAddModalRenderer'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ selection: mockUserBase(), submitting: true })).toMatchSnapshot( | |||
'with selection and submitting' | |||
); | |||
}); | |||
it('should render options correctly', () => { | |||
expect( | |||
customOptions({ avatar: 'A', name: 'name', login: 'login', value: 'login' }) | |||
).toMatchSnapshot('user'); | |||
expect(customOptions({ name: 'group name', value: 'group name' })).toMatchSnapshot('group'); | |||
}); | |||
function shallowRender(overrides: Partial<QualityGatePermissionsAddModalRendererProps> = {}) { | |||
return shallow( | |||
<QualityGatePermissionsAddModalRenderer | |||
onClose={jest.fn()} | |||
onSelection={jest.fn()} | |||
onSubmit={jest.fn()} | |||
handleSearch={jest.fn()} | |||
submitting={false} | |||
{...overrides} | |||
/> | |||
); | |||
} |
@@ -1,62 +0,0 @@ | |||
/* | |||
* 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||
import { mockUserBase } from '../../../../helpers/mocks/users'; | |||
import { mockUser } from '../../../../helpers/testMocks'; | |||
import QualityGatePermissionsRenderer, { | |||
QualityGatePermissionsRendererProps | |||
} from '../QualityGatePermissionsRenderer'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('with users and groups'); | |||
expect(shallowRender({ users: [] })).toMatchSnapshot('with no users'); | |||
expect(shallowRender({ groups: [] })).toMatchSnapshot('with no groups'); | |||
expect(shallowRender({ groups: [], users: [] })).toMatchSnapshot('with no users or groups'); | |||
expect(shallowRender({ showAddModal: true })).toMatchSnapshot('show add modal'); | |||
expect(shallowRender({ permissionToDelete: mockUserBase() })).toMatchSnapshot( | |||
'show remove modal for user' | |||
); | |||
expect(shallowRender({ permissionToDelete: { name: 'deletable group' } })).toMatchSnapshot( | |||
'show remove modal for group' | |||
); | |||
}); | |||
function shallowRender(overrides: Partial<QualityGatePermissionsRendererProps> = {}) { | |||
return shallow( | |||
<QualityGatePermissionsRenderer | |||
groups={[{ name: 'group' }]} | |||
loading={false} | |||
onClickAddPermission={jest.fn()} | |||
onCloseAddPermission={jest.fn()} | |||
onSubmitAddPermission={jest.fn()} | |||
onCloseDeletePermission={jest.fn()} | |||
onClickDeletePermission={jest.fn()} | |||
onConfirmDeletePermission={jest.fn()} | |||
qualityGate={mockQualityGate()} | |||
showAddModal={false} | |||
submitting={false} | |||
users={[mockUser()]} | |||
{...overrides} | |||
/> | |||
); | |||
} |
@@ -1,147 +0,0 @@ | |||
// 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} | |||
prioritizeSeoTags={false} | |||
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} | |||
prioritizeSeoTags={false} | |||
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> | |||
<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} | |||
prioritizeSeoTags={false} | |||
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> | |||
<Details | |||
id="1" | |||
onSetDefault={[Function]} | |||
qualityGates={ | |||
Array [ | |||
Object { | |||
"id": "1", | |||
"name": "qualitygate", | |||
}, | |||
Object { | |||
"id": "2", | |||
"isDefault": true, | |||
"name": "qualitygate 2", | |||
}, | |||
] | |||
} | |||
refreshQualityGates={[Function]} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; |
@@ -1,53 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: loaded 1`] = ` | |||
<div | |||
className="layout-page-main" | |||
> | |||
<DeferredSpinner | |||
loading={false} | |||
timeout={200} | |||
> | |||
<Helmet | |||
defer={false} | |||
encodeSpecialCharacters={true} | |||
prioritizeSeoTags={false} | |||
title="qualitygate" | |||
/> | |||
<DetailsHeader | |||
onSetDefault={[Function]} | |||
qualityGate={ | |||
Object { | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
refreshItem={[Function]} | |||
refreshList={[MockFunction]} | |||
/> | |||
<Memo(DetailsContent) | |||
isDefault={false} | |||
onAddCondition={[Function]} | |||
onRemoveCondition={[Function]} | |||
onSaveCondition={[Function]} | |||
qualityGate={ | |||
Object { | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
</DeferredSpinner> | |||
</div> | |||
`; | |||
exports[`should render correctly: loading 1`] = ` | |||
<div | |||
className="layout-page-main" | |||
> | |||
<DeferredSpinner | |||
loading={true} | |||
timeout={200} | |||
/> | |||
</div> | |||
`; |
@@ -1,275 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: Admin 1`] = ` | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<withMetricsContext(withAppStateContext(Conditions)) | |||
canEdit={false} | |||
conditions={Array []} | |||
onAddCondition={[MockFunction]} | |||
onRemoveCondition={[MockFunction]} | |||
onSaveCondition={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"actions": Object { | |||
"delegate": true, | |||
}, | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
<div | |||
className="display-flex-row huge-spacer-top" | |||
> | |||
<div | |||
className="quality-gate-section width-50 big-padded-right" | |||
id="quality-gate-projects" | |||
> | |||
<header | |||
className="display-flex-center spacer-bottom" | |||
> | |||
<h3> | |||
quality_gates.projects | |||
</h3> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<div | |||
className="big-padded-top big-padded-bottom" | |||
> | |||
quality_gates.projects.help | |||
</div> | |||
} | |||
/> | |||
</header> | |||
<Projects | |||
key="1" | |||
qualityGate={ | |||
Object { | |||
"actions": Object { | |||
"delegate": true, | |||
}, | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
</div> | |||
<div | |||
className="width-50 big-padded-left" | |||
> | |||
<QualityGatePermissions | |||
qualityGate={ | |||
Object { | |||
"actions": Object { | |||
"delegate": true, | |||
}, | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: is default 1`] = ` | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<withMetricsContext(withAppStateContext(Conditions)) | |||
canEdit={false} | |||
conditions={ | |||
Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
] | |||
} | |||
onAddCondition={[MockFunction]} | |||
onRemoveCondition={[MockFunction]} | |||
onSaveCondition={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"conditions": Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
], | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
<div | |||
className="display-flex-row huge-spacer-top" | |||
> | |||
<div | |||
className="quality-gate-section width-50 big-padded-right" | |||
id="quality-gate-projects" | |||
> | |||
<header | |||
className="display-flex-center spacer-bottom" | |||
> | |||
<h3> | |||
quality_gates.projects | |||
</h3> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<div | |||
className="big-padded-top big-padded-bottom" | |||
> | |||
quality_gates.projects.help | |||
</div> | |||
} | |||
/> | |||
</header> | |||
quality_gates.projects_for_default | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: is default, no conditions 1`] = ` | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<Alert | |||
className="big-spacer-bottom" | |||
variant="warning" | |||
> | |||
quality_gates.is_default_no_conditions | |||
</Alert> | |||
<withMetricsContext(withAppStateContext(Conditions)) | |||
canEdit={false} | |||
conditions={Array []} | |||
onAddCondition={[MockFunction]} | |||
onRemoveCondition={[MockFunction]} | |||
onSaveCondition={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"conditions": Array [], | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
<div | |||
className="display-flex-row huge-spacer-top" | |||
> | |||
<div | |||
className="quality-gate-section width-50 big-padded-right" | |||
id="quality-gate-projects" | |||
> | |||
<header | |||
className="display-flex-center spacer-bottom" | |||
> | |||
<h3> | |||
quality_gates.projects | |||
</h3> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<div | |||
className="big-padded-top big-padded-bottom" | |||
> | |||
quality_gates.projects.help | |||
</div> | |||
} | |||
/> | |||
</header> | |||
quality_gates.projects_for_default | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: is not default 1`] = ` | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<withMetricsContext(withAppStateContext(Conditions)) | |||
canEdit={false} | |||
conditions={ | |||
Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
] | |||
} | |||
onAddCondition={[MockFunction]} | |||
onRemoveCondition={[MockFunction]} | |||
onSaveCondition={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"conditions": Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
], | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
<div | |||
className="display-flex-row huge-spacer-top" | |||
> | |||
<div | |||
className="quality-gate-section width-50 big-padded-right" | |||
id="quality-gate-projects" | |||
> | |||
<header | |||
className="display-flex-center spacer-bottom" | |||
> | |||
<h3> | |||
quality_gates.projects | |||
</h3> | |||
<HelpTooltip | |||
className="spacer-left" | |||
overlay={ | |||
<div | |||
className="big-padded-top big-padded-bottom" | |||
> | |||
quality_gates.projects.help | |||
</div> | |||
} | |||
/> | |||
</header> | |||
<Projects | |||
key="1" | |||
qualityGate={ | |||
Object { | |||
"conditions": Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
], | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -1,163 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: admin actions 1`] = ` | |||
<div | |||
className="layout-page-header-panel layout-page-main-header issues-main-header" | |||
> | |||
<div | |||
className="layout-page-header-panel-inner layout-page-main-header-inner" | |||
> | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<div | |||
className="pull-left display-flex-center" | |||
> | |||
<h2> | |||
qualitygate | |||
</h2> | |||
</div> | |||
<div | |||
className="pull-right" | |||
> | |||
<ModalButton | |||
modal={[Function]} | |||
> | |||
<Component /> | |||
</ModalButton> | |||
<ModalButton | |||
modal={[Function]} | |||
> | |||
<Component /> | |||
</ModalButton> | |||
<Tooltip | |||
overlay={null} | |||
> | |||
<Button | |||
className="little-spacer-left" | |||
disabled={false} | |||
id="quality-gate-toggle-default" | |||
onClick={[Function]} | |||
> | |||
set_as_default | |||
</Button> | |||
</Tooltip> | |||
<withRouter(DeleteQualityGateForm) | |||
onDelete={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"actions": Object { | |||
"copy": true, | |||
"delete": true, | |||
"rename": true, | |||
"setAsDefault": true, | |||
}, | |||
"conditions": Array [ | |||
Object { | |||
"error": "10", | |||
"id": "1", | |||
"metric": "coverage", | |||
"op": "LT", | |||
}, | |||
], | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: built-in 1`] = ` | |||
<div | |||
className="layout-page-header-panel layout-page-main-header issues-main-header" | |||
> | |||
<div | |||
className="layout-page-header-panel-inner layout-page-main-header-inner" | |||
> | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<div | |||
className="pull-left display-flex-center" | |||
> | |||
<h2> | |||
qualitygate | |||
</h2> | |||
<BuiltInQualityGateBadge | |||
className="spacer-left" | |||
/> | |||
</div> | |||
<div | |||
className="pull-right" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: default 1`] = ` | |||
<div | |||
className="layout-page-header-panel layout-page-main-header issues-main-header" | |||
> | |||
<div | |||
className="layout-page-header-panel-inner layout-page-main-header-inner" | |||
> | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<div | |||
className="pull-left display-flex-center" | |||
> | |||
<h2> | |||
qualitygate | |||
</h2> | |||
</div> | |||
<div | |||
className="pull-right" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render correctly: no conditions, cannot set as default 1`] = ` | |||
<div | |||
className="layout-page-header-panel layout-page-main-header issues-main-header" | |||
> | |||
<div | |||
className="layout-page-header-panel-inner layout-page-main-header-inner" | |||
> | |||
<div | |||
className="layout-page-main-inner" | |||
> | |||
<div | |||
className="pull-left display-flex-center" | |||
> | |||
<h2> | |||
qualitygate | |||
</h2> | |||
</div> | |||
<div | |||
className="pull-right" | |||
> | |||
<Tooltip | |||
overlay="quality_gates.cannot_set_default_no_conditions" | |||
> | |||
<Button | |||
className="little-spacer-left" | |||
disabled={true} | |||
id="quality-gate-toggle-default" | |||
onClick={[Function]} | |||
> | |||
set_as_default | |||
</Button> | |||
</Tooltip> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -1,49 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: group 1`] = ` | |||
<div | |||
className="display-flex-center permission-list-item padded" | |||
> | |||
<GroupIcon | |||
className="pull-left spacer-right" | |||
size={32} | |||
/> | |||
<div | |||
className="overflow-hidden flex-1" | |||
> | |||
<strong> | |||
groupname | |||
</strong> | |||
</div> | |||
<DeleteButton | |||
onClick={[Function]} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly: user 1`] = ` | |||
<div | |||
className="display-flex-center permission-list-item padded" | |||
> | |||
<withAppStateContext(Avatar) | |||
className="spacer-right" | |||
name="John Doe" | |||
size={32} | |||
/> | |||
<div | |||
className="overflow-hidden flex-1" | |||
> | |||
<strong> | |||
John Doe | |||
</strong> | |||
<div | |||
className="note" | |||
> | |||
john.doe | |||
</div> | |||
</div> | |||
<DeleteButton | |||
onClick={[Function]} | |||
/> | |||
</div> | |||
`; |
@@ -1,59 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: default 1`] = ` | |||
<SelectList | |||
elements={ | |||
Array [ | |||
"test1", | |||
"test2", | |||
"test3", | |||
] | |||
} | |||
elementsTotalCount={55} | |||
labelAll="quality_gates.projects.all" | |||
labelSelected="quality_gates.projects.with" | |||
labelUnselected="quality_gates.projects.without" | |||
needToReload={false} | |||
onSearch={[Function]} | |||
onSelect={[Function]} | |||
onUnselect={[Function]} | |||
readOnly={true} | |||
renderElement={[Function]} | |||
selectedElements={ | |||
Array [ | |||
"test3", | |||
] | |||
} | |||
withPaging={true} | |||
/> | |||
`; | |||
exports[`should render correctly: known project 1`] = ` | |||
<div | |||
className="select-list-list-item" | |||
> | |||
<React.Fragment> | |||
test1 | |||
<br /> | |||
<span | |||
className="note" | |||
> | |||
test1 | |||
</span> | |||
</React.Fragment> | |||
</div> | |||
`; | |||
exports[`should render correctly: quality gate without conditions 1`] = ` | |||
<div> | |||
quality_gates.projects.cannot_associate_projects_no_conditions | |||
</div> | |||
`; | |||
exports[`should render correctly: unknown project 1`] = ` | |||
<div | |||
className="select-list-list-item" | |||
> | |||
test_foo | |||
</div> | |||
`; |
@@ -1,23 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<QualityGatePermissionsRenderer | |||
groups={Array []} | |||
loading={true} | |||
onClickAddPermission={[Function]} | |||
onClickDeletePermission={[Function]} | |||
onCloseAddPermission={[Function]} | |||
onCloseDeletePermission={[Function]} | |||
onConfirmDeletePermission={[Function]} | |||
onSubmitAddPermission={[Function]} | |||
qualityGate={ | |||
Object { | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
showAddModal={false} | |||
submitting={false} | |||
users={Array []} | |||
/> | |||
`; |
@@ -1,11 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<QualityGatePermissionsAddModalRenderer | |||
handleSearch={[Function]} | |||
onClose={[MockFunction]} | |||
onSelection={[Function]} | |||
onSubmit={[Function]} | |||
submitting={false} | |||
/> | |||
`; |
@@ -1,165 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: default 1`] = ` | |||
<Modal | |||
contentLabel="quality_gates.permissions.grant" | |||
onRequestClose={[MockFunction]} | |||
> | |||
<header | |||
className="modal-head" | |||
> | |||
<h2> | |||
quality_gates.permissions.grant | |||
</h2> | |||
</header> | |||
<form | |||
onSubmit={[MockFunction]} | |||
> | |||
<div | |||
className="modal-body" | |||
> | |||
<div | |||
className="modal-field" | |||
> | |||
<label> | |||
quality_gates.permissions.search | |||
</label> | |||
<SearchSelect | |||
autoFocus={true} | |||
components={ | |||
Object { | |||
"Control": [Function], | |||
"Option": [Function], | |||
"SingleValue": [Function], | |||
} | |||
} | |||
defaultOptions={true} | |||
getOptionValue={[Function]} | |||
isClearable={false} | |||
large={true} | |||
loadOptions={[MockFunction]} | |||
noOptionsMessage={[Function]} | |||
onChange={[MockFunction]} | |||
placeholder="" | |||
/> | |||
</div> | |||
</div> | |||
<footer | |||
className="modal-foot" | |||
> | |||
<SubmitButton | |||
disabled={true} | |||
> | |||
add_verb | |||
</SubmitButton> | |||
<ResetButtonLink | |||
onClick={[MockFunction]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
</Modal> | |||
`; | |||
exports[`should render correctly: with selection and submitting 1`] = ` | |||
<Modal | |||
contentLabel="quality_gates.permissions.grant" | |||
onRequestClose={[MockFunction]} | |||
> | |||
<header | |||
className="modal-head" | |||
> | |||
<h2> | |||
quality_gates.permissions.grant | |||
</h2> | |||
</header> | |||
<form | |||
onSubmit={[MockFunction]} | |||
> | |||
<div | |||
className="modal-body" | |||
> | |||
<div | |||
className="modal-field" | |||
> | |||
<label> | |||
quality_gates.permissions.search | |||
</label> | |||
<SearchSelect | |||
autoFocus={true} | |||
components={ | |||
Object { | |||
"Control": [Function], | |||
"Option": [Function], | |||
"SingleValue": [Function], | |||
} | |||
} | |||
defaultOptions={true} | |||
getOptionValue={[Function]} | |||
isClearable={false} | |||
large={true} | |||
loadOptions={[MockFunction]} | |||
noOptionsMessage={[Function]} | |||
onChange={[MockFunction]} | |||
placeholder="" | |||
/> | |||
</div> | |||
</div> | |||
<footer | |||
className="modal-foot" | |||
> | |||
<i | |||
className="spinner spacer-right" | |||
/> | |||
<SubmitButton | |||
disabled={true} | |||
> | |||
add_verb | |||
</SubmitButton> | |||
<ResetButtonLink | |||
onClick={[MockFunction]} | |||
> | |||
cancel | |||
</ResetButtonLink> | |||
</footer> | |||
</form> | |||
</Modal> | |||
`; | |||
exports[`should render options correctly: group 1`] = ` | |||
<span | |||
className="display-flex-center" | |||
> | |||
<GroupIcon | |||
size={16} | |||
/> | |||
<strong | |||
className="spacer-left" | |||
> | |||
group name | |||
</strong> | |||
</span> | |||
`; | |||
exports[`should render options correctly: user 1`] = ` | |||
<span | |||
className="display-flex-center" | |||
> | |||
<withAppStateContext(Avatar) | |||
hash="A" | |||
name="name" | |||
size={16} | |||
/> | |||
<strong | |||
className="spacer-left" | |||
> | |||
name | |||
</strong> | |||
<span | |||
className="note little-spacer-left" | |||
> | |||
login | |||
</span> | |||
</span> | |||
`; |
@@ -1,409 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: show add modal 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="john.doe" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
<li | |||
key="group" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"name": "group", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
<QualityGatePermissionsAddModal | |||
onClose={[MockFunction]} | |||
onSubmit={[MockFunction]} | |||
qualityGate={ | |||
Object { | |||
"id": "1", | |||
"name": "qualitygate", | |||
} | |||
} | |||
submitting={false} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly: show remove modal for group 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="john.doe" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
<li | |||
key="group" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"name": "group", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
<ConfirmModal | |||
confirmButtonText="remove" | |||
confirmData={ | |||
Object { | |||
"name": "deletable group", | |||
} | |||
} | |||
header="quality_gates.permissions.remove.group" | |||
isDestructive={true} | |||
onClose={[MockFunction]} | |||
onConfirm={[MockFunction]} | |||
> | |||
<FormattedMessage | |||
defaultMessage="quality_gates.permissions.remove.group.confirmation" | |||
id="remove.confirmation" | |||
values={ | |||
Object { | |||
"user": <strong> | |||
deletable group | |||
</strong>, | |||
} | |||
} | |||
/> | |||
</ConfirmModal> | |||
</div> | |||
`; | |||
exports[`should render correctly: show remove modal for user 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="john.doe" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
<li | |||
key="group" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"name": "group", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
<ConfirmModal | |||
confirmButtonText="remove" | |||
confirmData={ | |||
Object { | |||
"login": "userlogin", | |||
} | |||
} | |||
header="quality_gates.permissions.remove.user" | |||
isDestructive={true} | |||
onClose={[MockFunction]} | |||
onConfirm={[MockFunction]} | |||
> | |||
<FormattedMessage | |||
defaultMessage="quality_gates.permissions.remove.user.confirmation" | |||
id="remove.confirmation" | |||
values={ | |||
Object { | |||
"user": <strong />, | |||
} | |||
} | |||
/> | |||
</ConfirmModal> | |||
</div> | |||
`; | |||
exports[`should render correctly: with no groups 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="john.doe" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
</div> | |||
`; | |||
exports[`should render correctly: with no users 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="group" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"name": "group", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
</div> | |||
`; | |||
exports[`should render correctly: with no users or groups 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul /> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
</div> | |||
`; | |||
exports[`should render correctly: with users and groups 1`] = ` | |||
<div | |||
className="quality-gate-permissions" | |||
> | |||
<h3 | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions | |||
</h3> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
quality_gates.permissions.help | |||
</p> | |||
<div> | |||
<DeferredSpinner | |||
loading={false} | |||
> | |||
<ul> | |||
<li | |||
key="john.doe" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"active": true, | |||
"local": true, | |||
"login": "john.doe", | |||
"name": "John Doe", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
<li | |||
key="group" | |||
> | |||
<PermissionItem | |||
item={ | |||
Object { | |||
"name": "group", | |||
} | |||
} | |||
onClickDelete={[MockFunction]} | |||
/> | |||
</li> | |||
</ul> | |||
</DeferredSpinner> | |||
</div> | |||
<Button | |||
className="big-spacer-top" | |||
onClick={[MockFunction]} | |||
> | |||
quality_gates.permissions.grant | |||
</Button> | |||
</div> | |||
`; |