graphdb-workbench-tests 2.8.1 → 3.0.0-TR1

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.
@@ -269,7 +269,7 @@
269
269
  "loading_rules": "Error during ACL rules",
270
270
  "updating_rules": "Error during ACL rules update",
271
271
  "duplicated_rules": "Every ACL rule should be unique.",
272
- "role_length_too_short": "Too short"
272
+ "role_length_too_short": "Too short or not \"*\""
273
273
  },
274
274
  "defaults": {
275
275
  "asterisk": "* - Any RDF value",
@@ -2,8 +2,6 @@ import ClassViewsSteps, {ALL_GRAPHS, GRAPH_FILE, NEWS_GRAPH} from "../../steps/c
2
2
 
3
3
  const INITIAL_CLASS_COUNT = 50;
4
4
  const CLASS_COUNT_OF_NEWS_GRAPH = 35;
5
- const SEARCH_INPUT_DROPDOWN_ID = '#search_input_dropdown';
6
- const CLASS_LABEL_SELECTOR = '#main-group > text.label';
7
5
  const FILE_TO_IMPORT = 'wine.rdf';
8
6
  const CLASS_HIERARCHY = 'class hierarchy';
9
7
 
@@ -14,253 +12,202 @@ describe('Class hierarchy screen validation', () => {
14
12
  repositoryId = 'repo' + Date.now();
15
13
  cy.createRepository({id: repositoryId});
16
14
  cy.presetRepository(repositoryId);
17
-
18
15
  cy.importServerFile(repositoryId, FILE_TO_IMPORT);
19
-
20
- cy.visit('/hierarchy');
21
- cy.window();
22
- // Wait for the chart and diagram to be visible, also check if a class is displayed.
23
- cy.get('#classChart').scrollIntoView().should('be.visible').within(() => {
24
- cy.get('#main-group').scrollIntoView().should('be.visible');
25
- findClassByName('food:Grape');
26
- cy.get('@classInHierarchy').scrollIntoView().should('be.visible');
27
- });
16
+ ClassViewsSteps.visit();
17
+ ClassViewsSteps.waitForPageLoad();
28
18
  });
29
19
 
30
20
  afterEach(() => {
31
21
  cy.deleteRepository(repositoryId);
32
22
  });
33
23
 
34
- it('Test initial state of the diagram has a class count 50', () => {
24
+ it('should have an initial state of the diagram with a class count of 50', () => {
35
25
  verifyCounterValue(INITIAL_CLASS_COUNT);
36
26
  });
37
27
 
38
- it('Test show/hide prefixes', () => {
39
- // Verify that switching on/off Show/hide prefixes is reflected on the diagram -
40
- // prefixes are displayed/hidden
28
+ it('should show/hide prefixes', () => {
29
+ // Given I verify that switching on/off Show/hide prefixes is reflected on the diagram - prefixes are displayed/hidden
41
30
  verifyPrefixes(($element) => cy.wrap($element.text()).should('contain', ':'));
42
31
 
43
32
  // Because some of the labels are truncated and is not guaranteed,
44
33
  // that after calling cy.get labels will be in the same order,
45
34
  // get the initial value of 'Chardonnay' label's text
46
- cy.get(CLASS_LABEL_SELECTOR).contains('Chardonnay').then($initialVal => {
47
- // Switch show prefixes to off
48
- cy.get('.toolbar-holder')
49
- .find('.prefix-toggle-btn')
50
- .scrollIntoView()
51
- .should('be.visible')
52
- .click()
53
- .then(() => {
54
- // Because of the timeout of 50 milliseconds after which the redraw of the prefixes happens
55
- // and we would like to validate successful removal, wait until the value of the 'Chardonnay'
56
- // label has changed. If not the test will fail
57
- cy.waitUntil(() =>
58
- cy.get(CLASS_LABEL_SELECTOR).contains('Chardonnay')
59
- .then($newVal =>
60
- $newVal.text() !== $initialVal.text()));
61
- // Verify that prefixes are removed from diagram
62
- verifyPrefixes(($element) => cy.wrap($element.text()).should('not.contain', ':'));
35
+ // When I get the initial value of 'Chardonnay' label's text
36
+ ClassViewsSteps.getMainGroupTextLabel()
37
+ .contains('Chardonnay')
38
+ .invoke('text')
39
+ .then((initialVal) => {
40
+ // When I switch "show prefixes" to off
41
+ ClassViewsSteps.getToolbarPrefixToggleButton()
42
+ .scrollIntoView()
43
+ .should('be.visible');
44
+ // Then I toggle the prefixes
45
+ ClassViewsSteps.clickPrefixToggleButton();
46
+ // Then I wait until the value of the 'Chardonnay' label has changed
47
+ ClassViewsSteps.getMainGroupTextLabel()
48
+ .contains('Chardonnay')
49
+ .invoke('text')
50
+ .should((newVal) => {
51
+ expect(newVal).not.to.equal(initialVal);
52
+ });
53
+ // Then I verify that prefixes are removed from diagram
54
+ verifyPrefixes(($element) => {
55
+ cy.wrap($element.text()).should('not.contain', ':');
63
56
  });
64
- });
57
+ });
65
58
  });
66
59
 
67
- it('Test focus on diagram', () => {
68
- // This must not be a top-level class and it must have no children,
69
- // otherwise asserting the zooming becomes tricky
70
- let className = ':SweetRiesling';
71
- findClassByName(className);
72
- cy.get('@classInHierarchy').then(verifyClassIsNotExpanded);
73
-
74
- // Verify that the diagram zooms that class
60
+ it('should focus on diagram', () => {
61
+ // This must not be a top-level class, and it must have no children, otherwise asserting the zooming becomes tricky
62
+ const className = ':SweetRiesling';
63
+ // Given the class is not expanded
64
+ verifyClassFocus(className, false);
65
+ // When I search for a class
75
66
  searchForClass(className);
76
-
77
- // Verify font-size is changed
78
- findClassByName(className);
79
- cy.get('@classInHierarchy').then(verifyClassIsExpanded);
80
-
81
- // When a class is focused in diagram a side panel is opened on the right and covers the
82
- // buttons toolbar.
83
- cy.get('[ps-class=rdf-info-side-panel] .close').click()
84
- .should('not.be.visible');
85
- cy.get('.toolbar-holder .focus-diagram-btn').click();
86
-
87
- // Verify that the diagram zooms out without resetting the class count.
88
- findClassByName(className);
89
- cy.get('@classInHierarchy').then(verifyClassIsNotExpanded);
67
+ // Then I expect the class to become expanded
68
+ verifyClassFocus(className, true);
69
+ // When a class is focused in diagram a side panel is opened on the right and covers the buttons toolbar
70
+ ClassViewsSteps.closeInfoSidePanel();
71
+ // Then I close the side panel
72
+ ClassViewsSteps.getInfoSidePanelCloseButton().should('not.be.visible');
73
+ // Then I focus the diagram
74
+ ClassViewsSteps.focusDiagram();
75
+ // Then I verify that the diagram zooms out, without resetting the class count
76
+ ClassViewsSteps.findClassByName(className);
77
+ ClassViewsSteps.getClassInHierarchy().then(verifyClassIsNotExpanded);
90
78
  });
91
79
 
92
- it('Test reload diagram', () => {
93
- // Initial class count is 50
94
- // Change the class count to a custom value
95
- cy.get('.class-cnt-slider > .ng-isolate-scope').trigger('click', 'center');
96
-
97
- // Reload diagram
98
- ClassViewsSteps.reloadDiagram();
99
-
100
- // Verify that warning message appears
101
- ClassViewsSteps.confirmReloadWarningAppear(CLASS_HIERARCHY);
102
-
103
- // Confirm diagram reloading
104
- ClassViewsSteps.confirmReload();
105
-
106
- // Verify that the diagram zooms out and the class count is reset
107
- verifyCounterValue(INITIAL_CLASS_COUNT);
80
+ it('should reload diagram', () => {
81
+ // Given I change the initial class count (50) to a custom value
82
+ ClassViewsSteps.positionSlider('center');
83
+ // Then I confirm the diagram has reloaded
84
+ reloadDiagramAndVerify(INITIAL_CLASS_COUNT);
108
85
  });
109
86
 
110
- it('Test export diagram', () => {
111
- // TODO: Verify that there aren't issues with this approach as there is no guarantee that the click will happen after mouseover event!
112
- // Eventually file an issue for refactoring.
113
- cy.get('#download-svg')
114
- .then(($element) => {
115
- let href = $element.prop('href');
116
- // Verify that a svg with the current diagram state is saved on your hdd.
117
- expect(href).to.contain(Cypress.config("baseUrl"));
118
- });
119
-
120
- // This is how I see it should be tested properly but for some reason when the whole spec is
121
- // executed the test fails.
122
- // Verify that the diagram converted to svg is present as base64 encoded string in
123
- // the href attribute. This is done in the mouseover over the link
124
- // (https://github.com/Ontotext-AD/graphdb-workbench/blob/master/src/js/angular/graphexplore/directives/rdf-class-hierarchy.directive.js#L127)
125
- // cy.get('#download-svg')
126
- // .trigger('mouseover')
127
- // .should('have.attr', 'download', `class-hierarchy-${repositoryId}.svg`)
128
- // .should('have.attr', 'href')
129
- // .and('not.be.empty')
130
- // .and('include', 'data:image/svg+xml;charset=utf-8;base64,');
87
+ it('should export diagram', () => {
88
+ // Given I verify that the diagram converted to svg. It should be present as a base64 encoded string in the href attribute.
89
+ // Note: This is done in the 'mouseover' callback for the link
90
+ // (https://github.com/Ontotext-AD/graphdb-workbench/blob/master/src/js/angular/graphexplore/directives/rdf-class-hierarchy.directive.js#L123)
91
+ ClassViewsSteps.mouseOverSVGButton()
92
+ .should('have.attr', 'download', `class-hierarchy-${repositoryId}.svg`)
93
+ .should('have.attr', 'href')
94
+ .and('not.be.empty')
95
+ .and('include', 'data:image/svg+xml;charset=utf-8;base64,');
131
96
  });
132
97
 
133
- it('Test search for a class', () => {
134
- let className = 'wine';
135
- cy.get(SEARCH_INPUT_DROPDOWN_ID)
98
+ it('should search for a class', () => {
99
+ const className = 'wine';
100
+ ClassViewsSteps.getSearchInputDropdown()
136
101
  .should('not.be.visible');
137
-
102
+ // When I search for a class
138
103
  searchForClass(className);
139
-
140
- // Verify that a list of suggestions is displayed.
141
- cy.get(SEARCH_INPUT_DROPDOWN_ID)
104
+ // Then a list of suggestions is displayed
105
+ ClassViewsSteps.getSearchInputDropdown()
142
106
  .should('be.visible')
143
107
  .and('length.be.gt', 0);
144
-
145
- // Click on a specific element that isn't a top-level one and has children,
108
+ // When I click on a specific element that isn't a top-level one and has children,
146
109
  // otherwise it gets tricky to assert whether it was zoomed
147
- cy.get('#search_input_dropdown').contains('WineColor')
110
+ ClassViewsSteps.getSearchInputDropdown()
111
+ .contains('WineColor')
148
112
  .then(($el) => {
149
- let selectedClassName = $el.text().trim();
150
-
151
- // Find selected class from drop-down menu and verify that isn't expanded
152
- findClassByName(selectedClassName);
153
- cy.get('@classInHierarchy').then(verifyClassIsNotExpanded);
113
+ const selectedClassName = $el.text().trim();
154
114
 
155
- cy.wrap($el).click();
115
+ // Then I find the selected class from the drop-down menu and verify that it isn't expanded
116
+ ClassViewsSteps.findClassByName(selectedClassName);
117
+ ClassViewsSteps.getClassInHierarchy().then(verifyClassIsNotExpanded);
118
+ // And I click the class name element
119
+ ClassViewsSteps.clickJQueryElement(cy.wrap($el));
156
120
 
157
- // Find selected class from drop-down menu after clicking on it and verify that it is expanded
158
- findClassByName(selectedClassName);
159
- cy.get('@classInHierarchy').then(verifyClassIsExpanded);
121
+ // Then I find the selected class from the drop-down menu and verify that it is expanded
122
+ ClassViewsSteps.findClassByName(selectedClassName);
123
+ ClassViewsSteps.getClassInHierarchy().then(verifyClassIsExpanded);
160
124
  });
161
125
  });
162
126
 
163
- it('Test domain range graph', () => {
164
- let className = ':Region';
127
+ it('should load domain range graph', () => {
128
+ const className = ':Region';
129
+ // When I search for a class
165
130
  searchForClass(className);
166
- getDomainRangeGraphButton().click();
167
- getDomainRangeGraphHeader().should('contain', 'Domain-Range graph');
168
- getLegendContainer().should('be.visible');
169
- getLegendContainer().should('contain', 'main class node').and('contain', 'class node').and('contain', 'collapsed property');
170
- getMainDomainRangeDiagram().should('be.visible');
171
- getMainDomainRangeDiagram().should('contain', className).and('contain', 'locatedIn').and('contain', ':adjacentRegion').and('contain', 'owl:Thing');
172
- getReturnButton().should('be.visible').click();
131
+ // And I open a domain range graph
132
+ ClassViewsSteps.openDomainRangeGraph();
133
+ // Then the graph should contain all necessary data
134
+ ClassViewsSteps.getDomainRangeGraphHeader()
135
+ .should('contain', 'Domain-Range graph');
136
+ ClassViewsSteps.getLegendContainer()
137
+ .should('be.visible');
138
+ ClassViewsSteps.getLegendContainer()
139
+ .should('contain', 'main class node')
140
+ .and('contain', 'class node')
141
+ .and('contain', 'collapsed property');
142
+ ClassViewsSteps.getMainDomainRangeDiagram()
143
+ .should('be.visible');
144
+ ClassViewsSteps.getMainDomainRangeDiagram()
145
+ .should('contain', className)
146
+ .and('contain', 'locatedIn')
147
+ .and('contain', ':adjacentRegion')
148
+ .and('contain', 'owl:Thing');
149
+ ClassViewsSteps.getReturnButton()
150
+ .should('be.visible');
151
+ ClassViewsSteps.goBack();
173
152
  });
174
153
 
175
- it('Test class-hierarchy for given graph', () => {
154
+ it('should load class-hierarchy for given graph', () => {
176
155
  cy.importServerFile(repositoryId, GRAPH_FILE, {"context": NEWS_GRAPH});
177
- // Should re-enter page to display Graph dropdown
178
- cy.visit('/hierarchy');
156
+ // Given I re-enter the page to display Graph dropdown
157
+ ClassViewsSteps.visit();
179
158
  ClassViewsSteps.verifyDataChangedWarning();
180
159
  verifyCounterValue(INITIAL_CLASS_COUNT);
181
160
  ClassViewsSteps.verifyGraphIsDisplayed(ALL_GRAPHS);
182
-
183
- // Reload diagram
184
- ClassViewsSteps.reloadDiagram();
185
- cy.intercept('/rest/class-hierarchy*').as('hierarchyReload');
186
- ClassViewsSteps.confirmReloadWarningAppear(CLASS_HIERARCHY);
187
- ClassViewsSteps.confirmReload();
188
- cy.wait('@hierarchyReload');
189
- verifyCounterValue(INITIAL_CLASS_COUNT + CLASS_COUNT_OF_NEWS_GRAPH);
161
+ // When I reload the diagram
162
+ reloadDiagramAndVerify(INITIAL_CLASS_COUNT + CLASS_COUNT_OF_NEWS_GRAPH);
190
163
  ClassViewsSteps.clickGraphBtn();
164
+ // Then I can see the correct graph is displayed
191
165
  ClassViewsSteps.selectGraphFromDropDown(NEWS_GRAPH);
192
166
  ClassViewsSteps.verifyGraphIsDisplayed(NEWS_GRAPH);
193
167
  verifyCounterValue(CLASS_COUNT_OF_NEWS_GRAPH);
194
168
  });
195
169
 
196
- function getDomainRangeGraphButton() {
197
- return cy.get('.domain-range-graph-btn');
198
- }
199
-
200
- function getDomainRangeGraphHeader() {
201
- return cy.get('h1');
202
- }
203
-
204
- function getLegendContainer() {
205
- return cy.get('.legend-container');
206
- }
207
-
208
- function getMainDomainRangeDiagram() {
209
- return cy.get('g');
210
- }
211
-
212
- function getReturnButton() {
213
- return cy.get('.icon-arrow-left');
214
- }
215
-
216
- function getCurrentSliderValue() {
217
- // The count is taken from the rz-pointer's attribute and not from a visible in the UI value
218
- // as the rz-slider library doesn't provide a reliable way to get this. It just has multiple
219
- // '.rz-bubble' elements and no appropriate selector for the one which holds the visible
220
- // value.
221
- return cy.get('.rz-pointer[role="slider"]');
222
- }
223
-
224
170
  function searchForClass(name) {
225
- cy.get('.toolbar-holder .icon-search')
226
- .click()
227
- .then(() => {
228
- cy.get('#search_input_value').type(name).type('{enter}');
229
- });
171
+ ClassViewsSteps.searchForClass();
172
+ ClassViewsSteps.searchForClassName(name);
230
173
  }
231
174
 
232
175
  function verifyPrefixes(expectation) {
233
- cy.get(CLASS_LABEL_SELECTOR)
234
- .each(($element) => {
235
- if ($element.prop('style').display !== 'none') {
236
- expectation($element);
237
- }
238
- });
239
- }
240
-
241
- function findClassByName(className) {
242
- cy.get(CLASS_LABEL_SELECTOR)
243
- .each(($element) => {
244
- let data = $element.prop('__data__');
245
- if (data.data.name === className) {
246
- cy.wrap($element).as('classInHierarchy');
247
- }
248
- });
176
+ ClassViewsSteps.getMainGroupTextLabel()
177
+ .filter(':visible')
178
+ .each(expectation);
249
179
  }
250
180
 
251
181
  function verifyClassIsNotExpanded($element) {
252
182
  // This works well only for classes that aren't top level and have no children
253
183
  return cy.wrap($element)
254
- .should('have.css', 'display').and('eq', 'none');
184
+ .should('have.css', 'display')
185
+ .and('eq', 'none');
255
186
  }
256
187
 
257
188
  function verifyClassIsExpanded($element) {
258
189
  // This works well only for classes that aren't top level and have no children
259
190
  return cy.wrap($element)
260
- .should('have.css', 'display').and('not.eq', 'none');
191
+ .should('have.css', 'display')
192
+ .and('not.eq', 'none');
261
193
  }
262
194
 
263
195
  function verifyCounterValue(classCount) {
264
- getCurrentSliderValue().should('be.visible').and('have.attr', 'aria-valuenow', classCount);
196
+ ClassViewsSteps.getCurrentSliderValue()
197
+ .should('be.visible')
198
+ .and('have.attr', 'aria-valuenow', classCount);
199
+ }
200
+
201
+ function reloadDiagramAndVerify(expectedClassCount) {
202
+ ClassViewsSteps.reloadDiagram();
203
+ ClassViewsSteps.waitForPageLoad();
204
+ ClassViewsSteps.confirmReloadWarningAppear(CLASS_HIERARCHY);
205
+ ClassViewsSteps.confirmReload();
206
+ verifyCounterValue(expectedClassCount);
207
+ }
208
+
209
+ function verifyClassFocus(className, expanded) {
210
+ ClassViewsSteps.findClassByName(className);
211
+ ClassViewsSteps.getClassInHierarchy().then(expanded ? verifyClassIsExpanded : verifyClassIsNotExpanded);
265
212
  }
266
213
  });
@@ -492,7 +492,10 @@ describe('Repositories', () => {
492
492
  RepositorySteps.getRepositoryIdEditElement().should('have.css', 'cursor').and('match', /not-allowed/);
493
493
  });
494
494
 
495
- it('should allow editing of repository name if repository is not in cluster', () => {
495
+ /**
496
+ * Skip it temporarily because it needs backend changes to be merged
497
+ */
498
+ it.skip('should allow editing of repository name if repository is not in cluster', () => {
496
499
  // When I create a repository,
497
500
  cy.createRepository({id: repositoryId});
498
501
  // and go to edit the repository page.
@@ -211,6 +211,10 @@ describe('ACL Management: create rule', () => {
211
211
  AclManagementSteps.addRuleInBeginning();
212
212
  AclManagementSteps.selectPolicy(0, 'allow');
213
213
  AclManagementSteps.fillRole(0, 'A');
214
+ // And I expect the prefix warning to NOT appear
215
+ AclManagementSteps.getPrefixWarning(0).should('not.exist');
216
+ // And I expect the prefix warning icon to NOT appear
217
+ AclManagementSteps.getWarningIcon(0).should('not.exist');
214
218
  AclManagementSteps.selectOperation(0, 'write');
215
219
  AclManagementSteps.fillSubject(0, '<urn:Mary>');
216
220
  AclManagementSteps.fillPredicate(0, '*');
@@ -218,14 +222,39 @@ describe('ACL Management: create rule', () => {
218
222
  AclManagementSteps.fillContext(0, '*');
219
223
 
220
224
  // Then I expect an error notification to be displayed that tells me this ROLE length is not allowed
221
- AclManagementSteps.getFieldError().contains('Too short');
225
+ AclManagementSteps.getFieldError().contains('Too short or not "*"');
226
+ });
227
+
228
+ it('should allow creating a new rule if CUSTOM ROLE is a wildcard (*)', () => {
229
+ // Given I have a defined number of rules at the beginning
230
+ AclManagementSteps.getAclRules().should('have.length', 5);
231
+ // When I am on "ACL Management" page and create a new rule with a CUSTOM ROLE of 1 symbol (a wildcard)
232
+ AclManagementSteps.addRuleInBeginning();
233
+ AclManagementSteps.selectPolicy(0, 'allow');
234
+ AclManagementSteps.fillRole(0, '*');
235
+ AclManagementSteps.selectOperation(0, 'write');
236
+ AclManagementSteps.fillSubject(0, '<urn:Mary>');
237
+ AclManagementSteps.fillPredicate(0, '*');
238
+ AclManagementSteps.fillObject(0, '*');
239
+ AclManagementSteps.fillContext(0, '*');
240
+
241
+ // Then I expect to not see an error
242
+ AclManagementSteps.getFieldError().should('not.exist');
243
+ // When I save the rule
244
+ AclManagementSteps.saveRule(0);
245
+ // When I save the rules
246
+ AclManagementSteps.saveAcl();
247
+ // Then the table should contain the new rule
248
+ AclManagementSteps.getSavedRoleField(0).should('contain', '*');
249
+ AclManagementSteps.getAclRules().should('have.length', 6);
222
250
  });
223
251
 
224
252
  it('should show message if role prefix is CUSTOM_', () => {
225
253
  // When I am on "ACL Management" page and create a new rule with a CUSTOM_ prefix
226
254
  AclManagementSteps.addRuleInBeginning();
227
255
  AclManagementSteps.selectPolicy(0, 'allow');
228
- AclManagementSteps.fillRole(0, 'CUSTOM_ROLE_FOO');
256
+ // When I enter the prefix in lowercase, the logic should still detect it
257
+ AclManagementSteps.fillRole(0, 'custom_ROLE_FOO');
229
258
 
230
259
  // Then I expect the prefix warning to appear
231
260
  AclManagementSteps.getPrefixWarning(0).should('be.visible');
@@ -12,6 +12,8 @@ describe('Plugins view', () => {
12
12
  cy.presetRepository(repositoryId);
13
13
  cy.initializeRepository(repositoryId);
14
14
  LicenseStubs.spyGetLicense();
15
+ PluginsStubs.spyPluginsGet(repositoryId);
16
+ PluginsSteps.visit();
15
17
  });
16
18
 
17
19
  afterEach(() => {
@@ -19,8 +21,6 @@ describe('Plugins view', () => {
19
21
  });
20
22
 
21
23
  it('Should allow to enable and disable the plugins', () => {
22
- PluginsStubs.spyPluginsGet(repositoryId);
23
- PluginsSteps.visit();
24
24
  cy.wait('@get-license');
25
25
  cy.wait('@get-plugins');
26
26
  PluginsSteps.waitUntilPluginsPageIsLoaded();
@@ -31,9 +31,10 @@ describe('Plugins view', () => {
31
31
  PluginsSteps.getPluginSwitchField('history').should('be.checked');
32
32
  PluginsSteps.togglePlugin('history');
33
33
 
34
- PluginsSteps.visit();
34
+ cy.reload();
35
35
  cy.wait('@get-plugins');
36
-
36
+ PluginsSteps.waitUntilPluginsPageIsLoaded();
37
+ PluginsSteps.getPluginsView().should('be.visible');
37
38
  PluginsSteps.getPluginByName('history').should('be.visible');
38
39
  PluginsSteps.getPluginSwitchField('history').should('not.be.checked');
39
40
  });
@@ -0,0 +1,53 @@
1
+ import {UserAndAccessSteps} from "../../../steps/setup/user-and-access-steps";
2
+ import {RepositoriesStubs} from "../../../stubs/repositories/repositories-stubs";
3
+ import {ModalDialogSteps} from "../../../steps/modal-dialog-steps";
4
+ import {ToasterSteps} from "../../../steps/toaster-steps";
5
+
6
+ const DEFAULT_ADMIN_PASSWORD = "root";
7
+ // Moved out of the standard test suite, because Cypress can't verify Free Access is ON in CI
8
+ describe('Security and Free Access', () => {
9
+ beforeEach(() => {
10
+ UserAndAccessSteps.visit();
11
+ cy.window();
12
+ // Users table should be visible
13
+ UserAndAccessSteps.getUsersTable().should('be.visible');
14
+ });
15
+
16
+ afterEach(() => {
17
+ UserAndAccessSteps.visit();
18
+ UserAndAccessSteps.getToggleSecurityCheckbox()
19
+ .then(($toggle) => {
20
+ if ($toggle.prop('checked')) {
21
+ // Uncheck the security toggle button at the end of each test, if it is checked
22
+ UserAndAccessSteps.toggleSecurity();
23
+ }
24
+ });
25
+ });
26
+
27
+ it('should toggle free access after Admin has logged in', () => {
28
+ // Given I have available repositories to allow Free Access for
29
+ RepositoriesStubs.stubRepositories();
30
+ // When I enable security
31
+ UserAndAccessSteps.toggleSecurity();
32
+ // When I log in as an Admin
33
+ UserAndAccessSteps.loginWithUser("admin", DEFAULT_ADMIN_PASSWORD);
34
+ // Then the page should load
35
+ UserAndAccessSteps.getSplashLoader().should('not.be.visible');
36
+ UserAndAccessSteps.getUsersTable().should('be.visible');
37
+ // The Free Access toggle should be OFF
38
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('not.be.checked');
39
+ // When I toggle Free Access ON
40
+ UserAndAccessSteps.toggleFreeAccess();
41
+ // Then I click OK in the modal
42
+ ModalDialogSteps.clickOKButton();
43
+ // Then the toggle button should be ON
44
+ UserAndAccessSteps.getFreeAccessSwitchInput().should('be.checked');
45
+ // And I should see a success message
46
+ ToasterSteps.verifySuccess('Free access has been enabled.');
47
+ UserAndAccessSteps.getUsersTable().should('be.visible');
48
+ // When I toggle Free Access OFF
49
+ UserAndAccessSteps.toggleFreeAccess();
50
+ // Then I should see a success message
51
+ ToasterSteps.verifySuccess('Free access has been disabled.');
52
+ });
53
+ });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.8.1",
3
+ "version": "3.0.0-TR1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "graphdb-workbench-tests",
9
- "version": "2.8.1",
9
+ "version": "3.0.0-TR1",
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
12
  "cypress": "^13.3.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.8.1",
3
+ "version": "3.0.0-TR1",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "scripts": {
6
6
  "prepack": "npm shrinkwrap",
@@ -7,6 +7,145 @@ export const ALL_GRAPHS = 'All graphs';
7
7
  export const NEWS_GRAPH = 'http://example.org/news';
8
8
 
9
9
  class ClassViewsSteps {
10
+ static visit() {
11
+ cy.visit('/hierarchy');
12
+ cy.window();
13
+ }
14
+
15
+ static waitForPageLoad() {
16
+ // Wait for the chart and diagram to be visible, also check if a class is displayed.
17
+ this.getClassChart().scrollIntoView().should('be.visible').within(() => {
18
+ this.getMainGroup().scrollIntoView().should('be.visible');
19
+ this.findClassByName('food:Grape');
20
+ this.getClassInHierarchy().scrollIntoView().should('be.visible');
21
+ });
22
+ }
23
+
24
+ static getClassChart() {
25
+ return cy.get('#classChart');
26
+ }
27
+
28
+ static getMainGroup() {
29
+ return cy.get('#main-group');
30
+ }
31
+
32
+ static getMainGroupTextLabel() {
33
+ return this.getMainGroup().find('text.label');
34
+ }
35
+
36
+ static getClassInHierarchy() {
37
+ return cy.get('@classInHierarchy');
38
+ }
39
+
40
+ static getToolbarHolder() {
41
+ return cy.get('.toolbar-holder');
42
+ }
43
+
44
+ static getToolbarPrefixToggleButton() {
45
+ return this.getToolbarHolder().find('.prefix-toggle-btn');
46
+ }
47
+
48
+ static clickPrefixToggleButton() {
49
+ return this.getToolbarPrefixToggleButton().click();
50
+ }
51
+
52
+ static getSearchInputDropdown() {
53
+ return cy.get('#search_input_dropdown');
54
+ }
55
+
56
+ static getInfoSidePanelCloseButton() {
57
+ return cy.get('[ps-class=rdf-info-side-panel] .close');
58
+ }
59
+
60
+ static closeInfoSidePanel() {
61
+ this.getInfoSidePanelCloseButton().click();
62
+ }
63
+
64
+ static getFocusDiagramButton() {
65
+ return cy.get('.toolbar-holder .focus-diagram-btn');
66
+ }
67
+
68
+ static focusDiagram() {
69
+ this.getFocusDiagramButton().click();
70
+ }
71
+
72
+ static getSlider() {
73
+ return cy.get('.class-cnt-slider > .ng-isolate-scope');
74
+ }
75
+
76
+ static positionSlider(location) {
77
+ this.getSlider().trigger('click', location);
78
+ }
79
+
80
+ static getSVGButton() {
81
+ return cy.get('#download-svg');
82
+ }
83
+
84
+ static mouseOverSVGButton() {
85
+ return this.getSVGButton().trigger('mouseover');
86
+ }
87
+
88
+ static getDomainRangeGraphButton() {
89
+ return cy.get('.domain-range-graph-btn');
90
+ }
91
+
92
+ static openDomainRangeGraph() {
93
+ this.getDomainRangeGraphButton().click();
94
+ }
95
+
96
+ static getDomainRangeGraphHeader() {
97
+ return cy.get('h1');
98
+ }
99
+
100
+ static getLegendContainer() {
101
+ return cy.get('.legend-container');
102
+ }
103
+
104
+ static getMainDomainRangeDiagram() {
105
+ return cy.get('g');
106
+ }
107
+
108
+ static getReturnButton() {
109
+ return cy.get('.icon-arrow-left');
110
+ }
111
+
112
+ static goBack() {
113
+ this.getReturnButton().click();
114
+ }
115
+
116
+ static getCurrentSliderValue() {
117
+ // The count is taken from the rz-pointer's attribute and not from a visible in the UI value
118
+ // as the rz-slider library doesn't provide a reliable way to get this. It just has multiple
119
+ // '.rz-bubble' elements and no appropriate selector for the one which holds the visible
120
+ // value.
121
+ return cy.get('.rz-pointer[role="slider"]');
122
+ }
123
+
124
+ static searchForClass() {
125
+ return cy.get('.toolbar-holder .icon-search').click();
126
+ }
127
+
128
+ static getSearchInput() {
129
+ return cy.get('#search_input_value');
130
+ }
131
+
132
+ static searchForClassName(name) {
133
+ this.getSearchInput().type(name).type('{enter}');
134
+ }
135
+
136
+ static clickJQueryElement(element) {
137
+ element.click();
138
+ }
139
+
140
+ static findClassByName(className) {
141
+ this.getMainGroupTextLabel()
142
+ .each(($element) => {
143
+ const data = $element.prop('__data__');
144
+ if (data.data.name === className) {
145
+ cy.wrap($element).as('classInHierarchy');
146
+ }
147
+ });
148
+ }
10
149
 
11
150
  static selectGraphFromDropDown(graph) {
12
151
  cy.get('#selectGraphDropdown .dropdown-item')
@@ -39,6 +39,10 @@ export class ModalDialogSteps {
39
39
  ModalDialogSteps.getConfirmButton().click();
40
40
  }
41
41
 
42
+ static clickOKButton() {
43
+ ModalDialogSteps.getDialogFooter().find('.btn-primary').click();
44
+ }
45
+
42
46
  static confirm() {
43
47
  ModalDialogSteps.getConfirmButton().click();
44
48
  }
@@ -23,10 +23,25 @@ export class UserAndAccessSteps {
23
23
  return cy.get('#toggle-security span.switch');
24
24
  }
25
25
 
26
+ static getToggleSecurityCheckbox() {
27
+ return cy.get('#toggle-security input[type="checkbox"]');
28
+ }
26
29
  static toggleSecurity() {
27
30
  this.getToggleSecuritySwitch().click();
28
31
  }
29
32
 
33
+ static getFreeAccessSwitchInput() {
34
+ return cy.get('#toggle-freeaccess .switch input');
35
+ }
36
+
37
+ static getFreeAccessSwitch() {
38
+ return cy.get('#toggle-freeaccess span.switch');
39
+ }
40
+
41
+ static toggleFreeAccess() {
42
+ this.getFreeAccessSwitch().click();
43
+ }
44
+
30
45
  static getSecuritySwitchLabel() {
31
46
  return cy.get('#toggle-security').find('.security-switch-label');
32
47
  }
@@ -2,12 +2,12 @@ import {Stubs} from "./stubs";
2
2
 
3
3
  export class GlobalOperationsStatusesStub extends Stubs {
4
4
  static stubGlobalOperationsStatusesResponse(repositoryId, withDelay = 0) {
5
- GlobalOperationsStatusesStub.stubQueryResponse(`/rest/monitor/${repositoryId}/operations`, '/monitoring/global-operation-statuses.json', 'backup-and-restore-response', withDelay);
5
+ GlobalOperationsStatusesStub.stubQueryResponse(`/rest/monitor/repository/${repositoryId}/operations`, '/monitoring/global-operation-statuses.json', 'backup-and-restore-response', withDelay);
6
6
  }
7
7
 
8
8
  static stubNoOperationsResponse(repositoryId, withDelay = 0) {
9
9
  GlobalOperationsStatusesStub.stubQueryResponse(
10
- `/rest/monitor/${repositoryId}/operations`,
10
+ `/rest/monitor/repository/${repositoryId}/operations`,
11
11
  '/monitoring/no-operations.json',
12
12
  'backup-and-restore-response', withDelay);
13
13
  }