Merge branch 'main' into 19069-workflow-launching
[arvados.git] / cypress / integration / project.spec.js
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 describe('Project tests', function() {
6     let activeUser;
7     let adminUser;
8
9     before(function() {
10         // Only set up common users once. These aren't set up as aliases because
11         // aliases are cleaned up after every test. Also it doesn't make sense
12         // to set the same users on beforeEach() over and over again, so we
13         // separate a little from Cypress' 'Best Practices' here.
14         cy.getUser('admin', 'Admin', 'User', true, true)
15             .as('adminUser').then(function() {
16                 adminUser = this.adminUser;
17             }
18         );
19         cy.getUser('user', 'Active', 'User', false, true)
20             .as('activeUser').then(function() {
21                 activeUser = this.activeUser;
22             }
23         );
24     });
25
26     beforeEach(function() {
27         cy.clearCookies();
28         cy.clearLocalStorage();
29     });
30
31     it('creates a new project with properties', function() {
32         const projName = `Test project (${Math.floor(999999 * Math.random())})`;
33         cy.loginAs(activeUser);
34         cy.get('[data-cy=side-panel-button]').click();
35         cy.get('[data-cy=side-panel-new-project]').click();
36         cy.get('[data-cy=form-dialog]')
37             .should('contain', 'New Project')
38             .within(() => {
39                 cy.get('[data-cy=name-field]').within(() => {
40                     cy.get('input').type(projName);
41                 });
42
43             });
44         // Key: Color (IDTAGCOLORS) - Value: Magenta (IDVALCOLORS3)
45         cy.get('[data-cy=form-dialog]').should('not.contain', 'Color: Magenta');
46         cy.get('[data-cy=resource-properties-form]').within(() => {
47             cy.get('[data-cy=property-field-key]').within(() => {
48                 cy.get('input').type('Color');
49             });
50             cy.get('[data-cy=property-field-value]').within(() => {
51                 cy.get('input').type('Magenta');
52             });
53             cy.root().submit();
54         });
55         // Confirm proper vocabulary labels are displayed on the UI.
56         cy.get('[data-cy=form-dialog]').should('contain', 'Color: Magenta');
57
58         // Create project and confirm the properties' real values.
59         cy.get('[data-cy=form-submit-btn]').click();
60         cy.get('[data-cy=breadcrumb-last]').should('contain', projName);
61         cy.doRequest('GET', '/arvados/v1/groups', null, {
62             filters: `[["name", "=", "${projName}"], ["group_class", "=", "project"]]`,
63         })
64         .its('body.items').as('projects')
65         .then(function() {
66             expect(this.projects).to.have.lengthOf(1);
67             expect(this.projects[0].properties).to.deep.equal(
68                 {IDTAGCOLORS: 'IDVALCOLORS3'});
69         });
70     });
71
72     it('creates new project on home project and then a subproject inside it', function() {
73         const createProject = function(name, parentName) {
74             cy.get('[data-cy=side-panel-button]').click();
75             cy.get('[data-cy=side-panel-new-project]').click();
76             cy.get('[data-cy=form-dialog]')
77                 .should('contain', 'New Project')
78                 .within(() => {
79                     cy.get('[data-cy=parent-field]').within(() => {
80                         cy.get('input').invoke('val').then((val) => {
81                             expect(val).to.include(parentName);
82                         });
83                     });
84                     cy.get('[data-cy=name-field]').within(() => {
85                         cy.get('input').type(name);
86                     });
87                 });
88             cy.get('[data-cy=form-submit-btn]').click();
89         }
90
91         cy.loginAs(activeUser);
92         cy.goToPath(`/projects/${activeUser.user.uuid}`);
93         cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects');
94         cy.get('[data-cy=breadcrumb-last]').should('not.exist');
95         // Create new project
96         const projName = `Test project (${Math.floor(999999 * Math.random())})`;
97         createProject(projName, 'Home project');
98         // Confirm that the user was taken to the newly created thing
99         cy.get('[data-cy=form-dialog]').should('not.exist');
100         cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects');
101         cy.get('[data-cy=breadcrumb-last]').should('contain', projName);
102         // Create a subproject
103         const subProjName = `Test project (${Math.floor(999999 * Math.random())})`;
104         createProject(subProjName, projName);
105         cy.get('[data-cy=form-dialog]').should('not.exist');
106         cy.get('[data-cy=breadcrumb-first]').should('contain', 'Projects');
107         cy.get('[data-cy=breadcrumb-last]').should('contain', subProjName);
108     });
109
110     it('navigates to the parent project after trashing the one being displayed', function() {
111         cy.createGroup(activeUser.token, {
112             name: `Test root project ${Math.floor(Math.random() * 999999)}`,
113             group_class: 'project',
114         }).as('testRootProject').then(function() {
115             cy.createGroup(activeUser.token, {
116                 name : `Test subproject ${Math.floor(Math.random() * 999999)}`,
117                 group_class: 'project',
118                 owner_uuid: this.testRootProject.uuid,
119             }).as('testSubProject');
120         });
121         cy.getAll('@testRootProject', '@testSubProject').then(function([testRootProject, testSubProject]) {
122             cy.loginAs(activeUser);
123
124             // Go to subproject and trash it.
125             cy.goToPath(`/projects/${testSubProject.uuid}`);
126             cy.get('[data-cy=side-panel-tree]').should('contain', testSubProject.name);
127             cy.get('[data-cy=breadcrumb-last]')
128                 .should('contain', testSubProject.name)
129                 .rightclick();
130             cy.get('[data-cy=context-menu]').contains('Move to trash').click();
131
132             // Confirm that the parent project should be displayed.
133             cy.get('[data-cy=breadcrumb-last]').should('contain', testRootProject.name);
134             cy.url().should('contain', `/projects/${testRootProject.uuid}`);
135             cy.get('[data-cy=side-panel-tree]').should('not.contain', testSubProject.name);
136
137             // Checks for bugfix #17637.
138             cy.get('[data-cy=not-found-content]').should('not.exist');
139             cy.get('[data-cy=not-found-page]').should('not.exist');
140         });
141     });
142
143     it('navigates to the root project after trashing the parent of the one being displayed', function() {
144         cy.createGroup(activeUser.token, {
145             name: `Test root project ${Math.floor(Math.random() * 999999)}`,
146             group_class: 'project',
147         }).as('testRootProject').then(function() {
148             cy.createGroup(activeUser.token, {
149                 name : `Test subproject ${Math.floor(Math.random() * 999999)}`,
150                 group_class: 'project',
151                 owner_uuid: this.testRootProject.uuid,
152             }).as('testSubProject').then(function() {
153                 cy.createGroup(activeUser.token, {
154                     name : `Test sub subproject ${Math.floor(Math.random() * 999999)}`,
155                     group_class: 'project',
156                     owner_uuid: this.testSubProject.uuid,
157                 }).as('testSubSubProject');
158             });
159         });
160         cy.getAll('@testRootProject', '@testSubProject', '@testSubSubProject').then(function([testRootProject, testSubProject, testSubSubProject]) {
161             cy.loginAs(activeUser);
162
163             // Go to innermost project and trash its parent.
164             cy.goToPath(`/projects/${testSubSubProject.uuid}`);
165             cy.get('[data-cy=side-panel-tree]').should('contain', testSubSubProject.name);
166             cy.get('[data-cy=breadcrumb-last]').should('contain', testSubSubProject.name);
167             cy.get('[data-cy=side-panel-tree]')
168                 .contains(testSubProject.name)
169                 .rightclick();
170             cy.get('[data-cy=context-menu]').contains('Move to trash').click();
171
172             // Confirm that the trashed project's parent should be displayed.
173             cy.get('[data-cy=breadcrumb-last]').should('contain', testRootProject.name);
174             cy.url().should('contain', `/projects/${testRootProject.uuid}`);
175             cy.get('[data-cy=side-panel-tree]').should('not.contain', testSubProject.name);
176             cy.get('[data-cy=side-panel-tree]').should('not.contain', testSubSubProject.name);
177
178             // Checks for bugfix #17637.
179             cy.get('[data-cy=not-found-content]').should('not.exist');
180             cy.get('[data-cy=not-found-page]').should('not.exist');
181         });
182     });
183
184     it('shows details panel when clicking on the info icon', () => {
185         cy.createGroup(activeUser.token, {
186             name: `Test root project ${Math.floor(Math.random() * 999999)}`,
187             group_class: 'project',
188         }).as('testRootProject').then(function(testRootProject) {
189             cy.loginAs(activeUser);
190
191             cy.get('[data-cy=side-panel-tree]').contains(testRootProject.name).click();
192
193             cy.get('[data-cy=additional-info-icon]').click();
194
195             cy.contains(testRootProject.uuid).should('exist');
196         });
197     });
198
199     it('clears search input when changing project', () => {
200         cy.createGroup(activeUser.token, {
201             name: `Test root project ${Math.floor(Math.random() * 999999)}`,
202             group_class: 'project',
203         }).as('testProject1').then((testProject1) => {
204             cy.shareWith(adminUser.token, activeUser.user.uuid, testProject1.uuid, 'can_write');
205         });
206
207         cy.getAll('@testProject1').then(function([testProject1]) {
208             cy.loginAs(activeUser);
209
210             cy.get('[data-cy=side-panel-tree]').contains(testProject1.name).click();
211
212             cy.get('[data-cy=search-input] input').type('test123');
213
214             cy.get('[data-cy=side-panel-tree]').contains('Projects').click();
215
216             cy.get('[data-cy=search-input] input').should('not.have.value', 'test123');
217         });
218     });
219
220     it('opens advanced popup for project with username', () => {
221         const projectName = `Test project ${Math.floor(Math.random() * 999999)}`;
222
223         cy.createGroup(adminUser.token, {
224             name: projectName,
225             group_class: 'project',
226         }).as('mainProject')
227
228         cy.getAll('@mainProject')
229             .then(function ([mainProject]) {
230                 cy.loginAs(adminUser);
231                 
232                 cy.get('[data-cy=side-panel-tree]').contains('Groups').click();
233
234                 cy.get('[data-cy=uuid]').eq(0).invoke('text').then(uuid => {
235                     cy.createLink(adminUser.token, {
236                         name: 'can_write',
237                         link_class: 'permission',
238                         head_uuid: mainProject.uuid,
239                         tail_uuid: uuid
240                     });
241
242                     cy.createLink(adminUser.token, {
243                         name: 'can_write',
244                         link_class: 'permission',
245                         head_uuid: mainProject.uuid,
246                         tail_uuid: activeUser.user.uuid
247                     });
248
249                     cy.get('[data-cy=side-panel-tree]').contains('Projects').click();
250
251                     cy.get('main').contains(projectName).rightclick();
252
253                     cy.get('[data-cy=context-menu]').contains('Advanced').click();
254
255                     cy.get('[role=tablist]').contains('METADATA').click();
256
257                     cy.get('td').contains(uuid).should('exist');
258
259                     cy.get('td').contains(activeUser.user.uuid).should('exist');
260                 });
261         });
262     });
263 });