graphdb-workbench-tests 2.4.0-TR9 → 2.4.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.
@@ -162,7 +162,8 @@
162
162
  "delete_rule_confirmation": "Are you sure you want to delete the selected rule #{{index}}?",
163
163
  "revert_acl_list": "This operation will revert all the changes done in the ACL. Are you sure you want to proceed?",
164
164
  "rules_updated": "ACL was updated successfully",
165
- "rules_reverted": "ACL was reverted successfully"
165
+ "rules_reverted": "ACL was reverted successfully",
166
+ "unsaved_changes_confirmation": "You have unsaved changes. Are you sure that you want to exit?"
166
167
  }
167
168
  },
168
169
  "errors": {
@@ -231,6 +232,7 @@
231
232
  "closes.config.no.save": "Closes the configuration without saving the changes.",
232
233
  "refresh.to.retry": "Refresh the page to retry.",
233
234
  "temp.pause": "Temporarily pauses query monitoring so you can copy text",
235
+ "temp.pause.backup_and_restore": "Temporarily pauses backup and restore monitoring so you can copy text",
234
236
  "paused.btn": "Paused",
235
237
  "pause.btn": "Pause",
236
238
  "node.label": "node",
@@ -1912,5 +1914,23 @@
1912
1914
  "ttyg.settings.topk": "Number of top results",
1913
1915
  "ttyg.settings.topk.tooltip": "Number of results returned to the chat bot when it requests more information. More results will provide more information but they may also introduce noise.",
1914
1916
  "ttyg.settings.echo.vector.query": "Echo vector query",
1915
- "ttyg.settings.echo.vector.query.tooltip": "If enabled the bot will use the generated queries as feedback to the GPT API."
1917
+ "ttyg.settings.echo.vector.query.tooltip": "If enabled the bot will use the generated queries as feedback to the GPT API.",
1918
+ "global.operations_statuses.queries.title": "Running query",
1919
+ "global.operations_statuses.queries.title.plural": "Running queries",
1920
+ "global.operations_statuses.updates.title": "Running update",
1921
+ "global.operations_statuses.updates.title.plural": "Running updates",
1922
+ "global.operations_statuses.imports.title": "Running import",
1923
+ "global.operations_statuses.imports.title.plural": "Running imports",
1924
+ "global.operations_statuses.CREATE_BACKUP_IN_PROGRESS.title": "Creating backup",
1925
+ "global.operations_statuses.CREATE_BACKUP_IN_PROGRESS.title.plural": "Creating backups",
1926
+ "global.operations_statuses.RESTORE_BACKUP_IN_PROGRESS.title": "Restoring backup",
1927
+ "global.operations_statuses.RESTORE_BACKUP_IN_PROGRESS.title.plural": "Restoring backups",
1928
+ "global.operations_statuses.CREATE_CLOUD_BACKUP_IN_PROGRESS.title": "Creating cloud backup",
1929
+ "global.operations_statuses.CREATE_CLOUD_BACKUP_IN_PROGRESS.title.plural": "Creating cloud backups",
1930
+ "global.operations_statuses.RESTORE_CLOUD_BACKUP_IN_PROGRESS.title": "Restoring cloud backup",
1931
+ "global.operations_statuses.RESTORE_CLOUD_BACKUP_IN_PROGRESS.title.plural": "Restoring cloud backups",
1932
+ "global.operations_statuses.IN_SYNC.title": "In sync",
1933
+ "global.operations_statuses.RECOVERING.title": "Recovering",
1934
+ "global.operations_statuses.OUT_OF_SYNC.title": "Out of sync",
1935
+ "global.operations_statuses.UNAVAILABLE_NODES.title": "Unavailable nodes"
1916
1936
  }
