19093: Improve cypress test reliability
[arvados.git] / cypress / integration / user-profile.spec.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 describe('User profile tests', function() {
6     let activeUser;
7     let adminUser;
8     const roleGroupName = `Test role group (${Math.floor(999999 * Math.random())})`;
9     const projectGroupName = `Test project group (${Math.floor(999999 * Math.random())})`;
10
11     before(function() {
12         // Only set up common users once. These aren't set up as aliases because
13         // aliases are cleaned up after every test. Also it doesn't make sense
14         // to set the same users on beforeEach() over and over again, so we
15         // separate a little from Cypress' 'Best Practices' here.
16         cy.getUser('admin', 'Admin', 'User', true, true)
17             .as('adminUser').then(function() {
18                 adminUser = this.adminUser;
19             }
20         );
21         cy.getUser('user', 'Active', 'User', false, true)
22             .as('activeUser').then(function() {
23                 activeUser = this.activeUser;
24             }
25         );
26     });
27
28     function assertProfileValues({
29         firstName,
30         lastName,
31         email,
32         username,
33         org,
34         org_email,
35         role,
36         website,
37     }) {
38         cy.get('[data-cy=profile-form] input[name="firstName"]').invoke('val').should('equal', firstName);
39         cy.get('[data-cy=profile-form] input[name="lastName"]').invoke('val').should('equal', lastName);
40         cy.get('[data-cy=profile-form] [data-cy=email] [data-cy=value]').contains(email);
41         cy.get('[data-cy=profile-form] [data-cy=username] [data-cy=value]').contains(username);
42
43         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').invoke('val').should('equal', org);
44         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').invoke('val').should('equal', org_email);
45         cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').invoke('val').should('equal', role);
46         cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').invoke('val').should('equal', website);
47     }
48
49     function enterProfileValues({
50         org,
51         org_email,
52         role,
53         website,
54     }) {
55         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').clear();
56         if (org) {
57             cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').type(org);
58         }
59         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').clear();
60         if (org_email) {
61             cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').type(org_email);
62         }
63         cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').select(role);
64         cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').clear();
65         if (website) {
66             cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').type(website);
67         }
68     }
69
70     function assertContextMenuItems({
71         account,
72         activate,
73         deactivate,
74         login,
75         setup
76     }) {
77         cy.get('[data-cy=user-profile-panel-options-btn]').click();
78         cy.get('[data-cy=context-menu]').within(() => {
79             cy.get('[role=button]').contains('Advanced');
80
81             cy.get('[role=button]').should(account ? 'contain' : 'not.contain', 'Account Settings');
82             cy.get('[role=button]').should(activate ? 'contain' : 'not.contain', 'Activate User');
83             cy.get('[role=button]').should(deactivate ? 'contain' : 'not.contain', 'Deactivate User');
84             cy.get('[role=button]').should(login ? 'contain' : 'not.contain', 'Login As User');
85             cy.get('[role=button]').should(setup ? 'contain' : 'not.contain', 'Setup User');
86         });
87         cy.get('div[role=presentation]').click();
88     }
89
90     beforeEach(function() {
91         cy.updateResource(adminUser.token, 'users', adminUser.user.uuid, {
92             prefs: {
93                 profile: {
94                     organization: '',
95                     organization_email: '',
96                     role: '',
97                     website_url: '',
98                 },
99             },
100         });
101         cy.updateResource(adminUser.token, 'users', activeUser.user.uuid, {
102             prefs: {
103                 profile: {
104                     organization: '',
105                     organization_email: '',
106                     role: '',
107                     website_url: '',
108                 },
109             },
110         });
111     });
112
113     it('non-admin can edit own profile', function() {
114         cy.loginAs(activeUser);
115
116         cy.get('header button[title="Account Management"]').click();
117         cy.get('#account-menu').contains('My account').click();
118
119         // Admin actions should be hidden, no account menu
120         assertContextMenuItems({
121             account: false,
122             activate: false,
123             deactivate: false,
124             login: false,
125             setup: false,
126         });
127
128         // Check initial values
129         assertProfileValues({
130             firstName: 'Active',
131             lastName: 'User',
132             email: 'user@example.local',
133             username: 'user',
134             org: '',
135             org_email: '',
136             role: '',
137             website: '',
138         });
139
140         // Change values
141         enterProfileValues({
142             org: 'Org name',
143             org_email: 'email@example.com',
144             role: 'Data Scientist',
145             website: 'example.com',
146         });
147
148         // Submit
149         cy.get('[data-cy=profile-form] button[type="submit"]').click();
150
151         // Check new values
152         assertProfileValues({
153             firstName: 'Active',
154             lastName: 'User',
155             email: 'user@example.local',
156             username: 'user',
157             org: 'Org name',
158             org_email: 'email@example.com',
159             role: 'Data Scientist',
160             website: 'example.com',
161         });
162     });
163
164     it('non-admin cannot edit other profile', function() {
165         cy.loginAs(activeUser);
166         cy.goToPath('/user/' + adminUser.user.uuid);
167
168         assertProfileValues({
169             firstName: 'Admin',
170             lastName: 'User',
171             email: 'admin@example.local',
172             username: 'admin',
173             org: '',
174             org_email: '',
175             role: '',
176             website: '',
177         });
178
179         // Inputs should be disabled
180         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization"]').should('be.disabled');
181         cy.get('[data-cy=profile-form] input[name="prefs.profile.organization_email"]').should('be.disabled');
182         cy.get('[data-cy=profile-form] select[name="prefs.profile.role"]').should('be.disabled');
183         cy.get('[data-cy=profile-form] input[name="prefs.profile.website_url"]').should('be.disabled');
184
185         // Submit should be disabled
186         cy.get('[data-cy=profile-form] button[type="submit"]').should('be.disabled');
187
188         // Admin actions should be hidden, no account menu
189         assertContextMenuItems({
190             account: false,
191             activate: false,
192             deactivate: false,
193             login: false,
194             setup: false,
195         });
196     });
197
198     it('admin can edit own profile', function() {
199         cy.loginAs(adminUser);
200
201         cy.get('header button[title="Account Management"]').click();
202         cy.get('#account-menu').contains('My account').click();
203
204         // Admin actions should be visible, no account menu
205         assertContextMenuItems({
206             account: false,
207             activate: false,
208             deactivate: true,
209             login: false,
210             setup: false,
211         });
212
213         // Check initial values
214         assertProfileValues({
215             firstName: 'Admin',
216             lastName: 'User',
217             email: 'admin@example.local',
218             username: 'admin',
219             org: '',
220             org_email: '',
221             role: '',
222             website: '',
223         });
224
225         // Change values
226         enterProfileValues({
227             org: 'Admin org name',
228             org_email: 'admin@example.com',
229             role: 'Researcher',
230             website: 'admin.local',
231         });
232         cy.get('[data-cy=profile-form] button[type="submit"]').click();
233
234         // Check new values
235         assertProfileValues({
236             firstName: 'Admin',
237             lastName: 'User',
238             email: 'admin@example.local',
239             username: 'admin',
240             org: 'Admin org name',
241             org_email: 'admin@example.com',
242             role: 'Researcher',
243             website: 'admin.local',
244         });
245     });
246
247     it('admin can edit other profile', function() {
248         cy.loginAs(adminUser);
249         cy.goToPath('/user/' + activeUser.user.uuid);
250
251         // Check new values
252         assertProfileValues({
253             firstName: 'Active',
254             lastName: 'User',
255             email: 'user@example.local',
256             username: 'user',
257             org: '',
258             org_email: '',
259             role: '',
260             website: '',
261         });
262
263         enterProfileValues({
264             org: 'Changed org name',
265             org_email: 'changed@example.com',
266             role: 'Researcher',
267             website: 'changed.local',
268         });
269         cy.get('[data-cy=profile-form] button[type="submit"]').click();
270
271         // Check new values
272         assertProfileValues({
273             firstName: 'Active',
274             lastName: 'User',
275             email: 'user@example.local',
276             username: 'user',
277             org: 'Changed org name',
278             org_email: 'changed@example.com',
279             role: 'Researcher',
280             website: 'changed.local',
281         });
282
283         // Admin actions should be visible, no account menu
284         assertContextMenuItems({
285             account: false,
286             activate: false,
287             deactivate: true,
288             login: true,
289             setup: false,
290         });
291     });
292
293     it('displays role groups on user profile', function() {
294         cy.loginAs(adminUser);
295
296         cy.createGroup(adminUser.token, {
297             name: roleGroupName,
298             group_class: 'role',
299         }).as('roleGroup').then(function() {
300             cy.createLink(adminUser.token, {
301                 name: 'can_write',
302                 link_class: 'permission',
303                 head_uuid: this.roleGroup.uuid,
304                 tail_uuid: adminUser.user.uuid
305             });
306             cy.createLink(adminUser.token, {
307                 name: 'can_write',
308                 link_class: 'permission',
309                 head_uuid: this.roleGroup.uuid,
310                 tail_uuid: activeUser.user.uuid
311             });
312         });
313
314         cy.createGroup(adminUser.token, {
315             name: projectGroupName,
316             group_class: 'project',
317         }).as('projectGroup').then(function() {
318             cy.createLink(adminUser.token, {
319                 name: 'can_write',
320                 link_class: 'permission',
321                 head_uuid: this.projectGroup.uuid,
322                 tail_uuid: adminUser.user.uuid
323             });
324             cy.createLink(adminUser.token, {
325                 name: 'can_write',
326                 link_class: 'permission',
327                 head_uuid: this.projectGroup.uuid,
328                 tail_uuid: activeUser.user.uuid
329             });
330         });
331
332         cy.goToPath('/user/' + activeUser.user.uuid);
333         cy.get('div [role="tab"]').contains('GROUPS').click();
334         cy.get('[data-cy=user-profile-groups-data-explorer]').contains(roleGroupName);
335         cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', projectGroupName);
336
337         cy.goToPath('/user/' + adminUser.user.uuid);
338         cy.get('div [role="tab"]').contains('GROUPS').click();
339         cy.get('[data-cy=user-profile-groups-data-explorer]').contains(roleGroupName);
340         cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', projectGroupName);
341     });
342
343     it('allows performing admin functions', function() {
344         cy.loginAs(adminUser);
345         cy.goToPath('/user/' + activeUser.user.uuid);
346
347         // Check that user is active
348         cy.get('[data-cy=account-status]').contains('Active');
349         cy.get('div [role="tab"]').contains('GROUPS').click();
350         cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
351         cy.get('div [role="tab"]').contains('PROFILE').click();
352         assertContextMenuItems({
353             account: false,
354             activate: false,
355             deactivate: true,
356             login: true,
357             setup: false,
358         });
359
360         // Deactivate user
361         cy.get('[data-cy=user-profile-panel-options-btn]').click();
362         cy.get('[data-cy=context-menu]').contains('Deactivate User').click();
363         cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
364
365         // Check that user is deactivated
366         cy.get('[data-cy=account-status]').contains('Inactive');
367         cy.get('div [role="tab"]').contains('GROUPS').click();
368         cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', 'All users');
369         cy.get('div [role="tab"]').contains('PROFILE').click();
370         assertContextMenuItems({
371             account: false,
372             activate: true,
373             deactivate: false,
374             login: true,
375             setup: true,
376         });
377
378         // Setup user
379         cy.get('[data-cy=user-profile-panel-options-btn]').click();
380         cy.get('[data-cy=context-menu]').contains('Setup User').click();
381         cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
382
383         // Check that user is setup
384         cy.get('[data-cy=account-status]').contains('Setup');
385         cy.get('div [role="tab"]').contains('GROUPS').click();
386         cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
387         cy.get('div [role="tab"]').contains('PROFILE').click();
388         assertContextMenuItems({
389             account: false,
390             activate: true,
391             deactivate: true,
392             login: true,
393             setup: false,
394         });
395
396         // Activate user
397         cy.get('[data-cy=user-profile-panel-options-btn]').click();
398         cy.get('[data-cy=context-menu]').contains('Activate User').click();
399         cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
400
401         // Check that user is active
402         cy.get('[data-cy=account-status]').contains('Active');
403         cy.get('div [role="tab"]').contains('GROUPS').click();
404         cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
405         cy.get('div [role="tab"]').contains('PROFILE').click();
406         assertContextMenuItems({
407             account: false,
408             activate: false,
409             deactivate: true,
410             login: true,
411             setup: false,
412         });
413
414         // Deactivate and activate user skipping setup
415         cy.get('[data-cy=user-profile-panel-options-btn]').click();
416         cy.get('[data-cy=context-menu]').contains('Deactivate User').click();
417         cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
418         // Check
419         cy.get('[data-cy=account-status]').contains('Inactive');
420         cy.get('div [role="tab"]').contains('GROUPS').click();
421         cy.get('[data-cy=user-profile-groups-data-explorer]').should('not.contain', 'All users');
422         cy.get('div [role="tab"]').contains('PROFILE').click();
423         assertContextMenuItems({
424             account: false,
425             activate: true,
426             deactivate: false,
427             login: true,
428             setup: true,
429         });
430         // reactivate
431         cy.get('[data-cy=user-profile-panel-options-btn]').click();
432         cy.get('[data-cy=context-menu]').contains('Activate User').click();
433         cy.get('[data-cy=confirmation-dialog-ok-btn]').click();
434
435         // Check that user is active
436         cy.get('[data-cy=account-status]').contains('Active');
437         cy.get('div [role="tab"]').contains('GROUPS').click();
438         cy.get('[data-cy=user-profile-groups-data-explorer]').should('contain', 'All users');
439         cy.get('div [role="tab"]').contains('PROFILE').click();
440         assertContextMenuItems({
441             account: false,
442             activate: false,
443             deactivate: true,
444             login: true,
445             setup: false,
446         });
447     });
448
449 });