graphdb-workbench-tests 3.5.0-reactodia-resource-construct-TR1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/e2e-legacy/guides/ttyg/configure-agent/configure-agent-guide.spec.js +2 -1
  2. package/e2e-legacy/guides/welcome/welcome-guide.spec.js +1 -1
  3. package/e2e-legacy/home/solr-banner/solr-banner.spec.js +137 -0
  4. package/e2e-legacy/repository/ontop-repository.spec.js +132 -0
  5. package/e2e-legacy/resource/resource.spec.js +4 -17
  6. package/e2e-legacy/setup/aclmanagement/create-rule.spec.js +1 -1
  7. package/e2e-legacy/setup/aclmanagement/delete-rule.spec.js +1 -1
  8. package/e2e-legacy/setup/aclmanagement/edit-rule.spec.js +1 -1
  9. package/e2e-legacy/setup/aclmanagement/render-rules.spec.js +1 -1
  10. package/e2e-legacy/setup/aclmanagement/reorder-rules.spec.js +1 -1
  11. package/e2e-legacy/setup/aclmanagement/revert-rules.spec.js +1 -1
  12. package/e2e-legacy/setup/aclmanagement/scopes.spec.js +2 -2
  13. package/e2e-legacy/setup/aclmanagement/update-rules.spec.js +2 -2
  14. package/e2e-legacy/setup/jdbc/jdbc-create.spec.js +1 -1
  15. package/e2e-legacy/setup/settings/my-settings-initial-state.spec.js +2 -6
  16. package/e2e-legacy/setup/settings/my-settings.spec.js +1 -1
  17. package/e2e-legacy/setup/users-and-access/user-and-access.spec.js +706 -337
  18. package/e2e-legacy/sparql-editor/saved-query/readonly-query.spec.js +1 -1
  19. package/e2e-legacy/ttyg/agent-select-menu.spec.js +7 -1
  20. package/e2e-legacy/ttyg/chat-list.spec.js +1 -1
  21. package/e2e-legacy/ttyg/create-chat.spec.js +1 -1
  22. package/e2e-legacy/ttyg/edit-agent.spec.js +2 -2
  23. package/e2e-legacy/ttyg/ttyg-permission.spec.js +2 -1
  24. package/e2e-security/setup/users-and-access/create-user-permissions.spec.js +15 -15
  25. package/e2e-security/setup/users-and-access/graphql-user.spec.js +3 -3
  26. package/e2e-security/setup/users-and-access/repo-admin-role.spec.js +2 -2
  27. package/eslint.config.js +1 -0
  28. package/fixtures/ontop/university-complete_edited.obda +106 -0
  29. package/npm-shrinkwrap.json +448 -278
  30. package/package.json +5 -6
  31. package/steps/application-steps.js +1 -1
  32. package/steps/deprecation-banner/deprecation-banner-steps.js +13 -0
  33. package/steps/deprecation-steps.js +13 -0
  34. package/steps/main-menu-steps.js +5 -1
  35. package/steps/ontop-repository-steps.js +20 -0
  36. package/steps/repository-steps.js +44 -3
  37. package/steps/resource/resource-steps.js +0 -8
  38. package/steps/setup/settings-steps.js +3 -3
  39. package/steps/setup/user-and-access-steps.js +84 -13
  40. package/steps/ttyg/ttyg-view-steps.js +15 -1
  41. package/stubs/repositories/repositories-stubs.js +4 -0
  42. package/stubs/security-stubs.js +4 -0
  43. package/support/security-command.js +43 -0
  44. package/cypress-guides.config.js +0 -45
  45. package/e2e-legacy/reactodia/reactodia.spec.js +0 -96
  46. package/steps/reactodia-steps.js +0 -42
@@ -7,6 +7,7 @@ import HomeSteps from '../../../steps/home-steps';
7
7
  import {LoginSteps} from '../../../steps/login-steps';
8
8
  import {MainMenuSteps} from '../../../steps/main-menu-steps';
9
9
  import {SecurityStubs} from '../../../stubs/security-stubs.js';
10
+ import {RepositorySteps} from '../../../steps/repository-steps.js';
10
11
 
