graphdb-workbench-tests 2.4.2 → 2.5.0-RC1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/Dockerfile +1 -1
  2. package/fixtures/cluster/3-nodes-cluster-created.json +5 -0
  3. package/fixtures/cluster/3-nodes-cluster-group-status.json +35 -0
  4. package/fixtures/cluster/cluster-config.json +13 -0
  5. package/fixtures/cluster/cluster-node-status.json +10 -0
  6. package/fixtures/cluster/delete-cluster.json +5 -0
  7. package/fixtures/cluster/no-cluster-group-status.json +12 -0
  8. package/fixtures/cluster/no-cluster-node-status.json +10 -0
  9. package/fixtures/cluster/replace-nodes.json +1 -0
  10. package/fixtures/locale-en.json +10 -15
  11. package/fixtures/monitoring/no-operations.json +1 -0
  12. package/fixtures/remote-location/add-remote-location +1 -0
  13. package/fixtures/remote-location/get-0-remote-locations.json +15 -0
  14. package/fixtures/remote-location/get-1-remote-locations.json +28 -0
  15. package/fixtures/remote-location/get-2-remote-locations.json +41 -0
  16. package/fixtures/remote-location/get-3-remote-locations.json +54 -0
  17. package/fixtures/remote-location/get-no-remote-locations.json +1 -0
  18. package/fixtures/remote-location/remote-location-check +1 -0
  19. package/fixtures/remote-location/remote-location-status-in-cluster.json +13 -0
  20. package/fixtures/remote-location/remote-location-status-not-in-cluster.json +13 -0
  21. package/fixtures/remote-location/remote-locations-filter.json +15 -0
  22. package/integration/cluster/cluster-management.spec.js +197 -0
  23. package/integration/explore/class.hierarchy.spec.js +1 -1
  24. package/integration/explore/visual.graph.spec.js +1 -3
  25. package/integration/monitor/monitor.resources.spec.js +1 -1
  26. package/integration/sparql/sparql.menu.spec.js +2 -2
  27. package/integration-flaky/explore/visual.graph.spec.js +6 -5
  28. package/package.json +2 -2
  29. package/steps/cluster/add-remote-location-dialog-steps.js +11 -0
  30. package/steps/cluster/cluster-page-steps.js +57 -0
  31. package/steps/cluster/create-cluster-dialog-steps.js +39 -0
  32. package/steps/cluster/delete-cluster-dialog-steps.js +11 -0
  33. package/steps/cluster/replace-nodes-dialog-steps.js +39 -0
  34. package/stubs/cluster/cluster-stubs.js +67 -0
  35. package/stubs/cluster/remote-location-stubs.js +52 -0
  36. package/stubs/global-operations-statuses-stub.js +7 -0
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM cypress/base:12
1
+ FROM cypress/base:16.18.1
2
2
 
3
3
  COPY . /workbench/tests-cypress/
4
4
 
@@ -0,0 +1,5 @@
1
+ {
2
+ "pc-desktop:7300": "Cluster was successfully created.",
3
+ "pc-desktop:7301": "Cluster was successfully created.",
4
+ "pc-desktop:7302": "Cluster was successfully created."
5
+ }
@@ -0,0 +1,35 @@
1
+ [
2
+ {
3
+ "address": "pc-desktop:7300",
4
+ "nodeState": "FOLLOWER",
5
+ "term": 2,
6
+ "syncStatus": {},
7
+ "lastLogTerm": 0,
8
+ "lastLogIndex": 0,
9
+ "endpoint": "http://pc-desktop:7200",
10
+ "recoveryStatus": {}
11
+ },
12
+ {
13
+ "address": "pc-desktop:7301",
14
+ "nodeState": "LEADER",
15
+ "term": 2,
16
+ "syncStatus": {
17
+ "pc-desktop:7300": "IN_SYNC",
18
+ "pc-desktop:7302": "IN_SYNC"
19
+ },
20
+ "lastLogTerm": 0,
21
+ "lastLogIndex": 0,
22
+ "endpoint": "http://pc-desktop:7201",
23
+ "recoveryStatus": {}
24
+ },
25
+ {
26
+ "address": "pc-desktop:7302",
27
+ "nodeState": "FOLLOWER",
28
+ "term": 2,
29
+ "syncStatus": {},
30
+ "lastLogTerm": 0,
31
+ "lastLogIndex": 0,
32
+ "endpoint": "http://pc-desktop:7202",
33
+ "recoveryStatus": {}
34
+ }
35
+ ]
@@ -0,0 +1,13 @@
1
+ {
2
+ "electionMinTimeout": 8000,
3
+ "electionRangeTimeout": 6000,
4
+ "heartbeatInterval": 2000,
5
+ "messageSizeKB": 64,
6
+ "verificationTimeout": 1500,
7
+ "transactionLogMaximumSizeGB": 50.0,
8
+ "nodes": [
9
+ "pc-desktop:7302",
10
+ "pc-desktop:7300",
11
+ "pc-desktop:7301"
12
+ ]
13
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "address": "pc-desktop:7300",
3
+ "nodeState": "FOLLOWER",
4
+ "term": 1,
5
+ "syncStatus": {},
6
+ "lastLogTerm": 0,
7
+ "lastLogIndex": 0,
8
+ "endpoint": "http://pc-desktop:7200",
9
+ "recoveryStatus": {}
10
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "pc-desktop:7300": "Cluster was deleted on this node.",
3
+ "pc-desktop:7301": "Cluster was deleted on this node.",
4
+ "pc-desktop:7302": "Cluster was deleted on this node."
5
+ }
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "address": "pc-desktop:7300",
4
+ "nodeState": "NO_CLUSTER",
5
+ "term": 0,
6
+ "syncStatus": {},
7
+ "lastLogTerm": 0,
8
+ "lastLogIndex": 0,
9
+ "endpoint": "http://pc-desktop:7200",
10
+ "recoveryStatus": {}
11
+ }
12
+ ]
@@ -0,0 +1,10 @@
1
+ {
2
+ "address": "pc-desktop:7300",
3
+ "nodeState": "NO_CLUSTER",
4
+ "term": 0,
5
+ "syncStatus": {},
6
+ "lastLogTerm": 0,
7
+ "lastLogIndex": 0,
8
+ "endpoint": "http://pc-desktop:7200",
9
+ "recoveryStatus": {}
10
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -168,7 +168,8 @@
168
168
  },
