graphdb-workbench-tests 4.0.0-TR14 → 4.0.0-TR16

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.
@@ -5,12 +5,15 @@ import {MainMenuSteps} from '../../steps/main-menu-steps.js';
5
5
  import {YasqeSteps} from '../../steps/yasgui/yasqe-steps.js';
6
6
  import {YasrSteps} from '../../steps/yasgui/yasr-steps.js';
7
7
  import {ToasterSteps} from '../../steps/toaster-steps.js';
8
+ import {GraphNavigatorStubs} from '../../stubs/graph-navigator-stubs.js';
8
9
 
9
10
  const FILE_TO_IMPORT = 'resource-test-data.ttl';
10
11
  const SEED_RESOURCE_ENCODED = 'http:%2F%2Fexample.com%2Fontology%23CustomerLoyalty';
11
12
  const SEED_RESOURCE_LABEL = 'CustomerLoyalty';
12
13
  const SETTINGS_FILE_NAME = 'graph-navigator-settings.ttl';
13
14
  const SETTINGS_FILE = `fixtures/graph-navigator/${SETTINGS_FILE_NAME}`;
15
+ const INVALID_SETTINGS_FILE_NAME = 'graph-navigator-settings-invalid.ttl';
16
+ const INVALID_SETTINGS_FILE = `fixtures/graph-navigator/${INVALID_SETTINGS_FILE_NAME}`;
14
17
 
15
18
  const CONSTRUCT_QUERY = 'CONSTRUCT { <http://example.com/ontology#CustomerLoyalty> ?p ?o } WHERE { <http://example.com/ontology#CustomerLoyalty> ?p ?o }';
16
19
  const CONSTRUCT_TARGET_LABEL = 'Metric';
@@ -219,6 +222,43 @@ describe('Graph Navigator', () => {
219
222
  GraphNavigatorSteps.getWorkspace().should('exist');
220
223
  });
221
224
 
225
+ it('should show the validation errors of a rejected file on its row', () => {
226
+ // Given I have selected a settings file with invalid values and an unknown property.
227
+ GraphNavigatorSteps.visit();
228
+ GraphNavigatorSteps.openSettings();
229
+ GraphNavigatorSteps.selectSettingsFile(INVALID_SETTINGS_FILE);
230
+
231
+ // When I upload it.
232
+ GraphNavigatorSteps.clickUpload();
233
+ GraphNavigatorSteps.confirmDialog();
234
+
235
+ // Then I expect the errors in a table on the file row.
236
+ ToasterSteps.verifyNewToasterError('Could not upload the settings');
237
+ GraphNavigatorSteps.getSelectedSettingsFile(INVALID_SETTINGS_FILE_NAME).should('exist');
238
+ GraphNavigatorSteps.getUploadErrors().should('be.visible')
239
+ .and('contain', '3 validation errors')
240
+ .and('contain', 'Fix these properties in the file and upload it again.');
241
+ GraphNavigatorSteps.getUploadError('gn:acceptBlankNodes').should('contain', 'Must be of type boolean');
242
+ GraphNavigatorSteps.getUploadError('gn:openWorldProperties').should('contain', 'Must be of type boolean');
243
+ GraphNavigatorSteps.getUploadError('gn:unknownSetting')
244
+ .should('contain', 'Not a known property');
245
+
246
+ // When I close and reopen the settings.
247
+ GraphNavigatorSteps.closeSettings();
248
+ GraphNavigatorSteps.openSettings();
249
+
250
+ // Then I expect the file and its errors to be kept.
251
+ GraphNavigatorSteps.getSelectedSettingsFile(INVALID_SETTINGS_FILE_NAME).should('exist');
252
+ GraphNavigatorSteps.getUploadErrors().should('be.visible')
253
+ .and('contain', '3 validation errors');
254
+
255
+ // When I remove the file.
256
+ GraphNavigatorSteps.clickCancelFile();
257
+
258
+ // Then I expect the errors to be cleared.
259
+ GraphNavigatorSteps.getUploadErrors().should('not.exist');
260
+ });
261
+
222
262
  it('should ask for confirmation before resetting', () => {
223
263
  // Given the repository has uploaded settings.
224
264
  GraphNavigatorSteps.visit();
@@ -264,6 +304,48 @@ describe('Graph Navigator', () => {
264
304
  });
265
305
  });