11
12
  describe('User and Access', () => {
12
13
 
@@ -16,11 +17,25 @@ describe('User and Access', () => {
16
17
  const ROLE_CUSTOM_ADMIN = '#roleAdmin';
17
18
  const DEFAULT_ADMIN_PASSWORD = 'root';
18
19
 
19
- // eslint-disable-next-line no-undef
20
- context('', () => {
20
+ context('User and access management', () => {
21
21
  const user = 'user';
22
+ let repoName;
23
+
24
+ before(() => {
25
+ repoName = 'user-access-repo1-' + Date.now();
26
+ cy.createRepository({id: repoName});
27
+ });
28
+
29
+ after(() => {
30
+ cy.loginAsAdmin().then(() => {
31
+ cy.switchOffSecurity(true);
32
+ cy.switchOffFreeAccess(false);
33
+ });
34
+ cy.deleteRepository(repoName, true);
35
+ });
22
36
 
23
37
  beforeEach(() => {
38
+ SecurityStubs.spyOnUserGet();
24
39
  UserAndAccessSteps.visit();
25
40
  // Users table should be visible
26
41
  UserAndAccessSteps.getUsersTable().should('be.visible');
@@ -35,191 +50,388 @@ describe('User and Access', () => {
35
50
  });
36
51
  });
37
52
 
38
- it('Initial state', () => {
39
- // Create new user button should be visible
40
- UserAndAccessSteps.getCreateNewUserButton().should('be.visible');
41
- // Security should be disabled
42
- UserAndAccessSteps.getSecuritySwitchLabel().should('be.visible').and('contain', 'Security is OFF');
43
- UserAndAccessSteps.getSecurityCheckbox().should('not.be.checked');
44
- // Only admin user should be created by default
45
- UserAndAccessSteps.getTableRow().should('have.length', 1);
46
- UserAndAccessSteps.findUserInTable('admin');
47
- UserAndAccessSteps.getUserType().should('be.visible').and('contain', 'Administrator');
48
- // The admin should have unrestricted rights
49
- UserAndAccessSteps.getRepositoryRights().should('be.visible').and('contain', 'Unrestricted');
50
- // And can be edited
51
- UserAndAccessSteps.getEditUserButton().should('be.visible').and('not.be.disabled');
52
- // And cannot be deleted
53
- UserAndAccessSteps.getDeleteUserButton().should('not.exist');
54
- // Date created should be visible
55
- UserAndAccessSteps.getDateCreated().should('be.visible');
53
+ context('Initial state', () => {
54
+ it('Initial state', () => {
55
+ // Create new user button should be visible
56
+ UserAndAccessSteps.getCreateNewUserButton().should('be.visible');
57
+ // Security should be disabled
58
+ UserAndAccessSteps.getSecuritySwitchLabel().should('be.visible').and('contain', 'Security is OFF');
59
+ UserAndAccessSteps.getSecurityCheckbox().should('not.be.checked');
60
+ // Only admin user should be created by default
61
+ UserAndAccessSteps.getTableRow().should('have.length', 1);
62
+ UserAndAccessSteps.findUserInTable('admin');
63
+ UserAndAccessSteps.getUserType().should('be.visible').and('contain', 'Administrator');
64
+ // The admin should have unrestricted rights
65
+ UserAndAccessSteps.getRepositoryRights().should('be.visible').and('contain', 'Unrestricted');
66
+ // And can be edited
67
+ UserAndAccessSteps.getEditUserButton().should('be.visible').and('not.be.disabled');
68
+ // And cannot be deleted
69
+ UserAndAccessSteps.getDeleteUserButton().should('not.exist');
70
+ // Date created should be visible
71
+ UserAndAccessSteps.getDateCreated().should('be.visible');
72
+ });
56
73
  });
57
74
 
58
- it('Create user', () => {
59
- //create a normal read/write user
60
- createUser(user, PASSWORD, ROLE_USER, {readWrite: true});
61
- testForUser(user, false);
62
- });
75
+ context('User creation', () => {
76
+ it('Create user', () => {
77
+ //create a normal read/write user
78
+ createUser(user, PASSWORD, ROLE_USER, {readWrite: true});
79
+ testForUser(user, false);
80
+ });
81
+
82
+ it('Create maintainer user', () => {
83
+ createUser(user, PASSWORD, ROLE_USER, {maintain: true, repoName});
84
+ testForUser(user, false);
85
+ });
86
+
87
+ it('Create repo-manager', () => {
88
+ //create a repo-manager
89
+ createUser(user, PASSWORD, ROLE_REPO_MANAGER);
90
+ testForUser(user, false);
91
+ });
92
+
93
+ it('Create second admin', () => {
94
+ //create a custom admin
95
+ createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN);
96
+ testForUser(user, true);
97
+ });
98
+
99
+ it('Create user with custom role', () => {
100
+ // When I create a read/write user
101
+ UserAndAccessSteps.clickCreateNewUserButton();
102
+ UserAndAccessSteps.typeUsername(user);
103
+ UserAndAccessSteps.typePassword(PASSWORD);
104
+ UserAndAccessSteps.typeConfirmPasswordField(PASSWORD);
105
+ UserAndAccessSteps.selectRoleRadioButton(ROLE_USER);
106
+ // And add a custom role of 1 letter
107
+ UserAndAccessSteps.addTextToCustomRoleField('A');
108
+ UserAndAccessSteps.toggleWriteAccessAny();
109
+
110
+ // Then the 'create' button should be disabled
111
+ UserAndAccessSteps.getConfirmUserCreateButton().should('be.disabled');
112
+ // And the field should show an error
113
+ UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long');
114
+ // When I add more text to the custom role tag
115
+ UserAndAccessSteps.addTextToCustomRoleField('A{enter}');
116
+ // Then the 'create' button should be enabled
117
+ UserAndAccessSteps.getConfirmUserCreateButton().should('be.enabled');
118
+ // And the field error should not exist
119
+ UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible');
120
+
121
+ // When I type an invalid tag
122
+ UserAndAccessSteps.addTextToCustomRoleField('B{enter}');
123
+ // And the field shows an error
124
+ UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long');
125
+ // When I delete the invalid text
126
+ UserAndAccessSteps.addTextToCustomRoleField('{backspace}');
127
+ // Then the error should not be visible
128
+ UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible');
129
+
130
+ // When I create the user with a valid custom role
131
+ UserAndAccessSteps.toggleWriteAccessAny();
132
+ SecurityStubs.spyOnUserCreate();
133
+ UserAndAccessSteps.confirmUserCreate();
134
+ // Then the user should be created with that custom role
135
+ cy.wait('@create-user').its('request.body').then((body) => {
136
+ expect(body).to.deep.eq({
137
+ 'password': 'password',
138
+ 'grantedAuthorities': [
139
+ 'ROLE_USER',
140
+ 'CUSTOM_AA',
141
+ 'WRITE_REPO_*',
142
+ 'READ_REPO_*',
143
+ ],
144
+ 'appSettings': {
145
+ 'DEFAULT_VIS_GRAPH_SCHEMA': true,
146
+ 'DEFAULT_INFERENCE': true,
147
+ 'DEFAULT_SAMEAS': true,
148
+ 'IGNORE_SHARED_QUERIES': false,
149
+ 'EXECUTE_COUNT': true,
150
+ },
151
+ });
152
+ });
153
+
154
+ cy.url().should('include', '/users');
155
+ UserAndAccessSteps.findUserInTable(user).should('be.visible');
156
+ UserAndAccessSteps.getUserCustomRoles('@user')
157
+ .should('have.length', 1)
158
+ .eq(0).and('have.text', 'AA');
159
+ // And when I open the edit page for that user, the custom role should be visible in the field without the prefix
160
+ UserAndAccessSteps.openEditUserPage(user);
161
+ cy.wait('@get-user');
162
+ UserAndAccessSteps.getCustomRoleField().find('.tag-item span')
163
+ .should('have.length', 1)
164
+ .eq(0).and('have.text', 'AA');
165
+ });
166
+
167
+ it('Adding a role with a CUSTOM_ prefix shows a warning message', () => {
168
+ // When I create a user
169
+ UserAndAccessSteps.clickCreateNewUserButton();
170
+ // And I add a custom role tag with prefix CUSTOM_
171
+ UserAndAccessSteps.addTextToCustomRoleField('CUSTOM_USER{Enter}');
172
+ // There should be a warning text
173
+ UserAndAccessSteps.getPrefixWarning(0).should('contain', 'Custom roles should be entered without the "CUSTOM_" prefix in Workbench');
174
+ });
63
175
 
64
- it('Create repo-manager', () => {
65
- //create a repo-manager
66
- createUser(user, PASSWORD, ROLE_REPO_MANAGER);
67
- testForUser(user, false);
176
+ it('Warn users when setting no password when creating new user admin', () => {
177
+ UserAndAccessSteps.getUsersTable().should('be.visible');
178
+ createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN, {noPassword: true});
179
+ UserAndAccessSteps.getUsersTable().should('be.visible');
180
+ UserAndAccessSteps.getSplashLoader().should('not.be.visible');
181
+ });
182
+
183
+ // Skipped until image with GDB implementation is available
184
+ it.skip('should create user with maintain repo permission for specific repo', () => {
185
+ SecurityStubs.spyOnUserCreate();
186
+ UserAndAccessSteps.getUsersCatalogContainer().should('be.visible');
187
+ createUser(user, PASSWORD, ROLE_USER, {maintain: true, repoName: repoName});
188
+ // Then the user should be created with that custom role
189
+ cy.wait('@create-user').its('request.body').then((body) => {
190
+ expect(body).to.deep.eq({
191
+ 'password': 'password',
192
+ 'grantedAuthorities': [
193
+ 'ROLE_USER',
194
+ `MAINTAIN_REPO_${repoName}`,
195
+ `WRITE_REPO_${repoName}`,
196
+ `READ_REPO_${repoName}`,
197
+ ],
198
+ 'appSettings': {
199
+ 'DEFAULT_VIS_GRAPH_SCHEMA': true,
200
+ 'DEFAULT_INFERENCE': true,
201
+ 'DEFAULT_SAMEAS': true,
202
+ 'IGNORE_SHARED_QUERIES': false,
203
+ 'EXECUTE_COUNT': true,
204
+ },
205
+ });
206
+ });
207
+ UserAndAccessSteps.getUsersCatalogContainer().should('be.visible');
208
+ assertUserAuthsInCatalog(user, {repo: repoName, read: false, maintain: true, graphql: false});
209
+
210
+ UserAndAccessSteps.openEditUserPage(user);
211
+ cy.wait('@get-user');
212
+ UserAndAccessSteps.getRepositoryRightsList().should('be.visible');
213
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: true, graphql: false});
214
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: false, graphql: true});
215
+ });
68
216
  });
69
217
 
70
- it('Create second admin', () => {
71
- //create a custom admin
72
- createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN);
73
- testForUser(user, true);
218
+ context('Free access', () => {
219
+ it('should toggle free access after Admin has logged in', () => {
220
+ // Given I have available repositories to allow Free Access for
221
+ RepositoriesStubs.stubRepositories();
222
+ RepositoriesStubs.stubFreeAccess();
223
+ // When I enable security
224
+ UserAndAccessSteps.toggleSecurity();
225
+ // When I log in as an Admin
226
+ LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
227
+ // Then the page should load
228
+ UserAndAccessSteps.getSplashLoader().should('not.be.visible');
229
+ UserAndAccessSteps.getUsersTable().should('be.visible');
230
+ // The Free Access toggle should be OFF
231
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
232
+ // When I toggle Free Access ON
233
+ UserAndAccessSteps.toggleFreeAccess();
234
+ // And I allow free access to a repository
235
+ ModalDialogSteps.getDialog().should('be.visible');
236
+ // Then I click OK in the modal
237
+ ModalDialogSteps.clickOKButton();
238
+ // Then the toggle button should be ON
239
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked');
240
+ // And I should see a success message
241
+ ToasterSteps.verifySuccess('Free access has been enabled.');
242
+ ToasterSteps.getToast().should('not.exist');
243
+ UserAndAccessSteps.getUsersTable().should('be.visible');
244
+ // When I toggle Free Access OFF
245
+ UserAndAccessSteps.toggleFreeAccess();
246
+ // Then I should see a success message
247
+ ToasterSteps.getToast().should('exist');
248
+ ToasterSteps.getToasterMessage().should('contain', 'Free access has been disabled.');
249
+ });
74
250
  });
75
251
 
76
- it('Create user with custom role', () => {
77
- // When I create a read/write user
78
- UserAndAccessSteps.clickCreateNewUserButton();
79
- UserAndAccessSteps.typeUsername(user);
80
- UserAndAccessSteps.typePassword(PASSWORD);
81
- UserAndAccessSteps.typeConfirmPasswordField(PASSWORD);
82
- UserAndAccessSteps.selectRoleRadioButton(ROLE_USER);
83
- // And add a custom role of 1 letter
84
- UserAndAccessSteps.addTextToCustomRoleField('A');
85
- clickWriteAccessForRepo('*');
86
-
87
- // Then the 'create' button should be disabled
88
- UserAndAccessSteps.getConfirmUserCreateButton().should('be.disabled');
89
- // And the field should show an error
90
- UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long');
91
- // When I add more text to the custom role tag
92
- UserAndAccessSteps.addTextToCustomRoleField('A{enter}');
93
- // Then the 'create' button should be enabled
94
- UserAndAccessSteps.getConfirmUserCreateButton().should('be.enabled');
95
- // And the field error should not exist
96
- UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible');
97
-
98
- // When I type an invalid tag
99
- UserAndAccessSteps.addTextToCustomRoleField('B{enter}');
100
- // And the field shows an error
101
- UserAndAccessSteps.getCustomRoleFieldError().should('contain.text', 'Must be at least 2 symbols long');
102
- // When I delete the invalid text
103
- UserAndAccessSteps.addTextToCustomRoleField('{backspace}');
104
- // Then the error should not be visible
105
- UserAndAccessSteps.getCustomRoleFieldError().should('not.be.visible');
106
-
107
- // When I create the user with a valid custom role
108
- UserAndAccessSteps.clickWriteAccessAny();
109
- SecurityStubs.spyOnUserCreate()
110
- UserAndAccessSteps.confirmUserCreate();
111
- // Then the user should be created with that custom role
112
- cy.wait('@create-user').its('request.body').then((body) => {
113
- expect(body).to.deep.eq({
114
- "password": "password",
115
- "grantedAuthorities": [
116
- "ROLE_USER",
117
- "CUSTOM_AA",
118
- "WRITE_REPO_*",
119
- "READ_REPO_*"
120
- ],
121
- "appSettings": {
122
- "DEFAULT_VIS_GRAPH_SCHEMA": true,
123
- "DEFAULT_INFERENCE": true,
124
- "DEFAULT_SAMEAS": true,
125
- "IGNORE_SHARED_QUERIES": false,
126
- "EXECUTE_COUNT": true
127
- }
128
- })
129
- });
130
-
131
- cy.url().should('include', '/users');
132
- UserAndAccessSteps.findUserInTable(user).should('be.visible');
133
- UserAndAccessSteps.getUserCustomRoles('@user')
134
- .should('have.length', 1)
135
- .eq(0).and('have.text', 'AA');
136
- // And when I open the edit page for that user, the custom role should be visible in the field without the prefix
137
- UserAndAccessSteps.openEditUserPage(user);
138
- UserAndAccessSteps.getCustomRoleField().find('.tag-item span')
139
- .should('have.length', 1)
140
- .eq(0).and('have.text', 'AA');
252
+ context('Login / return URL redirects', () => {
253
+ it('should not add the active repository to the login page URL', () => {
254
+ cy.presetRepository(repoName);
255
+ UserAndAccessSteps.visit();
256
+ cy.url().should('include', `repositoryId=${repoName}`);
257
+
258
+ UserAndAccessSteps.toggleSecurity();
259
+
260
+ cy.url()
261
+ .should('include', '/login')
262
+ .and('not.include', 'repositoryId=');
263
+ });
264
+
265
+ it('should redirect to previous page after logout and then login', () => {
266
+ UserAndAccessSteps.toggleSecurity();
267
+ LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
268
+ MainMenuSteps.clickOnSparqlMenu();
269
+ cy.get('h1').should('be.visible').should('contain', 'SPARQL Query & Update');
270
+ cy.url().should('include', '/sparql');
271
+
272
+ LoginSteps.logout();
273
+ cy.url().should('include', '/login');
274
+ LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
275
+ cy.url().should('include', '/sparql');
276
+ });
277
+
278
+ it('should redirect to correct return url when user is authenticated and on login page', () => {
279
+ UserAndAccessSteps.visit();
280
+ UserAndAccessSteps.toggleSecurity();
281
+ LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
282
+ UserAndAccessSteps.getUsersTable().should('be.visible');
283
+
284
+ cy.visit('/login?r=%252Fsparql');
285
+ cy.reload();
286
+ UserAndAccessSteps.getUrl().should('include', '/sparql');
287
+ });
141
288
  });
289
+ });
142
290
 
143
- it('Adding a role with a CUSTOM_ prefix shows a warning message', () => {
144
- // When I create a user
145
- UserAndAccessSteps.clickCreateNewUserButton();
146
- // And I add a custom role tag with prefix CUSTOM_
147
- UserAndAccessSteps.addTextToCustomRoleField('CUSTOM_USER{Enter}');
148
- // There should be a warning text
149
- UserAndAccessSteps.getPrefixWarning(0).should('contain', 'Custom roles should be entered without the "CUSTOM_" prefix in Workbench');
291
+ context('Verify access states', () => {
292
+ let repoName;
293
+
294
+ before(() => {
295
+ repoName = 'user-access-repo1-' + Date.now();
296
+ cy.createRepository({id: repoName});
297
+ cy.switchOffSecurity(true);
298
+ SecurityStubs.spyOnUserGet();
150
299
  });
151
300
 
152
- it('Warn users when setting no password when creating new user admin', () => {
153
- UserAndAccessSteps.getUsersTable().should('be.visible');
154
- createUser(user, PASSWORD, ROLE_CUSTOM_ADMIN, {noPassword: true});
301
+ beforeEach(() => {
302
+ UserAndAccessSteps.visit();
303
+ // Users table should be visible
155
304
  UserAndAccessSteps.getUsersTable().should('be.visible');
156
- UserAndAccessSteps.getSplashLoader().should('not.be.visible');
157
305
  });
158
306
 
159
- it('should toggle free access after Admin has logged in', () => {
160
- // Given I have available repositories to allow Free Access for
161
- RepositoriesStubs.stubRepositories();
162
- RepositoriesStubs.stubFreeAccess();
163
- // When I enable security
164
- UserAndAccessSteps.toggleSecurity();
165
- // When I log in as an Admin
166
- LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
167
- // Then the page should load
168
- UserAndAccessSteps.getSplashLoader().should('not.be.visible');
169
- UserAndAccessSteps.getUsersTable().should('be.visible');
170
- // The Free Access toggle should be OFF
171
- UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
172
- // When I toggle Free Access ON
173
- UserAndAccessSteps.toggleFreeAccess();
174
- // And I allow free access to a repository
175
- ModalDialogSteps.getDialog().should('be.visible');
176
- // Then I click OK in the modal
177
- ModalDialogSteps.clickOKButton();
178
- // Then the toggle button should be ON
179
- UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked');
180
- // And I should see a success message
181
- ToasterSteps.verifySuccess('Free access has been enabled.');
182
- ToasterSteps.getToast().should('not.exist');
183
- UserAndAccessSteps.getUsersTable().should('be.visible');
184
- // When I toggle Free Access OFF
185
- UserAndAccessSteps.toggleFreeAccess();
186
- // Then I should see a success message
187
- ToasterSteps.getToast().should('exist');
188
- ToasterSteps.getToasterMessage().should('contain', 'Free access has been disabled.');
307
+ after(() => {
308
+ cy.loginAsAdmin().then(() => {
309
+ cy.deleteRepository(repoName, true);
310
+ cy.switchOffFreeAccess(true);
311
+ cy.switchOffSecurity(true);
312
+ });
189
313
  });
190
314
 
191
- it('should redirect to previous page after logout and then login', () => {
192
- UserAndAccessSteps.toggleSecurity();
193
- LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
194
- MainMenuSteps.clickOnSparqlMenu();
195
- cy.url().should('include', '/sparql');
196
-
197
- LoginSteps.logout();
198
- cy.url().should('include', '/login');
199
- LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
200
- cy.url().should('include', '/sparql');
315
+ it('initial state', () => {
316
+ UserAndAccessSteps.clickCreateNewUserButton();
317
+ verifyCheckedUserAuth('*', {read: false, write: false, maintain: false, graphql: false});
318
+ verifyDisabledUserAuth('*', {read: false, write: false, maintain: true, graphql: true});
319
+ verifyCheckedUserAuth(repoName, {read: false, write: false, maintain: false, graphql: false});
320
+ verifyDisabledUserAuth(repoName, {read: false, write: false, maintain: false, graphql: true});
201
321
  });
202
322
 
203
- it('should redirect to correct return url when user is authenticated and on login page', () => {
204
- UserAndAccessSteps.visit();
205
- UserAndAccessSteps.toggleSecurity();
206
- LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
207
- UserAndAccessSteps.getUsersTable().should('be.visible');
323
+ context('for non user roles', () => {
324
+ it('admin', () => {
325
+ UserAndAccessSteps.clickCreateNewUserButton();
326
+ UserAndAccessSteps.selectRoleRadioButton(ROLE_CUSTOM_ADMIN);
327
+ verifyCheckedUserAuth('*', {read: true, write: true, maintain: true, graphql: false});
328
+ verifyDisabledUserAuth('*', {read: true, write: true, maintain: true, graphql: true});
329
+
330
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: true, graphql: false});
331
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: true, graphql: true});
332
+ });
333
+
334
+ it('repository manager', () => {
335
+ UserAndAccessSteps.clickCreateNewUserButton();
336
+ UserAndAccessSteps.selectRoleRadioButton(ROLE_REPO_MANAGER);
337
+
338
+ verifyCheckedUserAuth('*', {read: true, write: true, maintain: true, graphql: false});
339
+ verifyDisabledUserAuth('*', {read: true, write: true, maintain: true, graphql: true});
340
+
341
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: true, graphql: false});
342
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: true, graphql: true});
343
+ });
344
+ });
345
+
346
+ context('for specific repo', () => {
347
+ it('read', () => {
348
+ UserAndAccessSteps.clickCreateNewUserButton();
349
+ setRoles({read: true, repoName});
350
+ verifyCheckedUserAuth(repoName, {read: true, write: false, maintain: false, graphql: false});
351
+ verifyDisabledUserAuth(repoName, {read: false, write: false, maintain: false, graphql: false});
352
+ });
353
+
354
+ it('write', () => {
355
+ UserAndAccessSteps.clickCreateNewUserButton();
356
+ setRoles({readWrite: true, repoName});
357
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: false, graphql: false});
358
+ verifyDisabledUserAuth(repoName, {read: true, write: false, maintain: false, graphql: false});
359
+ });
360
+
361
+ it('maintain', () => {
362
+ UserAndAccessSteps.clickCreateNewUserButton();
363
+ setRoles({maintain: true, repoName});
364
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: true, graphql: false});
365
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: false, graphql: true});
366
+ });
367
+
368
+ it('graphql with read', () => {
369
+ UserAndAccessSteps.clickCreateNewUserButton();
370
+ setRoles({read: true, graphql: true, repoName});
371
+ verifyCheckedUserAuth(repoName, {read: true, write: false, maintain: false, graphql: true});
372
+ verifyDisabledUserAuth(repoName, {read: false, write: false, maintain: false, graphql: false});
373
+ });
374
+
375
+ it('graphql with write', () => {
376
+ UserAndAccessSteps.clickCreateNewUserButton();
377
+ setRoles({readWrite: true, graphql: true, repoName});
378
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: false, graphql: true});
379
+ verifyDisabledUserAuth(repoName, {read: true, write: false, maintain: false, graphql: false});
380
+ });
381
+ });
382
+
383
+ context('for any repo', () => {
384
+ let anyRepo = '*';
385
+
386
+ it('read', () => {
387
+ UserAndAccessSteps.clickCreateNewUserButton();
388
+ setRoles({read: true, anyRepo});
389
+ verifyCheckedUserAuth(anyRepo, {read: true, write: false, maintain: false, graphql: false});
390
+ verifyDisabledUserAuth(anyRepo, {read: false, write: false, maintain: true, graphql: false});
391
+
392
+ verifyCheckedUserAuth(repoName, {read: true, write: false, maintain: false, graphql: false});
393
+ verifyDisabledUserAuth(repoName, {read: true, write: false, maintain: false, graphql: false});
394
+ });
395
+
396
+ it('write', () => {
397
+ UserAndAccessSteps.clickCreateNewUserButton();
398
+ setRoles({readWrite: true, anyRepo});
399
+ verifyCheckedUserAuth(anyRepo, {read: true, write: true, maintain: false, graphql: false});
400
+ verifyDisabledUserAuth(anyRepo, {read: true, write: false, maintain: true, graphql: false});
401
+
402
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: false, graphql: false});
403
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: false, graphql: false});
404
+ });
405
+
406
+ it('graphql with read', () => {
407
+ UserAndAccessSteps.clickCreateNewUserButton();
408
+ setRoles({read: true, graphql: true, anyRepo});
409
+ verifyCheckedUserAuth(anyRepo, {read: true, write: false, maintain: false, graphql: true});
410
+ verifyDisabledUserAuth(anyRepo, {read: false, write: false, maintain: true, graphql: false});
411
+
412
+ verifyCheckedUserAuth(repoName, {read: true, write: false, maintain: false, graphql: true});
413
+ verifyDisabledUserAuth(repoName, {read: true, write: false, maintain: false, graphql: true});
414
+ });
415
+
416
+ it('graphql with write', () => {
417
+ UserAndAccessSteps.clickCreateNewUserButton();
418
+ setRoles({readWrite: true, graphql: true, anyRepo});
419
+ verifyCheckedUserAuth(anyRepo, {read: true, write: true, maintain: false, graphql: true});
420
+ verifyDisabledUserAuth(anyRepo, {read: true, write: false, maintain: true, graphql: false});
208
421
 
209
- cy.visit('/login?r=%252Fsparql');
210
- cy.reload();
211
- UserAndAccessSteps.getUrl().should('include', '/sparql');
422
+ verifyCheckedUserAuth(repoName, {read: true, write: true, maintain: false, graphql: true});
423
+ verifyDisabledUserAuth(repoName, {read: true, write: true, maintain: false, graphql: true});
424
+ });
212
425
  });