169
169
  "errors": {
170
170
  "loading_rules": "Error during ACL rules",
171
- "updating_rules": "Error during ACL rules update"
171
+ "updating_rules": "Error during ACL rules update",
172
+ "duplicated_rules": "Every ACL rule should be unique."
172
173
  }
173
174
  },
174
175
  "config.name.label": "Config name",
@@ -926,10 +927,9 @@
926
927
  "core.errors.fedx.repository.warning.msg": " view is not supported by FedX Repository.",
927
928
  "core.errors.select.repository.warning.msg": "Click one of the repositories below to connect to it",
928
929
  "core.errors.or.create.repository.warning.msg": " or create a new repository",
929
- "core.errors.no.accessible.warning.msg": "There are no accessible ",
930
- "core.errors.writable": "writable ",
931
- "core.errors.repositories": "repositories",
932
- "core.errors.create.repository.warning.msg": ". You can create a new repository",
930
+ "core.errors.no.accessible.repositories.warning.msg": "There are no accessible repositories.",
931
+ "core.errors.no.accessible.writable.repositories.warning.msg": "There are no accessible writable repositories.",
932
+ "core.errors.create.repository.warning.msg": " You can create a new repository",
933
933
  "core.errors.show.remote.locations.btn": "Show remote locations",
934
934
  "core.errors.hide.remote.locations.btn": "Hide remote locations",
935
935
  "core.errors.location.local.label": "Local",
@@ -1187,6 +1187,7 @@
1187
1187
  "repo.properties": "Repository properties",
1188
1188
  "repo.id.label": "Repository ID*",
1189
1189
  "edit.repo.id.tooltip": "Edit repository id",
1190
+ "edit.repo.id.cannot_edit_in_cluster.tooltip": "Cannot rename repository while in cluster.",
1190
1191
  "invalid.repo.name.error": "Repository name can contain only letters (a-z, A-Z), numbers (0-9), \"-\" and \"_\"",
1191
1192
  "upload.custom.ruleset.file": "Upload a custom ruleset file.",
1192
1193
  "custom.ruleset": "Custom ruleset...",
@@ -1705,6 +1706,7 @@
1705
1706
  "target.label": "Target",
1706
1707
  "show.blank.nodes.label": "Show Blank Nodes",
1707
1708
  "download.as.label": "Download as",
1709
+ "download.as.progress.msg": "Downloading SPARQL result",
1708
1710
  "visual.graph.label": "Visual graph",
1709
1711
  "explore.graph.visually.popover": "Click to explore the graph visually",
1710
1712
  "pred.label": "Predicate",
@@ -1915,20 +1917,13 @@
1915
1917
  "ttyg.settings.topk.tooltip": "Number of results returned to the chat bot when it requests more information. More results will provide more information but they may also introduce noise.",
1916
1918
  "ttyg.settings.echo.vector.query": "Echo vector query",
1917
1919
  "ttyg.settings.echo.vector.query.tooltip": "If enabled the bot will use the generated queries as feedback to the GPT API.",
1918
- "global.operations_statuses.queries.title": "Running query",
1919
- "global.operations_statuses.queries.title.plural": "Running queries",
1920
- "global.operations_statuses.updates.title": "Running update",
1921
- "global.operations_statuses.updates.title.plural": "Running updates",
1922
- "global.operations_statuses.imports.title": "Running import",
1923
- "global.operations_statuses.imports.title.plural": "Running imports",
1920
+ "global.operations_statuses.queries.title": "Running queries",
1921
+ "global.operations_statuses.updates.title": "Running updates",
1922
+ "global.operations_statuses.imports.title": "Running imports",
1924
1923
  "global.operations_statuses.CREATE_BACKUP_IN_PROGRESS.title": "Creating backup",
1925
- "global.operations_statuses.CREATE_BACKUP_IN_PROGRESS.title.plural": "Creating backups",
1926
1924
  "global.operations_statuses.RESTORE_BACKUP_IN_PROGRESS.title": "Restoring backup",
1927
- "global.operations_statuses.RESTORE_BACKUP_IN_PROGRESS.title.plural": "Restoring backups",
1928
1925
  "global.operations_statuses.CREATE_CLOUD_BACKUP_IN_PROGRESS.title": "Creating cloud backup",
1929
- "global.operations_statuses.CREATE_CLOUD_BACKUP_IN_PROGRESS.title.plural": "Creating cloud backups",
1930
1926
  "global.operations_statuses.RESTORE_CLOUD_BACKUP_IN_PROGRESS.title": "Restoring cloud backup",
