graphdb-workbench-tests 2.0.0-TR1 → 2.0.0-TR12

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.
@@ -103,5 +103,5 @@
103
103
  }
104
104
  },
105
105
  "title": "",
106
- "type": "free"
106
+ "type": "graphdb"
107
107
  }
@@ -216,15 +216,21 @@ describe('Similarity screen validation', () => {
216
216
  cy.window();
217
217
 
218
218
  // Then I expect a message to be displayed informing me that the plugin is disabled.
219
- cy.get('.plugin-disabled-warning').should('be.visible').and('contain', 'Similarity Plugin is disabled for this repository.');
219
+ cy.get('.plugin-not-active-warning').should('be.visible').and('contain', 'Similarity Plugin is not active for this repository.');
220
220
 
221
221
  // When I enable the plugin
222
- cy.get('.enable-plugin-link')
222
+ cy.get('.confirm-btn')
223
223
  .should('be.visible')
224
- .and('contain', 'Enable plugin')
224
+ .and('contain', 'Activate')
225
225
  .click().then(() => {
226
- // Then I expect default similarity view with no indexes available
227
- checkSimilarityPageDefaultState();
226
+ // Should confirm that want to activate plugin
227
+ cy.get('.modal-footer > .btn-primary')
228
+ .should('be.visible')
229
+ .click()
230
+ .then(() => {
231
+ // Then I expect default similarity view with no indexes available
232
+ checkSimilarityPageDefaultState();
233
+ });
228
234
  });
229
235
  });
230
236
 