213
426
  });
214
- // eslint-disable-next-line no-undef
215
- context('GraphQL only', () => {
427
+
428
+ context('GraphQL access', () => {
216
429
  let repositoryId1;
217
430
  let repositoryId2;
218
431
  let repositoryId3;
219
432
  const graphqlUser = 'graphqlUser';
220
433
 
221
434
  beforeEach(() => {
222
- cy.viewport(1280, 1000);
223
435
  RepositoriesStubs.spyGetRepositories();
224
436
  repositoryId1 = 'user-access-repo1-' + Date.now();
225
437
  repositoryId2 = 'user-access-repo2-' + Date.now();
@@ -231,6 +443,7 @@ describe('User and Access', () => {
231
443
  UserAndAccessSteps.visit();
232
444
  // Users table should be visible
233
445
  UserAndAccessSteps.getUsersTable().should('be.visible');
446
+ SecurityStubs.spyOnUserGet();
234
447
  });
235
448
 
236
449
  afterEach(() => {
@@ -245,174 +458,318 @@ describe('User and Access', () => {
245
458
 
246
459
  });
247
460
 
248
- it('Create user with GraphQL-only access', () => {
249
- cy.wait('@getRepositories');
250
- createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2});
251
- });
461
+ context('GraphQL checkbox behavior', () => {
462
+ it('Create user with GraphQL-only access', () => {
463
+ cy.wait('@getRepositories');
464
+ createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2});
465
+ });
252
466
 
253
- // Fails for unknown reason only in CI
254
- it.skip('Can create user with different auth combinations', () => {
255
- cy.wait('@getRepositories');
256
- // WHEN I create a user with read + GraphQL for repository #2
257
- createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2});
258
- // THEN the user should have read + GraphQL on that repo
259
- assertUserAuths(graphqlUser, {repo: repositoryId2, read: true, graphql: true});
260
- // WHEN I open the edit page for that user
261
- UserAndAccessSteps.openEditUserPage(graphqlUser);
262
- // THEN for repository #1, the GraphQL checkbox should be disabled initially
263
- UserAndAccessSteps.getGraphqlAccessForRepo(repositoryId1).should('be.disabled');
264
- // WHEN I enable "read" for repository #1
265
- editUserAuths({repo: repositoryId1, read: true});
266
- // THEN GraphQL for repository #1 should become enabled
267
- UserAndAccessSteps.getGraphqlAccessForRepo(repositoryId1).should('be.enabled');
268
- // WHEN I enable GraphQL and read
269
- editUserAuths({repo: repositoryId1, graphql: true});
270
- editUserAuths({repo: repositoryId1, read: true});
271
- // THEN GraphQL should be checked and disabled
272
- UserAndAccessSteps.getGraphqlAccessForRepo(repositoryId1).should('be.checked').and('be.disabled');
273
- // THEN for repository #3, GraphQL should be disabled initially
274
- UserAndAccessSteps.getGraphqlAccessForRepo(repositoryId3).should('be.disabled');
275
- // WHEN I enable "write" for repository #3
276
- editUserAuths({repo: repositoryId3, write: true});
277
- // THEN GraphQL for repository #3 should become enabled
278
- UserAndAccessSteps.getGraphqlAccessForRepo(repositoryId3).should('be.enabled');
279
- // And I expect "read" to be checked and disabled
280
- UserAndAccessSteps.getReadAccessForRepo(repositoryId3).should('be.checked').and('be.disabled');
281
- // I enable GraphQL for repository #3
282
- editUserAuths({repo: repositoryId3, graphql: true});
283
-
284
- // WHEN I confirm the user edit
285
- UserAndAccessSteps.confirmUserEdit();
286
- // THEN verify the final rights:
287
- // - repo #1 has no read/write/graphql
288
- // - repo #2 has read + graphql
289
- // - repo #3 has write + graphql (and read was auto-checked but disabled)
290
- assertUserAuths(graphqlUser, {repo: repositoryId1, read: false, write: false, graphql: false});
291
- assertUserAuths(graphqlUser, {repo: repositoryId2, read: true, write: false, graphql: true});
292
- assertUserAuths(graphqlUser, {repo: repositoryId3, read: false, write: true, graphql: true});
467
+ // Fails for unknown reason only in CI
468
+ it('Can create user with different auth combinations', () => {
469
+ cy.wait('@getRepositories');
470
+ cy.wait('@getRepositories');
471
+ UserAndAccessSteps.getUsersCatalogContainer().should('be.visible');
472
+ // WHEN I create a user with read + GraphQL for repository #2
473
+ createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId2});
474
+ // THEN the user should have read + GraphQL on that repo
475
+ assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId2, read: true, graphql: true});
476
+ // WHEN I open the edit page for that user
477
+ UserAndAccessSteps.openEditUserPage(graphqlUser);
478
+ cy.wait('@get-user');
479
+ // THEN for repository #1, the GraphQL checkbox should be disabled initially
480
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {disabled: true});
481
+ // WHEN I enable "read" for repository #1
482
+ setUserAuths({repo: repositoryId1, read: true});
483
+ // THEN GraphQL for repository #1 should become enabled
484
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {disabled: false});
485
+ // WHEN I enable GraphQL with read
486
+ setUserAuths({repo: repositoryId1, graphql: true});
487
+ // THEN GraphQL should be checked and enabled
488
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {checked: true, disabled: false});
489
+ // THEN for repository #3, GraphQL should be disabled initially
490
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId3, {disabled: true});
491
+ // WHEN I enable "write" for repository #3
492
+ setUserAuths({repo: repositoryId3, write: true});
493
+ // THEN GraphQL for repository #3 should become enabled
494
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId3, {disabled: false});
495
+ // And I expect "read" to be checked and disabled
496
+ UserAndAccessSteps.validateReadAccessForRepo(repositoryId3, {checked: true, disabled: true});
497
+ // I enable GraphQL for repository #3
498
+ setUserAuths({repo: repositoryId3, graphql: true});
499
+ // THEN GraphQL should be checked and enabled
500
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId1, {checked: true, disabled: false});
501
+ // When I remove "read" for repository #2
502
+ UserAndAccessSteps.toggleReadAccessForRepo(repositoryId2);
503
+ // THEN I expect "graphql" to be unchecked and disabled for repository #2
504
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repositoryId2, {checked: false, disabled: true});
505
+
506
+ // WHEN I confirm the user edit
507
+ UserAndAccessSteps.confirmUserEdit();
508
+ // THEN verify the final rights:
509
+ // - repo #1 has no read/write/graphql
510
+ // - repo #2 has read + graphql
511
+ // - repo #3 has write + graphql (and read was auto-checked but disabled)
512
+ assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId1, read: true, write: false, graphql: true});
513
+ assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId2, read: false, write: false, graphql: false});
514
+ assertUserAuthsInCatalog(graphqlUser, {repo: repositoryId3, read: false, write: true, graphql: true});
515
+ });
293
516
  });