1931
- "global.operations_statuses.RESTORE_CLOUD_BACKUP_IN_PROGRESS.title.plural": "Restoring cloud backups",
1932
1927
  "global.operations_statuses.IN_SYNC.title": "In sync",
1933
1928
  "global.operations_statuses.RECOVERING.title": "Recovering",
1934
1929
  "global.operations_statuses.OUT_OF_SYNC.title": "Out of sync",
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1 @@
1
+ Successfully connected new GraphDB location.
@@ -0,0 +1,15 @@
1
+ [
2
+ {
3
+ "uri": "",
4
+ "label": "Local",
5
+ "username": null,
6
+ "password": null,
7
+ "authType": "none",
8
+ "active": true,
9
+ "local": true,
10
+ "system": true,
11
+ "errorMsg": null,
12
+ "defaultRepository": null,
13
+ "isInCluster": false
14
+ }
15
+ ]
@@ -0,0 +1,28 @@
1
+ [
2
+ {
3
+ "uri": "",
4
+ "label": "Local",
5
+ "username": null,
6
+ "password": null,
7
+ "authType": "none",
8
+ "active": true,
9
+ "local": true,
10
+ "system": true,
11
+ "errorMsg": null,
12
+ "defaultRepository": null,
13
+ "isInCluster": false
14
+ },
15
+ {
16
+ "uri": "http://localhost:7201",
17
+ "label": "Remote (http://localhost:7201)",
18
+ "username": "",
19
+ "password": "",
20
+ "authType": "signature",
21
+ "active": false,
22
+ "local": false,
23
+ "system": false,
24
+ "errorMsg": null,
25
+ "defaultRepository": null,
26
+ "isInCluster": false
27
+ }
28
+ ]
@@ -0,0 +1,41 @@
1
+ [
2
+ {
3
+ "uri": "",
4
+ "label": "Local",
5
+ "username": null,
6
+ "password": null,
7
+ "authType": "none",
8
+ "active": true,
9
+ "local": true,
10
+ "system": true,
11
+ "errorMsg": null,
12
+ "defaultRepository": null,
13
+ "isInCluster": false
14
+ },
15
+ {
16
+ "uri": "http://localhost:7201",
17
+ "label": "Remote (http://localhost:7201)",
18
+ "username": "",
19
+ "password": "",
20
+ "authType": "signature",
21
+ "active": false,
22
+ "local": false,
23
+ "system": false,
24
+ "errorMsg": null,
25
+ "defaultRepository": null,
26
+ "isInCluster": false
27
+ },
28
+ {
29
+ "uri": "http://localhost:7202",
30
+ "label": "Remote (http://localhost:7202)",
31
+ "username": "",
32
+ "password": "",
33
+ "authType": "signature",
34
+ "active": false,
35
+ "local": false,
36
+ "system": false,
37
+ "errorMsg": null,
38
+ "defaultRepository": null,
39
+ "isInCluster": false
40
+ }
41
+ ]
@@ -0,0 +1,54 @@
1
+ [
2
+ {
3
+ "uri": "",
4
+ "label": "Local",
5
+ "username": null,
6
+ "password": null,
7
+ "authType": "none",
8
+ "active": true,
9
+ "local": true,
10
+ "system": true,
11
+ "errorMsg": null,
12
+ "defaultRepository": null,
13
+ "isInCluster": true
14
+ },
15
+ {
16
+ "uri": "http://localhost:7201",
17
+ "label": "Remote (http://localhost:7201)",
18
+ "username": "",
19
+ "password": "",
20
+ "authType": "signature",
21
+ "active": false,
22
+ "local": false,
23
+ "system": false,
24
+ "errorMsg": null,
25
+ "defaultRepository": null,
26
+ "isInCluster": true
27
+ },
28
+ {
29
+ "uri": "http://localhost:7202",
30
+ "label": "Remote (http://localhost:7202)",
31
+ "username": "",
32
+ "password": "",
33
+ "authType": "signature",
34
+ "active": false,
35
+ "local": false,
36
+ "system": false,
37
+ "errorMsg": null,
38
+ "defaultRepository": null,
39
+ "isInCluster": true
40
+ },
41
+ {
42
+ "uri": "http://localhost:7203",
43
+ "label": "Remote (http://localhost:7203)",
44
+ "username": "",
45
+ "password": "",
46
+ "authType": "signature",
47
+ "active": false,
48
+ "local": false,
49
+ "system": false,
50
+ "errorMsg": null,
51
+ "defaultRepository": null,
52
+ "isInCluster": false
53
+ }
54
+ ]
@@ -0,0 +1 @@
1
+ pc-desktop:7301
@@ -0,0 +1,13 @@
1
+ {
2
+ "uri": "",
3
+ "label": "Local",
4
+ "username": null,
5
+ "password": null,
6
+ "authType": null,
7
+ "active": true,
8
+ "local": true,
9
+ "system": true,
10
+ "errorMsg": null,
11
+ "defaultRepository": null,
12
+ "isInCluster": true
13
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "uri": "",
3
+ "label": "Local",
4
+ "username": null,
5
+ "password": null,
6
+ "authType": null,
7
+ "active": true,
8
+ "local": true,
9
+ "system": true,
10
+ "errorMsg": null,
11
+ "defaultRepository": null,
12
+ "isInCluster": false
13
+ }
@@ -0,0 +1,15 @@
1
+ [
2
+ {
3
+ "uri": "",
4
+ "label": "Local",
5
+ "username": null,
6
+ "password": null,
7
+ "authType": "none",
8
+ "active": true,
9
+ "local": true,
10
+ "system": true,
11
+ "errorMsg": null,
12
+ "defaultRepository": null,
13
+ "isInCluster": false
14
+ }
15
+ ]
@@ -0,0 +1,197 @@
1
+ import {ClusterPageSteps} from "../../steps/cluster/cluster-page-steps";
2
+ import {GlobalOperationsStatusesStub} from "../../stubs/global-operations-statuses-stub";
3
+ import {ClusterStubs} from "../../stubs/cluster/cluster-stubs";
4
+ import {CreateClusterDialogSteps} from "../../steps/cluster/create-cluster-dialog-steps";
5
+ import {AddRemoteLocationDialogSteps} from "../../steps/cluster/add-remote-location-dialog-steps";
6
+ import {RemoteLocationStubs} from "../../stubs/cluster/remote-location-stubs";
7
+ import {DeleteClusterDialogSteps} from "../../steps/cluster/delete-cluster-dialog-steps";
8
+ import {ReplaceNodesDialogSteps} from "../../steps/cluster/replace-nodes-dialog-steps";
9
+ import {ApplicationSteps} from "../../steps/application-steps";
10
+
11
+ describe('Cluster management', () => {
12
+
13
+ let repositoryId;
14
+
15
+ beforeEach(() => {
16
+ repositoryId = 'cluster-repo' + Date.now();
17
+ GlobalOperationsStatusesStub.stubNoOperationsResponse(repositoryId);
18
+ });
19
+
20
+ it('Should be able to open a create cluster dialog', () => {
21
+ // Given I have opened the cluster management page
22
+ ClusterPageSteps.visit();
23
+
24
+ ClusterStubs.stubNoClusterGroupStatus();
25
+ ClusterStubs.stubNoClusterNodeStatus();
26
+ ClusterStubs.stubNoClusterConfig();
27
+ RemoteLocationStubs.stubAddRemoteLocation();
28
+ RemoteLocationStubs.stubGetRemoteLocations(0);
29
+
30
+ // Then I expect that the page should be loaded
31
+ ClusterPageSteps.getClusterPage().should('be.visible');
32
+ // And the create cluster button to be visible
33
+ ClusterPageSteps.getCreateClusterButton().should('be.visible').and('have.class', 'no-cluster');
34
+ // When I click on the create cluster button
35
+ ClusterPageSteps.createCluster();
36
+ // Then I expect create cluster dialog to become visible
37
+ CreateClusterDialogSteps.getDialog().should('be.visible');
38
+ CreateClusterDialogSteps.getDialogHeader().should('contain.text', 'Create cluster');
39
+ // And I expect to see a single node in the cluster nodes list
40
+ CreateClusterDialogSteps.getClusterNodesList().should('have.length', 1);
41
+ // And I expect to see no remote locations in the locations list
42
+ CreateClusterDialogSteps.getRemoteLocationsList().should('have.length', 0);
43
+ // And I expect that the create cluster button should be disabled
44
+ CreateClusterDialogSteps.getNoSelectedNodesWarning().should('be.visible');
45
+ // And I expect that the create cluster button should be disabled
46
+ CreateClusterDialogSteps.getSaveClusterConfigButton().should('be.disabled');
47
+ // When I click on the cancel button
48
+ CreateClusterDialogSteps.clickOnCancelButton();
49
+ // Then I expect that the create cluster dialog should be closed
50
+ CreateClusterDialogSteps.getDialog().should('not.exist');
51
+ });
52
+
53
+ it('Should be able to create a cluster', () => {
54
+ // Given I have opened the cluster management page
55
+ ClusterPageSteps.visit();
56
+
57
+ // When there is no cluster configured yet
58
+ ClusterStubs.stubNoClusterGroupStatus();
59
+ ClusterStubs.stubNoClusterNodeStatus();
60
+ ClusterStubs.stubNoClusterConfig();
61
+ RemoteLocationStubs.stubAddRemoteLocation();
62
+ RemoteLocationStubs.stubGetRemoteLocations(0);
63
+
64
+ // When I open the create cluster dialog
65
+ ClusterPageSteps.getClusterPage().should('be.visible');
66
+ ClusterPageSteps.createCluster();
67
+ CreateClusterDialogSteps.getDialog().should('be.visible');
68
+ // And I add a remote location
69
+ RemoteLocationStubs.stubRemoteLocationCheck();
70
+ addRemoteLocation('http://localhost:7201', 1);
71
+ CreateClusterDialogSteps.getRemoteLocationsList().should('have.length', 1);
72
+ // When I select the added remote location
73
+ CreateClusterDialogSteps.selectRemoteLocation(0);
74
+ // Then I expect that the remote location will be added to the cluster nodes list
75
+ CreateClusterDialogSteps.getRemoteLocationsList().should('have.length', 0);
76
+ CreateClusterDialogSteps.getClusterNodesList().should('have.length', 2);
77
+ // And the no selected nodes warning should disappear
78
+ CreateClusterDialogSteps.getNoSelectedNodesWarning().should('not.exist');
79
+ // When I add another remote location
80
+ addRemoteLocation('http://localhost:7202', 2);
81
+ // Then I expect it to be added to the cluster nodes list
82
+ CreateClusterDialogSteps.getRemoteLocationsList().should('have.length', 1);
83
+ CreateClusterDialogSteps.selectRemoteLocation(0);
84
+ CreateClusterDialogSteps.getRemoteLocationsList().should('have.length', 0);
85
+ CreateClusterDialogSteps.getClusterNodesList().should('have.length', 3);
86
+ // When I click on create cluster button
87
+ ClusterStubs.stubCreateCluster();
88
+ CreateClusterDialogSteps.saveClusterConfig();
89
+ // Then I expect that the create cluster dialog should be closed
90
+ CreateClusterDialogSteps.getDialog().should('not.exist');
91
+ // And cluster should be created
92
+ ClusterStubs.stubClusterConfig();
93
+ ClusterStubs.stubClusterGroupStatus();
94
+ ClusterStubs.stubClusterNodeStatus();
95
+ RemoteLocationStubs.stubRemoteLocationFilter();
96
+ RemoteLocationStubs.stubRemoteLocationStatusInCluster();
97
+ // And cluster management actions should be accessible
98
+ ClusterPageSteps.getClusterDeleteButton().should('be.visible');
99
+ ClusterPageSteps.getRemoveNodesButton().should('be.visible');
100
+ ClusterPageSteps.getAddNodesButton().should('be.visible');
101
+ ClusterPageSteps.getReplaceNodesButton().should('be.visible');
102
+ ClusterPageSteps.getPreviewClusterConfigButton().should('be.visible');
103
+ ClusterPageSteps.getCreateClusterButton().should('not.have.class', 'no-cluster');
104
+ });
105
+
106
+ it('Should be able to delete cluster', () => {
107
+ // Given I have opened the cluster management page
108
+ ClusterPageSteps.visit();
109
+
110
+ // Given there is an existing cluster created
111
+ ClusterStubs.stubClusterConfig();
112
+ ClusterStubs.stubClusterGroupStatus();
113
+ ClusterStubs.stubClusterNodeStatus();
114
+ RemoteLocationStubs.stubRemoteLocationFilter();
115
+ RemoteLocationStubs.stubRemoteLocationStatusInCluster();
116
+ ClusterPageSteps.getClusterPage().should('be.visible');
117
+ ClusterPageSteps.getCreateClusterButton().should('not.have.class', 'no-cluster');
118
+ // When I click on delete cluster
119
+ ClusterPageSteps.deleteCluster();
120
+ // Then I expect a confirmation dialog to appear
121
+ DeleteClusterDialogSteps.getDialog().should('be.visible');
122
+ // When I confirm
123
+ ClusterStubs.stubDeleteCluster();
124
+ ClusterStubs.stubNoClusterGroupStatus();
125
+ ClusterStubs.stubNoClusterNodeStatus();
126
+ DeleteClusterDialogSteps.confirmDeleteCluster();
127
+ // Then Cluster should be deleted
128
+ ClusterStubs.stubNoClusterConfig();
129
+ RemoteLocationStubs.stubRemoteLocationStatusNotCluster();
130
+ DeleteClusterDialogSteps.getDialog().should('not.exist');
131
+ ClusterPageSteps.getClusterDeleteButton().should('not.exist');
132
+ ClusterPageSteps.getRemoveNodesButton().should('not.exist');
133
+ ClusterPageSteps.getAddNodesButton().should('not.exist');
134
+ ClusterPageSteps.getReplaceNodesButton().should('not.exist');
135
+ ClusterPageSteps.getPreviewClusterConfigButton().should('not.exist');
136
+ ClusterPageSteps.getCreateClusterButton().should('have.class', 'no-cluster');
137
+ });
138
+
139
+ it('Should be able to replace nodes in cluster', () => {
140
+ // Given I have opened the cluster management page
141
+ RemoteLocationStubs.stubGetRemoteLocations();
142
+ ClusterPageSteps.visit();
143
+
144
+ // Given there is an existing cluster created
145
+ ClusterStubs.stubClusterConfig();
146
+ ClusterStubs.stubClusterGroupStatus();
147
+ ClusterStubs.stubClusterNodeStatus();
148
+ RemoteLocationStubs.stubRemoteLocationFilter();
149
+ RemoteLocationStubs.stubRemoteLocationStatusInCluster();
150
+ ClusterPageSteps.getClusterPage().should('be.visible');
151
+ ClusterPageSteps.getCreateClusterButton().should('not.have.class', 'no-cluster');
152
+ // When I click on replace nodes button
153
+ ClusterPageSteps.replaceNodes();
154
+ // Then I expect a replace nodes dialog to appear
155
+ ReplaceNodesDialogSteps.getDialog().should('be.visible');
156
+ ReplaceNodesDialogSteps.getClusterNodes().should('have.length', 3);
157
+ ReplaceNodesDialogSteps.getRemoteLocations().should('have.length', 0);
158
+ ReplaceNodesDialogSteps.getReplaceNodesButton().should('be.disabled');
159
+ // When I add a new remote location
160
+ RemoteLocationStubs.stubAddRemoteLocation();
161
+ RemoteLocationStubs.stubRemoteLocationCheck();
162
+ addRemoteLocation('http://localhost:7203', 3);
163
+ ClusterPageSteps.getClusterPage().should('be.visible');
164
+ ClusterPageSteps.getCreateClusterButton().should('not.have.class', 'no-cluster');
165
+ // And I select the new location as replacement node
166
+ ReplaceNodesDialogSteps.selectRemoteLocation(0);
167
+ ReplaceNodesDialogSteps.getSelectedRemoteLocations().should('have.length', 1);
168
+ // And I select a node from the cluster to be replaced
169
+ ReplaceNodesDialogSteps.selectClusterNode(2);
170
+ // Then I expect the replace nodes button to become enabled
171
+ ReplaceNodesDialogSteps.getReplaceNodesButton().should('not.be.disabled');
172
+ // When I click on replace nodes button
173
+ ClusterStubs.stubReplaceNodes();
174
+ ReplaceNodesDialogSteps.replaceNodes();
175
+ // Then I expect nodes to be replaced
176
+ cy.wait('@replace-nodes').then((interception) => {
177
+ expect(interception.request.body).to.deep.equal({
178
+ "addNodes": [
179
+ "pc-desktop:7301\n"
180
+ ],
181
+ "removeNodes": [
182
+ "pc-desktop:7302"
183
+ ]
184
+ });
185
+ });
186
+ ReplaceNodesDialogSteps.getDialog().should('not.exist');
187
+ ApplicationSteps.getSuccessNotifications().should('be.visible');
188
+ });
189
+ });
190
+
191
+ function addRemoteLocation(location, locationsCount) {
192
+ CreateClusterDialogSteps.openAddRemoteLocationDialog();
193
+ AddRemoteLocationDialogSteps.getDialog().should('be.visible');
194
+ AddRemoteLocationDialogSteps.typeLocation(location);
195
+ RemoteLocationStubs.stubGetRemoteLocations(locationsCount);
196
+ AddRemoteLocationDialogSteps.addLocation();
197
+ }
@@ -242,7 +242,7 @@ describe('Class hierarchy screen validation', () => {
242
242
  cy.get(CLASS_LABEL_SELECTOR)
243
243
  .each(($element) => {
244
244
  let data = $element.prop('__data__');
245
- if (data.name === className) {
245
+ if (data.data.name === className) {
246
246
  cy.wrap($element).as('classInHierarchy');
247
247
  }
248
248
  });
@@ -231,9 +231,7 @@ describe('Visual graph screen validation', () => {
231
231
 
232
232
  // Double click on collapsed node
233
233
  // This is ugly but unfortunately I couldn't make cypress's dblclick to work reliably here
234
- getTargetNodeElement().click().then(() => {
235
- getTargetNodeElement().click();
236
- });
234
+ getTargetNodeElement().dblclick()
237
235
 
238
236
  // Verify that all links to the USRegion node are expanded
239
237
  getPredicates().should('have.length', 3);
@@ -63,7 +63,7 @@ describe('Monitor Resources', () => {
63
63
  function verifyCharts(charts) {
64
64
  charts.forEach((chart) => {
65
65
  getChart(chart.id).scrollIntoView().find('.title').should('contain', chart.label);
66
- getChart(chart.id).scrollIntoView().find(`.${chart.type}`).should('be.visible');
66
+ getChart(chart.id).scrollIntoView().find(`svg`).should('be.visible');
67
67
  });
68
68
  }
69
69
 
@@ -854,10 +854,10 @@ describe('SPARQL screen validation', () => {
854
854
  SparqlSteps.getQueryArea().should('contain', 'SELECT');
855
855
  SparqlSteps.executeQuery();
856
856
  getUpdateMessage().should('not.be.visible');
857
- cy.verifyResultsMessage('Showing results from 1 to 74 of 74');
857
+ cy.verifyResultsMessage('Showing results from 1 to 72 of 72');
858
858
  cy.verifyResultsMessage('Query took');
859
859
 
860
- verifyResultsPageLength(74);
860
+ verifyResultsPageLength(72);
861
861
  });
862
862
 
863
863
  it('Test saved query link', () => {
@@ -33,12 +33,13 @@ describe('Visual graph screen validation', () => {
33
33
  cy.visit('graphs-visualizations');
34
34
  getCreateCustomGraphLink().click();
35
35
  cy.url().should('include', '/config/save');
36
- getGraphConfigName().type(graphConfigName);
37
36
  cy.get('[data-cy="graph-config-by-graph-query-checkbox"]').check();
38
- cy.pasteQuery('CONSTRUCT WHERE {?s ?p ?o} LIMIT 10').then( () => {
39
- getSaveConfig().click();
40
- }
41
- );
37
+ getGraphConfigName().type(graphConfigName, {force: true});
38
+
39
+ cy.waitUntil(() => getGraphConfigName().should('have.value', graphConfigName));
40
+ cy.pasteQuery('CONSTRUCT WHERE {?s ?p ?o} LIMIT 10');
41
+ cy.waitUntilQueryIsVisible();
42
+
42
43
  getSaveConfig().click();
43
44
  cy.url().should('include', 'graphs-visualizations');
44
45
  cy.contains('td', graphConfigName).should('be.visible').parent().within(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphdb-workbench-tests",
3
- "version": "2.4.2",
3
+ "version": "2.5.0-RC1",
4
4
  "description": "Cypress tests for GraphDB workbench",
5
5
  "scripts": {
6
6
  "start": "cypress open",
@@ -23,7 +23,7 @@
23
23
  "url": "git+https://github.com/Ontotext-AD/graphdb-workbench.git"
24
24
  },
25
25
  "dependencies": {
26
- "cypress": "^12.5.1",
26
+ "cypress": "^13.3.1",
27
27
  "cypress-failed-log": "^2.10.0",
28
28
  "cypress-localstorage-commands": "^1.4.4",
29
29
  "cypress-terminal-report": "^5.2.0",
@@ -0,0 +1,11 @@
1
+ import {ModalDialogSteps} from "../modal-dialog-steps";
2
+
3
+ export class AddRemoteLocationDialogSteps extends ModalDialogSteps {
4
+ static typeLocation(location) {
5
+ this.getDialog().find('#sesameLocation').type(location);
6
+ }
7
+
8
+ static addLocation() {
9
+ this.getDialogFooter().find('.add-location-btn').click();
10
+ }
11
+ }
@@ -0,0 +1,57 @@
1
+ export class ClusterPageSteps {
2
+ static visit() {
3
+ cy.visit('/cluster');
4
+ }
5
+
6
+ static getClusterPage() {
7
+ return cy.get('.cluster-view');
8
+ }
9
+
10
+ static getCreateClusterButton() {
11
+ return cy.get('.cluster-zone');
12
+ }
13
+
14
+ static createCluster() {
15
+ this.getCreateClusterButton().click();
16
+ }
17
+
18
+ static getClusterDeleteButton() {
19
+ return cy.get('.delete-cluster-btn');
20
+ }
21
+
22
+ static deleteCluster() {
23
+ this.getClusterDeleteButton().click();
24
+ }
25
+
26
+ static getRemoveNodesButton() {
27
+ return cy.get('.remove-node-btn');
28
+ }
29
+
30
+ static removeNodes() {
31
+ this.getRemoveNodesButton().click();
32
+ }
33
+
34
+ static getAddNodesButton() {
35
+ return cy.get('.add-node-btn');
36
+ }
37
+
38
+ static addNodes() {
39
+ this.getAddNodesButton().click();
40
+ }
41
+
42
+ static getReplaceNodesButton() {
43
+ return cy.get('.replace-nodes-btn');
44
+ }
45
+
46
+ static replaceNodes() {
47
+ this.getReplaceNodesButton().click();
48
+ }
49
+
50
+ static getPreviewClusterConfigButton() {
51
+ return cy.get('.preview-cluster-config-btn');
52
+ }
53
+
54
+ static previewClusterConfig() {
55
+ this.getPreviewClusterConfigButton().click();
56
+ }
57
+ }
@@ -0,0 +1,39 @@
1
+ import {ModalDialogSteps} from "../modal-dialog-steps";
2
+
3
+ export class CreateClusterDialogSteps extends ModalDialogSteps {
4
+ static getCreateClusterDialog() {
5
+ return this.getDialog().find('.create-cluster-dialog');
6
+ }
7
+
8
+ static getClusterNodesPanel() {
9
+ return this.getCreateClusterDialog().find('.cluster-nodes');
10
+ }
11
+
12
+ static getClusterNodesList() {
13
+ return this.getClusterNodesPanel().find('.nodes-list .list-group-item');
14
+ }
15
+
16
+ static getRemoteLocationsList() {
17
+ return this.getCreateClusterDialog().find('.remote-locations .location-item');
18
+ }
19
+
20
+ static getSaveClusterConfigButton() {
21
+ return this.getDialogFooter().find('.create-cluster-btn');
22
+ }
23
+
24
+ static saveClusterConfig() {
25
+ return this.getSaveClusterConfigButton().click();
26
+ }
27
+
28
+ static openAddRemoteLocationDialog() {
29
+ this.getDialog().find('#addLocation').click();
30
+ }
31
+
32
+ static selectRemoteLocation(index) {
33
+ this.getRemoteLocationsList().eq(index).click();
34
+ }
35
+
36
+ static getNoSelectedNodesWarning() {
37
+ return this.getDialog().find('.no-selected-nodes');
38
+ }
39
+ }
@@ -0,0 +1,11 @@
1
+ import {ModalDialogSteps} from "../modal-dialog-steps";
2
+
3
+ export class DeleteClusterDialogSteps extends ModalDialogSteps {
4
+ static getConfirmButton() {
5
+ return ModalDialogSteps.getDialogFooter().find('#wb-delete-cluster-submit');
6
+ }
7
+
8
+ static confirmDeleteCluster() {
9
+ this.getConfirmButton().click();
10
+ }
11
+ }
@@ -0,0 +1,39 @@
1
+ import {ModalDialogSteps} from "../modal-dialog-steps";
2
+
3
+ export class ReplaceNodesDialogSteps extends ModalDialogSteps {
4
+ static getReplaceClusterDialog() {
5
+ return this.getDialog().find('.replace-cluster-nodes-dialog');
6
+ }
7
+
8
+ static getClusterNodes() {
9
+ return this.getDialogBody().find('.nodes-list .list-group-item-node');
10
+ }
11
+
12
+ static selectClusterNode(index) {
13
+ this.getClusterNodes().eq(index).click();
14
+ }
15
+
16
+ static getRemoteLocations() {
17
+ return this.getDialogBody().find('.locations-list .location-item');
18
+ }
19
+
20
+ static getReplaceNodesButton() {
21
+ return this.getDialogFooter().find('#wb-replace-nodes-in-cluster-submit');
22
+ }
23
+
24
+ static replaceNodes() {
25
+ this.getReplaceNodesButton().click();
26
+ }
27
+
28
+ static getRemoteLocationsList() {
29
+ return this.getReplaceClusterDialog().find('.remote-locations .location-item');
30
+ }
31
+
32
+ static selectRemoteLocation(index) {
33
+ this.getRemoteLocationsList().eq(index).click();
34
+ }
35
+
36
+ static getSelectedRemoteLocations() {
37
+ return this.getReplaceClusterDialog().find('.selected-remote-locations .list-group-item-node');
38
+ }
39
+ }
@@ -0,0 +1,67 @@
1
+ import {Stubs} from "../stubs";
2
+
3
+ export class ClusterStubs extends Stubs {
4
+ static stubNoClusterGroupStatus() {
5
+ cy.intercept('/rest/cluster/group/status', {
6
+ fixture: '/cluster/no-cluster-group-status.json',
7
+ statusCode: 404
8
+ }).as('no-cluster-group-status');
9
+ }
10
+
11
+ static stubClusterGroupStatus() {
12
+ cy.intercept('/rest/cluster/group/status', {
13
+ fixture: '/cluster/3-nodes-cluster-group-status.json',
14
+ statusCode: 200
15
+ }).as('3-nodes-cluster-group-status');
16
+ }
17
+
18
+ static stubNoClusterNodeStatus() {
19
+ cy.intercept('/rest/cluster/node/status', {
20
+ fixture: '/cluster/no-cluster-node-status.json',
21
+ statusCode: 404
22
+ }).as('no-cluster-node-status');
23
+ }
24
+
25
+ static stubClusterNodeStatus() {
26
+ cy.intercept('/rest/cluster/node/status', {
27
+ fixture: '/cluster/cluster-node-status.json',
28
+ statusCode: 200
29
+ }).as('cluster-node-status');
30
+ }
31
+
32
+ static stubNoClusterConfig() {
33
+ cy.intercept('/rest/cluster/config', {
34
+ statusCode: 404
35
+ }).as('no-cluster-config');
36
+ }
37
+
38
+ static stubClusterConfig() {
39
+ cy.intercept('/rest/cluster/config', {
40
+ fixture: '/cluster/cluster-config.json',
41
+ statusCode: 200
42
+ }).as('cluster-config');
43
+ }
44
+
45
+ static stubCreateCluster() {
46
+ cy.intercept('/rest/cluster/config', {
47
+ fixture: '/cluster/3-nodes-cluster-created.json',
48
+ statusCode: 201
49
+ }).as('3-nodes-cluster-created');
50
+ }
51
+
52
+ static stubDeleteCluster() {
53
+ cy.intercept('/rest/cluster/config?force=false', {
54
+ fixture: '/cluster/delete-cluster.json',
55
+ statusCode: 200,
56
+ method: 'DELETE'
57
+ }).as('delete-cluster');
58
+ }
59
+
60
+ static stubReplaceNodes() {
61
+ cy.intercept('/rest/cluster/config/node', {
62
+ fixture: '/cluster/replace-nodes.json',
63
+ statusCode: 200,
64
+ method: 'PATCH'
65
+ }).as('replace-nodes');
66
+ }
67
+ }
@@ -0,0 +1,52 @@
1
+ import {Stubs} from "../stubs";
2
+
3
+ export class RemoteLocationStubs extends Stubs {
4
+ static stubAddRemoteLocation() {
5
+ cy.intercept('POST', '/rest/locations', {
6
+ fixture: '/remote-location/add-remote-location'
7
+ }).as('add-remote-location');
8
+ }
9
+
10
+ static stubGetRemoteLocations(count = 'no') {
11
+ cy.intercept('GET', '/rest/locations', {
12
+ fixture: `/remote-location/get-${count}-remote-locations.json`,
13
+ statusCode: 200
14
+ }).as(`get-${count}-remote-locations`);
15
+ }
16
+
17
+ static stubGetOneRemoteLocations() {
18
+ cy.intercept('GET', '/rest/locations', {
19
+ fixture: '/remote-location/get-1-remote-locations.json'
20
+ }).as('get-1-remote-locations');
21
+ }
22
+
23
+ static stubGetTwoRemoteLocations() {
24
+ cy.intercept('GET', '/rest/locations', {
25
+ fixture: '/remote-location/get-2-remote-locations.json'
26
+ }).as('get-remote-locations');
27
+ }
28
+
29
+ static stubRemoteLocationCheck() {
30
+ cy.intercept('GET', '/rest/info/rpc-address?location=*', {
31
+ fixture: '/remote-location/remote-location-check'
32
+ }).as('check-remote-location');
33
+ }
34
+
35
+ static stubRemoteLocationFilter() {
36
+ cy.intercept('GET', '/rest/locations?filterClusterLocations=true', {
37
+ fixture: '/remote-location/remote-location-check'
38
+ }).as('check-remote-location');
39
+ }
40
+
41
+ static stubRemoteLocationStatusInCluster() {
42
+ cy.intercept('GET', '/rest/locations/active', {
43
+ fixture: '/remote-location/remote-location-status-in-cluster.json'
44
+ }).as('remote-location-status-in-cluster');
45
+ }
46
+
47
+ static stubRemoteLocationStatusNotCluster() {
48
+ cy.intercept('GET', '/rest/locations/active', {
49
+ fixture: '/remote-location/remote-location-status-not-in-cluster.json'
50
+ }).as('remote-location-status-not-in-cluster');
51
+ }
52
+ }
@@ -4,4 +4,11 @@ export class GlobalOperationsStatusesStub extends Stubs {
4
4
  static stubGlobalOperationsStatusesResponse(repositoryId, withDelay = 0) {
5
5
  GlobalOperationsStatusesStub.stubQueryResponse(`/rest/monitor/${repositoryId}/operations`, '/monitoring/global-operation-statuses.json', 'backup-and-restore-response', withDelay);
6
6
  }
7
+
8
+ static stubNoOperationsResponse(repositoryId, withDelay = 0) {
9
+ GlobalOperationsStatusesStub.stubQueryResponse(
10
+ `/rest/monitor/${repositoryId}/operations`,
11
+ '/monitoring/no-operations.json',
12
+ 'backup-and-restore-response', withDelay);
13
+ }
7
14
  }