graphdb-workbench-tests 4.0.0-TR6 → 4.0.0-TR8
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/e2e-flaky/import/import-server-files-operations.spec.js +1 -23
- package/e2e-legacy/import/import-server-files.spec.js +3 -5
- package/e2e-legacy/import/import-user-data-text-snippet.spec.js +0 -39
- package/e2e-legacy/import/import-user-data-url.spec.js +6 -3
- package/e2e-legacy/rdf-version/rdf-version-accept-header.spec.js +145 -0
- package/e2e-legacy/reactodia/reactodia-restrictions.spec.js +200 -0
- package/e2e-legacy/reactodia/reactodia.spec.js +129 -0
- package/e2e-legacy/resource/resource.spec.js +176 -39
- package/e2e-legacy/setup/aclmanagement/create-rule.spec.js +14 -25
- package/e2e-legacy/setup/aclmanagement/delete-rule.spec.js +6 -6
- package/e2e-legacy/setup/aclmanagement/edit-rule.spec.js +15 -15
- package/e2e-legacy/setup/aclmanagement/render-rules.spec.js +1 -1
- package/e2e-legacy/setup/aclmanagement/reorder-rules.spec.js +2 -2
- package/e2e-legacy/setup/aclmanagement/revert-rules.spec.js +2 -2
- package/e2e-legacy/setup/aclmanagement/update-rules.spec.js +3 -3
- package/e2e-legacy/setup/aclmanagement/validate-uri.spec.js +152 -0
- package/e2e-legacy/sparql-editor/yasr/download-as.spec.js +4 -7
- package/fixtures/graphdb-import/wine.rdf +279 -285
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/steps/base-steps.js +4 -0
- package/steps/import/import-test-constants.js +1 -1
- package/steps/main-menu-steps.js +9 -0
- package/steps/page-restrictions-steps.js +24 -0
- package/steps/reactodia-steps.js +42 -0
- package/steps/repository-picker-list-steps.js +40 -0
- package/steps/repository-steps.js +4 -0
- package/steps/resource/resource-steps.js +72 -5
- package/steps/setup/acl-management-steps.js +3 -23
- package/fixtures/graphdb-import/test-trigstar.trigs +0 -32
- package/fixtures/graphdb-import/test_turtlestar.ttls +0 -6
- package/fixtures/graphdb-import/turtlestar-data.ttls +0 -77
|
@@ -9,8 +9,6 @@ describe('Import server files - Operations', () => {
|
|
|
9
9
|
const CONTEXT = 'http://example.org/context';
|
|
10
10
|
const FILE_FOR_IMPORT = 'italian_public_schools_links.nt.gz';
|
|
11
11
|
const FILE_FROM_DIRECTORY_FOR_IMPORT = 'rdfxml.rdf';
|
|
12
|
-
const TTLS_FOR_IMPORT = 'test_turtlestar.ttls';
|
|
13
|
-
const TRIGS_FOR_IMPORT = 'test-trigstar.trigs';
|
|
14
12
|
const JSONLD_FILE_FOR_IMPORT = '0007-import-file.jsonld';
|
|
15
13
|
const JSONLD_CONTEXT = 'https://w3c.github.io/json-ld-api/tests/compact/0007-context.jsonld';
|
|
16
14
|
|
|
@@ -18,7 +16,7 @@ describe('Import server files - Operations', () => {
|
|
|
18
16
|
repositoryId = 'server-import-' + Date.now();
|
|
19
17
|
cy.createRepository({id: repositoryId});
|
|
20
18
|
ImportServerFilesSteps.visitServerImport(repositoryId);
|
|
21
|
-
ImportServerFilesSteps.getResources().should('have.length',
|
|
19
|
+
ImportServerFilesSteps.getResources().should('have.length', 17);
|
|
22
20
|
});
|
|
23
21
|
|
|
24
22
|
afterEach(() => {
|
|
@@ -119,24 +117,4 @@ describe('Import server files - Operations', () => {
|
|
|
119
117
|
// Then Import status of the file should not be visible
|
|
120
118
|
ImportServerFilesSteps.getResourceStatus(FILE_FROM_DIRECTORY_FOR_IMPORT).should('be.hidden');
|
|
121
119
|
});
|
|
122
|
-
|
|
123
|
-
it('Should import turtlestar from Server files successfully without changing settings', () => {
|
|
124
|
-
// Given I have opened the server files tab
|
|
125
|
-
ImportServerFilesSteps.importResourceByName(TTLS_FOR_IMPORT);
|
|
126
|
-
// When I select to import a ttl file without changing settings
|
|
127
|
-
ImportSettingsDialogSteps.import();
|
|
128
|
-
// Then I should see the file imported successfully
|
|
129
|
-
ImportServerFilesSteps.checkImportedResourceByIndex(0, TTLS_FOR_IMPORT);
|
|
130
|
-
// ImportSteps.verifyImportStatusDetails(TTLS_FOR_IMPORT, '"preserveBNodeIds": false,');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('Should import trigstar from Server files successfully without changing settings', () => {
|
|
134
|
-
// Given I have opened the server files tab
|
|
135
|
-
ImportServerFilesSteps.importResourceByName(TRIGS_FOR_IMPORT);
|
|
136
|
-
// When I select to import a trigstar file without changing settings
|
|
137
|
-
ImportSettingsDialogSteps.import();
|
|
138
|
-
// Then I should see the file imported successfully
|
|
139
|
-
ImportServerFilesSteps.checkImportedResourceByIndex(0, TRIGS_FOR_IMPORT);
|
|
140
|
-
// ImportSteps.verifyImportStatusDetails(TRIGS_FOR_IMPORT, '"preserveBNodeIds": false,');
|
|
141
|
-
});
|
|
142
120
|
});
|
|
@@ -165,8 +165,7 @@ describe('Import server files', () => {
|
|
|
165
165
|
ImportServerFilesSteps.getResourceTitleRow(6).should('contain', "import-resource-with-long-error.rdf");
|
|
166
166
|
// checks files in root
|
|
167
167
|
ImportServerFilesSteps.getResourceTitleRow(7).should('contain', "bnodes.ttl");
|
|
168
|
-
ImportServerFilesSteps.getResourceTitleRow(8).should('contain', "
|
|
169
|
-
ImportServerFilesSteps.getResourceTitleRow(9).should('contain', "0007-import-file.jsonld");
|
|
168
|
+
ImportServerFilesSteps.getResourceTitleRow(8).should('contain', "0007-import-file.jsonld");
|
|
170
169
|
|
|
171
170
|
// When I change the order by size.
|
|
172
171
|
ImportServerFilesSteps.orderBySize();
|
|
@@ -182,9 +181,8 @@ describe('Import server files', () => {
|
|
|
182
181
|
ImportServerFilesSteps.getResourceTitleRow(5).should('contain', "rdfxml.rdf");
|
|
183
182
|
ImportServerFilesSteps.getResourceTitleRow(6).should('contain', "jsonld-file.jsonld");
|
|
184
183
|
// checks files in root
|
|
185
|
-
ImportServerFilesSteps.getResourceTitleRow(
|
|
186
|
-
ImportServerFilesSteps.getResourceTitleRow(
|
|
187
|
-
ImportServerFilesSteps.getResourceTitleRow(19).should('contain', "bnodes.ttl");
|
|
184
|
+
ImportServerFilesSteps.getResourceTitleRow(15).should('contain', "0007-import-file.jsonld");
|
|
185
|
+
ImportServerFilesSteps.getResourceTitleRow(16).should('contain', "bnodes.ttl");
|
|
188
186
|
});
|
|
189
187
|
|
|
190
188
|
it('should allow importing jsonld with empty "JSON-LD Context"', () => {
|
|
@@ -21,25 +21,6 @@ describe('Import user data: Text snippet', () => {
|
|
|
21
21
|
'ab:richard ab:email "richard49@hotmail.com".\n' +
|
|
22
22
|
'ab:richard ab:email "richard491@hotmail.com".';
|
|
23
23
|
|
|
24
|
-
const TURTLESTAR_SNIPPET = '@prefix ex:<http:/base.org/> .\n' +
|
|
25
|
-
'ex:foo ex:pred ex:obj .\n' +
|
|
26
|
-
'<<ex:foo rdfs:label "label">> ex:author "guest" .\n' +
|
|
27
|
-
'ex:obj ex:quote <<ex:meta ex:data ex:foo>> .\n' +
|
|
28
|
-
'<<<<ex:foo rdfs:label "label">> ex:data ex:foo>> ex:recursive true .';
|
|
29
|
-
|
|
30
|
-
const TRIGSTAR_SNIPPET = '@prefix ex: <http://example.com/> .\n' +
|
|
31
|
-
'@prefix dct: <http://purl.org/dc/terms/> .\n' +
|
|
32
|
-
'@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n' +
|
|
33
|
-
'@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n' +
|
|
34
|
-
'graph ex:rdfstar {\n' +
|
|
35
|
-
' ex:bob foaf:knows << ex:alice foaf:knows<<ex:bob dct:created ex:book>> >> .\n' +
|
|
36
|
-
' <<<< ex:bob dct:created ex:book >> foaf:knows ex:alice >> dct:source ex:otherbook .\n' +
|
|
37
|
-
' ex:bobshomepage dct:source<< ex:book dct:creator ex:alice >> .\n' +
|
|
38
|
-
' << ex:book dct:creator ex:alice >> dct:source ex:bobshomepage .\n' +
|
|
39
|
-
' << ex:book dct:creator ex:alice >> dct:requires << ex:alice dct:created ex:book >> .\n' +
|
|
40
|
-
' <<<http://example.org/a>ex:b ex:c>>ex:valid "1999-08-16"^^xsd:date .\n' +
|
|
41
|
-
'}';
|
|
42
|
-
|
|
43
24
|
const JSONLD_TEXT_SNIPPET = '[\n' +
|
|
44
25
|
' {\n' +
|
|
45
26
|
' "@id": "http://www.w3.org/1999/02/22-rdf-syntax-ns#Property",\n' +
|
|
@@ -55,8 +36,6 @@ describe('Import user data: Text snippet', () => {
|
|
|
55
36
|
const CONTEXT = 'http://example.org/graph';
|
|
56
37
|
const TEXT_SNIPPET = 'Text snippet';
|
|
57
38
|
const JSONLD_FORMAT = 'JSON-LD';
|
|
58
|
-
const VALID_SNIPPET_TURTLESTAR_FORMAT = 'Turtle*';
|
|
59
|
-
const VALID_SNIPPET_TRIGSTAR_FORMAT = 'TriG*';
|
|
60
39
|
const VALID_SNIPPET_RDF_FORMAT = 'Turtle';
|
|
61
40
|
const RDF_ERROR_MESSAGE = 'RDF Parse Error:';
|
|
62
41
|
|
|
@@ -96,24 +75,6 @@ describe('Import user data: Text snippet', () => {
|
|
|
96
75
|
ImportUserDataSteps.checkImportedResourceByIndex(0, TEXT_SNIPPET);
|
|
97
76
|
});
|
|
98
77
|
|
|
99
|
-
it('Should import Turtle* text snippet successfully with valid RDF star format selected', () => {
|
|
100
|
-
ImportUserDataSteps.openImportTextSnippetDialog();
|
|
101
|
-
ImportUserDataSteps.fillRDFTextSnippet(TURTLESTAR_SNIPPET);
|
|
102
|
-
ImportUserDataSteps.selectRDFFormat(VALID_SNIPPET_TURTLESTAR_FORMAT);
|
|
103
|
-
ImportUserDataSteps.clickImportTextSnippetButton();
|
|
104
|
-
ImportSettingsDialogSteps.import();
|
|
105
|
-
ImportUserDataSteps.checkImportedResourceByIndex(0, TEXT_SNIPPET);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('Should import TriG* text snippet successfully with valid RDF star format selected', () => {
|
|
109
|
-
ImportUserDataSteps.openImportTextSnippetDialog();
|
|
110
|
-
ImportUserDataSteps.fillRDFTextSnippet(TRIGSTAR_SNIPPET);
|
|
111
|
-
ImportUserDataSteps.selectRDFFormat(VALID_SNIPPET_TRIGSTAR_FORMAT);
|
|
112
|
-
ImportUserDataSteps.clickImportTextSnippetButton();
|
|
113
|
-
ImportSettingsDialogSteps.import();
|
|
114
|
-
ImportUserDataSteps.checkImportedResourceByIndex(0, TEXT_SNIPPET);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
78
|
it('Should import RDF text snippet successfully with filled base URI and context', () => {
|
|
118
79
|
ImportUserDataSteps.openImportTextSnippetDialog();
|
|
119
80
|
ImportUserDataSteps.fillRDFTextSnippet(RDF_TEXT_SNIPPET_2);
|
|
@@ -54,7 +54,8 @@ describe('Import user data: URL import', () => {
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// FIXME: wine.rdf contains DOCTYPE which is forbidden in the TR for GDB 12
|
|
58
|
+
it.skip('Test import file via URL successfully with Auto format selected', () => {
|
|
58
59
|
ImportUserDataSteps.openImportURLDialog(IMPORT_URL);
|
|
59
60
|
ImportUserDataSteps.clickImportUrlButton();
|
|
60
61
|
// Without changing settings
|
|
@@ -62,7 +63,8 @@ describe('Import user data: URL import', () => {
|
|
|
62
63
|
ImportUserDataSteps.checkImportedResourceByIndex(0, IMPORT_URL);
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
// FIXME: wine.rdf contains DOCTYPE which is forbidden in the TR for GDB 12. Expected error message is different.
|
|
67
|
+
it.skip('Test import file via URL with invalid RDF format selected', () => {
|
|
66
68
|
ImportUserDataSteps.openImportURLDialog(IMPORT_URL);
|
|
67
69
|
ImportUserDataSteps.selectRDFFormat(JSONLD_FORMAT);
|
|
68
70
|
ImportUserDataSteps.clickImportUrlButton();
|
|
@@ -70,7 +72,8 @@ describe('Import user data: URL import', () => {
|
|
|
70
72
|
ImportUserDataSteps.checkImportedResourceByIndex(0, IMPORT_URL, RDF_ERROR_MESSAGE);
|
|
71
73
|
});
|
|
72
74
|
|
|
73
|
-
|
|
75
|
+
// FIXME: wine.rdf contains DOCTYPE which is forbidden in the TR for GDB 12
|
|
76
|
+
it.skip('Test import file via URL successfully with valid RDF format selected', () => {
|
|
74
77
|
ImportUserDataSteps.openImportURLDialog(IMPORT_URL);
|
|
75
78
|
ImportUserDataSteps.selectRDFFormat(VALID_URL_RDF_FORMAT);
|
|
76
79
|
ImportUserDataSteps.clickImportUrlButton();
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {SparqlEditorSteps} from "../../steps/sparql-editor-steps";
|
|
2
|
+
import {YasguiSteps} from "../../steps/yasgui/yasgui-steps";
|
|
3
|
+
import {YasqeSteps} from "../../steps/yasgui/yasqe-steps";
|
|
4
|
+
import {YasrSteps} from "../../steps/yasgui/yasr-steps";
|
|
5
|
+
import {QueryStubs} from "../../stubs/yasgui/query-stubs";
|
|
6
|
+
import {GraphsOverviewSteps} from "../../steps/explore/graphs-overview-steps";
|
|
7
|
+
import {JsonLdModalSteps} from "../../steps/json-ld-modal-steps";
|
|
8
|
+
|
|
9
|
+
// The workbench requests RDF 1.2 by adding the "version" media type parameter to the Accept header.
|
|
10
|
+
// The parameter must be present on every RDF media range and must precede the weight ("q"),
|
|
11
|
+
// because anything after the weight is not a media type parameter.
|
|
12
|
+
const SELECT_QUERY_ACCEPT = 'application/x-sparqlstar-results+json;version=1.2, application/sparql-results+json;version=1.2;q=0.9, */*;version=1.2;q=0.8';
|
|
13
|
+
const CONSTRUCT_QUERY_ACCEPT = 'application/x-graphdb-table-results+json;version=1.2, application/rdf+json;version=1.2;q=0.9, */*;version=1.2;q=0.8';
|
|
14
|
+
const JSONLD_EXPANDED_ACCEPT = 'application/ld+json;profile=http://www.w3.org/ns/json-ld#expanded;version=1.2';
|
|
15
|
+
|
|
16
|
+
describe('RDF version in the Accept header', () => {
|
|
17
|
+
let repositoryId;
|
|
18
|
+
|
|
19
|
+
afterEach(() => {
|
|
20
|
+
cy.deleteRepository(repositoryId);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('SPARQL editor', () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
repositoryId = 'rdf-version-sparql-' + Date.now();
|
|
26
|
+
QueryStubs.stubQueryCountResponse();
|
|
27
|
+
cy.createRepository({id: repositoryId});
|
|
28
|
+
cy.presetRepository(repositoryId);
|
|
29
|
+
QueryStubs.stubDefaultQueryResponse(repositoryId);
|
|
30
|
+
|
|
31
|
+
SparqlEditorSteps.visitSparqlEditorPage();
|
|
32
|
+
YasguiSteps.getYasgui().should('be.visible');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should request RDF 1.2 when executing a SELECT query', () => {
|
|
36
|
+
// Given I am about to execute the default SELECT query
|
|
37
|
+
cy.intercept('POST', `/repositories/${repositoryId}`).as('query');
|
|
38
|
+
|
|
39
|
+
// When I execute it
|
|
40
|
+
YasqeSteps.executeQuery();
|
|
41
|
+
|
|
42
|
+
// Then every media range of the Accept header should request RDF 1.2
|
|
43
|
+
verifyAcceptHeader('@query', SELECT_QUERY_ACCEPT);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should request RDF 1.2 when executing a CONSTRUCT query', () => {
|
|
47
|
+
// Given I am about to execute a CONSTRUCT query
|
|
48
|
+
cy.intercept('POST', `/repositories/${repositoryId}`).as('query');
|
|
49
|
+
|
|
50
|
+
// When I execute it
|
|
51
|
+
pasteAndExecuteConstructQuery();
|
|
52
|
+
|
|
53
|
+
// Then every media range of the Accept header should request RDF 1.2
|
|
54
|
+
verifyAcceptHeader('@query', CONSTRUCT_QUERY_ACCEPT);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should request RDF 1.2 when downloading SELECT results', () => {
|
|
58
|
+
// Given I have executed a SELECT query
|
|
59
|
+
YasqeSteps.executeQuery();
|
|
60
|
+
cy.intercept('POST', `/repositories/${repositoryId}`).as('download');
|
|
61
|
+
|
|
62
|
+
// When I download the results as XML
|
|
63
|
+
YasrSteps.openDownloadAsDropdown();
|
|
64
|
+
YasrSteps.selectDownloadAsOption(1);
|
|
65
|
+
|
|
66
|
+
// Then the download request should ask for RDF 1.2
|
|
67
|
+
verifyAcceptHeader('@download', 'application/sparql-results+xml;version=1.2');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should request RDF 1.2 when downloading CONSTRUCT results as JSON-LD', () => {
|
|
71
|
+
// Given I have executed a CONSTRUCT query
|
|
72
|
+
pasteAndExecuteConstructQuery();
|
|
73
|
+
cy.intercept('POST', `/repositories/${repositoryId}`).as('download');
|
|
74
|
+
|
|
75
|
+
// When I download the results as JSON-LD with the default settings
|
|
76
|
+
YasrSteps.openDownloadAsDropdown();
|
|
77
|
+
YasrSteps.selectDownloadAsOption(1);
|
|
78
|
+
JsonLdModalSteps.clickExportJSONLD();
|
|
79
|
+
|
|
80
|
+
// Then the version should follow the JSON-LD profile
|
|
81
|
+
verifyAcceptHeader('@download', JSONLD_EXPANDED_ACCEPT);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Graphs overview', () => {
|
|
86
|
+
beforeEach(() => {
|
|
87
|
+
repositoryId = 'rdf-version-graphs-' + Date.now();
|
|
88
|
+
cy.createRepository({id: repositoryId});
|
|
89
|
+
cy.presetRepository(repositoryId);
|
|
90
|
+
cy.importRDFTextSnippet(repositoryId, '<urn:s> <urn:p> <urn:o> .');
|
|
91
|
+
|
|
92
|
+
GraphsOverviewSteps.visit();
|
|
93
|
+
GraphsOverviewSteps.getResults().should('have.length.at.least', 1);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should request RDF 1.2 when exporting the repository', () => {
|
|
97
|
+
// Given the export opens the download URL in a new window
|
|
98
|
+
cy.window().then((win) => {
|
|
99
|
+
cy.stub(win, 'open').returns({closed: true}).as('windowOpen');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// When I export the repository as TriG
|
|
103
|
+
GraphsOverviewSteps.exportRepository();
|
|
104
|
+
cy.get('.export-repo-format-TriG').eq(0).click();
|
|
105
|
+
|
|
106
|
+
// Then the Accept parameter of the download URL should request RDF 1.2
|
|
107
|
+
cy.get('@windowOpen').should('have.been.calledOnce')
|
|
108
|
+
.its('firstCall.args.0')
|
|
109
|
+
.should('contain', '&Accept=' + encodeURIComponent('application/x-trig;version=1.2'));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should request RDF 1.2 when exporting the repository as JSON-LD', () => {
|
|
113
|
+
// Given I am about to export the repository
|
|
114
|
+
cy.intercept({method: 'GET', pathname: `/repositories/${repositoryId}/statements`}).as('export');
|
|
115
|
+
|
|
116
|
+
// When I export it as JSON-LD with the default settings
|
|
117
|
+
GraphsOverviewSteps.exportRepository();
|
|
118
|
+
GraphsOverviewSteps.selectJSONLDOption();
|
|
119
|
+
JsonLdModalSteps.clickExportJSONLD();
|
|
120
|
+
|
|
121
|
+
// Then the version should follow the JSON-LD profile
|
|
122
|
+
verifyAcceptHeader('@export', JSONLD_EXPANDED_ACCEPT);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should request RDF 1.2 when downloading all graphs', () => {
|
|
126
|
+
// Given I am about to download all graphs
|
|
127
|
+
cy.intercept({method: 'GET', pathname: `/repositories/${repositoryId}/contexts`}).as('downloadGraphs');
|
|
128
|
+
|
|
129
|
+
// When I download them
|
|
130
|
+
GraphsOverviewSteps.clickOnDownloadAllButton();
|
|
131
|
+
|
|
132
|
+
// Then RDF 1.2 should be requested for every media range except JSON
|
|
133
|
+
verifyAcceptHeader('@downloadGraphs', 'application/json, text/plain;version=1.2, */*;version=1.2');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
function verifyAcceptHeader(alias, expectedAccept) {
|
|
139
|
+
cy.wait(alias).its('request.headers.accept').should('equal', expectedAccept);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function pasteAndExecuteConstructQuery() {
|
|
143
|
+
YasqeSteps.pasteQuery('CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }');
|
|
144
|
+
YasqeSteps.executeQuery();
|
|
145
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {ReactodiaSteps} from '../../steps/reactodia-steps.js';
|
|
2
|
+
import {PageRestrictionsSteps} from '../../steps/page-restrictions-steps.js';
|
|
3
|
+
import {RepositoryPickerListSteps} from '../../steps/repository-picker-list-steps.js';
|
|
4
|
+
import {LicenseStubs} from '../../stubs/license-stubs.js';
|
|
5
|
+
import {RepositorySteps} from '../../steps/repository-steps.js';
|
|
6
|
+
|
|
7
|
+
const NO_REPOSITORY_MESSAGE = 'you are not connected to any repository';
|
|
8
|
+
const INVALID_LICENSE_MESSAGE = 'your license is not valid';
|
|
9
|
+
const SELECT_OR_CREATE_REPOSITORY_MESSAGE = 'Select a repository below or create a new one.';
|
|
10
|
+
const SELECT_REPOSITORY_MESSAGE = 'Select a repository below.';
|
|
11
|
+
|
|
12
|
+
describe('Reactodia view restrictions', () => {
|
|
13
|
+
let repositoryId;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
repositoryId = 'reactodia-view-restrictions-' + Date.now();
|
|
17
|
+
cy.createRepository({id: repositoryId});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
cy.deleteRepository(repositoryId);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should show the repository picker when no repository is selected', () => {
|
|
25
|
+
// GIVEN no repository is selected
|
|
26
|
+
|
|
27
|
+
// WHEN I open the Reactodia view
|
|
28
|
+
ReactodiaSteps.visit();
|
|
29
|
+
// THEN I expect the repository restriction is shown
|
|
30
|
+
PageRestrictionsSteps.getMessages().should('have.length', 1);
|
|
31
|
+
PageRestrictionsSteps.getMessage(NO_REPOSITORY_MESSAGE).should('be.visible');
|
|
32
|
+
// AND the existing repository is available in the picker
|
|
33
|
+
RepositoryPickerListSteps.getRepositoryRow(repositoryId).should('be.visible');
|
|
34
|
+
// AND the graph is not rendered
|
|
35
|
+
ReactodiaSteps.getComponent().should('not.exist');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should render the graph when a repository is selected from the picker', () => {
|
|
39
|
+
// GIVEN the Reactodia view is open with no repository selected
|
|
40
|
+
ReactodiaSteps.visit();
|
|
41
|
+
|
|
42
|
+
// WHEN I select a repository
|
|
43
|
+
RepositoryPickerListSteps.selectRepository(repositoryId);
|
|
44
|
+
// THEN I expect the restriction is removed and the graph is rendered
|
|
45
|
+
PageRestrictionsSteps.getRestrictions().should('not.exist');
|
|
46
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should not restrict the view when the license is valid and a repository is selected', () => {
|
|
50
|
+
// GIVEN a valid license and a selected repository
|
|
51
|
+
cy.presetRepository(repositoryId);
|
|
52
|
+
|
|
53
|
+
// WHEN I open the Reactodia view
|
|
54
|
+
ReactodiaSteps.visit();
|
|
55
|
+
// THEN I expect the view is not restricted
|
|
56
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
57
|
+
PageRestrictionsSteps.getRestrictions().should('not.exist');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
context('when the license is invalid', () => {
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
LicenseStubs.stubNoValidLicense();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should show the license restriction when a repository is selected', () => {
|
|
66
|
+
// GIVEN an invalid license and a selected repository
|
|
67
|
+
cy.presetRepository(repositoryId);
|
|
68
|
+
|
|
69
|
+
// WHEN I open the Reactodia view
|
|
70
|
+
ReactodiaSteps.visit();
|
|
71
|
+
// THEN I expect the license restriction is shown
|
|
72
|
+
PageRestrictionsSteps.getMessages().should('have.length', 1);
|
|
73
|
+
PageRestrictionsSteps.getMessage(INVALID_LICENSE_MESSAGE).should('be.visible');
|
|
74
|
+
// AND the "Set a new license" link is displayed
|
|
75
|
+
PageRestrictionsSteps.getInternalLink()
|
|
76
|
+
.should('contain.text', 'Set a new license')
|
|
77
|
+
.and('have.attr', 'href')
|
|
78
|
+
.and('include', '/license');
|
|
79
|
+
// AND the repository picker and graph are not rendered
|
|
80
|
+
RepositoryPickerListSteps.getRepositoryPickerList().should('not.exist');
|
|
81
|
+
ReactodiaSteps.getComponent().should('not.exist');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should show both restrictions when no repository is selected', () => {
|
|
85
|
+
// GIVEN an invalid license and no repository selected
|
|
86
|
+
|
|
87
|
+
// WHEN I open the Reactodia view
|
|
88
|
+
ReactodiaSteps.visit();
|
|
89
|
+
// THEN both restrictions are shown
|
|
90
|
+
PageRestrictionsSteps.getMessages().should('have.length', 2);
|
|
91
|
+
PageRestrictionsSteps.getMessage(INVALID_LICENSE_MESSAGE).should('be.visible');
|
|
92
|
+
PageRestrictionsSteps.getMessage(NO_REPOSITORY_MESSAGE)
|
|
93
|
+
.should('be.visible')
|
|
94
|
+
.and('not.contain.text', 'create a new one');
|
|
95
|
+
// AND the existing repository is available, but repository creation is not
|
|
96
|
+
RepositoryPickerListSteps.getRepositoryRow(repositoryId).should('be.visible');
|
|
97
|
+
RepositoryPickerListSteps.getCreateRepositoryButton().should('not.exist');
|
|
98
|
+
// AND the graph is not rendered
|
|
99
|
+
ReactodiaSteps.getComponent().should('not.exist');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
context('with security enabled', () => {
|
|
104
|
+
const readOnlyUser = 'reactodia-reader-' + Date.now();
|
|
105
|
+
const repoManagerUser = 'reactodia-repo-manager-' + Date.now();
|
|
106
|
+
const repoMaintainerUser = 'reactodia-repo-maintainer-' + Date.now();
|
|
107
|
+
const password = 'root';
|
|
108
|
+
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
cy.createUser({
|
|
111
|
+
username: readOnlyUser,
|
|
112
|
+
password,
|
|
113
|
+
grantedAuthorities: ['ROLE_USER', `READ_REPO_${repositoryId}`]
|
|
114
|
+
});
|
|
115
|
+
cy.createUser({
|
|
116
|
+
username: repoManagerUser,
|
|
117
|
+
password,
|
|
118
|
+
grantedAuthorities: ['ROLE_USER', 'ROLE_REPO_MANAGER']
|
|
119
|
+
});
|
|
120
|
+
cy.createUser({
|
|
121
|
+
username: repoMaintainerUser,
|
|
122
|
+
password,
|
|
123
|
+
grantedAuthorities: [
|
|
124
|
+
'ROLE_USER',
|
|
125
|
+
`READ_REPO_${repositoryId}`,
|
|
126
|
+
`WRITE_REPO_${repositoryId}`,
|
|
127
|
+
`MAINTAIN_REPO_${repositoryId}`
|
|
128
|
+
]
|
|
129
|
+
});
|
|
130
|
+
cy.switchOnSecurity();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
afterEach(() => {
|
|
134
|
+
cy.loginAsAdmin().then(() => {
|
|
135
|
+
cy.deleteUser(readOnlyUser, true);
|
|
136
|
+
cy.deleteUser(repoManagerUser, true);
|
|
137
|
+
cy.deleteUser(repoMaintainerUser, true);
|
|
138
|
+
cy.switchOffSecurity(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should not restrict the view for a user without write permission', () => {
|
|
143
|
+
// GIVEN a user with read-only access to the selected repository
|
|
144
|
+
cy.loginAs(readOnlyUser, password);
|
|
145
|
+
cy.presetRepository(repositoryId);
|
|
146
|
+
|
|
147
|
+
// WHEN I open the Reactodia view
|
|
148
|
+
ReactodiaSteps.visit();
|
|
149
|
+
// THEN I expect the view is not restricted
|
|
150
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
151
|
+
PageRestrictionsSteps.getRestrictions().should('not.exist');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should offer repository creation to the administrator', () => {
|
|
155
|
+
// GIVEN the administrator is logged in with no repository selected
|
|
156
|
+
cy.loginAs('admin', password);
|
|
157
|
+
|
|
158
|
+
// WHEN I open the Reactodia view
|
|
159
|
+
ReactodiaSteps.visit();
|
|
160
|
+
// THEN I expect the option to select or create a repository is displayed
|
|
161
|
+
PageRestrictionsSteps.getMessage(SELECT_OR_CREATE_REPOSITORY_MESSAGE).should('be.visible');
|
|
162
|
+
RepositoryPickerListSteps.getRepositoryRow(repositoryId).should('be.visible');
|
|
163
|
+
RepositoryPickerListSteps.getCreateRepositoryButton().should('be.visible');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should offer repository creation to a repository manager', () => {
|
|
167
|
+
// GIVEN a repository manager is logged in with no repository selected
|
|
168
|
+
cy.loginAs(repoManagerUser, password);
|
|
169
|
+
|
|
170
|
+
// WHEN I open the Reactodia view
|
|
171
|
+
ReactodiaSteps.visit();
|
|
172
|
+
// THEN the option to select or create a repository is displayed
|
|
173
|
+
PageRestrictionsSteps.getMessage(SELECT_OR_CREATE_REPOSITORY_MESSAGE).should('be.visible');
|
|
174
|
+
RepositoryPickerListSteps.getRepositoryRow(repositoryId).should('be.visible');
|
|
175
|
+
|
|
176
|
+
// WHEN I click the create repository button
|
|
177
|
+
RepositoryPickerListSteps.clickCreateRepositoryButton();
|
|
178
|
+
// THEN the create repository view is opened
|
|
179
|
+
RepositorySteps.verifyRepositoryCreateViewUrl().and('include', 'previous=%2Freactodia');
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
[
|
|
183
|
+
{role: 'a read-only user', username: readOnlyUser},
|
|
184
|
+
{role: 'a repository maintainer', username: repoMaintainerUser},
|
|
185
|
+
].forEach(({role, username}) => {
|
|
186
|
+
it(`should not offer repository creation to ${role}`, () => {
|
|
187
|
+
// GIVEN a user without repository management rights is logged in with no repository selected
|
|
188
|
+
cy.loginAs(username, password);
|
|
189
|
+
|
|
190
|
+
// WHEN I open the Reactodia view
|
|
191
|
+
ReactodiaSteps.visit();
|
|
192
|
+
// THEN only the option to select a repository is displayed
|
|
193
|
+
PageRestrictionsSteps.getMessage(SELECT_REPOSITORY_MESSAGE).should('be.visible');
|
|
194
|
+
PageRestrictionsSteps.getMessages().should('not.contain.text', 'create a new one');
|
|
195
|
+
RepositoryPickerListSteps.getRepositoryRow(repositoryId).should('be.visible');
|
|
196
|
+
RepositoryPickerListSteps.getCreateRepositoryButton().should('not.exist');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {ReactodiaSteps} from '../../steps/reactodia-steps.js';
|
|
2
|
+
import {LanguageSelectorSteps} from '../../steps/language-selector-steps.js';
|
|
3
|
+
import {RepositorySelectorSteps} from '../../steps/repository-selector-steps.js';
|
|
4
|
+
import {MainMenuSteps} from '../../steps/main-menu-steps.js';
|
|
5
|
+
import {YasqeSteps} from '../../steps/yasgui/yasqe-steps.js';
|
|
6
|
+
|
|
7
|
+
const FILE_TO_IMPORT = 'resource-test-data.ttl';
|
|
8
|
+
const SEED_RESOURCE_ENCODED = 'http:%2F%2Fexample.com%2Fontology%23CustomerLoyalty';
|
|
9
|
+
const SEED_RESOURCE_LABEL = 'CustomerLoyalty';
|
|
10
|
+
|
|
11
|
+
const CONSTRUCT_QUERY = 'CONSTRUCT { <http://example.com/ontology#CustomerLoyalty> ?p ?o } WHERE { <http://example.com/ontology#CustomerLoyalty> ?p ?o }';
|
|
12
|
+
const CONSTRUCT_TARGET_LABEL = 'Metric';
|
|
13
|
+
|
|
14
|
+
describe('Reactodia graph explorer', () => {
|
|
15
|
+
let repositoryId;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
repositoryId = 'repository-' + Date.now();
|
|
19
|
+
cy.createRepository({id: repositoryId});
|
|
20
|
+
cy.presetRepository(repositoryId);
|
|
21
|
+
cy.importServerFile(repositoryId, FILE_TO_IMPORT);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
cy.deleteRepository(repositoryId);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should mount the reactodia workspace when a repository is active', () => {
|
|
29
|
+
// Given I open the reactodia view without a start resource.
|
|
30
|
+
ReactodiaSteps.visit();
|
|
31
|
+
|
|
32
|
+
// Then I expect the reactodia workspace and its canvas to be rendered.
|
|
33
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
34
|
+
ReactodiaSteps.getCanvas().should('exist');
|
|
35
|
+
|
|
36
|
+
// And I expect the canvas to start empty because no start resource was provided.
|
|
37
|
+
ReactodiaSteps.getElements().should('not.exist');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should place the start resource on the canvas as a seed', () => {
|
|
41
|
+
// Given I open the reactodia view with a start resource.
|
|
42
|
+
ReactodiaSteps.visit(SEED_RESOURCE_ENCODED);
|
|
43
|
+
|
|
44
|
+
// Then I expect the start resource to be placed on the canvas as a seed element.
|
|
45
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
46
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should seed the canvas with the graph computed from a CONSTRUCT query', () => {
|
|
50
|
+
// Given I open the reactodia view with a CONSTRUCT query, as sent from the SPARQL editor.
|
|
51
|
+
ReactodiaSteps.visitWithQuery(CONSTRUCT_QUERY);
|
|
52
|
+
|
|
53
|
+
// Then I expect the computed graph to be seeded on the canvas: the subject and its related resource.
|
|
54
|
+
ReactodiaSteps.getElements().should('have.length', 2);
|
|
55
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
56
|
+
ReactodiaSteps.getElement(CONSTRUCT_TARGET_LABEL).should('exist');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should keep the displayed resources when the language is switched', () => {
|
|
60
|
+
// Given the reactodia view is opened with a start resource that gets seeded on the canvas.
|
|
61
|
+
ReactodiaSteps.visit(SEED_RESOURCE_ENCODED);
|
|
62
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
63
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
64
|
+
|
|
65
|
+
// When I switch the language.
|
|
66
|
+
LanguageSelectorSteps.switchToFr();
|
|
67
|
+
|
|
68
|
+
// Then I expect the same resources to remain visible because the layout is carried across the remount.
|
|
69
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
70
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should keep the diagram on refresh but clear it when navigating away and back', () => {
|
|
74
|
+
// Given the reactodia view is opened with a start resource that gets seeded on the canvas.
|
|
75
|
+
ReactodiaSteps.visit(SEED_RESOURCE_ENCODED);
|
|
76
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
77
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
78
|
+
|
|
79
|
+
// When I refresh the page.
|
|
80
|
+
cy.reload();
|
|
81
|
+
|
|
82
|
+
// Then I expect the diagram state to be preserved across the refresh.
|
|
83
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
84
|
+
ReactodiaSteps.getElement(SEED_RESOURCE_LABEL).should('exist');
|
|
85
|
+
|
|
86
|
+
// When I navigate to another view via the navigation bar.
|
|
87
|
+
MainMenuSteps.clickOnSparqlMenu();
|
|
88
|
+
ReactodiaSteps.getComponent().should('not.exist');
|
|
89
|
+
|
|
90
|
+
// Wait for the SPARQL Query & Update view to be loaded before continuing.
|
|
91
|
+
// Without this wait, Cypress may try to click the Reactodia menu item before the page is fully loaded,
|
|
92
|
+
// causing the test to fail intermittently with the error:
|
|
93
|
+
// "This element `<li.sub-menu-item>` is not visible because it has CSS property: `display: none`"
|
|
94
|
+
// when trying to click the Reactodia submenu.
|
|
95
|
+
YasqeSteps.getEditor().should('be.visible');
|
|
96
|
+
// And I return to the reactodia view via the navigation bar.
|
|
97
|
+
MainMenuSteps.clickOnReactodia();
|
|
98
|
+
|
|
99
|
+
// Then I expect the canvas to be cleared, because leaving the view drops the persisted diagram state.
|
|
100
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
101
|
+
ReactodiaSteps.getElements().should('not.exist');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('Repository switch', () => {
|
|
105
|
+
let secondRepositoryId;
|
|
106
|
+
|
|
107
|
+
beforeEach(() => {
|
|
108
|
+
secondRepositoryId = 'repository-second-' + Date.now();
|
|
109
|
+
cy.createRepository({id: secondRepositoryId});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
afterEach(() => {
|
|
113
|
+
cy.deleteRepository(secondRepositoryId);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should clear the canvas when the repository is switched', () => {
|
|
117
|
+
// Given the reactodia view is opened with a start resource that gets seeded on the canvas.
|
|
118
|
+
ReactodiaSteps.visit(SEED_RESOURCE_ENCODED);
|
|
119
|
+
ReactodiaSteps.getElements().should('have.length', 1);
|
|
120
|
+
|
|
121
|
+
// When I switch to another repository.
|
|
122
|
+
RepositorySelectorSteps.selectRepository(secondRepositoryId);
|
|
123
|
+
|
|
124
|
+
// Then I expect the workspace to still be mounted, but the canvas to be cleared.
|
|
125
|
+
ReactodiaSteps.getWorkspace().should('exist');
|
|
126
|
+
ReactodiaSteps.getElements().should('not.exist');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|