294
517
 
295
- // TODO remove skipped flag from all tests after merge of https://github.com/Ontotext-AD/graphdb-workbench/pull/2042
296
- it.skip('Should have access to 5 pages when have graphql only rights', () => {
297
- cy.wait('@getRepositories');
298
- // WHEN I create a user with read + GraphQL for repository #2
299
- createUser(graphqlUser, PASSWORD, ROLE_USER, {readWrite: true, graphql: true, repoName: repositoryId1});
300
- //enable security
301
- UserAndAccessSteps.toggleSecurity();
302
- //login new user
303
- LoginSteps.loginWithUser(graphqlUser, PASSWORD);
304
- RepositorySelectorSteps.selectRepository(repositoryId1);
305
-
306
- MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => {
307
- navigateMenuPath(path, expectedUrl, expectedTitle);
308
- if (checks) {
309
- runChecks(checks);
310
- }
518
+ context('Menu navigation based on permissions', () => {
519
+ it('Should have access to 5 pages when have graphql only rights', () => {
520
+ cy.wait('@getRepositories');
521
+ cy.wait('@getRepositories');
522
+ // WHEN I create a user with read + GraphQL for repository #2
523
+ createUser(graphqlUser, PASSWORD, ROLE_USER, {readWrite: true, graphql: true, repoName: repositoryId1});
524
+ //enable security
525
+ UserAndAccessSteps.toggleSecurity();
526
+ //login new user
527
+ LoginSteps.loginWithUser(graphqlUser, PASSWORD);
528
+ cy.wait('@getRepositories');
529
+ cy.wait('@getRepositories');
530
+
531
+ MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => {
532
+ navigateMenuPath(path, expectedUrl, expectedTitle);
533
+
534
+ if (checks) {
535
+ runChecks(checks);
536
+ }
537
+ navigateMenuPath(['Import'], '/import', 'Import');
538
+ });
311
539
  });
312
- });
313
540
 
314
- it.skip('Should not have access endpoints management when have read graphql only rights', () => {
315
- cy.wait('@getRepositories');
316
- // WHEN I create a user with read + GraphQL for repository #2
317
- createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId1});
318
- //enable security
319
- UserAndAccessSteps.toggleSecurity();
320
- //login new user
321
- LoginSteps.loginWithUser(graphqlUser, PASSWORD);
322
- RepositorySelectorSteps.selectRepository(repositoryId1);
323
-
324
- GRAPHQL_READ_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => {
325
- navigateMenuPath(path, expectedUrl, expectedTitle);
326
- if (checks) {
327
- runChecks(checks);
328
- }
541
+ it('Should not have access endpoints management when have read graphql only rights', () => {
542
+ cy.wait('@getRepositories');
543
+ cy.wait('@getRepositories');
544
+ // WHEN I create a user with read + GraphQL for repository #2
545
+ createUser(graphqlUser, PASSWORD, ROLE_USER, {read: true, graphql: true, repoName: repositoryId1});
546
+ //enable security
547
+ UserAndAccessSteps.toggleSecurity();
548
+ //login new user
549
+ LoginSteps.loginWithUser(graphqlUser, PASSWORD);
550
+ cy.wait('@getRepositories');
551
+ cy.wait('@getRepositories');
552
+ // RepositorySelectorSteps.selectRepository(repositoryId1);
553
+
554
+ GRAPHQL_READ_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => {
555
+ navigateMenuPath(path, expectedUrl, expectedTitle);
556
+ if (checks) {
557
+ runChecks(checks);
558
+ }
559
+ navigateMenuPath(['Import'], '/import', 'Import');
560
+ });
329
561
  });
330
- });
331
562
 
