graphdb-workbench-tests 2.2.3 → 2.3.0-RC1

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.
@@ -0,0 +1,80 @@
1
+ import SparqlSteps from "../../steps/sparql-steps";
2
+
3
+ const LONG_ERROR_MESSAGE = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
4
+ const MAX_VISIBLE_ERROR_CHARACTERS = 160;
5
+ const SHORTEN_PART_OFF_ERROR_MESSAGE = LONG_ERROR_MESSAGE.substring(0, MAX_VISIBLE_ERROR_CHARACTERS);
6
+ const SHORT_ERROR_MESSAGE = LONG_ERROR_MESSAGE.substring(0, MAX_VISIBLE_ERROR_CHARACTERS - 1);
7
+ describe.skip('Error handling', () => {
8
+ let repositoryId;
9
+
10
+ beforeEach(() => {
11
+ repositoryId = 'sparql-error-handling' + Date.now();
12
+ cy.createRepository({id: repositoryId});
13
+ cy.presetRepository(repositoryId);
14
+ SparqlSteps.visit();
15
+ });
16
+
17
+ afterEach(() => {
18
+ cy.deleteRepository(repositoryId);
19
+ });
20
+
21
+ it('should show all error message if message length is short', () => {
22
+ stubErrorResponse(400, SHORT_ERROR_MESSAGE);
23
+ // When I open sparql editor page
24
+ // Then I should see no query has been executed
25
+ SparqlSteps.getNoQueryRunInfo().should('be.visible');
26
+ // When I execute a query
27
+ SparqlSteps.executeQuery();
28
+
29
+ // Then I expect to see all message,
30
+ SparqlSteps.getResultInfo().should('contain', SHORT_ERROR_MESSAGE);
31
+ // and don't see the button "Show full exception message",
32
+ SparqlSteps.getShowFullExceptionMessage().should('not.exist');
33
+ // and don't see the button "Show less exception message",
34
+ SparqlSteps.getShowLessExceptionMessage().should('not.exist');
35
+
36
+ });
37
+
38
+ it('should show shorten error message if message length is long', () => {
39
+ stubErrorResponse(400, LONG_ERROR_MESSAGE);
40
+ // When I open sparql editor page
41
+ // Then I should see no query has been executed
42
+ SparqlSteps.getNoQueryRunInfo().should('be.visible');
43
+ // When I execute a query
44
+ SparqlSteps.executeQuery();
45
+
46
+ // Then I expect to see shorten error message,
47
+ SparqlSteps.getResultInfo().should('contain', SHORTEN_PART_OFF_ERROR_MESSAGE);
48
+ // and the button "Show full exception message" to be displayed,
49
+ SparqlSteps.getShowFullExceptionMessage().should('be.visible');
50
+ // and don't see the button "Show less exception message",
51
+ SparqlSteps.getShowLessExceptionMessage().should('not.exist');
52
+
53
+ // When I click on "Show full error message" button.
54
+ SparqlSteps.clickOnShowFullExceptionMessage();
55
+
56
+ // Then I expect to see full error message
57
+ SparqlSteps.getResultInfo().should('contain', LONG_ERROR_MESSAGE);
58
+ // and the button "Show full exception message" to not exist,
59
+ SparqlSteps.getShowFullExceptionMessage().should('not.exist');
60
+ // and see the button "Show less exception message",
61
+ SparqlSteps.getShowLessExceptionMessage().should('be.visible');
62
+
63
+ // When I click on "Show less error message" button.
64
+ SparqlSteps.clickOnShowLessExceptionMessage();
65
+
66
+ // Then I expect to see short error message
67
+ SparqlSteps.getResultInfo().should('contain', SHORTEN_PART_OFF_ERROR_MESSAGE);
68
+ // and the button "Show full exception message" to be displayed,
69
+ SparqlSteps.getShowFullExceptionMessage().should('be.exist');
70
+ // and don't see the button "Show less exception message",
71
+ SparqlSteps.getShowLessExceptionMessage().should('not.exist');
72
+ });
73
+
74
+ const stubErrorResponse = (statusCode, errorMessage) => {
75
+ cy.intercept('POST', '/repositories/' + repositoryId, {
76
+ statusCode,
77
+ body: errorMessage
78
+ }).as('queryResultStub');
79
+ };
80
+ });
@@ -79,7 +79,7 @@ describe('SPARQL screen validation', () => {
79
79
  verifyQueryAreaEquals(DEFAULT_QUERY);
80
80
 
81
81
  // No queries should have been run for this tab
82
- getNoQueryRun().should('be.visible');
82
+ SparqlSteps.getNoQueryRunInfo().should('be.visible');
83
83
 
84
84
  SparqlSteps.executeQuery();
85
85
 
@@ -491,7 +491,7 @@ describe('SPARQL screen validation', () => {
491
491
  verifyQueryAreaContains(DEFAULT_QUERY);
492
492
 
493
493
  // No queries for new tab
494
- getNoQueryRun().should('be.visible');
494
+ SparqlSteps.getNoQueryRunInfo().should('be.visible');
495
495
  });
496
496
 
497
497
  it('Test rename a tab', () => {
@@ -1068,10 +1068,6 @@ describe('SPARQL screen validation', () => {
1068
1068
  });
1069
1069
  }
1070
1070
 
1071
- function getNoQueryRun() {
1072
- return cy.get('#yasr-inner .no-query-run');
1073
- }
1074
-
1075
1071
  function goToPage(page) {
1076
1072
  getResultPages().contains(page).click();
1077
1073
  SparqlSteps.getLoader().should('not.exist');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.2.3",
3
+ "version": "2.3.0-RC1",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "scripts": {
6
6
  "start": "cypress open",
@@ -24,16 +24,19 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "cypress": "^12.5.1",
27
- "cypress-failed-log": "^2.5.1",
27
+ "cypress-failed-log": "^2.10.0",
28
28
  "cypress-localstorage-commands": "^1.4.4",
29
- "cypress-terminal-report": "^4.0.1",
29
+ "cypress-terminal-report": "^5.2.0",
30
30
  "cypress-wait-until": "^1.7.1"
31
31
  },
32
32
  "bin": {
33
33
  "graphdb-workbench-cypress": "bin/graphdb-workbench-cypress"
34
34
  },
35
35
  "devDependencies": {
36
- "minimist": "^1.2.5"
36
+ "cypress-multi-reporters": "^1.6.3",
37
+ "del": "^6.1.1",
38
+ "minimist": "^1.2.5",
39
+ "mocha-junit-reporter": "^2.2.0"
37
40
  },
38
41
  "resolutions": {
39
42
  "minimist": "^1.2.5"
package/plugins/index.js CHANGED
@@ -11,6 +11,8 @@
11
11
  // This function is called when a project is opened or re-opened (e.g. due to
12
12
  // the project's config changing)
13
13
 
14
+ const del = require('del');
15
+
14
16
  module.exports = (on, config) => {
15
17
  // `on` is used to hook into various events Cypress emits
16
18
  // `config` is the resolved Cypress config
@@ -26,4 +28,18 @@ module.exports = (on, config) => {
26
28
  'cypress-logs|txt': 'txt'
27
29
  }
28
30
  });
31
+
32
+ // keep only the videos for the failed specs
33
+ on('after:spec', (spec, results) => {
34
+ if (results && results.video) {
35
+ // Do we have failures for any retry attempts?
36
+ const failures = results.tests.some((test) => {
37
+ return test.attempts.some((attempt) => attempt.state === 'failed');
38
+ });
39
+ if (!failures) {
40
+ // delete the video if the spec passed and no tests retried
41
+ return del(results.video);
42
+ }
43
+ }
44
+ });
29
45
  };
@@ -2,21 +2,9 @@
2
2
  * Reusable functions for interacting with graph dropdown on Class hierarchy and relationships pages.
3
3
  */
4
4
 
5
- const GRAPH_FILE = 'graphdb-news-dataset.zip';
6
- const ALL_GRAPHS = 'All graphs';
7
- const NEWS_GRAPH = 'http://example.org/news';
8
-
9
- Object.defineProperty(global, 'GRAPH_FILE', {
10
- get: () => {return GRAPH_FILE;}
11
- });
12
-
13
- Object.defineProperty(global, 'ALL_GRAPHS', {
14
- get: () => {return ALL_GRAPHS;}
15
- });
16
-
17
- Object.defineProperty(global, 'NEWS_GRAPH', {
18
- get: () => {return NEWS_GRAPH;}
19
- });
5
+ export const GRAPH_FILE = 'graphdb-news-dataset.zip';
6
+ export const ALL_GRAPHS = 'All graphs';
7
+ export const NEWS_GRAPH = 'http://example.org/news';
20
8
 
21
9
  class ClassViewsSteps {
22
10
 
@@ -0,0 +1,101 @@
1
+ import {REPOSITORIES_URL} from "../support/repository-commands";
2
+
3
+ export class OntopRepositorySteps {
4
+
5
+ static visitCreate() {
6
+ cy.visit('/repository/create/ontop');
7
+ }
8
+ static getOBDAFileField() {
9
+ return cy.get('div').contains("OBDA or R2RML file *").parent();
10
+ }
11
+
12
+ static getOBDAUploadButton() {
13
+ return cy.get('span[for="obdaFile"]').contains("Upload file...");
14
+ }
15
+
16
+ static getOntologyFileField() {
17
+ return cy.get('div').contains("Ontology file");
18
+ }
19
+
20
+ static getOntologyUploadButton() {
21
+ return cy.get('span[for="owlFile"]').contains("Upload file...");
22
+ }
23
+
24
+ static getLensesFileField() {
25
+ return cy.get('div').contains("Lenses file");
26
+ }
27
+
28
+ static getLensesUploadButton() {
29
+ return cy.get('span[for="lensesFile"]').contains("Upload file...");
30
+ }
31
+
32
+ static getConstraintFileField() {
33
+ return cy.get('div').contains("Constraint file");
34
+ }
35
+
36
+ static getConstraintUploadButton() {
37
+ return cy.get('span[for="constraintFile"]').contains("Upload file...");
38
+ }
39
+
40
+ static uploadConfigurationFile(file, filename) {
41
+ const fileType = '';
42
+ const url = REPOSITORIES_URL + 'file/upload';
43
+ const blob = Cypress.Blob.binaryStringToBlob(file, fileType);
44
+ const formData = new FormData();
45
+ formData.set('file', blob, filename);
46
+ return cy.form_request(url, formData);
47
+ }
48
+
49
+ static getCreateRepositoryButton() {
50
+ return cy.get('#addSaveOntopRepository');
51
+ }
52
+
53
+ static clickOnCreateRepositoryButton() {
54
+ OntopRepositorySteps.getCreateRepositoryButton().click();
55
+ }
56
+
57
+ static getDatabaseDriver() {
58
+ return cy.get('#driverType');
59
+ }
60
+
61
+ static selectDatabaseDriver(driverType) {
62
+ OntopRepositorySteps.getDatabaseDriver()
63
+ .select(driverType);
64
+ }
65
+
66
+ static selectMySqlDatabase() {
67
+ OntopRepositorySteps.selectDatabaseDriver('MySQL');
68
+ }
69
+
70
+ static selectSnowflakeDatabase() {
71
+ OntopRepositorySteps.selectDatabaseDriver('Snowflake');
72
+ }
73
+
74
+ static selectOracleDatabase() {
75
+ OntopRepositorySteps.selectDatabaseDriver('Oracle');
76
+ }
77
+
78
+ static getDriverClassInput() {
79
+ return cy.get('#driverClass');
80
+ }
81
+
82
+ static getUrlInput() {
83
+ return cy.get('#url');
84
+ }
85
+
86
+ static getHostNameInput() {
87
+ return cy.get('#hostName');
88
+ }
89
+
90
+ static getPortInput() {
91
+ return cy.get('#port');
92
+ }
93
+
94
+ static getDatabaseNameInput() {
95
+ return cy.get('#databaseName');
96
+ }
97
+
98
+ static getTestConnectionButton() {
99
+ return cy.get('#testConnection');
100
+ }
101
+ }
@@ -0,0 +1,193 @@
1
+ import {REPOSITORIES_URL} from "../support/repository-commands";
2
+
3
+ export class RepositorySteps {
4
+
5
+ static visit() {
6
+ cy.intercept('/rest/locations?filterClusterLocations=true').as('getLocations');
7
+ cy.intercept(REPOSITORIES_URL + 'all').as('getRepositories');
8
+ cy.visit('/repository');
9
+ RepositorySteps.waitLoader();
10
+ cy.wait('@getLocations');
11
+ // cy.window();
12
+ RepositorySteps.waitUntilRepositoriesPageIsLoaded();
13
+ }
14
+
15
+ static getCreateRepositoryButton() {
16
+ return cy.get('#wb-repositories-addRepositoryLink');
17
+ }
18
+
19
+ static waitUntilRepositoriesPageIsLoaded() {
20
+ // Workbench loading screen should not be visible
21
+ cy.get('.ot-splash').should('not.be.visible');
22
+
23
+ RepositorySteps.getRepositoriesDropdown().should('not.be.disabled');
24
+ RepositorySteps.getCreateRepositoryButton().should('be.visible').and('not.be.disabled');
25
+ }
26
+
27
+ static getRepositoriesDropdown() {
28
+ return cy.get('#repositorySelectDropdown')
29
+ .scrollIntoView()
30
+ .should('be.visible');
31
+ }
32
+
33
+ static getRepositoriesList() {
34
+ return cy.get('#wb-repositories-repositoryInGetRepositories');
35
+ }
36
+
37
+ static getRepositoryFromList(repository) {
38
+ RepositorySteps.waitLoader();
39
+ return RepositorySteps.getRepositoriesList()
40
+ .find('.repository')
41
+ .contains(repository)
42
+ // Return the whole repo row
43
+ .closest('.repository');
44
+ }
45
+
46
+ static waitLoader() {
47
+ cy.get('.ot-loader').should('not.be.visible');
48
+ }
49
+
50
+ static getRepositoryConnectionOffBtn(id) {
51
+ return RepositorySteps.getRepositoryFromList(id).find('.icon-connection-off');
52
+ }
53
+
54
+ static getRepositoryConnectionOnBtn(id) {
55
+ return RepositorySteps.getRepositoryFromList(id).find('.icon-connection-on');
56
+ }
57
+
58
+ static clickRepositoryIcon(repositoryId, selector) {
59
+ RepositorySteps.getRepositoryFromList(repositoryId)
60
+ .should('be.visible')
61
+ .find(selector)
62
+ // Forcefully clicking it due to https://github.com/cypress-io/cypress/issues/695
63
+ .should('be.visible')
64
+ .and('not.be.disabled')
65
+ .click({force: true});
66
+ }
67
+
68
+ static editRepository(repositoryId) {
69
+ RepositorySteps.clickRepositoryIcon(repositoryId, '.repository-actions .edit-repository-btn');
70
+ }
71
+
72
+ static getRepositoryTypeDropdown() {
73
+ return cy.get('#type');
74
+ }
75
+
76
+ static restartRepository(repositoryId) {
77
+ RepositorySteps.clickRepositoryIcon(repositoryId, '.repository-actions .restart-repository-btn');
78
+ }
79
+
80
+ static createRepository() {
81
+ RepositorySteps.getCreateRepositoryButton().click();
82
+ }
83
+
84
+ static getRepositoryTypeButton(type) {
85
+ if (type) {
86
+ return cy.get('#repository-type-' + type + '-btn');
87
+ } else {
88
+ return cy.get('.create-repo-btn').first();
89
+ }
90
+ }
91
+
92
+ static chooseRepositoryType(type) {
93
+ RepositorySteps.getRepositoryTypeButton(type).click();
94
+ }
95
+
96
+ static getRepositoryCreateForm() {
97
+ return cy.get('#newRepoForm').should('be.visible');
98
+ }
99
+
100
+ static getRepositoryIdField() {
101
+ return RepositorySteps.getRepositoryCreateForm().find('#id');
102
+ }
103
+
104
+ static typeRepositoryId(id) {
105
+ RepositorySteps.getRepositoryIdField().type(id);
106
+ }
107
+
108
+ static getRepositoryTitleField() {
109
+ return RepositorySteps.getRepositoryCreateForm().find('#title');
110
+ }
111
+
112
+ static typeRepositoryTitle(title) {
113
+ RepositorySteps.getRepositoryTitleField().clear().type(title);
114
+ }
115
+
116
+ static getRepositoryRulesetMenu() {
117
+ return RepositorySteps.getRepositoryCreateForm().find('#ruleset');
118
+ }
119
+
120
+ static getAdditionalPropertiesTextArea() {
121
+ return RepositorySteps.getRepositoryCreateForm().find('#additionalProperties');
122
+ }
123
+
124
+ static getRepositoryDisableSameAsCheckbox() {
125
+ return RepositorySteps.getRepositoryCreateForm().find('#disableSameAs');
126
+ }
127
+
128
+ static getRepositoryBaseURLField() {
129
+ return RepositorySteps.getRepositoryCreateForm().find('#baseURL');
130
+ }
131
+
132
+ static typeRepositoryBaseURL(baseURL) {
133
+ return RepositorySteps.getRepositoryBaseURLField().clear().type(baseURL);
134
+ }
135
+
136
+ static getRepositoryContextIndexCheckbox() {
137
+ return RepositorySteps.getRepositoryCreateForm().find('#enableContextIndex');
138
+ }
139
+
140
+ static getRepositoryFtsCheckbox() {
141
+ return RepositorySteps.getRepositoryCreateForm().find('#enableFtsIndex');
142
+ }
143
+
144
+ static getSaveRepositoryButton() {
145
+ return cy.get('#addSaveRepository');
146
+ }
147
+
148
+ static saveRepository() {
149
+ RepositorySteps.getSaveRepositoryButton().click();
150
+ RepositorySteps.waitLoader();
151
+ }
152
+
153
+ static selectRepoFromDropdown(repositoryId) {
154
+ RepositorySteps.getRepositoriesDropdown()
155
+ .click()
156
+ .find('.dropdown-menu-right .dropdown-item')
157
+ .contains(repositoryId)
158
+ .closest('a')
159
+ // Force the click because Cypress sometimes determines that the item has 0x0 dimensions
160
+ .click({force: true});
161
+ }
162
+
163
+ static getSHACLRepositoryCheckbox() {
164
+ return cy.get('#isShacl');
165
+ }
166
+
167
+ static confirmModal() {
168
+ cy.get('.modal')
169
+ .should('be.visible')
170
+ .and('not.have.class', 'ng-animate')
171
+ .find('.modal-footer .btn-primary')
172
+ .click();
173
+ }
174
+
175
+ static getOntopContentConfiguration() {
176
+ return cy.get('#ontop-content');
177
+ }
178
+
179
+ static getOntopFunctionalityDisabledMessage() {
180
+ return cy.get('.repository-errors div.alert')
181
+ .should('be.visible')
182
+ .and('contain', 'Some functionalities are not available because')
183
+ .and('contain', ' is read-only Virtual Repository');
184
+ }
185
+
186
+ static getLocationsList() {
187
+ return cy.get('#wb-locations-locationInGetLocations')
188
+ .find('tr.location')
189
+ .should('have.length', 1)
190
+ .and('contain', 'Repositories from: ')
191
+ .and('contain', 'Local');
192
+ }
193
+ }
@@ -37,6 +37,10 @@ class SparqlSteps {
37
37
  this.getLoader().should('not.exist');
38
38
  }
39
39
 
40
+ static visit() {
41
+ cy.visit('/sparql');
42
+ }
43
+
40
44
  static visitSparql(resetLocalStorage, repositoryId) {
41
45
  cy.visit('/sparql', {
42
46
  onBeforeLoad: (win) => {
@@ -69,6 +73,10 @@ class SparqlSteps {
69
73
  return cy.get('#wb-sparql-runQuery');
70
74
  }
71
75
 
76
+ static getNoQueryRunInfo() {
77
+ return cy.get('#yasr-inner .no-query-run');
78
+ }
79
+
72
80
  static getQueryArea() {
73
81
  return cy.get('#queryEditor .CodeMirror');
74
82
  }
@@ -76,7 +84,7 @@ class SparqlSteps {
76
84
  static waitUntilQueryIsVisible() {
77
85
  return cy.waitUntil(() =>
78
86
  this.getQueryArea()
79
- .then(codeMirrorEl =>
87
+ .then((codeMirrorEl) =>
80
88
  codeMirrorEl && codeMirrorEl[0].CodeMirror.getValue().trim().length > 0));
81
89
  }
82
90
 
@@ -171,6 +179,10 @@ class SparqlSteps {
171
179
  return cy.get('#yasr-inner .yasr_results');
172
180
  }
173
181
 
182
+ static getResultInfo() {
183
+ return cy.get('.results-info');
184
+ }
185
+
174
186
  static getTableResultRows() {
175
187
  return SparqlSteps.getResultsWrapper().find('.resultsTable tbody tr');
176
188
  }
@@ -194,6 +206,22 @@ class SparqlSteps {
194
206
  static getResultNoUriCell(rowIndex, columnIndex) {
195
207
  return SparqlSteps.getResultCell(rowIndex, columnIndex).find('.nonUri');
196
208
  }
209
+
210
+ static getShowFullExceptionMessage() {
211
+ return cy.get('.show-full-message-link');
212
+ }
213
+
214
+ static clickOnShowFullExceptionMessage() {
215
+ SparqlSteps.getShowFullExceptionMessage().click();
216
+ }
217
+
218
+ static getShowLessExceptionMessage() {
219
+ return cy.get('.show-less-message-link');
220
+ }
221
+
222
+ static clickOnShowLessExceptionMessage() {
223
+ SparqlSteps.getShowLessExceptionMessage().click();
224
+ }
197
225
  }
198
226
 
199
227
  export default SparqlSteps;
@@ -0,0 +1,35 @@
1
+ export class ToasterSteps {
2
+ static getToast() {
3
+ return cy.get('#toast-container');
4
+ }
5
+
6
+ static verifyTitle(title) {
7
+ ToasterSteps.getToast()
8
+ .find('.toast-title')
9
+ .should('be.visible')
10
+ .and('contain', title);
11
+ }
12
+
13
+ static verifySuccess(successMessage) {
14
+ ToasterSteps.getToast()
15
+ .should('exist')
16
+ .find('.toast-message')
17
+ .and('contain', successMessage);
18
+ }
19
+
20
+ static verifyWarning(warningMessage) {
21
+ ToasterSteps.getToast()
22
+ .find('.toast-warning')
23
+ .should('be.visible')
24
+ .find('.toast-message')
25
+ .and('contain', warningMessage);
26
+ }
27
+
28
+ static verifyError(errorMessage) {
29
+ ToasterSteps.getToast()
30
+ .find('.toast-error')
31
+ .should('be.visible')
32
+ .find('.toast-message')
33
+ .and('contain', errorMessage);
34
+ }
35
+ }
@@ -36,17 +36,19 @@ Cypress.Commands.add('iframe', {prevSubject: 'element'}, ($iframe) => {
36
36
  // Performs an XMLHttpRequest instead of a cy.request (able to send data as
37
37
  // FormData - multipart/form-data)
38
38
  Cypress.Commands.add("form_request", (url, formData) => {
39
- return cy
40
- .server()
41
- .route("POST", url)
42
- .as("formRequest")
39
+ return cy.intercept({
40
+ method: "POST",
41
+ url,
42
+ times: 1
43
+ })
44
+ .as('formRequest')
43
45
  .window()
44
46
  .then((win) => {
45
47
  var xhr = new win.XMLHttpRequest();
46
48
  xhr.open("POST", url);
47
49
  xhr.send(formData);
48
50
  })
49
- .wait("@formRequest");
51
+ .wait('@formRequest');
50
52
  });
51
53
 
52
54
  /**