@@ -25,7 +25,7 @@ describe('Visual graph screen validation', () => {
25
25
 
26
26
  context('When autocomplete is disabled', () => {
27
27
  it('Test notification when autocomplete is disabled', () => {
28
- cy.visit('/graphs-visualizations');
28
+ cy.visit('graphs-visualizations');
29
29
  cy.window();
30
30
  getSearchField().should('be.visible').type('http://');
31
31
 
@@ -42,7 +42,7 @@ describe('Visual graph screen validation', () => {
42
42
  cy.enableAutocomplete(repositoryId);
43
43
  });
44
44
  beforeEach(() => {
45
- cy.visit('/graphs-visualizations');
45
+ cy.visit('graphs-visualizations');
46
46
  cy.window();
47
47
  });
48
48
 
@@ -108,6 +108,36 @@ describe('Visual graph screen validation', () => {
108
108
  });
109
109
  });
110
110
 
111
+ it('Test invalid links limit should show error to user ', () => {
112
+ searchForResource(VALID_RESOURCE);
113
+ openVisualGraphSettings();
114
+
115
+ cy.get('.filter-sidepanel').as('sidepanel').should('be.visible').within(() => {
116
+ // Verify that the default settings are as follows:
117
+ // Maximum links to show: 20
118
+ getLinksNumberField().and('have.value', '20');
119
+ // Update default 20
120
+ updateLinksLimitField('1001')
121
+ .then(() => {
122
+ // Try to put invalid value such as 1001
123
+ cy.get('.idError')
124
+ .should('be.visible')
125
+ .and('contain.text', 'Invalid links limit');
126
+ });
127
+ // Try to save the invalid value
128
+ getSaveSettingsButton().and('not.be.disabled')
129
+ .click();
130
+ // Then reset to default settings
131
+ getResetSettingsButton().and('not.be.disabled')
132
+ .click()
133
+ .then(() => {
134
+ getLinksNumberField().and('have.value', '20');
135
+ cy.get('.idError')
136
+ .should('not.exist');
137
+ });
138
+ });
139
+ });
140
+
111
141
  it('Test search for a valid resource with links', () => {
112
142
  searchForResource(VALID_RESOURCE);
113
143
  // Check include inferred
@@ -269,14 +299,14 @@ describe('Visual graph screen validation', () => {
269
299
 
270
300
  openVisualGraphSettings();
271
301
  // Set maximum links to 2
272
- getLinksNumberField().clear().type('2');
302
+ updateLinksLimitField('2');
273
303
  saveSettings();
274
304
  // Verify that the diagram is updated
275
305
  getPredicates().should('have.length', 2);
276
306
 
277
307
  openVisualGraphSettings();
278
308
  // Set maximum links to 100
279
- getLinksNumberField().clear().type('100');
309
+ updateLinksLimitField('100');
280
310
  saveSettings();
281
311
  // Verify that the diagram is updated
282
312
  getPredicates().should('have.length', 36);
@@ -333,11 +363,10 @@ describe('Visual graph screen validation', () => {
333
363
  getNodes().and('contain', 'Zinfandel');
334
364
 
335
365
  openVisualGraphSettings();
336
- // Go to Settings and set "vin:Zinfandel" as an ignored type
337
- getIgnoredTypesField().clear().type('vin:Zinfandel');
338
-
339
366
  // Set the connections limit to 10
340
- getLinksNumberField().clear().type('10');
367
+ updateLinksLimitField('10');
368
+ // Go to Settings and set "vin:Zinfandel" as an ignored type
369
+ getIgnoredTypesField().clear().type('vin:Zinfandel').type('{enter}');
341
370
 
342
371
  saveSettings();
343
372
  // Verify that "vin:Zinfandel" has been removed from the diagram
@@ -370,11 +399,12 @@ describe('Visual graph screen validation', () => {
370
399
  openVisualGraphSettings();
371
400
  // Go to predicates tab
372
401
  openPredicatesTab();
373
- // Set "vin:hasSugar" as an ignored predicate
374
- getIgnoredPredicatesField().clear().type('vin:hasSugar');
375
402
 
376
403
  // Set the connections limit to 10
377
- getLinksNumberField().clear().type('10');
404
+ updateLinksLimitField('10');
405
+ // Set "vin:hasSugar" as an ignored predicate
406
+ getIgnoredPredicatesField().clear().type('vin:hasSugar').type('{enter}');
407
+
378
408
  saveSettings();
379
409
 
380
410
  // Verify that "vin:hasSugar" has been removed from the diagram
@@ -388,7 +418,7 @@ describe('Visual graph screen validation', () => {
388
418
  openVisualGraphSettings();
389
419
  // Verify that the default settings are as follows:
390
420
  // Maximum links to show: 20
391
- getLinksNumberField().clear().type('10')
421
+ updateLinksLimitField('10')
392
422
  .should('have.value', '10');
393
423
  // Preferred lang: en
394
424
  cy.get('.preferred-languages .tag-item').should('have.length', 1)
@@ -472,7 +502,7 @@ describe('Visual graph screen validation', () => {
472
502
  });
473
503
 
474
504
  it('Test can create custom visual graph', () => {
475
- cy.visit('/graphs-visualizations');
505
+ cy.visit('graphs-visualizations');
476
506
  getCreateCustomGraphLink().click();
477
507
  cy.url().should('include', '/config/save');
478
508
  getGraphConfigName().type('configName');
@@ -507,14 +537,18 @@ describe('Visual graph screen validation', () => {
507
537
  }
508
538
 
509
539
  function searchForResource(resource) {
510
- cy.searchEasyVisualGraph(resource);
511
- // Verify redirection to existing visual graph
512
- cy.waitUntil(() =>
513
- cy.get('.graph-visualization')
514
- .find('.nodes-container')
515
- .then(nodesContainer => nodesContainer))
540
+ // verify that the easy graph search has occured and a valid resource was input and only
541
+ // after that execute the next operation
542
+ cy.searchEasyVisualGraph(resource)
516
543
  .then(() => {
517
- getNodes();
544
+ // Verify redirection to existing visual graph
545
+ cy.waitUntil(() =>
546
+ cy.get('.graph-visualization')
547
+ .find('.nodes-container')
548
+ .then(nodesContainer => nodesContainer))
549
+ .then(() => {
550
+ getNodes();
551
+ });
518
552
  });
519
553
  }
520
554
 
@@ -673,4 +707,8 @@ describe('Visual graph screen validation', () => {
673
707
  cy.get('.modal-footer .confirm-btn').click();
674
708
  cy.get('.modal').should('not.exist');
675
709
  }
710
+
711
+ function updateLinksLimitField(value) {
712
+ return getLinksNumberField().invoke('val', value).trigger('change', {force: true});
713
+ }
676
714
  });
@@ -107,11 +107,18 @@ describe('Home screen validation', () => {
107
107
  // When I click the button
108
108
  HomeSteps.openRdfSearchBox();
109
109
  // I should be able to type some text in the input
110
- cy.get('.search-rdf-input search-resource-input .view-res-input').type('hasPos');
111
- // When I select option from suggestions
112
- cy.get(".search-rdf-input #auto-complete-results-wrapper p").contains('hasPos').click();
113
- // Search result should be opened in new window
114
- cy.get('@window.open').should('be.calledWith', '/resource?uri=http%3A%2F%2Fwww.w3.org%2Fns%2Forg%23hasPost');
110
+ cy.get('.search-rdf-input search-resource-input .view-res-input')
111
+ .type('hasPos').then(() => {
112
+ // When I select option from suggestions
113
+ cy.get(".search-rdf-input #auto-complete-results-wrapper p")
114
+ .contains('hasPos')
115
+ .click()
116
+ .then(() => {
117
+ // Search result should be opened in new window
118
+ cy.get('@window.open').should('be.calledWith', 'resource?uri=http%3A%2F%2Fwww.w3.org%2Fns%2Forg%23hasPost');
119
+ });
120
+ });
121
+
115
122
  // When I revisit the home page
116
123
  cy.visit('/graphs');
117
124
  // When I open again the search box
@@ -121,10 +128,12 @@ describe('Home screen validation', () => {
121
128
  // And dropdown should be visible
122
129
  cy.get('.search-rdf-input #auto-complete-results-wrapper').should('be.visible');
123
130
  // When I press 'escape'
124
- cy.get('.search-rdf-input search-resource-input .view-res-input').type('{esc}');
125
- // Search box should not be visible
126
- cy.get('.search-rdf-input').should('not.be.visible');
127
-
131
+ cy.get('.search-rdf-input search-resource-input .view-res-input')
132
+ .type('{esc}')
133
+ .then(() => {
134
+ // Search box should not be visible
135
+ cy.get('.search-rdf-input').should('not.be.visible');
136
+ });
128
137
 
129
138
  cy.deleteRepository(repositoryId);
130
139
  });
@@ -171,11 +180,11 @@ describe('Home screen validation', () => {
171
180
  //Test table and visual buttons.
172
181
  cy.get("#auto_0").should('be.visible').click();
173
182
  // Search result should be opened in new window
174
- cy.get('@window.open').should('be.calledWith', '/resource?uri=http%3A%2F%2Fwww.w3.org%2FTR%2F2003%2FPR-owl-guide-20031209%2Fwine%23Dry');
183
+ cy.get('@window.open').should('be.calledWith', 'resource?uri=http%3A%2F%2Fwww.w3.org%2FTR%2F2003%2FPR-owl-guide-20031209%2Fwine%23Dry');
175
184
 
176
185
  getVisualButton().click();
177
186
  cy.get("#auto_0").should('be.visible').click();
178
- cy.get('@window.open').should('be.calledWith', '/graphs-visualizations?uri=http%3A%2F%2Fwww.w3.org%2FTR%2F2003%2FPR-owl-guide-20031209%2Fwine%23Dry');
187
+ cy.get('@window.open').should('be.calledWith', 'graphs-visualizations?uri=http%3A%2F%2Fwww.w3.org%2FTR%2F2003%2FPR-owl-guide-20031209%2Fwine%23Dry');
179
188
  cy.deleteRepository(repositoryId);
180
189
  });
181
190
  });
@@ -250,11 +259,11 @@ describe('Home screen validation', () => {
250
259
  .then(() => HomeSteps.autocompleteText('Green', GOBLIN_URI))
251
260
  .then(() => HomeSteps.getAutocompleteResultElement(GOBLIN_URI).click())
252
261
  .then(() => // Search result should be opened in new window
253
- cy.get('@window.open').should('be.calledWith', '/resource?uri=http%3A%2F%2Fexample.org%2F%23green-goblin'))
262
+ cy.get('@window.open').should('be.calledWith', 'resource?uri=http%3A%2F%2Fexample.org%2F%23green-goblin'))
254
263
  .then(() => HomeSteps.getAutocompleteDisplayTypeButton('visual').click())
255
264
  .then(() => HomeSteps.getAutocompleteResultElement(GOBLIN_URI).click())
256
265
  .then(() => // Search result should be opened in new window
257
- cy.get('@window.open').should('be.calledWith', '/graphs-visualizations?uri=http%3A%2F%2Fexample.org%2F%23green-goblin'));
266
+ cy.get('@window.open').should('be.calledWith', 'graphs-visualizations?uri=http%3A%2F%2Fexample.org%2F%23green-goblin'));
258
267
  cy.deleteRepository(repositoryId);
259
268
  });
260
269
 
@@ -36,6 +36,9 @@ describe('Repositories', () => {
36
36
  " ex:age 12.1 ;\n" +
37
37
  ".";
38
38
 
39
+ const GDB_REPOSITORY_TYPE = 'gdb';
40
+ const REPO_LIST_ID = '#wb-repositories-repositoryInGetRepositories';
41
+
39
42
  beforeEach(() => {
40
43
  repositoryId = 'repo-' + Date.now();
41
44
 
@@ -57,6 +60,21 @@ describe('Repositories', () => {
57
60
  getCreateRepositoryButton().should('be.visible').and('not.be.disabled');
58
61
  }
59
62
 
63
+ it('create repository page should list available repository types options', () => {
64
+ let expectedRepoTypes = ['GraphDB Repository', 'Ontop Virtual SPARQL', 'FedX Virtual SPARQL'];
65
+ createRepository();
66
+ cy.url().should('include', '/repository/create');
67
+
68
+ cy.get('.create-buttons')
69
+ .find('.h3.repo-type')
70
+ .should('have.length', 3)
71
+ .then((repoTypes) => {
72
+ repoTypes.each(($index, $repoType) => {
73
+ expect($repoType.innerText).to.equal(expectedRepoTypes[$index]);
74
+ });
75
+ });
76
+ });
77
+
60
78
  it('should allow creation of repositories with default settings', () => {
61
79
  // There should be a default repository location
62
80
  getLocationsList()
@@ -66,7 +84,7 @@ describe('Repositories', () => {
66
84
  createRepository();
67
85
  cy.url().should('include', '/repository/create');
68
86
 
69
- chooseRepositoryType();
87
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
70
88
  cy.url().should('include', '/repository/create/');
71
89
 
72
90
  // Create a repository by supplying only an identifier
@@ -136,7 +154,7 @@ describe('Repositories', () => {
136
154
 
137
155
  it('should disallow creation of repositories without mandatory settings', () => {
138
156
  createRepository();
139
- chooseRepositoryType();
157
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
140
158
  cy.url().should('include', '/repository/create/');
141
159
 
142
160
  saveRepository();
@@ -154,7 +172,7 @@ describe('Repositories', () => {
154
172
  const repoTitle = 'Repo title for ' + repositoryId;
155
173
 
156
174
  createRepository();
157
- chooseRepositoryType();
175
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
158
176
  cy.url().should('include', '/repository/create/');
159
177
 
160
178
  getRepositoryIdField().type(repositoryId);
@@ -201,14 +219,14 @@ describe('Repositories', () => {
201
219
  it('should allow to switch between repositories', () => {
202
220
  const secondRepoId = 'second-repo-' + Date.now();
203
221
  createRepository();
204
- chooseRepositoryType();
222
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
205
223
  cy.url().should('include', '/repository/create/');
206
224
 
207
225
  typeRepositoryId(repositoryId);
208
226
  saveRepository();
209
227
 
210
228
  createRepository();
211
- chooseRepositoryType();
229
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
212
230
  cy.url().should('include', '/repository/create/');
213
231
 
214
232
  typeRepositoryId(secondRepoId);
@@ -274,7 +292,7 @@ describe('Repositories', () => {
274
292
  const newTitle = 'Title edit';
275
293
 
276
294
  createRepository();
277
- chooseRepositoryType();
295
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
278
296
  cy.url().should('include', '/repository/create/');
279
297
 
280
298
  typeRepositoryId(repositoryId);
@@ -290,9 +308,12 @@ describe('Repositories', () => {
290
308
  typeRepositoryTitle(newTitle);
291
309
  getRepositoryContextIndexCheckbox().check();
292
310
 
293
- getSaveRepositoryButton().click();
294
- confirmModal();
295
- waitLoader();
311
+ getSaveRepositoryButton()
312
+ .click()
313
+ .then(() => {
314
+ confirmModal();
315
+ waitLoader();
316
+ });
296
317
 
297
318
  // See the title is rendered in the repositories list
298
319
  getRepositoryFromList(repositoryId).should('contain', newTitle);
@@ -306,7 +327,7 @@ describe('Repositories', () => {
306
327
 
307
328
  it('should allow to delete existing repository', () => {
308
329
  createRepository();
309
- chooseRepositoryType();
330
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
310
331
  cy.url().should('include', '/repository/create/');
311
332
 
312
333
  typeRepositoryId(repositoryId);
@@ -593,7 +614,7 @@ describe('Repositories', () => {
593
614
  it('should restart an existing repository', () => {
594
615
 
595
616
  createRepository();
596
- chooseRepositoryType();
617
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
597
618
 
598
619
  cy.url().should('include', '/repository/create');
599
620
 
@@ -659,7 +680,7 @@ describe('Repositories', () => {
659
680
  it('should create SHACL repo and test shapes validation', () => {
660
681
  //Prepare repository by enabling SHACL
661
682
  createRepository();
662
- chooseRepositoryType();
683
+ chooseRepositoryType(GDB_REPOSITORY_TYPE);
663
684
  cy.url().should('include', '/repository/create/');
664
685
  typeRepositoryId(repositoryId);
665
686
  getSHACLRepositoryCheckbox().check();
@@ -702,8 +723,6 @@ describe('Repositories', () => {
702
723
  .then($el => $el && $el.text() === status));
703
724
  }
704
725
 
705
- const REPO_LIST_ID = '#wb-repositories-repositoryInGetRepositories';
706
-
707
726
  function getRepositoriesList() {
708
727
  return cy.get(REPO_LIST_ID);
709
728
  }
@@ -29,18 +29,21 @@ describe('Setup / Connectors - Lucene', () => {
29
29
  it('Create, copy and delete a lucene connector', () => {
30
30
  getNewLuceneConnectorButton()
31
31
  .click();
32
+
32
33
  getCreateLuceneConnectorPage()
33
- .should('be.visible')
34
- .and('contain', 'Create new Lucene Connector');
35
- getConnectorNameField()
36
- .type(luceneConnectorName);
37
- getFieldNameField()
38
- .type(fieldName, {force:true});
39
- getPropertyChainField()
40
- .type(connectorPropertyChain, {force:true});
41
- getUriTypes()
42
- .type(uriType);
43
- confirmCreateConnector();
34
+ .should('contain', 'Create new Lucene Connector')
35
+ .within(() => {
36
+ getConnectorNameField()
37
+ .type(luceneConnectorName);
38
+ getFieldNameField()
39
+ .type(fieldName, {force: true});
40
+ getPropertyChainField()
41
+ .type(connectorPropertyChain, {force: true});
42
+ getUriTypes()
43
+ .type(uriType);
44
+ confirmCreateConnector();
45
+ });
46
+
44
47
  verifyStatusToastMessage(connectorCreateToastMessage);
45
48
  verifyConnectorExists(luceneConnectorName);
46
49
  //copy connector
@@ -49,7 +52,10 @@ describe('Setup / Connectors - Lucene', () => {
49
52
  .should('be.visible')
50
53
  .click()
51
54
  .then(() => {
52
- confirmCreateConnector();
55
+ getCreateLuceneConnectorPage()
56
+ .within(() => {
57
+ confirmCreateConnector();
58
+ });
53
59
  verifyStatusToastMessage(connectorCreateToastMessage + '-copy');
54
60
  verifyConnectorExists(luceneConnectorName + '-copy');
55
61
  //delete connector copy
@@ -61,7 +67,7 @@ describe('Setup / Connectors - Lucene', () => {
61
67
  .should('be.visible')
62
68
  .click();
63
69
  verifyStatusToastMessage(connectorDeleteToastMessage + '-copy');
64
- });
70
+ });
65
71
  });
66
72
 
67
73
  function getConnectorsPage() {
@@ -73,35 +79,32 @@ describe('Setup / Connectors - Lucene', () => {
73
79
  }
74
80
 
75
81
  function getCreateLuceneConnectorPage() {
76
- return cy.get('.modal-content').should('be.visible');
82
+ return cy.get('.modal-content').scrollIntoView().should('be.visible');
77
83
  }
78
84
 
79
85
  function getConnectorNameField() {
80
- return getCreateLuceneConnectorPage().find('.connector-name-field input');
86
+ return cy.get('.connector-name-field input');
81
87
  }
82
88
 
83
89
  function getFieldNameField() {
84
- return getCreateLuceneConnectorPage().find('.child-property-fieldName input');
90
+ return cy.get('.child-property-fieldName input');
85
91
  }
86
92
 
87
93
  function getPropertyChainField() {
88
- return getCreateLuceneConnectorPage().find('.child-property-propertyChain input');
94
+ return cy.get('.child-property-propertyChain input');
89
95
  }
90
96
 
91
97
  function getUriTypes() {
92
- return getCreateLuceneConnectorPage().find('.property-types input');
98
+ return cy.get('.property-types input');
93
99
  }
94
100
 
95
101
  function confirmCreateConnector() {
96
- getCreateLuceneConnectorPage()
97
- .within(() => {
98
- cy.get('.create-connector-btn')
99
- .scrollIntoView()
100
- .should('be.visible')
101
- .then((btn) => {
102
- cy.wrap(btn).click();
103
- });
104
- });
102
+ cy.get('.create-connector-btn')
103
+ .scrollIntoView()
104
+ .should('be.visible')
105
+ .then((btn) => {
106
+ cy.wrap(btn).click();
107
+ });
105
108
  }
106
109
 
107
110
  function verifyConnectorExists(connectorName) {
@@ -222,6 +222,23 @@ describe('My Settings', () => {
222
222
  });
223
223
  });
224
224
 
225
+ it('Saving administrator credentials with checked unset password should show modal window to warn user about' +
226
+ ' unsetting the' +
227
+ ' password', () => {
228
+ // User role is administrator
229
+ cy.get('#noPassword:checkbox').check()
230
+ .then(() => {
231
+ cy.get('#noPassword:checkbox')
232
+ .should('be.checked');
233
+ });
234
+ getSaveButton().click()
235
+ .then(() => {
236
+ cy.get('.modal-dialog').find('.lead').contains('If you unset the password and then enable security,' +
237
+ ' this administrator will not be able to log into GraphDB through the workbench.');
238
+ }
239
+ )
240
+ });
241
+
225
242
  function getUserRepositoryTable() {
226
243
  return cy.get('.user-repositories .table');
227
244
  }
@@ -0,0 +1,69 @@
1
+ describe('Plugins', () => {
2
+
3
+ let repositoryId;
4
+
5
+ function createRepository() {
6
+ repositoryId = 'plugin-' + Date.now();
7
+ cy.createRepository({id: repositoryId});
8
+ cy.presetRepository(repositoryId);
9
+ cy.initializeRepository(repositoryId);
10
+ }
11
+
12
+ function waitUntilPluginsPageIsLoaded() {
13
+ // Workbench loading screen should not be visible
14
+ cy.get('.ot-splash').should('not.be.visible');
15
+
16
+ // No active loader
17
+ cy.get('.ot-loader').should('not.exist');
18
+ }
19
+
20
+ beforeEach(() => {
21
+ createRepository();
22
+ cy.visit('/plugins');
23
+ cy.window();
24
+ waitUntilPluginsPageIsLoaded();
25
+ });
26
+
27
+ afterEach(() => {
28
+ cy.visit('/plugins');
29
+ cy.window();
30
+ // re-enable historyplugin
31
+ getPluginsHeader()
32
+ .should('be.visible').parent().within(() => {
33
+ cy.get('.switch').then((elem) => {
34
+ var value = elem.val();
35
+ if (!value.checked) {
36
+ getPluginsSwitch().click();
37
+ }
38
+ });
39
+ });
40
+ cy.deleteRepository(repositoryId);
41
+ });
42
+
43
+ it('should allow to enable and disable the plugins', () => {
44
+ // Verify initial status is ON
45
+ getPluginsHeader()
46
+ .should('be.visible').parent().within(() => {
47
+ cy.get('.tag-primary')
48
+ .contains('ON');
49
+
50
+ cy.get('.switch').should('be.checked');
51
+ getPluginsSwitch().click();
52
+ });
53
+ cy.visit('/plugins');
54
+ cy.window();
55
+
56
+ getPluginsHeader()
57
+ .should('be.visible').parent().within(() => {
58
+ cy.get('.switch').should('not.be.checked');
59
+ });
60
+ });
61
+
62
+ function getPluginsHeader() {
63
+ return cy.get('.plugins-header').contains("history");
64
+ }
65
+
66
+ function getPluginsSwitch() {
67
+ return cy.get('.plugins-switch');
68
+ }
69
+ });
@@ -17,7 +17,7 @@ describe('Setup / RDF Rank', () => {
17
17
 
18
18
  getRdfRankPage().find('.alert-warning').should('not.be.visible');
19
19
 
20
- getFilteringSwitch().should('be.visible');
20
+ getFilteringSwitch().scrollIntoView().should('be.visible');
21
21
  }
22
22
 
23
23
  beforeEach(() => {
@@ -0,0 +1,179 @@
1
+ describe('SPARQL Templates', () => {
2
+
3
+ let repositoryId;
4
+ const TEMPLATE_NAME = "http://example.com/salary_template";
5
+ const SPARQL_TEMPLATE = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
6
+ "PREFIX factory: <http://factory/>\n" +
7
+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>\n" +
8
+ "PREFIX spif: <http://spinrdf.org/spif#>\n" +
9
+ "INSERT {\n" +
10
+ "?id <http://factory/updatedOn> \"2021-10-01T07:55:38.238Z\"^^xsd:dateTime .\n" +
11
+ "?split spif:split (\"blaaa/blaa\" \"/\")\n" +
12
+ "} WHERE {\n" +
13
+ "?id rdf:type <http://factory/Factory> .\n" +
14
+ "?worker <http://factory/worksIn> ?id .\n" +
15
+ "?worker <http://factory/hasSalary> ?oldSalary .\n" +
16
+ "FILTER regex(STR(?id), \"fac\", \"i\")\n" +
17
+ "?split spif:split (\"blaaa/blaa\" \"/\")\n" +
18
+ "bind(now() as ?now)\n" +
19
+ "}";
20
+ const DEFAULT_QUERY = "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
21
+ "PREFIX ex: <http://example.com#>\n" +
22
+ "DELETE {\n" +
23
+ " ?subject ex:myPredicate ?oldValue .\n" +
24
+ "} INSERT {\n" +
25
+ " ?subject ex:myPredicate ?newValue .\n" +
26
+ "} WHERE {\n" +
27
+ " ?id rdf:type ex:MyType .\n" +
28
+ " ?subject ex:isRelatedTo ?id .\n" +
29
+ "}\n";
30
+
31
+ before(() => {
32
+ repositoryId = 'sparql-templates-repo' + Date.now();
33
+ cy.createRepository({id: repositoryId});
34
+ });
35
+
36
+ beforeEach(() => {
37
+ cy.visit('/sparql-templates', {
38
+ onBeforeLoad: (win) => {
39
+ win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
40
+ }
41
+ });
42
+ cy.window()
43
+ .then(() => getTemplatesTable().scrollIntoView().should('be.visible'));
44
+ });
45
+
46
+ after(() => {
47
+ cy.deleteRepository(repositoryId);
48
+ });
49
+
50
+ it('Initial state', () => {
51
+ cy.url().should('include', '/sparql-templates');
52
+ //Verify templates table is empty
53
+ getTemplatesTable().should('be.visible')
54
+ .and('contain','No templates are defined');
55
+ //Verify create template button is visible
56
+ getCreateSparqlTemplateButton().should('be.visible');
57
+ });
58
+
59
+ it('Should create/edit/delete a SPARQL template', () => {
60
+ //Click create template button
61
+ getCreateSparqlTemplateButton().click();
62
+ cy.waitUntilQueryIsVisible();
63
+ //Test Template IRI field validation
64
+ getSaveButton().click();
65
+ //Verify error toast
66
+ getToastError()
67
+ .should('be.visible')
68
+ .and('contain','SPARQL template IRI is required');
69
+ //Type a valid Template IRI value in the filed
70
+ getTemplateNameField().type(TEMPLATE_NAME);
71
+ //Verify default query
72
+ verifyQueryAreaEquals(DEFAULT_QUERY);
73
+ clearQuery();
74
+ //Paste new template query and verify content
75
+ cy.pasteQuery(SPARQL_TEMPLATE);
76
+ verifyQueryAreaEquals(SPARQL_TEMPLATE);
77
+ getSaveButton()
78
+ .scrollIntoView()
79
+ .click()
80
+ .then(() => {
81
+ cy.waitUntil(() =>
82
+ cy.get('.edit-query-btn')
83
+ .then(editBtn => editBtn));
84
+ });
85
+ //Verify new template is stored in the templates table
86
+ getTemplatesTable().should('be.visible')
87
+ .and('contain',TEMPLATE_NAME);
88
+ //Edit template
89
+ getEditTemplateButton(TEMPLATE_NAME);
90
+ cy.waitUntilQueryIsVisible();
91
+ verifyQueryAreaEquals(SPARQL_TEMPLATE);
92
+ clearQuery();
93
+ //Change query to the default template again
94
+ cy.pasteQuery(DEFAULT_QUERY);
95
+ verifyQueryAreaEquals(DEFAULT_QUERY);
96
+ getSaveButton().click();
97
+ //Verify change to default template is persisted
98
+ getEditTemplateButton(TEMPLATE_NAME);
99
+ cy.waitUntilQueryIsVisible();
100
+ verifyQueryAreaEquals(DEFAULT_QUERY);
101
+ //Cancel as no changes have been made
102
+ getCancelButton().click();
103
+ //Delete template and verify templates table is empty
104
+ getDeleteTemplateButton(TEMPLATE_NAME);
105
+ getConfirmDeleteTemplateButton().click();
106
+ cy.url().should('include', '/sparql-templates');
107
+ getTemplatesTable().should('be.visible')
108
+ .and('contain','No templates are defined');
109
+ });
110
+
111
+ function getTemplatesTable() {
112
+ return cy.get('.sparql-templates-list');
113
+ }
114
+
115
+ function getCreateSparqlTemplateButton() {
116
+ return cy.get('.clearfix .create-sql-table-configuration');
117
+ }
118
+
119
+ function getTemplateNameField() {
120
+ return cy.get('.sparql-template-name');
121
+ }
122
+
123
+ function verifyQueryAreaEquals(query) {
124
+ // Using the CodeMirror instance because getting the value from the DOM is very cumbersome
125
+ getQueryArea().should(codeMirrorEl => {
126
+ const cm = codeMirrorEl[0].CodeMirror;
127
+ expect(cm.getValue().trim()).to.equal(query.trim());
128
+ });
129
+ }
130
+
131
+ function getQueryArea() {
132
+ return cy.get('#queryEditor .CodeMirror');
133
+ }
134
+
135
+ function clearQuery() {
136
+ // Using force because the textarea is not visible
137
+ getQueryTextArea().type(Cypress.env('modifierKey') + 'a{backspace}', {force: true});
138
+ }
139
+
140
+ function getQueryTextArea() {
141
+ return getQueryArea().find('textarea');
142
+ }
143
+
144
+ function getSaveButton() {
145
+ return cy.get('.save-query-btn');
146
+ }
147
+
148
+ function getCancelButton() {
149
+ return cy.get('.cancel-query-btn');
150
+ }
151
+
152
+ function getToastError() {
153
+ return cy.get('#toast-container');
154
+ }
155
+
156
+ function getEditTemplateButton(templateName) {
157
+ return cy.get('#configurations-table tr')
158
+ .contains(templateName)
159
+ .parent()
160
+ .parent()
161
+ .within(() => {
162
+ cy.get('.icon-edit').click();
163
+ })
164
+ }
165
+
166
+ function getDeleteTemplateButton(templateName) {
167
+ return cy.get('#configurations-table tr')
168
+ .contains(templateName)
169
+ .parent()
170
+ .parent()
171
+ .within(() => {
172
+ cy.get('.icon-trash').click();
173
+ })
174
+ }
175
+
176
+ function getConfirmDeleteTemplateButton() {
177
+ return cy.get('.confirm-btn');
178
+ }
179
+ });
@@ -22,6 +22,17 @@ describe('User and Access', () => {
22
22
  });
23
23
 
24
24
  after(() => {
25
+ cy.visit('/users');
26
+ getUsersTable().should('be.visible');
27
+ cy.get('#wb-users-userInUsers tr').then((table) => {
28
+ cy.get('table > tbody > tr').each(($el, index, $list) => {
29
+ getUsersTable().should('be.visible');
30
+ const username = $el.find('.username').text();
31
+ if (username !=='admin') {
32
+ deleteUser(username);
33
+ }
34
+ });
35
+ });
25
36
  cy.deleteRepository(repositoryId);
26
37
  });
27
38
 
@@ -44,7 +55,7 @@ describe('User and Access', () => {
44
55
  cy.get('@user').find('.edit-user-btn').should('be.visible')
45
56
  .and('not.be.disabled');
46
57
  // And cannot be deleted
47
- cy.get('@user').find('.delete-user-btn').should('not.be.visible');
58
+ cy.get('@user').find('.delete-user-btn').should('not.exist');
48
59
  // Date created should be visible
49
60
  cy.get('@user').find('.date-created').should('be.visible');
50
61
  });
@@ -80,22 +91,33 @@ describe('User and Access', () => {
80
91
  cy.get('.ot-splash').should('not.be.visible');
81
92
  getUsersTable().should('be.visible');
82
93
  //delete repository manager
83
- deleteUser("repo-manager");
84
- //create a custom admin
85
- createUser("second-admin", PASSWORD, ROLE_CUSTOM_ADMIN);
86
- logout();
87
- //login with custom admin
88
- loginWithUser("second-admin", PASSWORD);
89
- cy.url().should('include', '/users');
90
- logout();
91
- //login with admin
92
- loginWithUser("admin", DEFAULT_ADMIN_PASSWORD);
93
- cy.get('.ot-splash').should('not.be.visible');
94
+ deleteUser("repo-manager")
95
+ .then(() => {
96
+ //create a custom admin
97
+ createUser("second-admin", PASSWORD, ROLE_CUSTOM_ADMIN);
98
+ logout();
99
+ //login with custom admin
100
+ loginWithUser("second-admin", PASSWORD);
101
+ cy.url().should('include', '/users');
102
+ logout();
103
+ //login with admin
104
+ loginWithUser("admin", DEFAULT_ADMIN_PASSWORD);
105
+ cy.get('.ot-splash').should('not.be.visible');
106
+ getUsersTable().should('be.visible');
107
+ //delete custom admin
108
+ deleteUser("second-admin")
109
+ .then(() => {
110
+ //disable security
111
+ getToggleSecuritySwitch().click();
112
+ });
113
+ });
114
+ });
115
+ it('Warn users when setting no password when creating new user admin', () => {
94
116
  getUsersTable().should('be.visible');
95
- //delete custom admin
96
- deleteUser("second-admin");
97
- //disable security
98
- getToggleSecuritySwitch().click();
117
+ createUser("adminWithNoPassword", PASSWORD, ROLE_CUSTOM_ADMIN);
118
+ getUsersTable().should('be.visible');
119
+ cy.get('.ot-splash').should('not.be.visible');
120
+ deleteUser("adminWithNoPassword");
99
121
  });
100
122
 
101
123
  function getCreateNewUserButton() {
@@ -145,25 +167,48 @@ describe('User and Access', () => {
145
167
  getPasswordField().type(password);
146
168
  getConfirmPasswordField().type(password);
147
169
  getRoleRadioButton(role).click();
148
- if(role === "#roleUser") {
170
+ if (role === "#roleUser") {
149
171
  getRepoitoryRightsList().contains('Any data repository').nextUntil('.write').within(() => {
150
172
  cy.get('.write').click();
151
173
  });
174
+ getConfirmUserCreateButton().click();
175
+ } else if (role === "#roleAdmin" && username === "adminWithNoPassword") {
176
+ cy.get('#noPassword:checkbox').check()
177
+ .then(() => {
178
+ cy.get('#noPassword:checkbox')
179
+ .should('be.checked');
180
+ });
181
+ getConfirmUserCreateButton().click()
182
+ .then(() => {
183
+ cy.get('.modal-dialog').find('.lead').contains('If the password is unset and security is enabled, this administrator will not be ' +
184
+ 'able to log into GraphDB through the workbench. Are you sure that you want to continue?');
185
+ cy.get('.modal-dialog').find('.confirm-btn').click();
186
+ });
187
+ } else {
188
+ getConfirmUserCreateButton().click();
152
189
  }
153
- getConfirmUserCreateButton().click();
154
190
  cy.get('.ot-splash').should('not.be.visible');
155
- getUsersTable().should('contain',username);
191
+ getUsersTable().should('contain', username);
156
192
  }
157
193
 
158
194
  function deleteUser(username) {
159
- cy.get('#wb-users-userInUsers tr').contains(username).parent().parent().within(() => {
160
- cy.get('.icon-trash').click();
161
- })
162
- cy.get('.confirm-btn').click();
195
+ findUserInTable(username);
196
+ cy.get('@user')
197
+ .should('have.length', 1)
198
+ .within(() => {
199
+ cy.get('.delete-user-btn')
200
+ .as('deleteBtn');
201
+ });
202
+ return cy.waitUntil(() =>
203
+ cy.get('@deleteBtn')
204
+ .then(deleteBtn => deleteBtn && Cypress.dom.isAttached(deleteBtn) && deleteBtn.trigger('click')))
205
+ .then(() => {
206
+ cy.get('.confirm-btn').click();
207
+ });
163
208
  }
164
209
 
165
210
  function loginWithUser(username, password) {
166
- cy.get('#wb-login-username').type(username)
211
+ cy.get('#wb-login-username').type(username);
167
212
  cy.get('#wb-login-password').type(password);
168
213
  cy.get('#wb-login-submitLogin').click();
169
214
  }
@@ -110,6 +110,11 @@ describe('Main menu tests', function () {
110
110
  visible: false,
111
111
  redirect: '/cluster'
112
112
  },
113
+ {
114
+ name: 'Plugins',
115
+ visible: false,
116
+ redirect: '/plugins'
117
+ },
113
118
  {
114
119
  name: 'Namespaces',
115
120
  visible: false,
@@ -164,7 +169,8 @@ describe('Main menu tests', function () {
164
169
  let menuVisibilityCheck = menu.visible ? 'be.visible' : 'not.be.visible';
165
170
  // Verify that main menu items are present and their visibility
166
171
  cy.get('.main-menu .menu-element-root').eq(menuIndex + 1).as('menu')
167
- .should(menuVisibilityCheck).and('contain', menu.name);
172
+ .should(menuVisibilityCheck).within(() =>
173
+ cy.get('.menu-item').contains(menu.name));
168
174
 
169
175
  // Verify submenu items and their visibility when the main menu is not opened
170
176
  (menu.submenu || []).forEach((submenu, submenuIndex) => {
@@ -435,10 +435,20 @@ describe('SPARQL screen validation', () => {
435
435
  verifyResultsPageLength(74);
436
436
 
437
437
  // Uncheck ‘Include inferred’
438
- getInferenceButton()
439
- .click()
440
- .find('.icon-inferred-off')
441
- .should('be.visible');
438
+ cy.waitUntil(() =>
439
+ getInferenceButton()
440
+ .within(infBtn =>
441
+ { cy.get('.icon-inferred-on');
442
+ console.log(infBtn);
443
+ infBtn && cy.wrap(infBtn).click();
444
+ }
445
+ ).then(() => {
446
+ getInferenceButton()
447
+ .within(button => {
448
+ cy.get('.icon-inferred-off')
449
+ cy.wrap(button).should('be.visible')
450
+ });
451
+ }))
442
452
 
443
453
  // Confirm that only inferred statements (only 2) are available
444
454
  executeQuery();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.0.0-TR1",
3
+ "version": "2.0.0-TR12",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "scripts": {
6
6
  "start": "cypress open",
@@ -1,7 +1,7 @@
1
1
  Cypress.Commands.add('pasteQuery', (query) => {
2
2
  clearQuery();
3
3
  // Using force because the textarea is not visible
4
- getQueryTextArea().invoke('val', query).trigger('change', {force: true});
4
+ getQueryTextArea().invoke('val', query).trigger('change', {force: true}).should('have.value', query);
5
5
  waitUntilQueryIsVisible();
6
6
  });
7
7
 
@@ -19,7 +19,9 @@ Cypress.Commands.add('verifyResultsPageLength', (resultLength) => {
19
19
  Cypress.Commands.add('verifyResultsMessage', (msg) => {
20
20
  cy.waitUntil(() =>
21
21
  getResultsMessage()
22
- .then(resultInfo => resultInfo.text().trim().indexOf(msg) > -1));
22
+ .then((resultInfo) => {
23
+ console.log(resultInfo.text());
24
+ return resultInfo && resultInfo.text().trim().indexOf(msg) > -1; }));
23
25
  });
24
26
 
25
27
  Cypress.Commands.add('getResultsMessage', () => {
@@ -51,7 +53,7 @@ function getQueryTextArea() {
51
53
  }
52
54
 
53
55
  function waitUntilQueryIsVisible() {
54
- cy.waitUntil(() =>
56
+ return cy.waitUntil(() =>
55
57
  getQueryArea()
56
58
  .then(codeMirrorEl =>
57
59
  codeMirrorEl && codeMirrorEl[0].CodeMirror.getValue().trim().length > 0));
@@ -1,12 +1,17 @@
1
1
  Cypress.Commands.add('searchEasyVisualGraph', (searchGraph) => {
2
2
  cy.get('.search-rdf-resources > #search-resource-box > .form-control')
3
3
  .invoke('val', searchGraph)
4
- .trigger('change')
4
+ .trigger('change', {force: true})
5
5
  .should('have.value', searchGraph)
6
6
  .then((searchInput) => {
7
7
  cy.waitUntil(() =>
8
8
  cy.get('#auto-complete-results-wrapper')
9
- .each((el) => el && el.text().indexOf(searchGraph) > -1))
10
- .then(() => cy.wrap(searchInput).type('{enter}'));
9
+ .then((el) => el))
10
+ .then(() => {
11
+ cy.get('.result-item.active')
12
+ .then((activeEl) => {
13
+ cy.wrap(activeEl).click();
14
+ });
15
+ });
11
16
  });
12
17
  });