332
- it.skip('Should have all access to endpoints management when have REPO_MANAGER role', () => {
333
- cy.wait('@getRepositories');
334
- createUser(graphqlUser, PASSWORD, ROLE_REPO_MANAGER);
335
- //enable security
336
- UserAndAccessSteps.toggleSecurity();
337
- HomeSteps.visit();
338
- //login new user
339
- LoginSteps.loginWithUser(graphqlUser, PASSWORD);
340
- GRAPHQL_REPO_MANAGER_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => {
341
- navigateMenuPath(path, expectedUrl, expectedTitle);
342
- if (checks) {
343
- runChecks(checks);
344
- }
563
+ it('Should have all access to endpoints management when have REPO_MANAGER role', () => {
564
+ cy.wait('@getRepositories');
565
+ cy.wait('@getRepositories');
566
+ createUser(graphqlUser, PASSWORD, ROLE_REPO_MANAGER);
567
+ //enable security
568
+ UserAndAccessSteps.toggleSecurity();
569
+ HomeSteps.visitAndWaitLoader();
570
+ //login new user
571
+ LoginSteps.loginWithUser(graphqlUser, PASSWORD);
572
+ cy.wait('@getRepositories');
573
+ cy.wait('@getRepositories');
574
+ GRAPHQL_REPO_MANAGER_MENU_ITEMS.forEach(({path, expectedUrl, checks, expectedTitle}) => {
575
+ navigateMenuPath(path, expectedUrl, expectedTitle);
576
+ if (checks) {
577
+ runChecks(checks);
578
+ }
579
+ navigateMenuPath(['Import'], '/import', 'Import');
580
+ });
581
+ });
582
+
583
+ it('Can have Free Access and GraphQL working together', () => {
584
+ cy.wait('@getRepositories');
585
+ cy.wait('@getRepositories');
586
+ //enable security
587
+ UserAndAccessSteps.toggleSecurity();
588
+ //login with the admin
589
+ LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
590
+ cy.wait('@getRepositories');
591
+ cy.wait('@getRepositories');
592
+ // The Free Access toggle should be OFF
593
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
594
+ // When I toggle Free Access ON
595
+ UserAndAccessSteps.toggleFreeAccess();
596
+ // Then I set repo auths
597
+ UserAndAccessSteps.clickFreeReadAccessRepo(repositoryId1);
598
+ UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId2);
599
+ UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId3);
600
+ UserAndAccessSteps.clickFreeGraphqlAccessRepo(repositoryId3);
601
+ // Then I click OK in the modal
602
+ ModalDialogSteps.clickOKButton();
603
+ // Then the toggle button should be ON
604
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked');
605
+ // And I should see a success message
606
+ ToasterSteps.verifySuccess('Free access has been enabled.');
607
+ UserAndAccessSteps.getUsersTable().should('be.visible');
608
+
609
+ // Then I logout
610
+ LoginSteps.logout();
611
+ HomeSteps.visit();
612
+ // I change the repository to this with GraphQL only rights
613
+ RepositorySelectorSteps.selectRepository(repositoryId3);
614
+ // Then I should have GraphQL only rights
615
+ FREE_ACCESS_MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => {
616
+ navigateMenuPath(path, expectedUrl, expectedTitle);
617
+ if (checks) {
618
+ runChecks(checks);
619
+ }
620
+ navigateMenuPath(['Import'], '/import', 'Import');
621
+ });
345
622
  });