266
306
 
307
+ describe('Autocomplete warning', () => {
308
+ beforeEach(() => {
309
+ GraphNavigatorStubs.stubSettingsWithAutocomplete();
310
+ });
311
+
312
+ it('should warn once that autocomplete is off', () => {
313
+ // Given the settings use autocomplete, but autocomplete is off.
314
+ GraphNavigatorStubs.spyEntityLookup(SEED_RESOURCE_LABEL);
315
+ GraphNavigatorSteps.visit();
316
+ cy.wait('@graph-navigator-settings');
317
+
318
+ // When I search for entities.
319
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
320
+ cy.wait('@entity-lookup');
321
+
322
+ // Then I expect a warning that autocomplete is off.
323
+ ToasterSteps.getWarningToast().should('be.visible').and('contain', 'Autocomplete is OFF');
324
+
325
+ // When the warning is gone and I search for entities again.
326
+ ToasterSteps.getToast().should('not.exist');
327
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
328
+ cy.wait('@entity-lookup');
329
+
330
+ // Then I expect no new warning.
331
+ ToasterSteps.getToast().should('not.exist');
332
+ });
333
+
334
+ it('should redirect to the autocomplete view when the warning is clicked', () => {
335
+ // Given the settings use autocomplete, but autocomplete is off.
336
+ GraphNavigatorSteps.visit();
337
+ cy.wait('@graph-navigator-settings');
338
+
339
+ // When I search for entities and click the warning.
340
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
341
+ ToasterSteps.getWarningToast().should('be.visible').and('contain', 'Autocomplete is OFF');
342
+ ToasterSteps.getWarningToast().click();
343
+
344
+ // Then I expect to be redirected to the autocomplete view.
345
+ cy.url().should('include', '/autocomplete');
346
+ });
347
+ });
348
+
267
349
  describe('Repository switch', () => {
268
350
  let secondRepositoryId;
269
351
 
@@ -314,5 +396,38 @@ describe('Graph Navigator', () => {
314
396
  GraphNavigatorSteps.getElements().should('not.exist');
315
397
  GraphNavigatorSteps.verifyOnlyRepositoryParam(secondRepositoryId);
316
398
  });
399
+
400
+ it('should warn that autocomplete is off once per repository selection', () => {
401
+ // Given the settings use autocomplete, but autocomplete is off.
402
+ GraphNavigatorStubs.stubSettingsWithAutocomplete();
403
+ GraphNavigatorSteps.visit();
404
+ cy.wait('@graph-navigator-settings');
405
+
406
+ // When I search for entities.
407
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
408
+
409
+ // Then I expect a warning that autocomplete is off.
410
+ ToasterSteps.getWarningToast().should('be.visible').and('contain', 'Autocomplete is OFF');
411
+
412
+ // When the warning is gone and I switch to another repository and search for entities.
413
+ ToasterSteps.getToast().should('not.exist');
414
+ RepositorySelectorSteps.selectRepository(secondRepositoryId);
415
+ GraphNavigatorSteps.confirmDialog();
416
+ cy.wait('@graph-navigator-settings');
417
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
418
+
419
+ // Then I expect a new warning, for the new repository.
420
+ ToasterSteps.getWarningToast().should('be.visible').and('contain', 'Autocomplete is OFF');
421
+
422
+ // When the warning is gone and I switch back to the first repository and search for entities.
423
+ ToasterSteps.getToast().should('not.exist');
424
+ RepositorySelectorSteps.selectRepository(repositoryId);
425
+ GraphNavigatorSteps.confirmDialog();
426
+ cy.wait('@graph-navigator-settings');
427
+ GraphNavigatorSteps.searchEntities(SEED_RESOURCE_LABEL);
428
+
429
+ // Then I expect a new warning, because the repository was selected again.
430
+ ToasterSteps.getWarningToast().should('be.visible').and('contain', 'Autocomplete is OFF');
431
+ });
317
432
  });