@@ -0,0 +1,30 @@
1
+ {
2
+ "status": "WARNING",
3
+ "allRunningOperations": [
4
+ {
5
+ "value": "25",
6
+ "status": "INFORMATION",
7
+ "type": "queries"
8
+ },
9
+ {
10
+ "value": "1",
11
+ "status": "INFORMATION",
12
+ "type": "updates"
13
+ },
14
+ {
15
+ "value": "1",
16
+ "status": "CRITICAL",
17
+ "type": "imports"
18
+ },
19
+ {
20
+ "value": "CREATE_BACKUP_IN_PROGRESS",
21
+ "status": "WARNING",
22
+ "type": "backupAndRestore"
23
+ },
24
+ {
25
+ "value": "UNAVAILABLE_NODES",
26
+ "status": "WARNING",
27
+ "type": "clusterHealth"
28
+ }
29
+ ]
30
+ }
@@ -193,7 +193,7 @@ describe('Similarity screen validation', () => {
193
193
 
194
194
  cy.visit('/sparql', {
195
195
  onBeforeLoad: (win) => {
196
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
196
+ win.localStorage.setItem('ls.repository-id', repositoryId);
197
197
  }
198
198
  });
199
199
  cy.window();
@@ -244,7 +244,7 @@ describe('Similarity screen validation', () => {
244
244
  initRepository();
245
245
  cy.visit('/similarity', {
246
246
  onBeforeLoad: (win) => {
247
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
247
+ win.localStorage.setItem('ls.repository-id', repositoryId);
248
248
  }
249
249
  });
250
250
  cy.window()
@@ -269,6 +269,7 @@ describe('Similarity screen validation', () => {
269
269
 
270
270
  function disableSimilarityPlugin() {
271
271
  const disableSimilarityPluginQuery = 'INSERT DATA { <u:a> <http://www.ontotext.com/owlim/system#stopplugin> \'similarity\' . }';
272
+ cy.waitUntilQueryIsVisible();
272
273
  cy.pasteQuery(disableSimilarityPluginQuery);
273
274
  cy.executeQuery();
274
275
  }
@@ -365,12 +366,9 @@ describe('Similarity screen validation', () => {
365
366
  cy.url().should('eq', Cypress.config('baseUrl') + '/similarity');
366
367
  cy.get('.clone-index-btn').click()
367
368
  .then(() => cy.url().should('contain', `${Cypress.config('baseUrl')}/similarity/index/create`));
368
- cy.window();
369
- // This is just an implicit wait in order to allow the view to catch up with the rendering
370
- // before trying to click the button. Its needed because the button doesn't always accept
371
- // the click most likely due to some async behavior
372
- cy.contains('Sample queries:').next('.list-group').should('be.visible');
373
369
 
370
+ // Makes sure YASQE has loaded before we click the Create button
371
+ cy.waitUntilQueryIsVisible();
374
372
  getCreateIndexButton().should('be.visible').click();
375
373
 
376
374
  getExistingIndexesPanel();
@@ -414,6 +412,7 @@ describe('Similarity screen validation', () => {
414
412
  let shouldAnalogicalTabBeVisible = (isPredication ? '' : 'not.') + 'be.visible';
415
413
  getAnalogicalQueryTab().should(shouldAnalogicalTabBeVisible);
416
414
  if (isPredication) {
415
+ cy.waitUntilQueryIsVisible();
417
416
  cy.verifyQueryAreaContains('SELECT ?entity ?score {');
418
417
  }
419
418
  }
@@ -424,6 +423,7 @@ describe('Similarity screen validation', () => {
424
423
  'filter(isLiteral(?documentText)) \n' +
425
424
  '}order by asc(str(?documentID))';
426
425
 
426
+ cy.waitUntilQueryIsVisible();
427
427
  cy.pasteQuery(MODIFIED_DATA_QUERY);
428
428
  cy.get('.test-query-btn').click();
429
429
  cy.get('.sparql-loader').should('not.exist');
@@ -433,6 +433,7 @@ describe('Similarity screen validation', () => {
433
433
 
434
434
  function changeSearchQuery() {
435
435
  getSearchQueryTab().scrollIntoView().should('be.visible').click();
436
+ cy.waitUntilQueryIsVisible();
436
437
  cy.pasteQuery(MODIFIED_SEARCH_QUERY);
437
438
  }
438
439
 
@@ -441,6 +442,7 @@ describe('Similarity screen validation', () => {
441
442
  .scrollIntoView()
442
443
  .should('be.visible').click()
443
444
  .then(() => {
445
+ cy.waitUntilQueryIsVisible();
444
446
  cy.pasteQuery(MODIFIED_ANALOGICAL_QUERY);
445
447
  });
446
448
  }
@@ -479,6 +481,7 @@ describe('Similarity screen validation', () => {
479
481
 
480
482
  function verifyQueryIsChanged() {
481
483
  const query = 'OPTIONAL { ?result <http://dbpedia.org/ontology/birthPlace> ?birthDate .';
484
+ cy.waitUntilQueryIsVisible();
482
485
  cy.verifyQueryAreaContains(query);
483
486
  }
484
487
  });
@@ -0,0 +1,106 @@
1
+ import HomeSteps from "../../steps/home-steps";
2
+ import {OperationsStatusesComponentSteps} from "../../steps/operations-statuses-component-steps";
3
+ import ImportSteps from "../../steps/import-steps";
4
+ import {GlobalOperationsStatusesStub} from "../../stubs/global-operations-statuses-stub";
5
+
6
+ describe('Operations Status Component', () => {
7
+
8
+ const repositoryId = 'backup-and-restore-' + Date.now();
9
+ beforeEach(() => {
10
+ cy.createRepository({id: repositoryId});
11
+ cy.presetRepository(repositoryId);
12
+ });
13
+
14
+ afterEach(() => {
15
+ cy.deleteRepository(repositoryId);
16
+ });
17
+
18
+ it('should not display the operation status component if there are not run operations.', () => {
19
+ // When I visit some page and there are no running operations.
20
+ HomeSteps.visitAndWaitLoader();
21
+ // Then I expect "Global Operations Component" to not be visible.
22
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('not.exist');
23
+
24
+ // When I visit some page and there are not running operations.
25
+ ImportSteps.visitUserImport(repositoryId);
26
+ // Then I expect "Global Operations Component" to not be visible.
27
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('not.exist');
28
+ });
29
+
30
+ it('should redirect to query and update view wen click on queries operation element', () => {
31
+ // When I visit some page and there are running operations.
32
+ GlobalOperationsStatusesStub.stubGlobalOperationsStatusesResponse(repositoryId);
33
+ HomeSteps.visitAndWaitLoader();
34
+ // Then I expect "Global Operations Component" to be displayed.
35
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
36
+
37
+ OperationsStatusesComponentSteps.openOperationStatusesDialog();
38
+ // When I click on "Running query" operation element.
39
+ // Then I expect to be redirected to "Query and Update monitoring" view.
40
+ OperationsStatusesComponentSteps.checkOperationElementUrl('monitor/queries', 3);
41
+ // Then I expect "Global Operations Component" to still be displayed.
42
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
43
+ });
44
+
45
+ it('should redirect to query and update view wen click on updates operation element', () => {
46
+ // When I visit some page and there are running operations.
47
+ GlobalOperationsStatusesStub.stubGlobalOperationsStatusesResponse(repositoryId);
48
+ HomeSteps.visitAndWaitLoader();
49
+ // Then I expect "Global Operations Component" to be displayed.
50
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
51
+
52
+ OperationsStatusesComponentSteps.openOperationStatusesDialog();
53
+ // When I click on "Running updates" operation element.
54
+ // Then I expect to be redirected to "Query and Update monitoring" view.
55
+ OperationsStatusesComponentSteps.checkOperationElementUrl('monitor/queries', 4);
56
+ // Then I expect "Global Operations Component" to still be displayed.
57
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
58
+ });
59
+
60
+ it('should redirect to query and update view wen click on imports operation element', () => {
61
+ // When I visit some page and there are running operations.
62
+ GlobalOperationsStatusesStub.stubGlobalOperationsStatusesResponse(repositoryId);
63
+ HomeSteps.visitAndWaitLoader();
64
+ // Then I expect "Global Operations Component" to be displayed.
65
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
66
+
67
+ OperationsStatusesComponentSteps.openOperationStatusesDialog();
68
+ // When I click on "Running imports" operation element.
69
+ // Then I expect to be redirected to "Query and Update monitoring" view.
70
+ OperationsStatusesComponentSteps.checkOperationElementUrl('import', 2);
71
+ // Then I expect "Global Operations Component" to still be displayed.
72
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
73
+ });
74
+
75
+ it('should redirect to query and update view wen click on backup and restore operation element', () => {
76
+ // When I visit some page and there are running operations.
77
+ GlobalOperationsStatusesStub.stubGlobalOperationsStatusesResponse(repositoryId);
78
+ HomeSteps.visitAndWaitLoader();
79
+ // Then I expect "Global Operations Component" to be displayed.
80
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
81
+
82
+ OperationsStatusesComponentSteps.openOperationStatusesDialog();
83
+ // When I click on "Creating backup" operation element.
84
+ // Then I expect to be redirected to "Backup and Restore" view.
85
+ OperationsStatusesComponentSteps.checkOperationElementUrl('monitor/backup-and-restore', 1);
86
+ // Then I expect "Global Operations Component" to still be displayed.
87
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
88
+
89
+ });
90
+
91
+ it('should redirect to query and update view wen click on cluster operation element', () => {
92
+ // When I visit some page and there are running operations.
93
+ GlobalOperationsStatusesStub.stubGlobalOperationsStatusesResponse(repositoryId);
94
+ HomeSteps.visitAndWaitLoader();
95
+ // Then I expect "Global Operations Component" to be displayed.
96
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
97
+
98
+ OperationsStatusesComponentSteps.openOperationStatusesDialog();
99
+ // When I click on "Unavailable nodes" operation element.
100
+ // Then I expect to be redirected to "Cluster Monitoring" view.
101
+ OperationsStatusesComponentSteps.checkOperationElementUrl('cluster', 0);
102
+ // Then I expect "Global Operations Component" to still be displayed.
103
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().should('exist');
104
+
105
+ });
106
+ });
@@ -3,12 +3,16 @@ import {BackupAndRestoreStubs} from "../../stubs/backup-and-restore-stubs";
3
3
 
4
4
  describe("Monitoring 'Backup And Restore'", () => {
5
5
 
6
+ const repositoryId = 'backup-and-restore-' + Date.now();
6
7
  beforeEach(() => {
7
- const repositoryId = 'backup-and-restore-' + Date.now();
8
8
  cy.createRepository({id: repositoryId});
9
9
  cy.presetRepository(repositoryId);
10
10
  });
11
11
 
12
+ afterEach(() => {
13
+ cy.deleteRepository(repositoryId);
14
+ });
15
+
12
16
  it('should show running backup or restore operations', () => {
13
17
  // When visit the "Backup and restore page",
14
18
  BackupAndRestoreSteps.visit();
@@ -1,5 +1,7 @@
1
1
  import {AclManagementSteps} from "../../../steps/setup/acl-management-steps";
2
2
  import {ACL} from "../../../steps/setup/acl-management-steps";
3
+ import {ToasterSteps} from "../../../steps/toaster-steps";
4
+ import {ApplicationSteps} from "../../../steps/application-steps";
3
5
 
4
6
  describe('ACL Management: create rule', () => {
5
7
 
@@ -103,5 +105,21 @@ describe('ACL Management: create rule', () => {
103
105
  AclManagementSteps.editRuleButtons().should('have.length', 0);
104
106
  AclManagementSteps.createRuleButtons().should('have.length', 0);
105
107
  });
108
+
109
+ it('should not allow creating of a new rule if it is not unique', () => {
110
+ // When I am on "ACL Management" page and create a rule that exist,
111
+ AclManagementSteps.addRuleInBeginning();
112
+ AclManagementSteps.fillSubject(0, '<urn:Mary>');
113
+ AclManagementSteps.fillPredicate(0, '*');
114
+ AclManagementSteps.fillObject(0, '*');
115
+ AclManagementSteps.fillContext(0, '*');
116
+ AclManagementSteps.fillRole(0, '!CUSTOM_ROLE2');
117
+ AclManagementSteps.selectPolicy(0, 'allow');
118
+ // and try to save it.
119
+ AclManagementSteps.saveRule(0);
120
+
121
+ // Then I expect an error notification to be displayed that describe me that ACL have to be unique.
122
+ ApplicationSteps.getErrorNotifications().contains('Every ACL rule should be unique.');
123
+ });
106
124
  });
107
125
 
@@ -52,5 +52,9 @@ describe('ACL Management: revert rules', () => {
52
52
  ApplicationSteps.getSuccessNotifications().should('be.visible');
53
53
  AclManagementSteps.getAclRules().should('have.length', 5);
54
54
  AclManagementSteps.checkRules(ACL);
55
+ // And the model should become pristine again after the revert
56
+ // I should be able to navigate away from the page without any confirmation
57
+ ApplicationSteps.openImportPage();
58
+ cy.url().should('contain', '/import');
55
59
  });
56
60
  });
@@ -72,4 +72,61 @@ describe('ACL Management: update rules', () => {
72
72
  };
73
73
  AclManagementSteps.checkRules([ACL[0], newRule, editedRule, ACL[2], ACL[3]]);
74
74
  });
75
+
76
+ it('Should prevent leaving the page when there is new rule added', () => {
77
+ // Given I have opened ACL management page
78
+ // When I don't change anything and try to leave the page
79
+ ApplicationSteps.openImportPage();
80
+ // Then I expect to be redirected to the new page without confirmation
81
+ cy.url().should('contain', '/import');
82
+ // When I add a new rule
83
+ AclManagementSteps.visit();
84
+ AclManagementSteps.addRule(1);
85
+ ApplicationSteps.openImportPage();
86
+ // Then I expect a confirmation dialog
87
+ ModalDialogSteps.getDialog().should('be.visible');
88
+ // When I cancel confirmation
89
+ ModalDialogSteps.clickOnCancelButton();
90
+ // Then I expect dialog to be closed and to stay on the current page
91
+ ModalDialogSteps.getDialog().should('not.exist');
92
+ cy.url().should('contain', '/aclmanagement');
93
+ // When I try to leave the page and I confirm the operation
94
+ ApplicationSteps.openImportPage();
95
+ ModalDialogSteps.clickOnConfirmButton();
96
+ // Then I expect to be redirected to the new page
97
+ cy.url().should('contain', '/import');
98
+ });
99
+
100
+ it('Should prevent leaving the page when there is an edited rule', () => {
101
+ // Given I have opened ACL management page
102
+ // When I edit a rule
103
+ AclManagementSteps.editRule(1);
104
+ AclManagementSteps.fillSubject(1, '<urn:Me>');
105
+ AclManagementSteps.saveRule(1);
106
+ // And I try to leave the page
107
+ ApplicationSteps.openImportPage();
108
+ // Then I expect a confirmation dialog
109
+ ModalDialogSteps.getDialog().should('be.visible');
110
+ });
111
+
112
+ it('Should prevent leaving the page when there is a deleted rule', () => {
113
+ // Given I have opened ACL management page
114
+ // When I delete a rule
115
+ AclManagementSteps.deleteRule(1);
116
+ ModalDialogSteps.clickOnConfirmButton();
117
+ // And I try to leave the page
118
+ ApplicationSteps.openImportPage();
119
+ // Then I expect a confirmation dialog
120
+ ModalDialogSteps.getDialog().should('be.visible');
121
+ });
122
+
123
+ it('Should prevent leaving the page when there is a moved rule', () => {
124
+ // Given I have opened ACL management page
125
+ // When I move a rule
126
+ AclManagementSteps.moveRuleDown(1);
127
+ // And I try to leave the page
128
+ ApplicationSteps.openImportPage();
129
+ // Then I expect a confirmation dialog
130
+ ModalDialogSteps.getDialog().should('be.visible');
131
+ });
75
132
  });
@@ -128,12 +128,12 @@ describe('My Settings', () => {
128
128
 
129
129
  //clear default query and paste a new one that will generate more than 1000 results
130
130
  cy.get('#queryEditor .CodeMirror').find('textarea')
131
- .type(Cypress.env('modifierKey') + 'a{backspace}', {force: true})
132
- .then(() => {
133
- cy.get('#queryEditor .CodeMirror').find('textarea')
134
- .invoke('val', testResultCountQuery).trigger('change', {force: true})
135
- .then(() => cy.verifyQueryAreaContains(testResultCountQuery));
136
- });
131
+ .type(Cypress.env('modifierKey') + 'a{backspace}', {force: true});
132
+
133
+ cy.get('#queryEditor .CodeMirror').find('textarea')
134
+ .invoke('val', testResultCountQuery).trigger('change', {force: true})
135
+ cy.waitUntilQueryIsVisible();
136
+ cy.verifyQueryAreaContains(testResultCountQuery);
137
137
 
138
138
  cy.get('#wb-sparql-runQuery')
139
139
  .should('be.visible')
@@ -293,7 +293,7 @@ describe('My Settings', () => {
293
293
  function visitSettingsView() {
294
294
  cy.visit('/settings', {
295
295
  onBeforeLoad: (win) => {
296
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
296
+ win.localStorage.setItem('ls.repository-id', repositoryId);
297
297
  }
298
298
  });
299
299
  cy.window()
@@ -36,7 +36,7 @@ describe('SPARQL Templates', () => {
36
36
  beforeEach(() => {
37
37
  cy.visit('/sparql-templates', {
38
38
  onBeforeLoad: (win) => {
39
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
39
+ win.localStorage.setItem('ls.repository-id', repositoryId);
40
40
  }
41
41
  });
42
42
  cy.window()
@@ -109,12 +109,11 @@ describe('Main menu tests', function () {
109
109
  visible: false,
110
110
  redirect: '/cluster'
111
111
  },
112
- // I wonder, why this sometimes works and others don't.
113
- // {
114
- // name: 'Plugins',
115
- // visible: false,
116
- // redirect: '/plugins'
117
- // },
112
+ {
113
+ name: 'Plugins',
114
+ visible: false,
115
+ redirect: '/plugins'
116
+ },
118
117
  {
119
118
  name: 'Namespaces',
120
119
  visible: false,
@@ -225,6 +225,7 @@ describe('SPARQL screen validation', () => {
225
225
 
226
226
  let describeQuery = 'describe ?t {bind (<<?s ?p ?o>> as ?t) .}';
227
227
 
228
+ cy.waitUntilQueryIsVisible();
228
229
  cy.pasteQuery(describeQuery);
229
230
 
230
231
  SparqlSteps.executeQuery();
@@ -305,6 +306,7 @@ describe('SPARQL screen validation', () => {
305
306
  it('Test execute (Describe) query', () => {
306
307
  let describeQuery = 'DESCRIBE <http://www.ontotext.com/SYSINFO> FROM <http://www.ontotext.com/SYSINFO>';
307
308
 
309
+ cy.waitUntilQueryIsVisible();
308
310
  cy.pasteQuery(describeQuery);
309
311
 
310
312
  SparqlSteps.executeQuery();
@@ -332,6 +334,7 @@ describe('SPARQL screen validation', () => {
332
334
  it('Test execute (ASK) query', () => {
333
335
  let askQuery = 'ASK WHERE { ?s ?p ?o .FILTER (regex(?o, "ontotext.com")) }';
334
336
 
337
+ cy.waitUntilQueryIsVisible();
335
338
  cy.pasteQuery(askQuery);
336
339
  SparqlSteps.executeQuery();
337
340
 
@@ -347,6 +350,7 @@ describe('SPARQL screen validation', () => {
347
350
  // This test depends on external service http://factforge.net/repositories/ff-news which can occasionally fail.
348
351
  it.skip('Test execute (CONSTRUCT) query', () => {
349
352
  cy.fixture('queries/construct-query.sparql').then(constructQuery => {
353
+ cy.waitUntilQueryIsVisible();
350
354
  cy.pasteQuery(constructQuery);
351
355
  });
352
356
 
@@ -367,6 +371,7 @@ describe('SPARQL screen validation', () => {
367
371
  });
368
372
 
369
373
  it('should test text mining plugin', () => {
374
+ cy.waitUntilQueryIsVisible();
370
375
  cy.pasteQuery(GATE_CLIENT_CREATE_QUERY);
371
376
  cy.executeQuery();
372
377
  cy.pasteQuery(GATE_CLIENT_SEARCH_QUERY);
@@ -412,6 +417,7 @@ describe('SPARQL screen validation', () => {
412
417
  '\t?s ?p ?o .\n' +
413
418
  '}';
414
419
 
420
+ cy.waitUntilQueryIsVisible();
415
421
  cy.pasteQuery(defaultQueryWithoutLimit);
416
422
  SparqlSteps.executeQuery();
417
423
 
@@ -446,6 +452,7 @@ describe('SPARQL screen validation', () => {
446
452
  ' :a ?p ?o .\n' +
447
453
  '}';
448
454
 
455
+ cy.waitUntilQueryIsVisible();
449
456
  cy.pasteQuery(updateToExecute);
450
457
  SparqlSteps.executeQuery();
451
458
  getUpdateMessage()
@@ -687,6 +694,7 @@ describe('SPARQL screen validation', () => {
687
694
  it('Test create, edit and delete saved query', () => {
688
695
  let savedQueryName = 'Saved query - ' + Date.now();
689
696
 
697
+ cy.waitUntilQueryIsVisible();
690
698
  cy.pasteQuery(QUERY_FOR_SAVING);
691
699
 
692
700
  saveQuery();
@@ -885,6 +893,7 @@ describe('SPARQL screen validation', () => {
885
893
 
886
894
  it('Test URL to current query', () => {
887
895
  const query = 'SELECT ?sub ?pred ?obj WHERE {?sub ?pred ?obj .} LIMIT 100';
896
+ cy.waitUntilQueryIsVisible();
888
897
  cy.pasteQuery(query);
889
898
 
890
899
  // Press the link icon to generate a link for a query
@@ -36,7 +36,7 @@ describe('SPARQL Templates', () => {
36
36
  beforeEach(() => {
37
37
  cy.visit('/sparql-templates', {
38
38
  onBeforeLoad: (win) => {
39
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
39
+ win.localStorage.setItem('ls.repository-id', repositoryId);
40
40
  }
41
41
  });
42
42
  cy.window()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.4.0-TR9",
3
+ "version": "2.4.0",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "scripts": {
6
6
  "start": "cypress open",
@@ -19,4 +19,9 @@ export class ApplicationSteps {
19
19
  static getWarningNotification() {
20
20
  return this.getNotifications().find('.toast-warning');
21
21
  }
22
+
23
+ // navigation via main menu
24
+ static openImportPage() {
25
+ cy.get('.main-menu .menu-element-root[href=import]').click();
26
+ }
22
27
  }
@@ -0,0 +1,21 @@
1
+ export class OperationsStatusesComponentSteps {
2
+
3
+ static getOperationsStatusesComponent() {
4
+ return cy.get('.operations-statuses');
5
+ }
6
+
7
+ static getOperationStatuses() {
8
+ return cy.get('.operation-status-content');
9
+ }
10
+
11
+ static openOperationStatusesDialog() {
12
+ OperationsStatusesComponentSteps.getOperationsStatusesComponent().click();
13
+ }
14
+
15
+ static checkOperationElementUrl(expectedUrl, operationIndex = 0) {
16
+ OperationsStatusesComponentSteps.getOperationStatuses().eq(operationIndex).then(($operationElement) => {
17
+ expect($operationElement).to.have.attr('target', '_blank');
18
+ expect($operationElement).to.have.attr('href', expectedUrl);
19
+ });
20
+ }
21
+ }
@@ -54,7 +54,7 @@ class SparqlSteps {
54
54
  win.sessionStorage.clear();
55
55
  }
56
56
  }
57
- win.localStorage.setItem('com.ontotext.graphdb.repository', repositoryId);
57
+ win.localStorage.setItem('ls.repository-id', repositoryId);
58
58
  }
59
59
  });
60
60
  this.waitUntilSparqlPageIsLoaded();
@@ -1,9 +1,7 @@
1
- export class BackupAndRestoreStubs {
1
+ import {Stubs} from "./stubs";
2
+
3
+ export class BackupAndRestoreStubs extends Stubs {
2
4
  static stubBackupAndRestoreResponse(withDelay = 0) {
3
5
  BackupAndRestoreStubs.stubQueryResponse('/rest/monitor/backup', '/monitoring/backup-and-restore.json', 'backup-and-restore-response', withDelay);
4
6
  }
5
-
6
- static stubQueryResponse(url, fixture, alias, withDelay = 0) {
7
- cy.intercept(url, {fixture, delay: withDelay}).as(alias);
8
- }
9
7
  }
@@ -0,0 +1,7 @@
1
+ import {Stubs} from "./stubs";
2
+
3
+ export class GlobalOperationsStatusesStub extends Stubs {
4
+ static stubGlobalOperationsStatusesResponse(repositoryId, withDelay = 0) {
5
+ GlobalOperationsStatusesStub.stubQueryResponse(`/rest/monitor/${repositoryId}/operations`, '/monitoring/global-operation-statuses.json', 'backup-and-restore-response', withDelay);
6
+ }
7
+ }
package/stubs/stubs.js ADDED
@@ -0,0 +1,5 @@
1
+ export class Stubs {
2
+ static stubQueryResponse(url, fixture, alias, withDelay = 0) {
3
+ cy.intercept(url, {fixture, delay: withDelay}).as(alias);
4
+ }
5
+ }
@@ -3,7 +3,7 @@ import repoTemplate from '../fixtures/repo-template.json';
3
3
  export const REPOSITORIES_URL = '/rest/repositories/';
4
4
  const AUTOCOMPLETE_URL = '/rest/autocomplete/';
5
5
 
6
- const PRESET_REPO = 'com.ontotext.graphdb.repository';
6
+ const PRESET_REPO = 'ls.repository-id';
7
7
 
8
8
  Cypress.Commands.add('createRepository', (options = {}) => {
9
9
  cy.request({
@@ -21,14 +21,22 @@ Cypress.Commands.add('createRepository', (options = {}) => {
21
21
  Cypress.Commands.add('deleteRepository', (id) => {
22
22
  // Note: Going through /rest/repositories because it would not fail if the repo is missing
23
23
  const url = REPOSITORIES_URL + id;
24
- cy.request('DELETE', url)
25
- .then((response) => {
26
- cy.waitUntil(() => response && response.status === 200);
24
+
25
+ // Navigates to the home view => helps by cancelling any pending requests
26
+ // if a test completes too fast and the tested view was about to load something
27
+ // that needs the just deleted repo.
28
+ cy.visit('/', {failOnStatusCode: false});
29
+
30
+ cy.request({
31
+ method: 'DELETE',
32
+ url: url,
33
+ // Prevent Cypress from failing the test on non-2xx status codes
34
+ failOnStatusCode: false
27
35
  });
28
36
  });
29
37
 
30
38
  Cypress.Commands.add('presetRepository', (id) => {
31
- cy.setLocalStorage('com.ontotext.graphdb.repository', id);
39
+ cy.setLocalStorage('ls.repository-id', id);
32
40
  cy.waitUntil(() =>
33
41
  cy.getLocalStorage(PRESET_REPO)
34
42
  .then((preset) => preset && preset === id));
@@ -1,8 +1,10 @@
1
1
  Cypress.Commands.add('pasteQuery', (query) => {
2
- clearQuery();
3
- // Using force because the textarea is not visible
4
- getQueryTextArea().invoke('val', query).trigger('change', {force: true}).should('have.value', query);
5
- waitUntilQueryIsVisible();
2
+ // Setting the textarea and the calling setValue seems to work
3
+ // more reliably then other strategies (see history)
4
+ getQueryTextArea().invoke('val', query);
5
+ getQueryArea().then(codeMirrorEl => {
6
+ codeMirrorEl[0].CodeMirror.setValue(query);
7
+ });
6
8
  });
7
9
 
8
10
  Cypress.Commands.add('executeQuery', () => {
@@ -18,8 +20,8 @@ Cypress.Commands.add('verifyResultsPageLength', (resultLength) => {
18
20
 
19
21
  Cypress.Commands.add('verifyResultsMessage', (msg) => {
20
22
  cy.waitUntil(() =>
21
- getResultsMessage()
22
- .then((resultInfo) => resultInfo && resultInfo.text().trim().indexOf(msg) > -1));
23
+ getResultsMessage().then((resultInfo) => resultInfo && resultInfo.text().trim().length > 0));
24
+ getResultsMessage().should('contain', msg);
23
25
  });
24
26
 
25
27
  Cypress.Commands.add('getResultsMessage', () => {
@@ -58,10 +60,11 @@ function waitUntilQueryIsVisible() {
58
60
  }
59
61
 
60
62
  function verifyQueryAreaContains(query) {
61
- // Using the CodeMirror instance because getting the value from the DOM is very cumbersome
62
63
  cy.waitUntil(() =>
63
64
  getQueryArea()
64
- .then(codeMirrorEl => codeMirrorEl && codeMirrorEl[0].CodeMirror.getValue().trim().indexOf(query) > -1));
65
+ .then(codeMirrorEl => codeMirrorEl && typeof codeMirrorEl[0].CodeMirror.getValue() === 'string'));
66
+ // Using the CodeMirror instance because getting the value from the DOM is very cumbersome
67
+ getQueryArea().then(codeMirrorEl => codeMirrorEl && codeMirrorEl[0].CodeMirror.getValue()).should('contain', query);
65
68
  }
66
69
 
67
70
  function getRunQueryButton() {