346
623
  });
624
+ });
347
625
 
348
- it.skip('Can have Free Access and GraphQL working together', () => {
349
- cy.wait('@getRepositories');
350
- //enable security
351
- UserAndAccessSteps.toggleSecurity();
352
- //login with the admin
353
- LoginSteps.loginWithUser('admin', DEFAULT_ADMIN_PASSWORD);
354
- // The Free Access toggle should be OFF
355
- UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
356
- // When I toggle Free Access ON
357
- UserAndAccessSteps.toggleFreeAccess();
358
- // Then I set repo auths
359
- UserAndAccessSteps.clickFreeReadAccessRepo(repositoryId1);
360
- UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId2);
361
- UserAndAccessSteps.clickFreeWriteAccessRepo(repositoryId3);
362
- UserAndAccessSteps.clickFreeGraphqlAccessRepo(repositoryId3);
363
- // Then I click OK in the modal
364
- ModalDialogSteps.clickOKButton();
365
- // Then the toggle button should be ON
366
- UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked');
367
- // And I should see a success message
368
- ToasterSteps.verifySuccess('Free access has been enabled.');
626
+ context('User with maintain permission', () => {
627
+ let withoutPermissionRepositoryId;
628
+ let readRepositoryId;
629
+ let writeRepositoryId;
630
+ let graphQLOnlyRepositoryId;
631
+ let maintainedRepositoryId;
632
+ const maintainerUser = 'maintainerUser';
633
+
634
+ beforeEach(() => {
635
+ RepositoriesStubs.spyGetRepositories();
636
+ readRepositoryId = 'readRepositoryId-' + Date.now();
637
+ writeRepositoryId = 'writeRepositoryId-' + Date.now();
638
+ graphQLOnlyRepositoryId = 'graphQLOnlyRepositoryId-' + Date.now();
639
+ maintainedRepositoryId = 'maintainedRepositoryId-' + Date.now();
640
+ withoutPermissionRepositoryId = 'withoutPermissionRepositoryId-' + Date.now();
641
+ cy.createRepository({id: readRepositoryId});
642
+ cy.createRepository({id: writeRepositoryId});
643
+ cy.createRepository({id: graphQLOnlyRepositoryId});
644
+ cy.createRepository({id: maintainedRepositoryId});
645
+ cy.createRepository({id: withoutPermissionRepositoryId});
646
+ UserAndAccessSteps.visit();
647
+ // Users table should be visible
369
648
  UserAndAccessSteps.getUsersTable().should('be.visible');
649
+ SecurityStubs.spyOnUserGet();
650
+ });
370
651
 
371
- // Then I logout
372
- LoginSteps.logout();
373
- HomeSteps.visit();
374
- // I change the repository to this with GraphQL only rights
375
- RepositorySelectorSteps.selectRepository(repositoryId3);
376
- // Then I should have GraphQL only rights
377
- FREE_ACCESS_MENU_ITEMS_WITHOUT_GRAPHQL.forEach(({path, expectedUrl, checks, expectedTitle}) => {
378
- navigateMenuPath(path, expectedUrl, expectedTitle);
379
- if (checks) {
380
- runChecks(checks);
381
- }
382
- });
383
- // Turn free access off
652
+ afterEach(() => {
384
653
  cy.loginAsAdmin().then(() => {
654
+ cy.deleteRepository(readRepositoryId, true);
655
+ cy.deleteRepository(writeRepositoryId, true);
656
+ cy.deleteRepository(graphQLOnlyRepositoryId, true);
657
+ cy.deleteRepository(maintainedRepositoryId, true);
658
+ cy.deleteRepository(withoutPermissionRepositoryId, true);
659
+ cy.deleteUser(maintainerUser, true);
385
660
  cy.switchOffFreeAccess(true);
661
+ cy.switchOffSecurity(true);
386
662
  });
387
663
  });
388
- });
389
664
 
390
- function clickGraphqlAccessForRepo(repoName) {
391
- if (repoName === '*') {
392
- UserAndAccessSteps.clickGraphqlAccessAny();
393
- } else {
394
- UserAndAccessSteps.clickGraphqlAccessRepo(repoName);
395
- }
396
- }
665
+ it('should list all repositories for which a user with maintain permission has at least read permission', () => {
666
+ // Given there are five repositories.
667
+ // And there is a user with permissions for four of them:
668
+ // 1. Maintain permission for one repository.
669
+ createUser(maintainerUser, PASSWORD, ROLE_USER, {maintain: true, repoName: maintainedRepositoryId});
670
+ // 2. Read permission for one repository.
671
+ UserAndAccessSteps.openEditUserPage(maintainerUser);
672
+ cy.wait('@get-user');
673
+ setUserAuths({repo: readRepositoryId, read: true});
674
+ // 3. Write permission for one repository.
675
+ setUserAuths({repo: writeRepositoryId, write: true});
676
+ // 4. GraphQL-only permission for one repository.
677
+ setUserAuths({repo: graphQLOnlyRepositoryId, write: true, graphql: true});
678
+ UserAndAccessSteps.confirmUserEdit();
397
679
 
398
- function clickReadAccessForRepo(repoName) {
399
- if (repoName === '*') {
400
- UserAndAccessSteps.clickReadAccessAny();
401
- } else {
402
- UserAndAccessSteps.clickReadAccessRepo(repoName);
403
- }
404
- }
680
+ // When I log in as a user with repository maintain permission.
681
+ UserAndAccessSteps.toggleSecurity();
682
+ LoginSteps.loginWithUser(maintainerUser, PASSWORD);
683
+ // And navigate to the repository list view.
684
+ RepositorySteps.visit(false);
685
+
686
+ // Then I should see all repositories for which the user has at least read permission.
687
+ RepositorySteps.getRepositories().should('have.length', 4);
688
+
689
+ // And I should see the actions allowed for the repository the user can maintain.
690
+ RepositorySteps.getCopyRepositoryButton(maintainedRepositoryId).should('be.visible');
691
+ RepositorySteps.getEditRepositoryButton(maintainedRepositoryId).should('be.visible');
692
+ RepositorySteps.getDownloadRepositoryConfigurationButton(maintainedRepositoryId).should('be.visible');
693
+ RepositorySteps.getRestartRepositoryButton(maintainedRepositoryId).should('be.visible');
694
+
695
+ // And the delete button should not be available because users with maintain permission
696
+ // are not allowed to delete repositories.
697
+ RepositorySteps.getDeleteRepositoryButton(maintainedRepositoryId).should('not.exist');
698
+
699
+ // And the "Set as default repository" button should not be available because users
700
+ // with maintain permission are not allowed to set the default repository.
701
+ RepositorySteps.getSetDefaultRepositoryButton(maintainedRepositoryId).should('not.exist');
702
+
703
+ // And should see the copy action for all repositories.
704
+ RepositorySteps.getCopyRepositoryButton(writeRepositoryId).should('be.visible');
705
+ RepositorySteps.getCopyRepositoryButton(readRepositoryId).should('be.visible');
706
+ RepositorySteps.getCopyRepositoryButton(graphQLOnlyRepositoryId).should('be.visible');
707
+
708
+ // And no repository management actions should be available for the other repositories.
709
+ RepositorySteps.getEditRepositoryButton(readRepositoryId).should('not.exist');
710
+ RepositorySteps.getDownloadRepositoryConfigurationButton(readRepositoryId).should('not.exist');
711
+ RepositorySteps.getRestartRepositoryButton(readRepositoryId).should('not.exist');
712
+ RepositorySteps.getDeleteRepositoryButton(readRepositoryId).should('not.exist');
713
+ RepositorySteps.getSetDefaultRepositoryButton(readRepositoryId).should('not.exist');
714
+
715
+ RepositorySteps.getEditRepositoryButton(writeRepositoryId).should('not.exist');
716
+ RepositorySteps.getDownloadRepositoryConfigurationButton(writeRepositoryId).should('not.exist');
717
+ RepositorySteps.getRestartRepositoryButton(writeRepositoryId).should('not.exist');
718
+ RepositorySteps.getDeleteRepositoryButton(writeRepositoryId).should('not.exist');
719
+ RepositorySteps.getSetDefaultRepositoryButton(writeRepositoryId).should('not.exist');
720
+
721
+ RepositorySteps.getEditRepositoryButton(graphQLOnlyRepositoryId).should('not.exist');
722
+ RepositorySteps.getDownloadRepositoryConfigurationButton(graphQLOnlyRepositoryId).should('not.exist');
723
+ RepositorySteps.getRestartRepositoryButton(graphQLOnlyRepositoryId).should('not.exist');
724
+ RepositorySteps.getDeleteRepositoryButton(graphQLOnlyRepositoryId).should('not.exist');
725
+ RepositorySteps.getSetDefaultRepositoryButton(graphQLOnlyRepositoryId).should('not.exist');
726
+
727
+ // And the "Create", "Create from file", and "Attach remote repository" page buttons
728
+ // should not be available to a user with maintain permission.
729
+ RepositorySteps.getPageButtons().should('not.exist');
730
+
731
+ // When I select a repository for which I have GraphQL-only permission.
732
+ RepositorySelectorSteps.selectRepository(graphQLOnlyRepositoryId);
733
+
734
+ // Then I should still see all repositories for which the user has at least read permission.
735
+ RepositorySteps.getRepositories().should('have.length', 4);
736
+ });
405
737
 
406
- function clickWriteAccessForRepo(repoName) {
407
- if (repoName === '*') {
408
- UserAndAccessSteps.clickWriteAccessAny();
409
- } else {
410
- UserAndAccessSteps.clickWriteAccessRepo(repoName);
411
- }
412
- }
738
+ it('should not allow a user with maintain permission to rename a repository', () => {
739
+ // Given there is a user with maintain permission for a repository.
740
+ createUser(maintainerUser, PASSWORD, ROLE_USER, {maintain: true, repoName: maintainedRepositoryId});
741
+ UserAndAccessSteps.toggleSecurity();
742
+ LoginSteps.loginWithUser(maintainerUser, PASSWORD);
743
+ RepositorySteps.visit(false);
744
+
745
+ // When the user opens the edit page of the repository they can maintain.
746
+ RepositorySteps.getEditRepositoryButton(maintainedRepositoryId).should('be.visible');
747
+ RepositorySteps.editRepository(maintainedRepositoryId);
748
+
749
+ // Then the repository id should be rendered as read only.
750
+ RepositorySteps.getGDBIdInput()
751
+ .should('have.value', maintainedRepositoryId)
752
+ .and('be.disabled');
753
+
754
+ // And the action which unlocks the repository id field should not be available, because renaming
755
+ // a repository is allowed only for administrators and repository managers.
756
+ RepositorySteps.getRepositoryIdEditElement().should('not.exist');
757
+
758
+ // But the rest of the repository configuration should still be editable.
759
+ RepositorySteps.typeRepositoryTitle('Renaming is not allowed');
760
+ RepositorySteps.getSaveRepositoryButton().click();
761
+ ModalDialogSteps.clickOKButton();
762
+
763
+ // And the repository should keep its original id after the configuration is saved.
764
+ RepositorySteps.getRepositoryFromList(maintainedRepositoryId).should('be.visible');
765
+ RepositorySteps.getEditRepositoryButton(maintainedRepositoryId).should('be.visible');
766
+ });
767
+ });
413
768
 
