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.
- package/fixtures/locale-en.json +1 -1
- package/integration/explore/class.hierarchy.spec.js +131 -184
- package/integration/repository/repositories.spec.js +4 -1
- package/integration/setup/aclmanagement/create-rule.spec.js +31 -2
- package/integration/setup/plugins.spec.js +5 -4
- package/integration-flaky/setup/users-and-access/security-and-free-access.spec.js +53 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/steps/class-views-steps.js +139 -0
- package/steps/modal-dialog-steps.js +4 -0
- package/steps/setup/user-and-access-steps.js +15 -0
- package/stubs/global-operations-statuses-stub.js +2 -2
package/fixtures/locale-en.json
CHANGED
|
@@ -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
|
-
|
|
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('
|
|
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('
|
|
39
|
-
//
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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('
|
|
68
|
-
// This must not be a top-level class and it must have no children,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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('
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
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('
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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('
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
110
|
+
ClassViewsSteps.getSearchInputDropdown()
|
|
111
|
+
.contains('WineColor')
|
|
148
112
|
.then(($el) => {
|
|
149
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
158
|
-
findClassByName(selectedClassName);
|
|
159
|
-
|
|
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('
|
|
164
|
-
|
|
127
|
+
it('should load domain range graph', () => {
|
|
128
|
+
const className = ':Region';
|
|
129
|
+
// When I search for a class
|
|
165
130
|
searchForClass(className);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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('
|
|
154
|
+
it('should load class-hierarchy for given graph', () => {
|
|
176
155
|
cy.importServerFile(repositoryId, GRAPH_FILE, {"context": NEWS_GRAPH});
|
|
177
|
-
//
|
|
178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
226
|
-
|
|
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
|
-
|
|
234
|
-
.
|
|
235
|
-
|
|
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')
|
|
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')
|
|
191
|
+
.should('have.css', 'display')
|
|
192
|
+
.and('not.eq', 'none');
|
|
261
193
|
}
|
|
262
194
|
|
|
263
195
|
function verifyCounterValue(classCount) {
|
|
264
|
-
getCurrentSliderValue()
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
});
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphdb-workbench-tests",
|
|
3
|
-
"version": "
|
|
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": "
|
|
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
|
@@ -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
|
}
|