graphdb-workbench-tests 3.0.0-TR13 → 3.0.0-TR15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fixtures/locale-en.json +114 -3
- package/integration/explore/visual-graph/visual-graph-node-labels.spec.js +68 -0
- package/integration/graphql/activate-deactivate-graphql-endpoint.spec.js +1 -2
- package/integration/graphql/edit-graphql-enpoint.spec.js +30 -1
- package/integration/import/import-server-files.spec.js +22 -0
- package/integration/import/import-user-data-url.spec.js +33 -0
- package/integration/repository/repositories.spec.js +1 -0
- package/integration/setup/user-and-access.spec.js +10 -10
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/steps/graphql/edit-graphql-endpoint-steps.js +34 -0
- package/steps/import/import-settings-dialog-steps.js +12 -0
- package/steps/import/import-steps.js +9 -4
- package/steps/import/import-user-data-steps.js +8 -0
- package/steps/visual-graph-steps.js +14 -0
- package/support/import-commands.js +4 -4
- package/utils/html-util.js +21 -0
package/fixtures/locale-en.json
CHANGED
|
@@ -625,7 +625,7 @@
|
|
|
625
625
|
"label": "Save"
|
|
626
626
|
},
|
|
627
627
|
"explain_settings": {
|
|
628
|
-
"label": "
|
|
628
|
+
"label": "Review agent instructions"
|
|
629
629
|
}
|
|
630
630
|
},
|
|
631
631
|
"dialog": {
|
|
@@ -871,6 +871,18 @@
|
|
|
871
871
|
"success_saving_configuration": "Endpoint configuration saved"
|
|
872
872
|
},
|
|
873
873
|
"settings": {
|
|
874
|
+
"graphql": {
|
|
875
|
+
"label": "GraphQL settings",
|
|
876
|
+
"description": "Settings for the GraphQL endpoint"
|
|
877
|
+
},
|
|
878
|
+
"security": {
|
|
879
|
+
"label": "Security settings",
|
|
880
|
+
"description": "Settings for the GraphQL endpoint security"
|
|
881
|
+
},
|
|
882
|
+
"integration": {
|
|
883
|
+
"label": "Integration settings",
|
|
884
|
+
"description": "Settings for the GraphQL endpoint integration"
|
|
885
|
+
},
|
|
874
886
|
"enableTypeCount": {
|
|
875
887
|
"label": "Enable Type Count Queries",
|
|
876
888
|
"tooltip": "Toggle to include count queries in the schema."
|
|
@@ -1078,6 +1090,18 @@
|
|
|
1078
1090
|
"endpoint_parameters": {
|
|
1079
1091
|
"title": "Parameters",
|
|
1080
1092
|
"settings": {
|
|
1093
|
+
"generic": {
|
|
1094
|
+
"label": "Generic settings",
|
|
1095
|
+
"tooltip": "Generic settings for the GraphQL endpoint"
|
|
1096
|
+
},
|
|
1097
|
+
"dataCleanup": {
|
|
1098
|
+
"label": "Data Cleanup",
|
|
1099
|
+
"tooltip": "Settings for data cleanup"
|
|
1100
|
+
},
|
|
1101
|
+
"enterprise": {
|
|
1102
|
+
"label": "Enterprise settings",
|
|
1103
|
+
"tooltip": "Enterprise settings for the GraphQL endpoint"
|
|
1104
|
+
},
|
|
1081
1105
|
"stringMode": {
|
|
1082
1106
|
"label": "Default String Mode",
|
|
1083
1107
|
"tooltip": "Specifies the default string mode for data properties without a range definition."
|
|
@@ -1122,10 +1146,9 @@
|
|
|
1122
1146
|
"overview": {
|
|
1123
1147
|
"title": "Overview",
|
|
1124
1148
|
"for_shapes": {
|
|
1125
|
-
"info": "{{endpointsCount}} GraphQL endpoints
|
|
1149
|
+
"info": "GraphDB will attempt to create {{endpointsCount}} GraphQL endpoints in the \"{{activeRepoId}}\" based on the selected resources. To modify the selection, go back to Step 1 (Select schema source).",
|
|
1126
1150
|
"included_endpoints": "Included GraphQL schema shapes",
|
|
1127
1151
|
"generated_endpoints": "GraphQL endpoints",
|
|
1128
|
-
"manage_endpoints_info": "Navigate to <a href=\"{{managementUrl}}\">Endpoint Management</a> to manage the endpoints",
|
|
1129
1152
|
"explore_in_playground_link_tooltip": "Explore in Playground (opens in a new tab)",
|
|
1130
1153
|
"view_report_link": "View report",
|
|
1131
1154
|
"view_report_link_tooltip": "Opens endpoint creation report in a modal dialog"
|
|
@@ -1135,6 +1158,34 @@
|
|
|
1135
1158
|
"generation_progress": "Endpoints creation in progress..."
|
|
1136
1159
|
}
|
|
1137
1160
|
},
|
|
1161
|
+
"generate_endpoint": {
|
|
1162
|
+
"title": "Create",
|
|
1163
|
+
"overview": {
|
|
1164
|
+
"title": "Overview",
|
|
1165
|
+
"for_shapes": {
|
|
1166
|
+
"info": "{{endpointsCount}} GraphQL endpoints will be created in \"{{activeRepoId}}\" repository based on the GraphQL schema shapes listed below. To modify the selection, navigate back to Step 1 (Select schema source).",
|
|
1167
|
+
"included_endpoints": "Included GraphQL schema shapes",
|
|
1168
|
+
"generated_endpoints": "GraphQL endpoints",
|
|
1169
|
+
"manage_endpoints_info": "Navigate to <a href=\"{{managementUrl}}\">Endpoint Management</a> to manage the endpoints",
|
|
1170
|
+
"explore_in_playground_link_tooltip": "Explore in Playground (opens in a new tab)",
|
|
1171
|
+
"view_report_link": "[View report]"
|
|
1172
|
+
}
|
|
1173
|
+
},
|
|
1174
|
+
"generation_failure_report": {
|
|
1175
|
+
"title": "GraphQL endpoint creation failed",
|
|
1176
|
+
"reason_message": "GraphQL endpoint \"{{endpointId}}\" creation failed because of errors/warnings during schema definition generation.",
|
|
1177
|
+
"errors": "Validation error [{{errorCount}}]",
|
|
1178
|
+
"warnings": "Warning [{{warningCount}}]",
|
|
1179
|
+
"actions": {
|
|
1180
|
+
"download_report": {
|
|
1181
|
+
"label": "Download report"
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
"messages": {
|
|
1186
|
+
"generation_progress": "Endpoints creation in progress..."
|
|
1187
|
+
}
|
|
1188
|
+
},
|
|
1138
1189
|
"shapes_multiselect": {
|
|
1139
1190
|
"available_options": {
|
|
1140
1191
|
"title": "Available (not included)",
|
|
@@ -1204,6 +1255,10 @@
|
|
|
1204
1255
|
},
|
|
1205
1256
|
"generate_endpoint": {
|
|
1206
1257
|
"label": "Create endpoint"
|
|
1258
|
+
},
|
|
1259
|
+
"finish_workflow": {
|
|
1260
|
+
"label": "Finish",
|
|
1261
|
+
"tooltip": "Finish the workflow and return to the endpoint management"
|
|
1207
1262
|
}
|
|
1208
1263
|
}
|
|
1209
1264
|
},
|
|
@@ -2455,6 +2510,8 @@
|
|
|
2455
2510
|
"common.attach": "Attach",
|
|
2456
2511
|
"common.close": "Close",
|
|
2457
2512
|
"common.preview": "Preview",
|
|
2513
|
+
"common.show_all": "Show all",
|
|
2514
|
+
"common.hide": "Hide",
|
|
2458
2515
|
"common.learn_more_in_documentation": "Learn more in the GraphDB documentation",
|
|
2459
2516
|
"paginator.first.page.label": "First",
|
|
2460
2517
|
"paginator.last.page.label": "Last",
|
|
@@ -2900,6 +2957,7 @@
|
|
|
2900
2957
|
"sidepanel.limit.links.tooltip": "Limit the number of links when often they are too many",
|
|
2901
2958
|
"sidepanel.maximum.links": "Maximum links to show",
|
|
2902
2959
|
"visual.search.instance.placeholder": "Search instance properties",
|
|
2960
|
+
"visual.node.tooltip.no_types": "No types",
|
|
2903
2961
|
"sidepanel.invalid.limit.links.msg": "Invalid links limit",
|
|
2904
2962
|
"sidepanel.invalid.limit.links.tooltip": "The valid limit range is 1-1000",
|
|
2905
2963
|
"sidepanel.preferred.languages": "Preferred languages",
|
|
@@ -3084,6 +3142,9 @@
|
|
|
3084
3142
|
"guide.step-intro.import-file": "The following steps show how to use the <b>{{viewName|translate}}</b> view to import data from a file.",
|
|
3085
3143
|
"guide.step-intro.class-hierarchy": "The following steps show how to use the <b>{{viewName|translate}}</b> view to inspect the class hierarchy and gain an insight on what the dataset contains.",
|
|
3086
3144
|
"guide.step-intro.table-graph": "The following steps show how to explore RDF data in tabular form without writing SPARQL queries. Click on the <b>{{iriLabel}}</b> IRI to explore it.",
|
|
3145
|
+
"guide.step-intro.create-ttyg-agent": "The following steps show how to use the <b>{{viewName|translate}}</b> view to create an agent.",
|
|
3146
|
+
"guide.step-intro.create-similarity-index": "The following steps show how to create a Similarity index for your dataset.",
|
|
3147
|
+
"guide.step-help-info.create-similarity-index": "The similarity index is used for finding words which have been used in similar contexts to the one which you search for. For example, searching for \"ontology\" will return \"knowledge graph\", while a simple textual similarity could return \"oncology\". This is an alternative for full-text search.",
|
|
3087
3148
|
"guide.step-menu.click-menu": "Click on the <b>{{menuLabelKey|translate}}</b> menu.",
|
|
3088
3149
|
"guide.step-action.create-repository": "Create repository",
|
|
3089
3150
|
"guide.step-action.select-repository": "Connect to repository",
|
|
@@ -3093,6 +3154,15 @@
|
|
|
3093
3154
|
"guide.step-action.execute-sparql-query": "Execute SPARQL query",
|
|
3094
3155
|
"guide.step-action.class-hierarchy": "Explore the class hierarchy",
|
|
3095
3156
|
"guide.step-action.table-graph": "Explore RDF as a table",
|
|
3157
|
+
"guide.step-action.create-ttyg-agent": "Create an agent",
|
|
3158
|
+
"guide.step-action.sparql-search-method": "SPARQL search query method",
|
|
3159
|
+
"guide.step-action.fts-search-method": "FTS search query method",
|
|
3160
|
+
"guide.step-action.similarity-search-method": "Similarity search query method",
|
|
3161
|
+
"guide.step-action.select-ttyg-agent": "Select an agent",
|
|
3162
|
+
"guide.step-action.ask-ttyg-agent": "Ask the agent",
|
|
3163
|
+
"guide.step-action.conversation-with-ttyg-agent": "Conversation with the agent",
|
|
3164
|
+
"guide.step-action.edit-ttyg-agent": "Edit an agent",
|
|
3165
|
+
"guide.step-action.create-similarity-index": "Create Similarity index",
|
|
3096
3166
|
"guide.step_plugin.execute-sparql-query.query-editor.content": "Enter the following SPARQL query: {{queryExplainMessageTranslated}}{{queryAsHtmlCodeElement}}",
|
|
3097
3167
|
"guide.step_plugin.execute-sparql-query.result-explain.content": "The table shows the results from executing the query.",
|
|
3098
3168
|
"guide.step_plugin.execute-sparql-query.run-sparql-query.content": "Click on the <b>{{'query.editor.run.btn'|translate}}</b> button.",
|
|
@@ -3103,6 +3173,8 @@
|
|
|
3103
3173
|
"guide.step_plugin.create_repository.repository_id.content": "Enter repository ID: <b>{{repositoryId}}.</b>",
|
|
3104
3174
|
"guide.step_plugin.create_repository.save_button.content": "Click on the <b>{{'common.create.btn'|translate}}</b> button.",
|
|
3105
3175
|
"guide.step_plugin.create_repository.ruleset_dropdown.content": "Choose ruleset: <b>{{rulesetName}}</b>.",
|
|
3176
|
+
"guide.step_plugin.create_repository.enable-fts.content": "Enable full-text search (FTS) index",
|
|
3177
|
+
"guide.step_plugin.create_repository.enable-fts.extra-content": "The full text search index is used for finding specific strings within the values associated with a given entity. For example, you can search for the word \"feature\" within a larger context. This is very helpful in cases where a lot of data is stored in literals.",
|
|
3106
3178
|
"guide.step_plugin.enable-autocomplete.content": "Click on the checkbox to enable the index.",
|
|
3107
3179
|
"guide.step_plugin.visual_graph_input_IRI.content": "Enter <b>{{easyGraphInputText}}</b> in the <b>Easy graph</b> text input.",
|
|
3108
3180
|
"guide.step_plugin.visual_graph_show_autocomplete.content": "Click on the <b>{{iri}}</b> IRI to show the visual graph.",
|
|
@@ -3160,6 +3232,45 @@
|
|
|
3160
3232
|
"guide.step_plugin.welcome.input-icon-hint": "<span class='icon icon-1-5x icon-edit'></span> tells you to type or paste something.",
|
|
3161
3233
|
"guide.step_plugin.welcome-what.title": "What is {{translatedGuideName}}?",
|
|
3162
3234
|
"guide.step_plugin.welcome-what.content": "{{translatedGuideDescription}}<p>Let's get started for real now!</p>",
|
|
3235
|
+
"guide.step_plugin.create-ttyg-agent.intro": "An agent is a helpful assistant that can answer your queries. You need to configure an agent in order to ask anything of Talk to Your Graph.",
|
|
3236
|
+
"guide.step_plugin.ttyg.missing-key.title": "Missing OpenAI key",
|
|
3237
|
+
"guide.step_plugin.ttyg.missing-key.content": "To use <b>Talk to Your Graph</b>, GraphDB must first be configured to work with OpenAI. Please ensure that the necessary API keys and settings are in place before starting. For detailed setup instructions, refer to the documentation or contact your administrator.",
|
|
3238
|
+
"guide.step_plugin.create-ttyg-agent.create-agent": "Click on the create agent button to create a new agent.",
|
|
3239
|
+
"guide.step_plugin.create-ttyg-agent.save-agent-settings": "Click to save the agent settings.",
|
|
3240
|
+
"guide.step_plugin.sparql-search-method.content": "Enabling SPARQL search allows the agent to answers questions by performing a SPARQL query. This works well for datasets with good ontologies and performs well on closed-ended questions, including aggregations.",
|
|
3241
|
+
"guide.step_plugin.sparql-search-method.enable-toggle": "Click on the toggle to enable SPARQL search query method.",
|
|
3242
|
+
"guide.step_plugin.sparql-search-method.disable-toggle": "Click on the toggle to disable SPARQL search query method.",
|
|
3243
|
+
"guide.step_plugin.sparql-search-method.enable-ontology-from-graph": "Click on the toggle to enable providing an ontology in a named graph.",
|
|
3244
|
+
"guide.step_plugin.sparql-search-method.type-ontology-graph-name": "Type <b>{{ontologyGraph}}</b> as the named graph which contains the ontology.",
|
|
3245
|
+
"guide.step_plugin.fts-search-method.content": "Enabling FTS search allows the agent to answer questions by using full-text search in literals and IRIs. Performs well on open-ended questions but not so well on providing aggregations.",
|
|
3246
|
+
"guide.step_plugin.fts-search-method.enable-toggle": "Click on the toggle to enable FTS search query method.",
|
|
3247
|
+
"guide.step_plugin.fts-search-method.disable-toggle": "Click on the toggle to disable FTS search query method.",
|
|
3248
|
+
"guide.step_plugin.similarity-search-method.content": "Enabling Similarity search allows the agent to answer questions by using Similarity search. Performs well on open-ended questions but not so well on providing aggregations.",
|
|
3249
|
+
"guide.step_plugin.similarity-search-method.enable-toggle": "Click on the toggle to enable Similarity search query method.",
|
|
3250
|
+
"guide.step_plugin.similarity-search-method.disable-toggle": "Click on the toggle to disable Similarity search query method.",
|
|
3251
|
+
"guide.step_plugin.similarity-search-method.select-index": "Select the index to use for Similarity search.",
|
|
3252
|
+
"guide.step_plugin.select-ttyg-agent.info.title": "Select your agent",
|
|
3253
|
+
"guide.step_plugin.select-ttyg-agent.info.content": "To talk to your graph, you need to select an agent first",
|
|
3254
|
+
"guide.step_plugin.select-ttyg-agent.open-agent-dropdown": "Click on the agents dropdown to see available agents",
|
|
3255
|
+
"guide.step_plugin.select-ttyg-agent.select-agent": "Click on you agent from the dropdown to select it",
|
|
3256
|
+
"guide.step_plugin.select-ttyg-agent.missing-repository": "The agent you selected has no repository. Please select an agent configured with current repository.",
|
|
3257
|
+
"guide.step_plugin.ask-ttyg-agent.input-question": "Type \"<b>{{question}}</b>\" in the input and press enter",
|
|
3258
|
+
"guide.step_plugin.ask-ttyg-agent.wait-for-answer": "Wait for the answer to be returned and explore it. When ready proceed by clicking next.",
|
|
3259
|
+
"guide.step_plugin.ask-ttyg-agent.explain-answer": "Explain the answer by clicking on the 'Explain response' button.",
|
|
3260
|
+
"guide.step_plugin.ask-ttyg-agent.explore-sparql": "You can open the query in the SPARQL editor by clicking on 'Open in SPARQL editor' button. When you are ready, return to the page.",
|
|
3261
|
+
"guide.step_plugin.ask-ttyg-agent.explain-answer-more": "You can ask the agent how it derived the answer by clicking on the button",
|
|
3262
|
+
"guide.step_plugin.conversation-with-ttyg-agent.info": "The Talk To Your Graph view provides a chat-like interface for querying your data. Natural language queries are written in the chatbox at the bottom of the screen. With the aid of LLM technology, they are translated into a machine-readable question and the RDF answer is narrated back to you.",
|
|
3263
|
+
"guide.step_plugin.conversation-with-ttyg-agent.start-conversation": "Click the button to create a new chat",
|
|
3264
|
+
"guide.step_plugin.edit-ttyg-agent.intro": "An agent's configuration such as the extraction methods can be reconfigured at any time",
|
|
3265
|
+
"guide.step_plugin.edit-ttyg-agent.edit-agent": "Click on the edit agent button to edit the configuration of the selected agent.",
|
|
3266
|
+
"guide.step_plugin.edit-ttyg-agent.save-agent-settings": "Click to save the agent settings.",
|
|
3267
|
+
"guide.step_plugin.create-similarity-index.create-similarity-index": "Click the link to start creating a new Similarity index",
|
|
3268
|
+
"guide.step_plugin.create-similarity-index.input-index-name": "Type a name for the index. You will refer to it later.",
|
|
3269
|
+
"guide.step_plugin.create-similarity-index.create-index": "Click the button to create the Similarity index.",
|
|
3270
|
+
"guide.step_plugin.create-similarity-index.wait": "Wait for index to be created",
|
|
3271
|
+
"guide.step_plugin.configure-agent.name-input": "Type a name for the agent. You will refer to it later.",
|
|
3272
|
+
"guide.step_plugin.configure-agent.model-input": "Here you can type the name of the OpenAI model to be used.<br>Type: \"<b>{{model}}</b>\" to configure the agent to use this model",
|
|
3273
|
+
"guide.step_plugin.configure-agent.user-instructions-input": "Here you can type additional instructions which will be passed to the agent.<br> Type: \"<b>{{userInstructions}}</b>\"",
|
|
3163
3274
|
"guide.confirm.cancel.message": "Are you sure you want to stop the guide?",
|
|
3164
3275
|
"guide.unexpected.error.message": "The guide was cancelled due to an unexpected error. Please run the guide again and if the problem persists contact the support.",
|
|
3165
3276
|
"guide.start.unexpected.error.message": "The guide cannot be started due to an unexpected error. Please try running the guide again and if the problem persists contact the support.",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { LicenseStubs } from "../../../stubs/license-stubs";
|
|
2
|
+
import { VisualGraphSteps } from "../../../steps/visual-graph-steps";
|
|
3
|
+
import { HtmlUtil } from "../../../utils/html-util";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RDF snippet with the necessary data to test all possible label scenarios:
|
|
7
|
+
* 1. (ex:node1) Node with a plain text label;
|
|
8
|
+
* 2. (ex:node2) Node with an HTML label;
|
|
9
|
+
* 3. (ex:node3) Node with a label that contains a new line ("\n") character;
|
|
10
|
+
* 4. (ex:node4) Node with a long label.
|
|
11
|
+
*
|
|
12
|
+
* @type {string}
|
|
13
|
+
*/
|
|
14
|
+
const RDF_SNIPPETS_WITH_NODE_LABELS_DATA =
|
|
15
|
+
'@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n' +
|
|
16
|
+
'@prefix ex: <http://example.com/> .\n' +
|
|
17
|
+
'\n' +
|
|
18
|
+
'# Define Nodes with Labels\n' +
|
|
19
|
+
'ex:node1 rdfs:label "Node One" .\n' +
|
|
20
|
+
'ex:node2 rdfs:label "Node<br>Two" .\n' +
|
|
21
|
+
'ex:node3 rdfs:label "Node\\nThree" .\n' +
|
|
22
|
+
'ex:node4 rdfs:label "A longer label for Node Four" .\n' +
|
|
23
|
+
'\n' +
|
|
24
|
+
'# Relationships Between Nodes\n' +
|
|
25
|
+
'ex:node1 ex:connectedTo ex:node2 .\n' +
|
|
26
|
+
'ex:node1 ex:connectedTo ex:node3 .\n' +
|
|
27
|
+
'ex:node1 ex:connectedTo ex:node4 .\n';
|
|
28
|
+
|
|
29
|
+
describe("Node Basics", () => {
|
|
30
|
+
|
|
31
|
+
let repositoryId;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
cy.clearLocalStorage('ls.graphs-viz');
|
|
35
|
+
repositoryId = 'graphRepo-node-labels-' + Date.now();
|
|
36
|
+
cy.createRepository({ id: repositoryId });
|
|
37
|
+
cy.presetRepository(repositoryId);
|
|
38
|
+
// cy.importServerFile(repositoryId, FILE_WITH_NODE_LABELS_DATA);
|
|
39
|
+
cy.importRDFTextSnippet(repositoryId, RDF_SNIPPETS_WITH_NODE_LABELS_DATA);
|
|
40
|
+
LicenseStubs.spyGetLicense();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
cy.clearLocalStorage('ls.graphs-viz');
|
|
45
|
+
cy.deleteRepository(repositoryId);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should allow the node label to be displayed on multiple lines only when a new line character is used', () => {
|
|
49
|
+
// When: I open a visual graph of a node that has links to other nodes.
|
|
50
|
+
VisualGraphSteps.openNodeLabelGraph();
|
|
51
|
+
|
|
52
|
+
// Then: I expect:
|
|
53
|
+
// The label of ex:node1 to be displayed as is, because it is short plain text.
|
|
54
|
+
VisualGraphSteps.getNodeLabel('http://example.com/node1').should('have.html', 'Node One');
|
|
55
|
+
|
|
56
|
+
// The label of ex:node2 to be displayed with all HTML tags removed.
|
|
57
|
+
VisualGraphSteps.getNodeLabel('http://example.com/node2').should('have.html', 'NodeTwo');
|
|
58
|
+
|
|
59
|
+
// The label of ex:node3 to be displayed with the new line character replaced by a <br> tag.
|
|
60
|
+
VisualGraphSteps.getNodeLabel('http://example.com/node3').should('have.html', 'Node<br>Three');
|
|
61
|
+
|
|
62
|
+
// The label of ex:node4 to be displayed with a long label (no truncation).
|
|
63
|
+
VisualGraphSteps.getNodeLabel('http://example.com/node4').should('have.html', 'A longer label for Node Four');
|
|
64
|
+
|
|
65
|
+
// The label of ex:node4 should be truncated with ellipsis because it has a long label.
|
|
66
|
+
HtmlUtil.verifyEllipsis(VisualGraphSteps.getNodeLabel('http://example.com/node4'));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -17,8 +17,7 @@ describe('GraphQL: activate and deactivate endpoint', () => {
|
|
|
17
17
|
cy.deleteRepository(repositoryId);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
it.skip('should be able to activate or deactivate an endpoint', () => {
|
|
20
|
+
it('should be able to activate or deactivate an endpoint', () => {
|
|
22
21
|
// Given I have a repository with active GraphQL endpoints
|
|
23
22
|
// When I visit the endpoint management view
|
|
24
23
|
GraphqlEndpointManagementSteps.visit();
|
|
@@ -26,6 +26,30 @@ describe('Graphql: edit endpoint settings', () => {
|
|
|
26
26
|
GraphqlEndpointManagementSteps.editEndpointConfiguration(0);
|
|
27
27
|
EditGraphqlEndpointSteps.getDialog().should('be.visible');
|
|
28
28
|
|
|
29
|
+
// I should see 3 groups of fields
|
|
30
|
+
EditGraphqlEndpointSteps.getFormGroups().should('have.length', 3);
|
|
31
|
+
EditGraphqlEndpointSteps.validateFormGroups([
|
|
32
|
+
{label: 'GraphQL settings'},
|
|
33
|
+
{label: 'Security settings'},
|
|
34
|
+
{label: 'Integration settings'}
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
// I should see 8 fields in the first group
|
|
38
|
+
EditGraphqlEndpointSteps.getVisibleFormGroupFields(0).should('have.length', 8);
|
|
39
|
+
EditGraphqlEndpointSteps.validateFormGroupFields(0, [
|
|
40
|
+
{"label": "Enable Type Count Queries"},
|
|
41
|
+
{"label": "Enable Collection Count"},
|
|
42
|
+
{"label": "Compact Error Messages"},
|
|
43
|
+
{"label": "Default Fetch Language"},
|
|
44
|
+
{"label": "Default Language Validation"},
|
|
45
|
+
{"label": "Default Implicit Language"},
|
|
46
|
+
{"label": "Include Inferred Data"},
|
|
47
|
+
{"label": "Expand owl:sameAs"}
|
|
48
|
+
]);
|
|
49
|
+
// When I expand the first group
|
|
50
|
+
EditGraphqlEndpointSteps.toggleFormGroupHiddenFields(0);
|
|
51
|
+
EditGraphqlEndpointSteps.getAllFormGroupFields(0).should('have.length', 10);
|
|
52
|
+
|
|
29
53
|
EditGraphqlEndpointSteps.getInputField(3).should('have.value', 'ANY');
|
|
30
54
|
EditGraphqlEndpointSteps.fillInputField(3, 'NONE')
|
|
31
55
|
|
|
@@ -55,6 +79,9 @@ describe('Graphql: edit endpoint settings', () => {
|
|
|
55
79
|
// Then the save button is disabled
|
|
56
80
|
EditGraphqlEndpointSteps.getOKButton().should('be.disabled');
|
|
57
81
|
|
|
82
|
+
// Show hidden fields
|
|
83
|
+
EditGraphqlEndpointSteps.toggleFormGroupHiddenFields(0);
|
|
84
|
+
|
|
58
85
|
// When I change some fields
|
|
59
86
|
EditGraphqlEndpointSteps.fillInputField(3, 'NONE');
|
|
60
87
|
EditGraphqlEndpointSteps.toggleBooleanField(0);
|
|
@@ -83,7 +110,6 @@ describe('Graphql: edit endpoint settings', () => {
|
|
|
83
110
|
"enableGraphQLExplain": true,
|
|
84
111
|
"exposeSomlInGraphQL": false,
|
|
85
112
|
"disabledChecks": null,
|
|
86
|
-
"defaultIntegrationRole": "Federation_SystemRole",
|
|
87
113
|
"queryPrefix": null,
|
|
88
114
|
"mutationPrefix": null
|
|
89
115
|
}
|
|
@@ -103,6 +129,9 @@ describe('Graphql: edit endpoint settings', () => {
|
|
|
103
129
|
GraphqlEndpointManagementSteps.editEndpointConfiguration(0);
|
|
104
130
|
EditGraphqlEndpointSteps.getDialog().should('be.visible');
|
|
105
131
|
|
|
132
|
+
// Show hidden fields
|
|
133
|
+
EditGraphqlEndpointSteps.toggleFormGroupHiddenFields(0);
|
|
134
|
+
|
|
106
135
|
// Fill in a field to allow form submission
|
|
107
136
|
EditGraphqlEndpointSteps.fillInputField(0, 'ANY');
|
|
108
137
|
|
|
@@ -184,4 +184,26 @@ describe('Import server files', () => {
|
|
|
184
184
|
ImportServerFilesSteps.getResource(18).should('contain', "test_turtlestar.ttls");
|
|
185
185
|
ImportServerFilesSteps.getResource(19).should('contain', "bnodes.ttl");
|
|
186
186
|
});
|
|
187
|
+
|
|
188
|
+
it('should allow importing jsonld with empty "JSON-LD Context"', () => {
|
|
189
|
+
// Given: The server files tab is loaded
|
|
190
|
+
|
|
191
|
+
// When: I open the import dialog for a file with JSON-LD content,
|
|
192
|
+
ImportServerFilesSteps.importResourceByName('import-resource-with-correct-data.jsonld');
|
|
193
|
+
// Then: I expect the import button be enabled, because the "JSON-LD Context" is not mandatory field.
|
|
194
|
+
ImportSettingsDialogSteps.getImportButton().should('be.enabled');
|
|
195
|
+
|
|
196
|
+
// When: I enter an invalid field.
|
|
197
|
+
ImportSettingsDialogSteps.getJSONLDContextInput().type('invalid context URL')
|
|
198
|
+
// Then I expect
|
|
199
|
+
// the import button be disabled because JSON-LD context URL is not valid
|
|
200
|
+
ImportSettingsDialogSteps.getImportButton().should('be.disabled');
|
|
201
|
+
// and an error message is displayed
|
|
202
|
+
ImportSettingsDialogSteps.getError().contains('Not a valid IRI!');
|
|
203
|
+
|
|
204
|
+
// When: I clear the URI
|
|
205
|
+
ImportSettingsDialogSteps.getJSONLDContextInput().clear().blur();
|
|
206
|
+
// Then: I expect the import button be enabled, because the "JSON-LD Context" is not mandatory field.
|
|
207
|
+
ImportSettingsDialogSteps.getImportButton().should('be.enabled');
|
|
208
|
+
});
|
|
187
209
|
});
|
|
@@ -21,6 +21,39 @@ describe('Import user data: URL import', () => {
|
|
|
21
21
|
cy.deleteRepository(repositoryId);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
+
it('should not allow import if the URL is not valid or empty', () => {
|
|
25
|
+
// Given: I have opened the "Import" view.
|
|
26
|
+
|
|
27
|
+
// When: I open the import menu
|
|
28
|
+
ImportUserDataSteps.openImportURLDialog();
|
|
29
|
+
// Then: I expect the import button to be disabled because the URL is a mandatory field.
|
|
30
|
+
ImportUserDataSteps.getImportUrlButton().should('be.disabled');
|
|
31
|
+
|
|
32
|
+
// When: I type an invalid URL
|
|
33
|
+
ImportUserDataSteps.getImportUrlInput().type('invalid url');
|
|
34
|
+
// Then: I expect
|
|
35
|
+
// an error message to be displayed,
|
|
36
|
+
ImportUserDataSteps.getError().contains('Not valid url!');
|
|
37
|
+
// and the import button to remain disabled because the URL is not valid.
|
|
38
|
+
ImportUserDataSteps.getImportUrlButton().should('be.disabled');
|
|
39
|
+
|
|
40
|
+
// When: I clear the URL
|
|
41
|
+
ImportUserDataSteps.getImportUrlInput().clear().blur();
|
|
42
|
+
// Then: I expect an error message to be displayed
|
|
43
|
+
ImportUserDataSteps.getError().contains('This field is required');
|
|
44
|
+
// and the import button to remain disabled because the URL is a mandatory field.
|
|
45
|
+
ImportUserDataSteps.getImportUrlButton().should('be.disabled');
|
|
46
|
+
|
|
47
|
+
// When: I type a valid URL
|
|
48
|
+
ImportUserDataSteps.getImportUrlInput().type(IMPORT_URL);
|
|
49
|
+
// Then: I expect
|
|
50
|
+
// no errors to be displayed,
|
|
51
|
+
ImportUserDataSteps.getErrors().should('have.length', 0);
|
|
52
|
+
// and the import button to be enabled because the URL is valid.
|
|
53
|
+
ImportUserDataSteps.getImportUrlButton().should('be.enabled');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
24
57
|
it('Test import file via URL successfully with Auto format selected', () => {
|
|
25
58
|
ImportUserDataSteps.openImportURLDialog(IMPORT_URL);
|
|
26
59
|
ImportUserDataSteps.clickImportUrlButton();
|
|
@@ -333,6 +333,7 @@ describe('Repositories', () => {
|
|
|
333
333
|
// Some fields should be disabled
|
|
334
334
|
RepositorySteps.getRepositoryRulesetMenu().should('be.disabled');
|
|
335
335
|
RepositorySteps.getRepositoryDisableSameAsCheckbox().should('be.disabled');
|
|
336
|
+
RepositorySteps.getEntityIndexSize().should('be.disabled');
|
|
336
337
|
|
|
337
338
|
RepositorySteps.typeRepositoryTitle(newTitle);
|
|
338
339
|
RepositorySteps.getRepositoryContextIndexCheckbox().check();
|
|
@@ -563,11 +563,6 @@ describe('User and Access', () => {
|
|
|
563
563
|
expectedTitle: 'Query and Update monitoring',
|
|
564
564
|
checks: noAuthChecks
|
|
565
565
|
},
|
|
566
|
-
{
|
|
567
|
-
path: ['Monitor', 'Backup and Restore'],
|
|
568
|
-
expectedUrl: '/monitor/backup-and-restore',
|
|
569
|
-
checks: noAuthChecks
|
|
570
|
-
},
|
|
571
566
|
|
|
572
567
|
// 6) Setup
|
|
573
568
|
{
|
|
@@ -629,11 +624,6 @@ describe('User and Access', () => {
|
|
|
629
624
|
},
|
|
630
625
|
|
|
631
626
|
// 8) Help
|
|
632
|
-
{
|
|
633
|
-
path: ['Help', 'Interactive guides'],
|
|
634
|
-
expectedUrl: '/guides',
|
|
635
|
-
checks: noAuthChecks
|
|
636
|
-
},
|
|
637
627
|
{
|
|
638
628
|
path: ['Help', 'REST API'],
|
|
639
629
|
expectedUrl: '/webapi',
|
|
@@ -659,6 +649,16 @@ describe('User and Access', () => {
|
|
|
659
649
|
path: ['GraphQL', 'GraphQL Playground'],
|
|
660
650
|
expectedUrl: '/graphql/playground',
|
|
661
651
|
checks: hasAuthChecks
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
path: ['Monitor', 'Backup and Restore'],
|
|
655
|
+
expectedUrl: '/monitor/backup-and-restore',
|
|
656
|
+
checks: hasAuthChecks
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
path: ['Help', 'Interactive guides'],
|
|
660
|
+
expectedUrl: '/guides',
|
|
661
|
+
checks: hasAuthChecks
|
|
662
662
|
}
|
|
663
663
|
];
|
|
664
664
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphdb-workbench-tests",
|
|
3
|
-
"version": "3.0.0-
|
|
3
|
+
"version": "3.0.0-TR15",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "graphdb-workbench-tests",
|
|
9
|
-
"version": "3.0.0-
|
|
9
|
+
"version": "3.0.0-TR15",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"cypress": "^14.0.3",
|
package/package.json
CHANGED
|
@@ -9,6 +9,26 @@ export class EditGraphqlEndpointSteps extends ModalDialogSteps {
|
|
|
9
9
|
return this.getDialog().find('dynamic-form');
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
static getFormGroup(index) {
|
|
13
|
+
return this.getDynamicForm().find('.form-group').eq(index).scrollIntoView();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static toggleFormGroupHiddenFields(index) {
|
|
17
|
+
this.getFormGroup(index).find('.toggle-hidden-fields').click();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static getFormGroups() {
|
|
21
|
+
return this.getDynamicForm().find('.form-group');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static getVisibleFormGroupFields(groupIndex) {
|
|
25
|
+
return this.getFormGroup(groupIndex).find('> dynamic-form-field .form-field');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
static getAllFormGroupFields(groupIndex) {
|
|
29
|
+
return this.getFormGroup(groupIndex).find('.form-field');
|
|
30
|
+
}
|
|
31
|
+
|
|
12
32
|
static getFormFields() {
|
|
13
33
|
return this.getDynamicForm().find('.form-field');
|
|
14
34
|
}
|
|
@@ -87,4 +107,18 @@ export class EditGraphqlEndpointSteps extends ModalDialogSteps {
|
|
|
87
107
|
static getSavingLoader() {
|
|
88
108
|
return this.getDialog().find('.saving-endpoint-settings')
|
|
89
109
|
}
|
|
110
|
+
|
|
111
|
+
static validateFormGroups(groups) {
|
|
112
|
+
groups.forEach((group, index) => {
|
|
113
|
+
this.getFormGroup(index).should('be.visible')
|
|
114
|
+
.and('contain', group.label);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static validateFormGroupFields(groupIndex, fields) {
|
|
119
|
+
fields.forEach((field, index) => {
|
|
120
|
+
this.getVisibleFormGroupFields(groupIndex).eq(index).should('be.visible')
|
|
121
|
+
.and('contain', field.label);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
90
124
|
}
|
|
@@ -68,6 +68,10 @@ export class ImportSettingsDialogSteps extends ModalDialogSteps {
|
|
|
68
68
|
this.getSettingsForm().find('input[name="contextLink"]').type(contextLink).should('have.value', contextLink);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
static getJSONLDContextInput() {
|
|
72
|
+
return this.getSettingsForm().find('.contextLinkRow .form-control');
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
static setContextLinkToBeVisible() {
|
|
72
76
|
this.getSettingsForm().within(() => {
|
|
73
77
|
cy.get('.contextLinkRow').invoke('attr', 'style', 'display: block !important');
|
|
@@ -77,4 +81,12 @@ export class ImportSettingsDialogSteps extends ModalDialogSteps {
|
|
|
77
81
|
static getReplaceExistingDataCheckbox() {
|
|
78
82
|
return this.getSettingsForm().find('input.existing-data-replacement');
|
|
79
83
|
}
|
|
84
|
+
|
|
85
|
+
static getErrors() {
|
|
86
|
+
return cy.get('.alert-danger');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static getError(index = 0) {
|
|
90
|
+
return this.getErrors().eq(index);
|
|
91
|
+
}
|
|
80
92
|
}
|
|
@@ -312,14 +312,19 @@ class ImportSteps {
|
|
|
312
312
|
cy.get('#import-user .import-from-url-btn').click();
|
|
313
313
|
// Forces the popover to disappear as it covers the modal and Cypress refuses to continue
|
|
314
314
|
this.closePopover();
|
|
315
|
-
|
|
316
|
-
|
|
315
|
+
if (importURL) {
|
|
316
|
+
this.getImportUrlInput().type(importURL).should('have.value', importURL);
|
|
317
|
+
this.closePopover();
|
|
318
|
+
}
|
|
317
319
|
return this;
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
static
|
|
321
|
-
cy.get('#wb-import-importUrl')
|
|
322
|
+
static getImportUrlButton() {
|
|
323
|
+
return cy.get('#wb-import-importUrl');
|
|
324
|
+
}
|
|
322
325
|
|
|
326
|
+
static clickImportUrlButton() {
|
|
327
|
+
this.getImportUrlButton().click();
|
|
323
328
|
return this;
|
|
324
329
|
}
|
|
325
330
|
|
|
@@ -44,6 +44,14 @@ export class ImportUserDataSteps extends ImportSteps {
|
|
|
44
44
|
cy.intercept('POST', `/rest/repositories/${repositoryId}/import/upload/url`).as('postJsonldUrl');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
static getErrors() {
|
|
48
|
+
return cy.get('.text-danger');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static getError(index = 0) {
|
|
52
|
+
return this.getErrors().eq(index);
|
|
53
|
+
}
|
|
54
|
+
|
|
47
55
|
// ==========================================================================
|
|
48
56
|
// utilities from text snippet tests
|
|
49
57
|
// ==========================================================================
|
|
@@ -19,6 +19,12 @@ export class VisualGraphSteps {
|
|
|
19
19
|
cy.visit('/graphs-visualizations?uri=http:%2F%2Fwww.w3.org%2FTR%2F2003%2FPR-owl-guide-20031209%2Fwine%23Dry');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
static openNodeLabelGraph() {
|
|
23
|
+
cy.visit('/graphs-visualizations?uri=http:%2F%2Fexample.com%2Fnode1');
|
|
24
|
+
// Wait for at least one predicate to be displayed, to ensure that the visual graph is open and ready for testing.
|
|
25
|
+
VisualGraphSteps.getPredicates().should('contain', 'connectedTo');
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
static verifyUrl() {
|
|
23
29
|
cy.url().should('include', `${Cypress.config('baseUrl')}${VIEW_URL}`);
|
|
24
30
|
}
|
|
@@ -116,6 +122,14 @@ export class VisualGraphSteps {
|
|
|
116
122
|
return cy.get('.node-wrapper').should('be.visible');
|
|
117
123
|
}
|
|
118
124
|
|
|
125
|
+
static getNode(nodeId) {
|
|
126
|
+
return cy.get(`.node-wrapper[id="${nodeId}"]`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static getNodeLabel(nodeId) {
|
|
130
|
+
return this.getNode(nodeId).find('.node-label-body div');
|
|
131
|
+
}
|
|
132
|
+
|
|
119
133
|
static getPredicates() {
|
|
120
134
|
return cy.get('.predicate');
|
|
121
135
|
}
|
|
@@ -10,10 +10,10 @@ Cypress.Commands.add('uploadGraphqlSchema', (repositoryId, schemaPath, schemaId
|
|
|
10
10
|
cy.fixture(schemaPath).then((schema) => {
|
|
11
11
|
cy.request({
|
|
12
12
|
method: 'POST',
|
|
13
|
-
url: `${REPOSITORIES_URL}${repositoryId}/
|
|
13
|
+
url: `${REPOSITORIES_URL}${repositoryId}/graphql/manage/endpoints/import`,
|
|
14
14
|
headers: {'Content-type': 'text/yaml'},
|
|
15
15
|
body: schema
|
|
16
|
-
}).should((response) => expect(response.status).to.equal(
|
|
16
|
+
}).should((response) => expect(response.status).to.equal(200));
|
|
17
17
|
waitForGraphqlSchema(repositoryId, schemaId);
|
|
18
18
|
});
|
|
19
19
|
});
|
|
@@ -22,10 +22,10 @@ Cypress.Commands.add('uploadGraphqlSchema', (repositoryId, schemaPath, schemaId
|
|
|
22
22
|
function waitForGraphqlSchema(repositoryId, schemaId) {
|
|
23
23
|
cy.request({
|
|
24
24
|
method: 'GET',
|
|
25
|
-
url: `${REPOSITORIES_URL}${repositoryId}/
|
|
25
|
+
url: `${REPOSITORIES_URL}${repositoryId}/graphql/manage/endpoints/${schemaId}`
|
|
26
26
|
}).then((response) => {
|
|
27
27
|
// const importStatus = Cypress._.find(response.body, (importStatus) => importStatus.name === fileName);
|
|
28
|
-
if (response.status === 200 && response.body && response.body.id ===
|
|
28
|
+
if (response.status === 200 && response.body && response.body.id === schemaId) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
cy.wait(POLL_INTERVAL);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class HtmlUtil {
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verifies that an element's content is truncated with an ellipsis by checking that
|
|
5
|
+
* the scroll width of the element is greater than its offset width.
|
|
6
|
+
* This is used to assert that the element's text is overflowing and is being clipped with ellipsis.
|
|
7
|
+
*
|
|
8
|
+
* @param {Cypress.Chainable<JQuery<HTMLElement>>} element - The Cypress chainable element to check.
|
|
9
|
+
* @throws {AssertionError} If the element's content is not truncated with ellipsis.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Example usage in a test
|
|
13
|
+
* HtmlUtil.verifyEllipsis(cy.get('.node-wrapper'));
|
|
14
|
+
*/
|
|
15
|
+
static verifyEllipsis(element) {
|
|
16
|
+
element.should(($el) => {
|
|
17
|
+
const el = $el[0];
|
|
18
|
+
expect(el.scrollWidth).to.be.greaterThan(el.offsetWidth);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|