318
433
  });
@@ -33,7 +33,9 @@ describe('Home page: without repositories', () => {
33
33
  HomeSteps.getRepositoryErrorsWidget().should('be.visible');
34
34
  RepositoryErrorsWidgetSteps.getInfoMessage().should('contain', 'Some functionalities are not available because you are not connected to any repository.');
35
35
  RepositoryErrorsWidgetSteps.getCreateRepositoryBtn().should('be.visible');
36
- RepositoryErrorsWidgetSteps.getShowRemoteLocationsBtn().should('be.visible');
36
+ // There are no repositories to filter.
37
+ RepositoryErrorsWidgetSteps.getRepositoryFilter().should('not.exist');
38
+ RepositoryErrorsWidgetSteps.getLocalOnlyCheckbox().should('not.exist');
37
39
  });
38
40
 
39
41
  it('should render license widget', () => {
@@ -29,7 +29,8 @@ describe('Home page: without selected repository', () => {
29
29
  HomeSteps.getRepositoryErrorsWidget().should('be.visible');
30
30
  RepositoryErrorsWidgetSteps.getInfoMessage().should('contain', 'Some functionalities are not available because you are not connected to any repository.');
31
31
  RepositoryErrorsWidgetSteps.getCreateRepositoryBtn().should('be.visible');
32
- RepositoryErrorsWidgetSteps.getShowRemoteLocationsBtn().should('be.visible');
32
+ RepositoryErrorsWidgetSteps.getRepositoryFilter().should('be.visible');
33
+ RepositoryErrorsWidgetSteps.getLocalOnlyCheckbox().should('be.visible').and('be.checked');
33
34
  });
34
35
 
35
36
  // This test is unreliable with the current implementation of the license widget.
@@ -245,48 +245,42 @@ describe('Ontop repositories', () => {
245
245
  context('Repository maintenance permission', () => {
246
246
 
247
247
  const PASSWORD = 'root';
248
- const REPOSITORY_MAINTAINER_USERNAME = 'repoMaintainer';
249
- const REPOSITORY_MANAGER_USERNAME = 'repoManager';
248
+ let repositoryMaintainerUsername;
250
249
 
251
250
  beforeEach(() => {
252
- cy.createUser({
253
- username: REPOSITORY_MAINTAINER_USERNAME,
254
- password: PASSWORD,
255
- grantedAuthorities: [
256
- `READ_REPO_${repositoryId}`,
257
- `MAINTAIN_REPO_${repositoryId}`,
258
- `WRITE_REPO_${repositoryId}`
259
- ]
260
- });
261
- cy.createUser({
262
- username: REPOSITORY_MANAGER_USERNAME,
263
- password: PASSWORD,
264
- grantedAuthorities: [
265
- 'ROLE_USER',
266
- 'ROLE_MONITORING',
267
- 'ROLE_REPO_MANAGER'
268
- ]
269
- });
270
- cy.switchOnSecurity();
251
+ repositoryMaintainerUsername = 'repo-maintainer-' + Date.now();
271
252
  });
272
253
 
273
254
  afterEach(() => {
274
255
  cy.loginAsAdmin()
275
256
  .then(() => {
276
- cy.deleteUser(REPOSITORY_MAINTAINER_USERNAME, true);
277
- cy.deleteUser(REPOSITORY_MANAGER_USERNAME, true);
257
+ cy.deleteUser(repositoryMaintainerUsername, true);
278
258
  cy.switchOffSecurity(true);
279
259
  });
280
260
  });
281
261
  it('should allow a repository maintainer to edit an Ontop repository', () => {
282
262
  RepositoryStubs.spyGetJDBCProperties();
283
263
  // GIVEN: An Ontop repository exists
284
- cy.loginAs(REPOSITORY_MANAGER_USERNAME, PASSWORD);
285
264
  OntopRepositorySteps.visitCreate();
286
265
  createOntopRepository(repositoryId);
266
+ RepositorySteps.waitUntilRepositoriesPageIsLoaded();
267
+ RepositorySteps.getRepositoryFromList(repositoryId).should('exist');
268
+
269
+ // AND: A user with maintenance permission for it is created after the repository,
270
+ // because creating a repository removes the permissions already granted for its ID.
271
+ cy.createUser({
272
+ username: repositoryMaintainerUsername,
273
+ password: PASSWORD,
274
+ grantedAuthorities: [
275
+ `READ_REPO_${repositoryId}`,
276
+ `MAINTAIN_REPO_${repositoryId}`,
277
+ `WRITE_REPO_${repositoryId}`
278
+ ]
279
+ });
280
+ cy.switchOnSecurity();
287
281
 
288
282
  // WHEN: I log in as a user with maintenance permission
289
- cy.loginAs(REPOSITORY_MAINTAINER_USERNAME, PASSWORD);
283
+ cy.loginAs(repositoryMaintainerUsername, PASSWORD);
290
284
  RepositorySteps.visit();
291
285
 
292
286
  // THEN: The repository is visible because the user can maintain it
@@ -326,8 +320,7 @@ describe('Ontop repositories', () => {
326
320
  .should('contain.value', 'ontop.cardinalityMode=LOOSE');
327
321
  // Saving of the OBDA file verifies that the repository maintainer can access rest/repositories/file/upload
328
322
  OntopRepositorySteps.editOBDAFile();
329
- ModalDialogSteps.getDialogBody()
330
- .find('textarea')
323
+ OntopRepositorySteps.getFileContentEditor()
331
324
  .invoke('val')
332
325
  .should('include', 'edited ODBA file');
333
326
  ModalDialogSteps.close();
@@ -339,8 +332,7 @@ describe('Ontop repositories', () => {
339
332
  ModalDialogSteps.getDialogHeader()
340
333
  .should('contain', 'Edit "OBDA or R2RML file" contents');
341
334
 
342
- ModalDialogSteps.getDialogBody()
343
- .find('textarea')
335
+ OntopRepositorySteps.getFileContentEditor()
344
336
  .type('{moveToStart}Add commentary for testing purpose');
345
337
 
346
338
  ModalDialogSteps.clickOKButton();
@@ -354,8 +346,7 @@ describe('Ontop repositories', () => {
354
346
  cy.wait('@getJDBCProperties');
355
347
  OntopRepositorySteps.editOBDAFile();
356
348
 
357
- ModalDialogSteps.getDialogBody()
358
- .find('textarea')
349
+ OntopRepositorySteps.getFileContentEditor()
359
350
  .invoke('val')
360
351
  .should('include', 'Add commentary for testing purpose');
361
352
  });
@@ -22,7 +22,7 @@ describe('Plugins without selected repository', () => {
22
22
  const verifyInitialStateWithoutSelectedRepository = () => {
23
23
  ErrorSteps.verifyNoConnectedRepoMessage();
24
24
  PluginsSteps.getPluginsView().should('be.visible');
25
- PluginsSteps.getSearchPluginBar().should('not.be.visible');
25
+ PluginsSteps.getSearchPluginBar().should('not.exist');
26
26
  PluginsSteps.getPluginsList().should('not.exist');
27
27
  };
28
28
  })
@@ -0,0 +1,149 @@
1
+ @prefix gn: <http://www.ontotext.com/graph-navigator#> .
2
+
3
+ gn:settings gn:defaultPrefix """PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
4
+ PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
5
+ PREFIX owl: <http://www.w3.org/2002/07/owl#>
6
+ """;
7
+ gn:schemaLabelProperty "rdfs:label";
8
+ gn:dataLabelProperty "rdfs:label";
9
+ gn:classTreeQuery """
10
+ SELECT ?class ?label ?parent
11
+ WHERE {
12
+ {
13
+ ?class a rdfs:Class
14
+ } UNION {
15
+ ?class a owl:Class
16
+ }
17
+ FILTER ISIRI(?class)
18
+ OPTIONAL {
19
+ ?class rdfs:label ?label
20
+ ${labelLanguageFilter}
21
+ }
22
+ OPTIONAL {?class rdfs:subClassOf ?parent. FILTER ISIRI(?parent)}
23
+ }
24
+ """;
25
+ gn:classInfoQuery """SELECT ?class ?label ?instcount WHERE {
26
+ VALUES(?class) {${ids}}
27
+ OPTIONAL {
28
+ ?class ${schemaLabelProperty} ?label
29
+ ${labelLanguageFilter}
30
+ }
31
+ BIND(\"\" as ?instcount)
32
+ }""";
33
+ gn:linkTypesQuery """SELECT DISTINCT ?link ?instcount ?label WHERE {
34
+ ${linkTypesPattern}
35
+ OPTIONAL {
36
+ ?link ${schemaLabelProperty} ?label
37
+ ${labelLanguageFilter}
38
+ }
39
+ }""";
40
+ gn:linkTypesPattern """
41
+ { ?link a rdf:Property }
42
+ UNION
43
+ { ?link a owl:ObjectProperty }
44
+ BIND('' as ?instcount)
45
+ """;
46
+ gn:linkTypesInfoQuery """SELECT ?link ?label WHERE {
47
+ VALUES(?link) {${ids}}
48
+ OPTIONAL {
49
+ ?link ${schemaLabelProperty} ?label
50
+ ${labelLanguageFilter}
51
+ }
52
+ }""";
53
+ gn:propertyInfoQuery """SELECT ?property ?label WHERE {
54
+ VALUES(?property) {${ids}}
55
+ OPTIONAL {
56
+ ?property ${schemaLabelProperty} ?label
57
+ ${labelLanguageFilter}
58
+ }
59
+ }""";
60
+ gn:elementInfoQuery """
61
+ CONSTRUCT {
62
+ ?inst <urn:reactodia:sparql:type> ?class .
63
+ ?inst <urn:reactodia:sparql:label> ?label .
64
+ ?inst ?propType ?propValue.
65
+ } WHERE {
66
+ VALUES (?inst) {${ids}}
67
+ OPTIONAL { ?inst a ?class }
68
+ OPTIONAL {
69
+ ?inst ${dataLabelProperty} ?label
70
+ ${labelLanguageFilter}
71
+ }
72
+ OPTIONAL {
73
+ ${propertyConfigurations}
74
+ FILTER (isLiteral(?propValue))
75
+ ${valueLanguageFilter}
76
+ }
77
+ }
78
+ """;
79
+ gn:linksInfoQuery """SELECT ?source ?type ?target
80
+ WHERE {
81
+ ${linkConfigurations}
82
+ VALUES (?source) {${sourceIris}}
83
+ VALUES (?target) {${targetIris}}
84
+ }""";
85
+ gn:imageQueryPattern "{ ?inst ?linkType ?image } UNION { [] ?linkType ?inst. BIND(?inst as ?image) }";
86
+ gn:linkTypesOfQuery """
87
+ SELECT DISTINCT ?link ?direction
88
+ WHERE {
89
+ ${linkConfigurations}
90
+ }
91
+ """;
92
+ gn:linkTypesStatisticsQuery """
93
+ SELECT ?link ?outCount ?inCount
94
+ WHERE {
95
+ {
96
+ SELECT (${linkId} as ?link) (count(?outObject) as ?outCount) WHERE {
97
+ ${linkConfigurationOut}
98
+ ${navigateElementFilterOut}
99
+ } LIMIT 101
100
+ } {
101
+ SELECT (${linkId} as ?link) (count(?inObject) as ?inCount) WHERE {
102
+ ${linkConfigurationIn}
103
+ ${navigateElementFilterIn}
104
+ } LIMIT 101
105
+ }
106
+ }
107
+ """;
108
+ gn:lookupQuery """SELECT ${outerProjection} WHERE {
109
+ ${filterInnerPrelude}
110
+ {
111
+ SELECT DISTINCT ${innerProjection} WHERE {
112
+ ${filterByType}
113
+ ${filterByRefElementLink}
114
+ ${filterByText}
115
+ ${filterAdditionalRestriction}
116
+ } ${orderBy} ${limit}
117
+ }
118
+ ${queryTypes}
119
+ ${queryElementInfo}
120
+ } ${orderBy}""";
121
+ gn:filterInnerPrelude "";
122
+ gn:filterRefElementLinkPattern "";
123
+ gn:filterTypePattern "?inst a ?instType. ?instType rdfs:subClassOf* ?class";
124
+ gn:filterElementInfoPattern """
125
+ OPTIONAL {?inst rdf:type ?foundClass}
126
+ BIND (coalesce(?foundClass, owl:Thing) as ?class)
127
+ OPTIONAL {
128
+ ?inst ${dataLabelProperty} ?label
129
+ ${labelLanguageFilter}
130
+ }
131
+ """;
132
+ gn:filterAdditionalRestriction "";
133
+ gn:openWorldLinks false;
134
+ gn:openWorldProperties "no";
135
+ gn:acceptBlankNodes "no";
136
+ gn:unknownSetting "x";
137
+ gn:blankNodeStatementLimit "20"^^<http://www.w3.org/2001/XMLSchema#int>;
138
+ gn:filterOnlyLanguages [ a <http://www.w3.org/1999/02/22-rdf-syntax-ns#List>;
139
+ <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "en";
140
+ <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>
141
+ ];
142
+ gn:fullTextSearch [
143
+ gn:prefix "";
144
+ gn:queryPattern """?inst ${dataLabelProperty} ?search1
145
+ FILTER regex(COALESCE(str(?search1)), \"${text}\", \"i\")
146
+ BIND(0 as ?score)
147
+ """;
148
+ gn:extractLabel true
149
+ ] .
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "4.0.0-TR14",
3
+ "version": "4.0.0-TR16",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "graphdb-workbench-tests",
9
- "version": "4.0.0-TR14",
9
+ "version": "4.0.0-TR16",
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
12
  "@bahmutov/cypress-code-coverage": "^2.7.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "4.0.0-TR14",
3
+ "version": "4.0.0-TR16",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,7 +1,7 @@
1
1
  export class ErrorSteps {
2
2
 
3
3
  static getRepositoryErrors() {
4
- return cy.get('.card.repository-errors')
4
+ return cy.get('.repository-errors')
5
5
  }
6
6
 
7
7
  static verifyError(errorMessage) {
@@ -44,6 +44,20 @@ export class GraphNavigatorSteps extends BaseSteps {
44
44
  return GraphNavigatorSteps.getCanvas().find(`[data-element-id]`).contains(text).first();
45
45
  }
46
46
 
47
+ static getSearchInput() {
48
+ return GraphNavigatorSteps.getComponent().find('.reactodia-unified-search__search-input');
49
+ }
50
+
51
+ static getSearchSectionTab(name) {
52
+ return GraphNavigatorSteps.getComponent().find('.reactodia-unified-search__section-tab').contains(name);
53
+ }
54
+
55
+ static searchEntities(text) {
56
+ GraphNavigatorSteps.getSearchInput().click();
57
+ GraphNavigatorSteps.getSearchSectionTab('Entities').click();
58
+ GraphNavigatorSteps.getSearchInput().clear().type(`${text}{enter}`);
59
+ }
60
+
47
61
  static getSettingsButton() {
48
62
  return cy.get('[data-test="graph-navigator-settings-btn"]');
49
63
  }
@@ -73,6 +87,14 @@ export class GraphNavigatorSteps extends BaseSteps {
73
87
  return GraphNavigatorSteps.getSettingsPopover().contains(fileName);
74
88
  }
75
89
 
90
+ static getUploadErrors() {
91
+ return this.getByTestId('graph-navigator-settings-upload-errors');
92
+ }
93
+
94
+ static getUploadError(property) {
95
+ return GraphNavigatorSteps.getUploadErrors().contains('[data-test="graph-navigator-settings-upload-error"]', property);
96
+ }
97
+
76
98
  static getUploadButton() {
77
99
  return GraphNavigatorSteps.getSettingsPopover().find('.p-fileupload-upload-button');
78
100
  }
@@ -25,6 +25,10 @@ export class OntopRepositorySteps {
25
25
  OntopRepositorySteps.getOBDAFileFieldEditButton().click();
26
26
  }
27
27
 
28
+ static getFileContentEditor() {
29
+ return cy.getByTestId('repository-file-content');
30
+ }
31
+
28
32
  static getOntologyFileField() {
29
33
  return cy.get('div').contains("Ontology file");
30
34
  }
@@ -190,7 +190,7 @@ export class AclManagementSteps {
190
190
  }
191
191
 
192
192
  static getWarningIcon(index) {
193
- return this.getSavedRoleField(index).get('.ri-alert-line');
193
+ return this.getSavedRoleField(index).find('.ri-alert-line');
194
194
  }
195
195
 
196
196
  static getWarningIconTooltipText(index) {
@@ -3,6 +3,10 @@ export class ToasterSteps {
3
3
  return cy.get('.toast');
4
4
  }
5
5
 
6
+ static getWarningToast() {
7
+ return ToasterSteps.getToast().filter('.warning');
8
+ }
9
+
6
10
  static verifyTitle(title) {
7
11
  return ToasterSteps.getToast()
8
12
  .find('.toast-title')
@@ -7,8 +7,12 @@ export class RepositoryErrorsWidgetSteps {
7
7
  return RepositoryErrorsWidgetSteps.getWidget().find('.create-repository-btn');
8
8
  }
9
9
 
10
- static getShowRemoteLocationsBtn() {
11
- return RepositoryErrorsWidgetSteps.getWidget().find('.show-remote-locations-btn');
10
+ static getRepositoryFilter() {
11
+ return RepositoryErrorsWidgetSteps.getWidget().getByTestId('core-errors-repository-filter');
12
+ }
13
+
14
+ static getLocalOnlyCheckbox() {
15
+ return RepositoryErrorsWidgetSteps.getWidget().getByTestId('core-errors-local-only-checkbox');
12
16
  }
13
17
 
14
18
  static getInfoMessage() {
@@ -0,0 +1,27 @@
1
+ import {Stubs} from './stubs';
2
+
3
+ export class GraphNavigatorStubs extends Stubs {
4
+ /**
5
+ * Makes the full-text search of the Graph Navigator settings use the GraphDB autocomplete index.
6
+ */
7
+ static stubSettingsWithAutocomplete() {
8
+ cy.intercept('GET', '/rest/repositories/*/graph-navigator/settings', (req) => {
9
+ req.continue((res) => {
10
+ res.body.fullTextSearch.prefix = 'PREFIX auto: <http://www.ontotext.com/plugins/autocomplete#>';
11
+ });
12
+ }).as('graph-navigator-settings');
13
+ }
14
+
15
+ /**
16
+ * Aliases the SPARQL requests that look up entities by the given text as `entity-lookup`.
17
+ */
18
+ static spyEntityLookup(text) {
19
+ cy.intercept('POST', '/repositories/*', (req) => {
20
+ // The body is form-encoded (`query=...`), so decode it to match the SPARQL text.
21
+ const body = new URLSearchParams(String(req.body)).get('query') ?? '';
22
+ if (body.includes('SELECT ?inst ?class ?label WHERE') && body.includes(text)) {
23
+ req.alias = 'entity-lookup';
24
+ }
25
+ });
26
+ }
27
+ }