414
769
  function createUser(username, password, role, opts = {}) {
415
770
  UserAndAccessSteps.clickCreateNewUserButton();
771
+ cy.url().should('include', '/user/create');
772
+ UserAndAccessSteps.getUsernameField().should('be.visible').and('be.enabled').and('not.be.disabled');
416
773
  UserAndAccessSteps.typeUsername(username);
417
774
  UserAndAccessSteps.typePassword(password);
418
775
  UserAndAccessSteps.typeConfirmPasswordField(password);
@@ -421,8 +778,9 @@ describe('User and Access', () => {
421
778
 
422
779
  if (role === '#roleUser') {
423
780
  setRoles(opts);
424
- UserAndAccessSteps.confirmUserCreate();
425
- } else if (role === ROLE_CUSTOM_ADMIN && opts.noPassword) {
781
+ }
782
+
783
+ if (role === ROLE_CUSTOM_ADMIN && opts.noPassword) {
426
784
  UserAndAccessSteps.getNoPasswordCheckbox().check()
427
785
  .then(() => {
428
786
  UserAndAccessSteps.getNoPasswordCheckbox()
@@ -442,16 +800,8 @@ describe('User and Access', () => {
442
800
  }
443
801
 
444
802
  function setRoles(opts = {}) {
445
- const {read = false, readWrite = false, graphql = false, repoName = '*'} = opts;
446
- if (read) {
447
- clickReadAccessForRepo(repoName);
448
- }
449
- if (readWrite) {
450
- clickWriteAccessForRepo(repoName);
451
- }
452
- if (graphql) {
453
- clickGraphqlAccessForRepo(repoName);
454
- }
803
+ const {read = false, readWrite = false, graphql = false, maintain = false, repoName = '*'} = opts;
804
+ setUserAuths({repo: repoName, read, write: readWrite, graphql, maintain});
455
805
  }
456
806
 
457
807
  function testForUser(name, isAdmin) {
@@ -470,10 +820,10 @@ describe('User and Access', () => {
470
820
  }
471
821
  }
472
822
 
473
- function assertUserAuths(username, {repo, read = false, write = false, graphql = false} = {}) {
823
+ function assertUserAuthsInCatalog(username, {repo, read = false, write = false, maintain = false, graphql = false} = {}) {
474
824
  UserAndAccessSteps.findUserRowAlias(username, 'userRow');
475
825
 
476
- if (!read && !write) {
826
+ if (!read && !write && !maintain) {
477
827
  return UserAndAccessSteps.getRepoLine('@userRow', repo).should('not.exist');
478
828
  }
479
829
 
@@ -492,6 +842,12 @@ describe('User and Access', () => {
492
842
  UserAndAccessSteps.findWriteIconAlias('@repoLine').should('not.exist');
493
843
  }
494
844
 
845
+ if (maintain) {
846
+ UserAndAccessSteps.findMaintainIconAlias('@repoLine').should('be.visible');
847
+ } else {
848
+ UserAndAccessSteps.findMaintainIconAlias('@repoLine').should('not.exist');
849
+ }
850
+
495
851
  if (graphql) {
496
852
  UserAndAccessSteps.findGraphqlIconAlias('@repoLine').should('exist');
497
853
  } else {
@@ -499,28 +855,56 @@ describe('User and Access', () => {
499
855
  }
500
856
  }
501
857
 
502
- function editUserAuths({repo, read = false, write = false, graphql = false} = {}) {
858
+ function setUserAuths({repo, read = false, write = false, graphql = false, maintain = false} = {}) {
503
859
  if (read === true) {
504
860
  UserAndAccessSteps.toggleReadAccessForRepo(repo);
861
+ UserAndAccessSteps.validateReadAccessForRepo(repo, {checked: read});
505
862
  }
506
863
 
507
864
  if (write === true) {
508
865
  UserAndAccessSteps.toggleWriteAccessForRepo(repo);
866
+ UserAndAccessSteps.validateWriteAccessForRepo(repo, {checked: write});
509
867
  }
510
868
 
511
869
  if (graphql === true) {
512
870
  UserAndAccessSteps.toggleGraphqlAccessForRepo(repo);
871
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {checked: graphql});
872
+ }
873
+
874
+ if (maintain === true) {
875
+ UserAndAccessSteps.toggleMaintainRepoForRepo(repo);
876
+ UserAndAccessSteps.validateMaintainAccessForRepo(repo, {checked: maintain});
513
877
  }
514
878
  }
515
879
 
880
+ function verifyCheckedUserAuth(repo, {read = false, write = false, graphql = false, maintain = false} = {}) {
881
+ UserAndAccessSteps.validateReadAccessForRepo(repo, {checked: read});
882
+ UserAndAccessSteps.validateWriteAccessForRepo(repo, {checked: write});
883
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {checked: graphql});
884
+ UserAndAccessSteps.validateMaintainAccessForRepo(repo, {checked: maintain});
885
+ }
886
+
887
+ function verifyDisabledUserAuth(repo, {read = false, write = false, graphql = false, maintain = false} = {}) {
888
+ UserAndAccessSteps.validateReadAccessForRepo(repo, {disabled: read});
889
+ UserAndAccessSteps.validateWriteAccessForRepo(repo, {disabled: write});
890
+ UserAndAccessSteps.validateGraphqlAccessForRepo(repo, {disabled: graphql});
891
+ UserAndAccessSteps.validateMaintainAccessForRepo(repo, {disabled: maintain});
892
+ }
893
+
516
894
  function navigateMenuPath(pathArray, expectedUrl, expectedTitle) {
517
895
  pathArray.forEach((label, index) => {
518
896
  if (index === 0) {
519
897
  MainMenuSteps.clickOnMenu(label);
898
+ if (pathArray.length > 1) {
899
+ MainMenuSteps.getSubmenuFor(label).scrollIntoView().should('be.visible');
900
+ }
520
901
  } else {
521
902
  MainMenuSteps.clickOnSubMenu(label);
903
+ }
904
+ if (index === pathArray.length - 1) {
905
+ // wait for the page label on the last navigation step to be visible before moving on
522
906
  const title = expectedTitle ? expectedTitle : label;
523
- cy.get('h1').should('contain', title);
907
+ cy.get('h1').should('be.visible').should('contain', title);
524
908
  }
525
909
  });
526
910
 
@@ -558,9 +942,6 @@ describe('User and Access', () => {
558
942
  }
559
943
 
560
944
  const noAuthChecks = {
561
- 'div[role="main]': [
562
- 'not.exist',
563
- ],
564
945
  '.no-authority-panel .alert-warning': [
565
946
  'be.visible',
566
947
  ['contains.text', 'Some functionalities are not available because'],
@@ -569,10 +950,6 @@ describe('User and Access', () => {
569
950
  };
570
951
 
571
952
  const hasAuthChecks = {
572
- 'div[role="main"]': [
573
- 'exist',
574
- 'be.visible',
575
- ],
576
953
  '.no-authority-panel .alert-warning': [
577
954
  'not.exist',
578
955
  ],
@@ -813,13 +1190,5 @@ describe('User and Access', () => {
813
1190
  expectedUrl: '/sparql-templates',
814
1191
  checks: noAuthChecks,
815
1192
  },
816
-
817
- // 7) Help
818
- {
819
- path: ['Help', 'REST API'],
820
- expectedUrl: '/webapi',
821
- expectedTitle: 'REST API documentation',
822
- checks: hasAuthChecks,
823
- },
824
1193
  ];
825
1194
  });