3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 import { act, screen } from '@testing-library/react';
22 import userEvent from '@testing-library/user-event';
23 import PermissionsServiceMock from '../../../../../api/mocks/PermissionsServiceMock';
24 import { mockComponent } from '../../../../../helpers/mocks/component';
25 import { mockPermissionGroup, mockPermissionUser } from '../../../../../helpers/mocks/permissions';
27 PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE,
28 PERMISSIONS_ORDER_FOR_VIEW,
29 } from '../../../../../helpers/permissions';
30 import { renderAppWithComponentContext } from '../../../../../helpers/testReactTestingUtils';
31 import { ComponentQualifier, Visibility } from '../../../../../types/component';
32 import { Permissions } from '../../../../../types/permissions';
33 import { Component, PermissionGroup, PermissionUser } from '../../../../../types/types';
34 import { projectPermissionsRoutes } from '../../../routes';
35 import { getPageObject } from '../../../test-utils';
37 let serviceMock: PermissionsServiceMock;
39 serviceMock = new PermissionsServiceMock();
46 describe('rendering', () => {
48 [ComponentQualifier.Project, 'roles.page.description2', PERMISSIONS_ORDER_FOR_PROJECT_TEMPLATE],
49 [ComponentQualifier.Portfolio, 'roles.page.description_portfolio', PERMISSIONS_ORDER_FOR_VIEW],
51 ComponentQualifier.Application,
52 'roles.page.description_application',
53 PERMISSIONS_ORDER_FOR_VIEW,
55 ])('should render correctly for %s', async (qualifier, description, permissions) => {
56 const user = userEvent.setup();
57 const ui = getPageObject(user);
58 renderPermissionsProjectApp({ qualifier, visibility: Visibility.Private });
61 expect(screen.getByText(description)).toBeInTheDocument();
62 permissions.forEach((permission) => {
63 expect(ui.projectPermissionCheckbox('johndoe', permission).get()).toBeInTheDocument();
68 describe('filtering', () => {
69 it('should allow to filter permission holders', async () => {
70 const user = userEvent.setup();
71 const ui = getPageObject(user);
72 renderPermissionsProjectApp();
75 expect(screen.getByText('sonar-users')).toBeInTheDocument();
76 expect(screen.getByText('johndoe')).toBeInTheDocument();
78 await ui.showOnlyUsers();
79 expect(screen.queryByText('sonar-users')).not.toBeInTheDocument();
80 expect(screen.getByText('johndoe')).toBeInTheDocument();
82 await ui.showOnlyGroups();
83 expect(screen.getByText('sonar-users')).toBeInTheDocument();
84 expect(screen.queryByText('johndoe')).not.toBeInTheDocument();
87 expect(screen.getByText('sonar-users')).toBeInTheDocument();
88 expect(screen.getByText('johndoe')).toBeInTheDocument();
90 await ui.searchFor('sonar-adm');
91 expect(screen.getByText('sonar-admins')).toBeInTheDocument();
92 expect(screen.queryByText('sonar-users')).not.toBeInTheDocument();
93 expect(screen.queryByText('johndoe')).not.toBeInTheDocument();
95 await ui.clearSearch();
96 expect(screen.getByText('sonar-users')).toBeInTheDocument();
97 expect(screen.getByText('johndoe')).toBeInTheDocument();
100 it('should allow to show only permission holders with a specific permission', async () => {
101 const user = userEvent.setup();
102 const ui = getPageObject(user);
103 renderPermissionsProjectApp();
104 await ui.appLoaded();
106 expect(screen.getAllByRole('row').length).toBe(7);
107 await ui.toggleFilterByPermission(Permissions.Admin);
108 expect(screen.getAllByRole('row').length).toBe(2);
109 await ui.toggleFilterByPermission(Permissions.Admin);
110 expect(screen.getAllByRole('row').length).toBe(7);
114 describe('assigning/revoking permissions', () => {
115 it('should allow to apply a permission template', async () => {
116 const user = userEvent.setup();
117 const ui = getPageObject(user);
118 renderPermissionsProjectApp();
119 await ui.appLoaded();
121 await ui.openTemplateModal();
122 expect(ui.confirmApplyTemplateBtn.get()).toBeDisabled();
123 await ui.chooseTemplate('Permission Template 2');
124 expect(ui.templateSuccessfullyApplied.get()).toBeInTheDocument();
125 await ui.closeTemplateModal();
126 expect(ui.templateSuccessfullyApplied.query()).not.toBeInTheDocument();
129 it('should allow to turn a public project private (and vice-versa)', async () => {
130 const user = userEvent.setup();
131 const ui = getPageObject(user);
132 renderPermissionsProjectApp();
133 await ui.appLoaded();
135 expect(ui.visibilityRadio(Visibility.Public).get()).toBeChecked();
137 ui.projectPermissionCheckbox('sonar-users', Permissions.Browse).query()
138 ).not.toBeInTheDocument();
139 await act(async () => {
140 await ui.turnProjectPrivate();
142 expect(ui.visibilityRadio(Visibility.Private).get()).toBeChecked();
144 ui.projectPermissionCheckbox('sonar-users', Permissions.Browse).get()
145 ).toBeInTheDocument();
147 await ui.turnProjectPublic();
148 expect(ui.makePublicDisclaimer.get()).toBeInTheDocument();
149 await act(async () => {
150 await ui.confirmTurnProjectPublic();
152 expect(ui.visibilityRadio(Visibility.Public).get()).toBeChecked();
155 it('should add and remove permissions to/from a group', async () => {
156 const user = userEvent.setup();
157 const ui = getPageObject(user);
158 renderPermissionsProjectApp();
159 await ui.appLoaded();
161 expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Admin).get()).not.toBeChecked();
163 await ui.toggleProjectPermission('sonar-users', Permissions.Admin);
164 await ui.appLoaded();
165 expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Admin).get()).toBeChecked();
167 await ui.toggleProjectPermission('sonar-users', Permissions.Admin);
168 await ui.appLoaded();
169 expect(ui.projectPermissionCheckbox('sonar-users', Permissions.Admin).get()).not.toBeChecked();
172 it('should add and remove permissions to/from a user', async () => {
173 const user = userEvent.setup();
174 const ui = getPageObject(user);
175 renderPermissionsProjectApp();
176 await ui.appLoaded();
178 expect(ui.projectPermissionCheckbox('johndoe', Permissions.Scan).get()).not.toBeChecked();
180 await ui.toggleProjectPermission('johndoe', Permissions.Scan);
181 await ui.appLoaded();
182 expect(ui.projectPermissionCheckbox('johndoe', Permissions.Scan).get()).toBeChecked();
184 await ui.toggleProjectPermission('johndoe', Permissions.Scan);
185 await ui.appLoaded();
186 expect(ui.projectPermissionCheckbox('johndoe', Permissions.Scan).get()).not.toBeChecked();
189 it('should handle errors correctly', async () => {
190 serviceMock.setIsAllowedToChangePermissions(false);
191 const user = userEvent.setup();
192 const ui = getPageObject(user);
193 renderPermissionsProjectApp();
194 await ui.appLoaded();
196 expect(ui.projectPermissionCheckbox('johndoe', Permissions.Scan).get()).not.toBeChecked();
197 await ui.toggleProjectPermission('johndoe', Permissions.Scan);
198 await ui.appLoaded();
199 expect(ui.projectPermissionCheckbox('johndoe', Permissions.Scan).get()).not.toBeChecked();
203 it('should correctly handle pagination', async () => {
204 const groups: PermissionGroup[] = [];
205 const users: PermissionUser[] = [];
206 Array.from(Array(20).keys()).forEach((i) => {
207 groups.push(mockPermissionGroup({ name: `Group ${i}` }));
208 users.push(mockPermissionUser({ login: `user-${i}` }));
210 serviceMock.setGroups(groups);
211 serviceMock.setUsers(users);
213 const user = userEvent.setup();
214 const ui = getPageObject(user);
215 renderPermissionsProjectApp();
216 await ui.appLoaded();
218 expect(screen.getAllByRole('row').length).toBe(11);
219 await ui.clickLoadMore();
220 expect(screen.getAllByRole('row').length).toBe(21);
223 function renderPermissionsProjectApp(override?: Partial<Component>) {
224 return renderAppWithComponentContext(
226 projectPermissionsRoutes,
229 component: mockComponent({
230 visibility: Visibility.Public,
232 canUpdateProjectVisibilityToPrivate: true,
233 canApplyPermissionTemplate: true,