You will create a quick web user interface within your existing web module to use your test framework with. Create a new folder called exerciseAsync
in you web->resources
file.
The first file will be the Component.js
, with the following code:
/*eslint no-console: 0, no-unused-vars: 0, no-use-before-define: 0, no-redeclare: 0*/
sap.ui.define([
"sap/ui/core/UIComponent"
], function(UIComponent) {
"use strict";
return UIComponent.extend("sap.xs.exerciseAsync.Component", {
metadata: {
manifest: "json"
},
init: function(){
jQuery.sap.require("sap.m.MessageBox");
jQuery.sap.require("sap.m.MessageToast");
sap.ui.core.UIComponent.prototype.init.apply(
this, arguments);
this.getSessionInfo();
// Chat Model
var oModel = this.getModel("chatModel");
oModel.setData({
chat: "",
message: ""
});
},
destroy: function() {
// call the base component's destroy function
UIComponent.prototype.destroy.apply(this, arguments);
},
getSessionInfo: function() {
var aUrl = "/xsjs/exercisesMaster.xsjs?cmd=getSessionInfo";
this.onLoadSession(
JSON.parse(jQuery.ajax({
url: aUrl,
method: "GET",
dataType: "json",
async: false
}).responseText));
},
onLoadSession: function(myJSON) {
for (var i = 0; i < myJSON.session.length; i++) {
var config = this.getModel("config");
config.setProperty("/UserName", myJSON.session[i].UserName);
}
}
});
});
Create the manifest.json
file. You would generally declare the internationalization model here (i18n) but you will hard code the texts in English as it is not the focus of this exercise.
{
"_version": "1.4.0",
"start_url": "index.html",
"sap.app": {
"_version": "1.4.0",
"type": "application",
"resources": "resources.json",
"id": "exerciseAsync",
"title": "My Async Node.js App",
"description": "Learning about Node.js asynchronous calls",
"applicationVersion": {
"version": "${project.version}"
}
},
"sap.fiori": {
"_version": "2.0.0",
"registrationIds": [],
"archeType": "transactional"
},
"sap.ui": {
"_version": "1.40.0",
"technology": "UI5",
"icons": {
"icon": "/images/favicon.ico",
"favIcon": "/images/favicon.ico"
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes": [
"sap_hcb",
"sap_bluecrystal",
"sap_belize"
]
},
"sap.ui5": {
"config": {
"sapFiori2Adaptation": true
},
"rootView": {
"viewName": "sap.xs.exerciseAsync.view.App",
"type": "XML",
"id": "app"
},
"dependencies": {
"minUI5Version": "1.40.0",
"libs": {
"sap.ui.core": {
"minVersion": "1.40.0"
},
"sap.ui.comp": {
"minVersion": "1.40.0"
},
"sap.m": {
"minVersion": "1.40.0"
},
"sap.ui.layout": {
"minVersion": "1.40.0"
}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"handleValidation": true,
"models": {
"chatModel": {
"type": "sap.ui.model.json.JSONModel",
"settings": {
"defaultBindingMode": "TwoWay"
}
},
"config": {
"type": "sap.ui.model.json.JSONModel"
}
}
}
}
Create an index.html
file with the following content:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<!-- <script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js" -->
<script id="sap-ui-bootstrap" src="{{{ui5liburl}}}/resources/sap-ui-core.js"
data-sap-ui-theme="sap_belize_plus"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"
data-sap-ui-language="en"
data-sap-ui-resourceroots='{
"sap.xs.exerciseAsync": "./",
"view": "./view" }'
data-sap-ui-libs="sap.m,sap.ui.comp,sap.ui.core,sap.ui.layout">
</script>
<script>
// WS handling
jQuery.sap.require("sap.ui.core.ws.WebSocket");
// var connection = new sap.ui.core.ws.WebSocket('ws://localhost:3081');
var connection = new sap.ui.core.ws.WebSocket('/node/excAsync');
</script>
<script>
sap.ui.getCore().attachInit(function () {
var ComponentContainer = new sap.ui.core.ComponentContainer({
height : "100%"
});
new sap.m.Shell({
app: ComponentContainer,
showLogout: true
}).placeAt("content");
var oComponent = sap.ui.component({
id: "comp",
name: "sap.xs.exerciseAsync",
manifestFirst: true,
async: true
}).then(function(oComponent){
ComponentContainer.setComponent(oComponent);
});
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>
You will now create the views and controller in their corresponding folders within the exerciseAsync
folder and the following code, respectively. You can check the oDataView
folder for further reference on the structure. The name of the components is referenced as App
as you can see in the root view specified in manifest.json
<core:View controllerName="sap.xs.exerciseAsync.controller.App" xmlns="sap.m" xmlns:l="sap.ui.layout" xmlns:mvc="sap.ui.core.mvc"
xmlns:u="sap.ui.unified" xmlns:core="sap.ui.core">
<u:Shell id="myShell" icon="/images/sap_18.png">
<u:user>
<u:ShellHeadUserItem image="sap-icon://person-placeholder" username="{config>/UserName}"/>
</u:user>
<u:content>
<ScrollContainer height="100%" width="100%" horizontal="true" vertical="true">
<Panel headerText="Node.js Async Test Framework" expandable="true" expanded="true">
<l:VerticalLayout class="sapUiContentPadding" width="100%">
<l:content>
<TextArea id="chatInfo" value="{chatModel>/chat}" cols="60" rows="8" editable="false"/>
</l:content>
</l:VerticalLayout>
<Button text="Basic Async" press="sendBasic"/>
<Button text="File Sync" press="sendFileS"/>
<Button text="File Async" press="sendFileA"/>
<Button text="HTTP Client" press="sendHTTP"/>
<Button text="DB1" press="sendDB1"/>
<Button text="DB2" press="sendDB2"/>
</Panel>
</ScrollContainer>
</u:content>
</u:Shell>
</core:View>
App.controller.js
:
/*eslint no-console: 0, no-unused-vars: 0, no-use-before-define: 0, no-redeclare: 0, no-undef: 0, no-sequences: 0, no-unused-expressions: 0*/
//To use a javascript controller its name must end with .controller.js
sap.ui.define([
"sap/xs/exerciseAsync/controller/BaseController",
"sap/ui/model/json/JSONModel"
], function(BaseController, JSONModel) {
"use strict";
return BaseController.extend("sap.xs.exerciseAsync.controller.App", {
onInit: function() {
this.getView().addStyleClass("sapUiSizeCompact"); // make everything inside this View appear in Compact mode
// connection opened
connection.attachOpen(function(oControlEvent) {
sap.m.MessageToast.show("connection opened");
});
// server messages
connection.attachMessage(function(oControlEvent) {
var oModel = sap.ui.getCore().getComponent("comp").getModel("chatModel");
var result = oModel.getData();
var data = jQuery.parseJSON(oControlEvent.getParameter("data"));
var msg = data.text,
lastInfo = result.chat;
if (lastInfo.length > 0) {
lastInfo += "\r\n";
}
oModel.setData({
chat: lastInfo + msg
}, true);
// scroll to textarea bottom to show new messages
$("#comp---app--chatInfo-inner").scrollTop($("#comp---app--chatInfo-inner")[0].scrollHeight);
});
// error handling
connection.attachError(function(oControlEvent) {
sap.m.MessageToast.show("Websocket connection error");
});
// onConnectionClose
connection.attachClose(function(oControlEvent) {
sap.m.MessageToast.show("Websocket connection closed");
});
},
// send message
sendBasic: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "async"
}));
},
sendFileS: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "fileSync"
}));
},
sendFileA: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "fileAsync"
}));
},
sendHTTP: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "httpClient"
}));
},
sendDB1: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "dbAsync"
}));
},
sendDB2: function() {
var oModel = this.getOwnerComponent().getModel("chatModel");
oModel.setData({
chat: ""
}, true);
connection.send(JSON.stringify({
action: "dbAsync2"
}));
},
onErrorCall: function(oError) {
if (oError.statusCode === 500 || oError.statusCode === 400 || oError.statusCode === "500" || oError.statusCode === "400") {
var errorRes = JSON.parse(oError.responseText);
if (!errorRes.error.innererror) {
sap.m.MessageBox.alert(errorRes.error.message.value);
} else {
if (!errorRes.error.innererror.message) {
sap.m.MessageBox.alert(errorRes.error.innererror.toString());
} else {
sap.m.MessageBox.alert(errorRes.error.innererror.message);
}
}
return;
} else {
sap.m.MessageBox.alert(oError.response.statusText);
return;
}
}
});
});
BaseController.controller.js
:
/*global history */
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History"
], function (Controller, History) {
"use strict";
return Controller.extend("sap.xs.exerciseAsync.controller.BaseController", {
/**
* Convenience method for accessing the router in every controller of the application.
* @public
* @returns {sap.ui.core.routing.Router} the router for this component
*/
getRouter : function () {
return this.getOwnerComponent().getRouter();
},
/**
* Convenience method for getting the view model by name in every controller of the application.
* @public
* @param {string} sName the model name
* @returns {sap.ui.model.Model} the model instance
*/
getModel : function (sName) {
return this.getView().getModel(sName);
},
/**
* Convenience method for setting the view model in every controller of the application.
* @public
* @param {sap.ui.model.Model} oModel the model instance
* @param {string} sName the model name
* @returns {sap.ui.mvc.View} the view instance
*/
setModel : function (oModel, sName) {
return this.getView().setModel(oModel, sName);
},
/**
* Event handler for navigating back.
* It there is a history entry we go one step back in the browser history
* If not, it will replace the current entry of the browser history with the master route.
* @public
*/
onNavBack : function() {
var sPreviousHash = History.getInstance().getPreviousHash();
if (sPreviousHash !== undefined) {
history.go(-1);
} else {
this.getRouter().navTo("master", {}, true);
}
}
});
}
);