Related
Relatively new to JavaScript Promises.
Trying to call a function - checktheData(recordidGuid) from within a Promise
and use the result in a .then chain.
The last line of the checktheData function is:
return outcomeString
My problem is that the result of the promise is "undefined", yet when I output it to the console in the checktheData function it is as expected
I know I need to add a return statement, but where please?
Simple code:
function masterDeploy(PrimaryControl){
var formContext = PrimaryControl;
formContext.data.refresh(true);
var recordidGuid = ""
recordidGuid = formContext.data.entity.getId();
var loggedinuser =
Xrm.Utility.getGlobalContext().userSettings.userId;
recordidGuid = recordidGuid.replace('{', '').replace('}', '');
loggedinuser = loggedinuser.replace('{', '').replace('}', '');
var outcomeString = ""
var checkOutcome = false;
let promise = new Promise(function(resolve, reject) {
resolve(checktheData(recordidGuid))
});
promise.then(
result => {
console.log(promise);
}
),
promise.catch(
function (error){
DisplayError(error)}
);
return // stops here whilst debugging
if (checkOutcome == true){
var alertStrings = { confirmButtonLabel: "Close", text: outcomeString, title: "Data check failed" };
var alertOptions = { height: 500, width: 1000 };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(
function success(result) {
return;
},
function (error) {
DisplayError(error)
});
}
else{
if(checkOutcome == false){
//2. Create the learner journal url
buildLearnerEntryURL(recordidGuid,loggedinuser)
if(checkOutcome == false){
//3. Create refinery user and enrol on courses
createUserandEnrol(recordidGuid,loggedinuser)
if(checkOutcome == false){
//4. Create Learning Aims
createLearningAims(recordidGuid)
}
};
};
}
formContext.data.refresh(true);
//Set text to be a concatenated summary of actions completed or skipped
alertStrings = { confirmButtonLabel: "Close", text: "Deployment completed etc etc", title: "Deployment Completed" };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(
function success(result) {
return;
},
function (error) {
DisplayError(error)
});
};
function checktheData(recordidGuid){
var outcomeString = ""
var checkOutcome = "false";
var str = "";
Xrm.WebApi.online.retrieveRecord("new_apprenticeshipflight", recordidGuid, "?$select=new_flighttype,new_programmelearningaimreference,new_apprenticeshipoverallaimreference,_new_mentor_value,_new_enrolledstandard_value,_new_clonelinkid_value,new_plannedstartdate,new_plannedenddate,crd80_overideendcalc,_new_contact_value,_new_apprenticeshipprogramme_value,_new_employer_value,_crd80_locationcontact_value,crd80_headofficedelivery,crd80_learningjournalurl,crd80_refineryid,crd80_addresstouse,_crd80_placementemployer_value,crd80_employeraddresstext,&$expand=new_Contact($select=emailaddress1,firstname,lastname),new_EnrolledStandard($select=crd80_learningjournalform),crd80_PlacementEmployer($select=name, accountid, address1_postalcode,address2_postalcode),crd80_LocationContact($select=emailaddress1,fullname,telephone1),new_Employer($select=name,address1_postalcode,address2_postalcode),new_Mentor($select=new_homepostcode),new_ApprenticeshipProgramme($select=crd80_learnerteamsiteurl)").then(
function success(result) {
if (result["new_flighttype"] == 100000001 && result["new_flighttype"] == null){outcomeString = outcomeString + "This must be a learner type flight"; checkOutcome = true};
//other lines removed for clarity
console.log(outcomeString)
return outcomeString
})
}
Xrm.WebApi.online.retrieveRecord return a promise, so you can just return it from checktheData().
What you need to handle is basically just to call the checktheData() and use .then() and .catch() for the result.
Example:
function masterDeploy(PrimaryControl) {
var formContext = PrimaryControl;
formContext.data.refresh(true);
var recordidGuid = "";
recordidGuid = formContext.data.entity.getId();
var loggedinuser = Xrm.Utility.getGlobalContext().userSettings.userId;
recordidGuid = recordidGuid.replace("{", "").replace("}", "");
loggedinuser = loggedinuser.replace("{", "").replace("}", "");
var outcomeString = "";
checktheData()
.then(checkOutcome => {
if (checkOutcome == true) {
var alertStrings = {
confirmButtonLabel: "Close",
text: outcomeString,
title: "Data check failed",
};
var alertOptions = { height: 500, width: 1000 };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(
function success(result) {
return;
},
function (error) {
DisplayError(error);
}
);
} else {
if (checkOutcome == false) {
//2. Create the learner journal url
buildLearnerEntryURL(recordidGuid, loggedinuser);
if (checkOutcome == false) {
//3. Create refinery user and enrol on courses
createUserandEnrol(recordidGuid, loggedinuser);
if (checkOutcome == false) {
//4. Create Learning Aims
createLearningAims(recordidGuid);
}
}
}
}
formContext.data.refresh(true);
//Set text to be a concatenated summary of actions completed or skipped
alertStrings = {
confirmButtonLabel: "Close",
text: "Deployment completed etc etc",
title: "Deployment Completed",
};
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions)
.then(function success(result) {
return;
})
.catch(error => {
DisplayError(error);
});
})
.catch(err => {
console.log(err);
});
}
function checktheData(recordidGuid) {
var outcomeString = "";
var checkOutcome = "false";
var str = "";
Xrm.WebApi.online
.retrieveRecord(
"new_apprenticeshipflight",
recordidGuid,
"?$select=new_flighttype,new_programmelearningaimreference,new_apprenticeshipoverallaimreference,_new_mentor_value,_new_enrolledstandard_value,_new_clonelinkid_value,new_plannedstartdate,new_plannedenddate,crd80_overideendcalc,_new_contact_value,_new_apprenticeshipprogramme_value,_new_employer_value,_crd80_locationcontact_value,crd80_headofficedelivery,crd80_learningjournalurl,crd80_refineryid,crd80_addresstouse,_crd80_placementemployer_value,crd80_employeraddresstext,&$expand=new_Contact($select=emailaddress1,firstname,lastname),new_EnrolledStandard($select=crd80_learningjournalform),crd80_PlacementEmployer($select=name, accountid, address1_postalcode,address2_postalcode),crd80_LocationContact($select=emailaddress1,fullname,telephone1),new_Employer($select=name,address1_postalcode,address2_postalcode),new_Mentor($select=new_homepostcode),new_ApprenticeshipProgramme($select=crd80_learnerteamsiteurl)"
)
.then(function success(result) {
if (
result["new_flighttype"] == 100000001 &&
result["new_flighttype"] == null
) {
outcomeString = outcomeString + "This must be a learner type flight";
checkOutcome = true;
}
//other lines removed for clarity
console.log(outcomeString);
return outcomeString;
});
}
Another example with async/await approach.
async function masterDeploy(PrimaryControl) {
var formContext = PrimaryControl;
formContext.data.refresh(true);
var recordidGuid = "";
recordidGuid = formContext.data.entity.getId();
var loggedinuser = Xrm.Utility.getGlobalContext().userSettings.userId;
recordidGuid = recordidGuid.replace("{", "").replace("}", "");
loggedinuser = loggedinuser.replace("{", "").replace("}", "");
var outcomeString = "";
const checkOutcome = await checktheData();
if (checkOutcome == true) {
var alertStrings = {
confirmButtonLabel: "Close",
text: outcomeString,
title: "Data check failed",
};
var alertOptions = { height: 500, width: 1000 };
try {
const result = await Xrm.Navigation.openAlertDialog(
alertStrings,
alertOptions
);
} catch (err) {
DisplayError(err);
}
} else {
if (checkOutcome == false) {
//2. Create the learner journal url
buildLearnerEntryURL(recordidGuid, loggedinuser);
if (checkOutcome == false) {
//3. Create refinery user and enrol on courses
createUserandEnrol(recordidGuid, loggedinuser);
if (checkOutcome == false) {
//4. Create Learning Aims
createLearningAims(recordidGuid);
}
}
}
}
formContext.data.refresh(true);
//Set text to be a concatenated summary of actions completed or skipped
alertStrings = {
confirmButtonLabel: "Close",
text: "Deployment completed etc etc",
title: "Deployment Completed",
};
try {
const result = await Xrm.Navigation.openAlertDialog(
alertStrings,
alertOptions
);
} catch (err) {
DisplayError(err);
}
}
async function checktheData(recordidGuid) {
var outcomeString = "";
var checkOutcome = "false";
var str = "";
const result = await Xrm.WebApi.online.retrieveRecord(
"new_apprenticeshipflight",
recordidGuid,
"?$select=new_flighttype,new_programmelearningaimreference,new_apprenticeshipoverallaimreference,_new_mentor_value,_new_enrolledstandard_value,_new_clonelinkid_value,new_plannedstartdate,new_plannedenddate,crd80_overideendcalc,_new_contact_value,_new_apprenticeshipprogramme_value,_new_employer_value,_crd80_locationcontact_value,crd80_headofficedelivery,crd80_learningjournalurl,crd80_refineryid,crd80_addresstouse,_crd80_placementemployer_value,crd80_employeraddresstext,&$expand=new_Contact($select=emailaddress1,firstname,lastname),new_EnrolledStandard($select=crd80_learningjournalform),crd80_PlacementEmployer($select=name, accountid, address1_postalcode,address2_postalcode),crd80_LocationContact($select=emailaddress1,fullname,telephone1),new_Employer($select=name,address1_postalcode,address2_postalcode),new_Mentor($select=new_homepostcode),new_ApprenticeshipProgramme($select=crd80_learnerteamsiteurl)"
);
if (
result["new_flighttype"] == 100000001 &&
result["new_flighttype"] == null
) {
outcomeString = outcomeString + "This must be a learner type flight";
checkOutcome = true;
}
//other lines removed for clarity
console.log(outcomeString);
return outcomeString;
}
I'm building an Electron application and I'm stuck with the following problem.
I'm getting information using a socket from an apparatus, and It was working fine. I wanted to change the html of the page if the program gets a type of message, so basically I used the loadUrl method, but then, after sending a message to the renderer process I't seems like it's not being received.
My code:
photoViewOn = false;
...
app.on('ready', function(){
// Create new window
mainWindow = new BrowserWindow({
backgroundColor: '#000000',
fullscreen : true,
frame : false,
icon : __dirname + "/res/logo.png",
webPreferences: {
nodeIntegration : true
}
});
mainWindow.webContents.openDevTools();
// Load html in window
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'bigNames.html'),
protocol: 'file:',
slashes:true,
}))...)
function HTMLupdate(msg) {
mainWindow && mainWindow.webContents.send('update', msg);
var server = socketBuilder('localhost', '7777', {
message: (msg, rinfo) => {
try {
console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`);
var infoMap = processCyrano(msg);
//if (infoMap["Com"] === "")
if (infoMap != null) {
if (infoMap["Com"] === "INFO") {
if (photoViewOn) {
photoViewOn = false;
bigNamesView();
}
console.log("Inside Infomap");
console.log(`Left Fencer: ${infoMap["LeftName"]}`);
console.log(`Right Fencer: ${infoMap["RightName"]}`);
HTMLupdate(infoMap);
}
}
}
catch (error) {
console.log(`Error ${error}`);
}
},
error: (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
},
listen: () => {
const address = server.address();
console.log(`server listening ${address.address}:${address.port}`);
}
});
function photoView() {
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'photos.html'),
protocol: 'file:',
slashes:true,
}));
}
function bigNamesView() {
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'bigNames.html'),
protocol: 'file:',
slashes:true,
}));
}
function processCyrano(msg) {
try {
let stripMsg = msg.toString().split("%");
let info = {};
let compInfo = stripMsg[0].split("|");
console.log(compInfo);
if(compInfo[2] === "INFO" || compInfo[2] === "DISP") {
let firstFencerInfo = stripMsg[1].split("|")
let secondFencerInfo = stripMsg[2].split("|")
info.Protocol = compInfo[1];
info.Com = compInfo[2]
info.Piste = compInfo[3]
info.Compe = compInfo[4];
info.Phase = compInfo[5];
info.PoulTab = compInfo[6];
info.Match = compInfo[7];
info.Round = compInfo[8];
info.RightId = firstFencerInfo[1];
info.RightName = firstFencerInfo[2];
info.RightNat = firstFencerInfo[3];
info.Rscore = firstFencerInfo[4];
info.Rstatus = firstFencerInfo[5];
info.RYcard = firstFencerInfo[6];
info.Rrcard = firstFencerInfo[7];
info.Rlight = firstFencerInfo[8];
info.RWlight = firstFencerInfo[9];
info.LeftId = secondFencerInfo[1];
info.LeftName = secondFencerInfo[2];
info.LeftNat = secondFencerInfo[3];
info.Lscore = secondFencerInfo[4];
info.Lstatus = secondFencerInfo[5];
info.LYcard = secondFencerInfo[6];
info.Lrcard = secondFencerInfo[7];
info.Llight = secondFencerInfo[8];
info.LWlight = secondFencerInfo[9];
lastMatch = info;
return info;
}
else if (compInfo[2] === "PHOTO-NEXT") {
console.log("Photo-Next received");
photoViewOn = true;
photoView();
}
else if (compInfo[2] === "PHOTO-SCORE") {
console.log("Photo-score received");
photoViewOn = true;
photoView();
}
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
return lastMatch;
}
return null;
}
catch (error) {
//Avoid empty messages of the protocol
console.log(`Error ${error}`);
return null;
}
}
Basically my attempt is, if I get a "Photo-Score" message, call photoView() (this works fine), and if "Photo-Stop" is received, call bigNamesView() and start sending information agoin using HTMLUpdate(msg), but it doesn't work for me. Any clue why this is happening?
Note that I remove some irrelevant code. Thanks.
hi my friend you problem is that lastMatch = info only happens inside
if(compInfo[2] === "INFO" || compInfo[2] === "DISP") {
So Only When "Photo-Stop" is received then you return lastMatch
.
inside the code your logic says only when we receive INFO call bigNamesView()
but you want only when we receive PHOTO-STOP call bigNamesView()
.
Also about the loadurl method you call mainWindow.webContents.send('update', msg); in HTMLupdate immediately you should wait for event did-finish-load then call send update msg
win.webContents.on('did-finish-load', () => {
HTMLupdate(infoMap);
})
In your server you have the condition
if (photoViewOn) {bigNamesView()}
but in function processCyrano your condition for 'PHOTO-STOP' doesn't set photoViewOn to true.
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
return lastMatch;
}
Change to
else if (compInfo[2] === "PHOTO-STOP") {
console.log("Photo-Stop received");
photoViewOn = true;
return lastMatch;
}
I am getting those errors and warning in my console after trying to create a PWA - Progressive Web App out of my website using this tutorial.
The FetchEvent for
"https://www.googletagmanager.com/gtag/js?id=UA-4562443-3" resulted in
a network error response: the promise was rejected. Promise.then
(async) (anonymous) # service-worker.js:228 service-worker.js:1
Uncaught (in promise) fetch failed 1:21 GET
https://www.googletagmanager.com/gtag/js?id=UA-4562443-3
net::ERR_FAILED The FetchEvent for
"https://fonts.googleapis.com/css?family=Open+Sans:300,400&display=swap&subset=cyrillic"
resulted in a network error response: the promise was rejected.
Promise.then (async) (anonymous) # service-worker.js:228
service-worker.js:1 Uncaught (in promise) fetch failed 1:28 GET
https://fonts.googleapis.com/css?family=Open+Sans:300,400&display=swap&subset=cyrillic
net::ERR_FAILED The FetchEvent for
"https://widget.uservoice.com/VuHfPZ0etI2eQ4REt1tiUg.js" resulted in a
network error response: the promise was rejected. Promise.then (async)
(anonymous) # service-worker.js:228 service-worker.js:1 Uncaught (in
promise) fetch failed 1:894 GET
https://widget.uservoice.com/VuHfPZ0etI2eQ4REt1tiUg.js net::ERR_FAILED
It actually works pretty well. I am able to get a fully working PWA icon in Audits in Chrome Dev Tools. Which is great, but after a refresh I am getting all those errors. My service-worker.js which is located at root of my website looks like this
"use strict";
const SERVICE_WORKER_VERSION = "REPLACED_WITH_SERVICE_WORKER_VERSION"; // updated with tools/service_worker_version.js (String)
const CACHE_VERSION = SERVICE_WORKER_VERSION;
//const fileNamesToSaveInCache = ["/"];
const HOME = "/";
const OFFLINE_ALTERNATIVE = "/offline";
const fileNamesToSaveInCache = [];
const fileNamesToSaveInCacheProd = [
OFFLINE_ALTERNATIVE,
"/",
"/publics/img/favicon/fav.gif",
"/publics/css/style.css",
"/publics/css/searchhelp.css",
"/publics/css/Helpa.css",
];
const rtcLength = 4; // "rtc/".length;
const rtcFetchDelay = 10000;//ms
const origin = location.origin;
const answerFromfileName = {};
const resolveFromfileName = {};
const rejectFromfileName = {};
const timeOutIdFromfileName = {};
let logLater = [];
// todo put all into single container
const resolveFetchFromPeerToPeer = function (fileName) {
clearTimeout(timeOutIdFromfileName[fileName]);
resolveFromfileName[fileName](answerFromfileName[fileName]);
delete answerFromfileName[fileName];//stop listening
delete resolveFromfileName[fileName];
delete rejectFromfileName[fileName];
};
const rejectFetchFromPeerToPeer = function (fileName, reason) {
if (rejectFromfileName[fileName]) {
rejectFromfileName[fileName](reason);
delete resolveFromfileName[fileName];
delete rejectFromfileName[fileName];
}
};
const fetchFromPeerToPeer = function (customRequestObject) {
/*asks all page for a fileName*/
const fileName = customRequestObject.header.fileName;
const promise = new Promise(function (resolve, reject) {
resolveFromfileName[fileName] = resolve;
rejectFromfileName[fileName] = reject;
if (answerFromfileName.hasOwnProperty(fileName)) {
resolveFetchFromPeerToPeer(fileName);
}
timeOutIdFromfileName[fileName] = setTimeout(function() {
rejectFetchFromPeerToPeer(fileName, "No answer after 10 seconds");
}, rtcFetchDelay);
});
self.clients.matchAll().then(function(clientList) {
clientList.forEach(function(client) {
client.postMessage(customRequestObject);
});
});
return promise;
};
const logInTheUI = (function () {
//console.log("logInTheUI function exists");
return function (what) {
console.log(what);
self.clients.matchAll().then(function(clientList) {
clientList.forEach(function(client) {
client.postMessage({LOG: JSON.parse(JSON.stringify(what))});
});
});
};
}());
const logInTheUIWhenActivated = function (what) {
logLater.push(what);
};
const fetchFromMainServer = function (request, options = {}) {
/*wrap over fetch. The problem with fetch here, it doesn't reject properly sometimes
see if statement below*/
return fetch(request, options).then(function (fetchResponse) {
// console.log("fetchFromMainServer:", fetchResponse.ok, fetchResponse);
// logInTheUI([request, options]);
if ((!fetchResponse) || (!fetchResponse.ok)) {
return Promise.reject("fetch failed");
}
return fetchResponse;
});
};
const fetchFromCache = function (request) {
return caches.open(CACHE_VERSION).then(function (cache) {
return cache.match(request).then(function (CacheResponse) {
//console.log("fetchFromCache:", CacheResponse.ok, CacheResponse);
if ((!CacheResponse) || (!CacheResponse.ok)) {
return Promise.reject("Not in Cache");
}
return CacheResponse;
});
});
};
const isLocalURL = function (url) {
return !(String(url).match("rtc"));
};
const fillServiceWorkerCache2 = function () {
/*It will not cache and also not reject for individual resources that failed to be added in the cache. unlike fillServiceWorkerCache which stops caching as soon as one problem occurs. see http://stackoverflow.com/questions/41388616/what-can-cause-a-promise-rejected-with-invalidstateerror-here*/
return caches.open(CACHE_VERSION).then(function (cache) {
return Promise.all(
fileNamesToSaveInCache.map(function (url) {
return cache.add(url).catch(function (reason) {
return logInTheUIWhenActivated([url + "failed: " + String(reason)]);
});
})
);
});
};
const latePutToCache = function (request, response) {
return caches.open(CACHE_VERSION).then(function(cache) {
cache.put(request, response.clone());
return response;
});
};
const deleteServiceWorkerOldCache = function () {
return caches.keys().then(function (cacheVersions) {
return Promise.all(
cacheVersions.map(function (cacheVersion) {
if (CACHE_VERSION === cacheVersion) {
//console.log("No change in cache");
} else {
//console.log("New SERVICE_WORKER_VERSION of cache, delete old");
return caches.delete(cacheVersion);
}
})
);
});
};
const useOfflineAlternative = function () {
return fetchFromCache(new Request(OFFLINE_ALTERNATIVE));
};
const isAppPage = function (url) {
/*appPage does not work offline, and we don't serve it if offline
returns Boolean*/
return (origin + HOME) === url;
};
self.addEventListener("install", function (event) {
/*the install event can occur while another service worker is still active
waitUntil blocks the state (here installing) of the service worker until the
promise is fulfilled (resolved or rejected). It is useful to make the service worker more readable and more deterministic
save in cache some static fileNames
this happens before activation */
event.waitUntil(
fillServiceWorkerCache2()
.then(skipWaiting)
);
});
self.addEventListener("activate", function (event) {
/* about to take over, other service worker are killed after activate, syncronous
a good moment to clear old cache*/
event.waitUntil(deleteServiceWorkerOldCache().then(function() {
//console.log("[ServiceWorker] Skip waiting on install caches:", caches);
return self.clients.claim();
}));
});
self.addEventListener("message", function (event) {
const message = event.data;
/*
if (message.hasOwnProperty("FUTURE")) {
console.log(message.FUTURE);
return;
}
*/
const fileName = message.fileName;
const answer = message.answer;
answerFromfileName[fileName] = answer;
//console.log(fileName, answer, resolveFromfileName);
if (resolveFromfileName.hasOwnProperty(fileName)) {//
resolveFetchFromPeerToPeer(fileName);
}
});
self.addEventListener("fetch", function (fetchEvent) {
/* fetchEvent interface FetchEvent
see https://www.w3.org/TR/service-workers/#fetch-event-interface
IMPORTANT: fetchEvent.respondWith must be called inside this handler immediately
synchronously fetchEvent.respondWith must be called with a response object or a
promise that resolves with a response object. if fetchEvent.respondWith is called
later in a callback the browser will take over and asks the remote server directly, do not do that
why have fetchEvent.respondWith( and not respond with the return value of the callback function ?
-->
It allows to do other thing before killing the service worker, like saving stuff in cache
*/
const request = fetchEvent.request;//Request implements Body;
//const requestClone = request.clone(); //no need to clone ?
const url = request.url;
if (logLater) {
logLater.forEach(logInTheUI);
logLater = undefined;
}
// logInTheUI(["fetch service worker " + SERVICE_WORKER_VERSION, fetchEvent]);
// Needs to activate to handle fetch
if (isLocalURL(url)) {
//Normal Fetch
if (request.method === "POST") {
// logInTheUI(["POST ignored", request]);
return;
}
// logInTheUI(["Normal Fetch"]);
fetchEvent.respondWith(
fetchFromCache(request.clone()).then(function (cacheResponse) {
/* cannot use request again from here, use requestClone */
//console.log(request, url);
return cacheResponse;
}).catch(function (reason) {
// We don't have it in the cache, fetch it
// logInTheUI(fetchEvent);
return fetchFromMainServer(request);
}).then(function (mainServerResponse) {
if (isAppPage(url)) {
return mainServerResponse;
}
return latePutToCache(request, mainServerResponse).catch(
function (reason) {
/*failed to put in cache do not propagate catch, not important enough*/
return mainServerResponse;
}
);
}).catch(function (reason) {
if (isAppPage(url)) {
//if it is the landing page that is asked
return useOfflineAlternative();
//todo if we are offline , display /offline directly
}
return Promise.reject(reason);
})
);
} else {
// Peer to peer Fetch
//console.log(SERVICE_WORKER_VERSION, "rtc fetch" url:", fetchEvent.request.url);
// request, url are defined
const method = request.method;
const requestHeaders = request.headers;
//logInTheUI(["Special Fetch"]);
const customRequestObject = {
header: {
fileName: url.substring(url.indexOf("rtc/") + rtcLength),
method
},
body: ""
};
requestHeaders.forEach(function (value, key) {
//value, key correct order
//is there a standard way to use Object.assign with Map like iterables ?
//todo handle duplicates
//https://fetch.spec.whatwg.org/#terminology-headers
customRequestObject.header[key] = value;
});
//console.log(request);
fetchEvent.respondWith(
/*should provide the peer the full request*/
request.arrayBuffer().then(function (bodyAsArrayBuffer) {
const bodyUsed = request.bodyUsed;
if (bodyUsed && bodyAsArrayBuffer) {
customRequestObject.body = bodyAsArrayBuffer;
}
}).catch(function (reason) {
/*console.log("no body sent, a normal GET or HEAD request has no body",
reason);*/
}).then(function (notUsed) {
return fetchFromPeerToPeer(customRequestObject);
}).then(function (response) {
const responseInstance = new Response(response.body, {
headers: response.header,
status: response.header.status || 200,
statusText : response.header.statusText || "OK"
});
return responseInstance;
}).catch(function (error) {
const responseInstance = new Response(`<html><p>${error}</p></html>`,
{
headers: {
"Content-type": "text/html"
},
status: 500,
statusText : "timedout"
});
return responseInstance;
})
);
}
/*here we could do more with event.waitUntil()*/
});
I am guessing the problem comes from loading those external libraries. So, this is my code loading those libraries.
// Include the UserVoice JavaScript SDK (only needed once on a page)
UserVoice = window.UserVoice || [];
(function() {
var uv = document.createElement('script');
uv.type = 'text/javascript';
uv.async = true;
uv.src = '//widget.uservoice.com/VuHfPZ0etI2eQ4REt1tiUg.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(uv, s)
})();
//
// UserVoice Javascript SDK developer documentation:
// https://www.uservoice.com/o/javascript-sdk
//
// Set colors
UserVoice.push(['set', {
accent_color: '#448dd6',
trigger_color: 'white',
trigger_background_color: 'rgba(46, 49, 51, 0.6)'
}]);
// Identify the user and pass traits
// To enable, replace sample data with actual user traits and uncomment the line
UserVoice.push(['identify', {
//email: 'john.doe#example.com', // User’s email address
//name: 'John Doe', // User’s real name
//created_at: 1364406966, // Unix timestamp for the date the user signed up
//id: 123, // Optional: Unique id of the user (if set, this should not change)
//type: 'Owner', // Optional: segment your users by type
//account: {
// id: 123, // Optional: associate multiple users with a single account
// name: 'Acme, Co.', // Account name
// created_at: 1364406966, // Unix timestamp for the date the account was created
// monthly_rate: 9.99, // Decimal; monthly rate of the account
// ltv: 1495.00, // Decimal; lifetime value of the account
// plan: 'Enhanced' // Plan name for the account
//}
}]);
// Add default trigger to the bottom-right corner of the window:
UserVoice.push(['addTrigger', {mode: 'contact', trigger_position: 'bottom-right'}]);
// Or, use your own custom trigger:
//UserVoice.push(['addTrigger', '#id', { mode: 'contact' }]);
// Autoprompt for Satisfaction and SmartVote (only displayed under certain conditions)
UserVoice.push(['autoprompt', {}]);
});//ready
#import url('https://fonts.googleapis.com/css?family=Open+Sans:300,400&display=swap&subset=cyrillic');
#font-face {
font-family: 'fa-solid-900';
font-display: swap;
src: url(https://use.fontawesome.com/releases/v5.8.2/webfonts/fa-solid-900.woff2) format('woff2');
}
#font-face {
font-family: 'fa-brands-400';
font-display: swap;
src: url(https://use.fontawesome.com/releases/v5.8.2/webfonts/fa-brands-400.woff2) format('woff2');
}
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-number-3"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-number-3');
</script>
What should i do in order to fix those errors. This is my first try in PWA so i am lost.
I end up using Workbox and everything is working great now.
I have function which return me application status
getDecision: function() {
browser.wait(protractor.ExpectedConditions.visibilityOf(decisionPage), 60000); // verify the decision and proceed further depending upon it.
element(by.xpath(rejectImage)).isPresent().then(function(result) {
if (result) {
console.log('Application is rejected');
finalResult = 'Rejected';
} else {
element(by.xpath(queueImage)).isPresent().then(function(result1) {
if (result1) {
console.log('Application is sent to underwriter for review');
finalResult = 'Queue';
} else {
console.log('Application is approved');
finalResult = 'Approved';
}
});
}
});
}
Then in same class I am returning the finalResult as :
returnDecision: function() {
console.log('Result is::' + finalResult);
return finalResult;
},
And then in admin portal again I need to take decision based upon status from above function as:
takeDecision: function(testData) {
// Verifying if the case is queued or rejected
if (decision.returnDecision() === 'Queue') {
// Approving the case
if (testData.croDecision.apprvDecision === "Approve") {
// basePage.clickElement(approveButton);
utils.sleep(2);
var approveButton = browser.driver.findElement(By.css(croApproveButton));
approveButton.click();
} else {
var declineButton = browser.driver.findElement(By.css(croDeclineButton));
declineButton.click();
utils.sleep(2);
browser.driver.findElement(By.xpath(remarkDecline)).sendKeys('for testing purpose');
}
utils.sleep(2);
browser.driver.findElement(By.linkText("Submit")).click();
utils.sleep(2);
expect(browser.driver.findElement(By.xpath(decisionSuccessMessage)).isDisplayed()).toBe(true);
} else /*if (decision.returnDecision() === 'Rejected')*/ {
console.log("Case is rejected, no further action");
}
},
and in spec file I am calling this method after I punch a case using user as follow:
fdescribe('Data Entry For Applicant(HL1)', function() {
beforeAll(function() {
this.actionwords = Object.create(require('../actionwords.js').Actionwords);
});
afterAll(function() {
testData.login.username = 'softcellqa1#gmail.com';
//logout of the app
loginPage.logout(testData)
});
fit('test', function() {
testData.loan.existingloan = 'No';
this.actionwords.housingLoanWithoutCoApplicant(testData);
this.actionwords.takeDecision(testData);
});
});
this.actionwords.takeDecision(testData) is always executed before this.actionwords.housingLoanWithoutCoApplicant
Please let me know what is wrong I am doing here?
When my page loads, I try to send a message to the server to initiate a connection, but it's not working. This script block is near the top of my file:
var connection = new WrapperWS();
connection.ident();
// var autoIdent = window.addEventListener('load', connection.ident(), false);
Most of the time, I see the error in the title:
Uncaught InvalidStateError: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state
So I tried to catch the exception, as you can see below, but now it seems InvalidStateError is not defined and that produces a ReferenceError.
Here's the wrapper object for my websocket connection:
// Define WrapperWS
function WrapperWS() {
if ("WebSocket" in window) {
var ws = new WebSocket("ws://server:8000/");
var self = this;
ws.onopen = function () {
console.log("Opening a connection...");
window.identified = false;
};
ws.onclose = function (evt) {
console.log("I'm sorry. Bye!");
};
ws.onmessage = function (evt) {
// handle messages here
};
ws.onerror = function (evt) {
console.log("ERR: " + evt.data);
};
this.write = function () {
if (!window.identified) {
connection.ident();
console.debug("Wasn't identified earlier. It is now.");
}
ws.send(theText.value);
};
this.ident = function () {
var session = "Test";
try {
ws.send(session);
} catch (error) {
if (error instanceof InvalidStateError) {
// possibly still 'CONNECTING'
if (ws.readyState !== 1) {
var waitSend = setInterval(ws.send(session), 1000);
}
}
}
window.identified = true;
theText.value = "Hello!";
say.click();
theText.disabled = false;
};
};
}
I am testing using Chromium on Ubuntu.
You could send messages via a proxy function that waits for the readyState to be 1.
this.send = function (message, callback) {
this.waitForConnection(function () {
ws.send(message);
if (typeof callback !== 'undefined') {
callback();
}
}, 1000);
};
this.waitForConnection = function (callback, interval) {
if (ws.readyState === 1) {
callback();
} else {
var that = this;
// optional: implement backoff for interval here
setTimeout(function () {
that.waitForConnection(callback, interval);
}, interval);
}
};
Then use this.send in place of ws.send, and put the code that should be run afterwards in a callback:
this.ident = function () {
var session = "Test";
this.send(session, function () {
window.identified = true;
theText.value = "Hello!";
say.click();
theText.disabled = false;
});
};
For something more streamlined you could look into promises.
This error is raised because you are sending your message before the WebSocket connection is established.
You can solve it by doing this simply:
conn.onopen = () => conn.send("Message");
This onopen function waits for your WebSocket connection to establish before sending your message.
if you use one websocket client object and connect from random app places then object can be in connecting mode (concurent access).
if you want to exchange through only one websoket then
create class with promise and keep it in property
class Ws {
get newClientPromise() {
return new Promise((resolve, reject) => {
let wsClient = new WebSocket("ws://demos.kaazing.com/echo");
console.log(wsClient)
wsClient.onopen = () => {
console.log("connected");
resolve(wsClient);
};
wsClient.onerror = error => reject(error);
})
}
get clientPromise() {
if (!this.promise) {
this.promise = this.newClientPromise
}
return this.promise;
}
}
create singleton
window.wsSingleton = new Ws()
use clientPromise property in any place of app
window.wsSingleton.clientPromise
.then( wsClient =>{wsClient.send('data'); console.log('sended')})
.catch( error => alert(error) )
http://jsfiddle.net/adqu7q58/11/
Method 1: Check connection
You can resolve a promise when socket is connected:
async function send(data) {
await checkConnection();
ws.send(data);
}
Implementation
This trick is implemented using an array of resolvers.
let ws = new WebSocket(url);
let connection_resolvers = [];
let checkConnection = () => {
return new Promise((resolve, reject) => {
if (ws.readyState === WebSocket.OPEN) {
resolve();
}
else {
connection_resolvers.push({resolve, reject});
}
});
}
ws.addEventListener('open', () => {
connection_resolvers.forEach(r => r.resolve())
});
Method 2: Wait for connection
You can resolve a promise when socket is not connected:
const MAX_RETRIES = 4;
async function send(data, retries = 0) {
try {
ws.send(data);
}
catch (error) {
if (retries < MAX_RETRIES error.name === "InvalidStateError") {
await waitForConnection();
send(data, retries + 1);
}
else {
throw error;
}
}
}
Implementation
This trick is implemented using an array of resolvers.
let ws = new WebSocket(url);
let connection_resolvers = [];
let waitForConnection = () => {
return new Promise((resolve, reject) => {
connection_resolvers.push({resolve, reject});
});
}
ws.addEventListener('open', () => {
connection_resolvers.forEach(r => r.resolve())
});
My opinion is that the second method has a little bit good performance!
It is possible to use functions and readyState with setTimeout.
function openSocket()
{
webSocket = new WebSocket("");
}
function sendData()
{
if(webSocket.readyState)
{
webSocket.send(JSON.stringify(
{
"event" : "",
"message" : ""
}));
}
else
{
setTimeout(sendData, 1000);
}
}
function eventHandler()
{
webSocket.onmessage = function(e)
{
data = JSON.parse(e.data);
event = data.event;
switch (event)
{...}
}
}
openSocket();
sendData();
enentHandler();