Browse Source

SONAR-16247 RTL migration for quality gates app

tags/9.5.0.56709
Revanshu Paliwal 2 years ago
parent
commit
7c59be8a74
25 changed files with 315 additions and 2335 deletions
  1. 93
    10
      server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts
  2. 4
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx
  3. 8
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx
  4. 1
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx
  5. 209
    1
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx
  6. 0
    91
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App.tsx
  7. 0
    124
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Details-test.tsx
  8. 0
    49
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DetailsContent-test.tsx
  9. 0
    97
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DetailsHeader-test.tsx
  10. 0
    32
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/PermissionItem-test.tsx
  11. 0
    119
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx
  12. 0
    247
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissions-test.tsx
  13. 0
    93
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModal-test.tsx
  14. 0
    53
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx
  15. 0
    62
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsRenderer-test.tsx
  16. 0
    147
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/App.tsx.snap
  17. 0
    53
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Details-test.tsx.snap
  18. 0
    275
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap
  19. 0
    163
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsHeader-test.tsx.snap
  20. 0
    49
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/PermissionItem-test.tsx.snap
  21. 0
    59
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Projects-test.tsx.snap
  22. 0
    23
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissions-test.tsx.snap
  23. 0
    11
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModal-test.tsx.snap
  24. 0
    165
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap
  25. 0
    409
      server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsRenderer-test.tsx.snap

+ 93
- 10
server/sonar-web/src/main/js/api/mocks/QualityGatesServiceMock.ts View File

@@ -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));
}

+ 4
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/PermissionItem.tsx View File

@@ -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>
);
}

+ 8
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx View File

@@ -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;


+ 1
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx View File

@@ -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} />
) : (

+ 209
- 1
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App-it.tsx View File

@@ -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 });
}

+ 0
- 91
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/App.tsx View File

@@ -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} />);
}

+ 0
- 124
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Details-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 49
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DetailsContent-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 97
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/DetailsHeader-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 32
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/PermissionItem-test.tsx View File

@@ -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} />);
}

+ 0
- 119
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/Projects-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 247
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissions-test.tsx View File

@@ -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} />
);
}

+ 0
- 93
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModal-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 53
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsAddModalRenderer-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 62
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGatePermissionsRenderer-test.tsx View File

@@ -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}
/>
);
}

+ 0
- 147
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/App.tsx.snap View File

@@ -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>
`;

+ 0
- 53
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Details-test.tsx.snap View File

@@ -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>
`;

+ 0
- 275
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsContent-test.tsx.snap View File

@@ -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>
`;

+ 0
- 163
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/DetailsHeader-test.tsx.snap View File

@@ -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>
`;

+ 0
- 49
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/PermissionItem-test.tsx.snap View File

@@ -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>
`;

+ 0
- 59
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/Projects-test.tsx.snap View File

@@ -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>
`;

+ 0
- 23
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissions-test.tsx.snap View File

@@ -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 []}
/>
`;

+ 0
- 11
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModal-test.tsx.snap View File

@@ -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}
/>
`;

+ 0
- 165
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsAddModalRenderer-test.tsx.snap View File

@@ -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>
`;

+ 0
- 409
server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/__snapshots__/QualityGatePermissionsRenderer-test.tsx.snap View File

@@ -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>
`;

Loading…
Cancel
Save