Heyo,
I have a following function
async function fnIsOnScreenOnce(img, desc,iCounter,client,repeatDelay=0) {
await timeout(repeatDelay);
let screenshot= await client.screenshot()
let buf = new Buffer(screenshot.value, 'base64');
let img1 = cv.imdecode(buf)
let result = img1.matchTemplate(img, 5).minMaxLoc();
result.screenshot=img1;
if (result.maxVal <= 0.65) {
// Fail
const msg = "Can't see object yet";
throw new Error(result);
}
// All good
console.log("result:"+result)
logger.info("Found image on screen: "+desc);
return result;
}
Call of the function
function fnIsOnScreen(img,client, repeats = 5, desc, wait = 2000,repeatDelay) {
logger.info("Looking for image on screen:" +desc +" with " + repeats + " repeats ");
let iCounter = 0;
let init = ()=> timeout(wait).then((asd)=>{
const attempt = () => fnIsOnScreenOnce(img, desc, iCounter,client,repeatDelay).then((data=>{
let imagepath=fnMarkOnImage(data.screenshot,img,data,outputDir)
let description={};
description.action="Is image on screen ?";
description.desc=desc;
description.repeats=repeats;
description.wait=wait;
description.img=imagepath;
description.message="is this correct element ? if is then it was found correctly";
fnPushToOutputArray(description)
return data;
})).catch(err => {
console.log(JSON.stringify(err));
console.log(err);
console.log(err.result);
iCounter++;
if (iCounter === repeats) {
// Failed, out of retries
logger.info("Object not found : " + desc);
return Promise.reject("Object not found : " + desc);
}
// Retry after waiting
return attempt();
});
return attempt();
})
return init();
}
result object contains some date.
On error result contains {} object with no values in it. I would need to get all the values. So how can i pass result object through throw new error to retrieve it in catch ?
One way to return extra data with error is to extend Error class and add them your self
class MyError extends Error {
constructor(message, errorExtraParams) {
super(message);
this._errorExtraParams = errorExtraParams;
}
get errorExtraParams() {
return this._errorExtraParams;
}
}
throw new MyError("Error!!!", {})
//or
let mError = new MyError("Error!!!", {})
console.log(mError.errorExtraParams)
But I suggest you don't use throw Error, because I don't like to throw Errors for insignificant reasons. What I mean is that in your case there is no reason to throw error cause there is no error and no reason to create an error just to tell you code "Hey I didnt find the image" instead just return false.
async function fnIsOnScreenOnce(img, desc, iCounter, client, repeatDelay = 0) {
await timeout(repeatDelay);
let screenshot = await client.screenshot()
let buf = new Buffer(screenshot.value, 'base64');
let img1 = cv.imdecode(buf)
let result = img1.matchTemplate(img, 5).minMaxLoc();
result.screenshot = img1;
if (result.maxVal <= 0.65) {
const msg = "Can't see object yet";
return false;
}
// All good
console.log("result:" + result)
logger.info("Found image on screen: " + desc);
return result;
}
function fnIsOnScreen(img, client, repeats = 5, desc, wait = 2000, repeatDelay) {
logger.info("Looking for image on screen:" + desc + " with " + repeats + " repeats ");
let iCounter = 0;
let init = () => timeout(wait).then((asd) => {
let found = false;
do {
let found = await fnIsOnScreenOnce(img, desc, iCounter, client, repeatDelay)
} while (found !== false && iCounter++ < 10)
let imagepath = fnMarkOnImage(found.screenshot, img, found, outputDir)
let description = {};
description.action = "Is image on screen ?";
description.desc = desc;
description.repeats = repeats;
description.wait = wait;
description.img = imagepath;
description.message = "is this correct element ? if is then it was found correctly";
fnPushToOutputArray(description)
return found;
})
return init();
}
You should pass a String to the Error Object, so if you want to exchange an object you could use JSON.stringify() like this:
try {
throw new Error(JSON.stringify({result:"Hello, World"}));
}
catch(error) {
console.log(JSON.parse(error.message))
}
As you can see, this is how you would send data from a try to a catch through throwing errors. You can ofc make the second part in the catch way shorter:
error = JSON.parse(error.message);
You can try an approach like this
try {
const err = new Error("My Error Occurred");
err.extra ='Extra details';
throw err;
}
catch (error) {
console.log(error.extra)
}
As Error itself is an Object ,We can make use of this to pass extra variables of our choice
Related
I'm really not sure what I am doing wrong
Please help out...
Is there a better way to access a variable declared within the useEffect?
Thanks
So I have the following code - but I get the error:
[TypeError: "setDevice" is read-only]
const [device, setDevice] = useState( '' );
React.useEffect(() => {
const device_id = async () => {
var DeviceInfo = require('react-native-device-info');
var deviceId = DeviceInfo.getUniqueId();
const filePath = RNFS.DocumentDirectoryPath + deviceId + "_secret.json";
if (await RNFS.exists(filePath)){
RNFS.readFile(filePath, 'utf8')
.then((contents) => {
try{
// setDev = String(contents);
var JSONObject = JSON.parse(contents);
console.log(JSONObject['device_id']);
setDevice = JSONObject['device_id'];
}catch(err){
console.log("Error: ", err);
}
});
console.log("FILE EXISTS: " + filePath);
} else {
function makeid() {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < 5; i++)
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
var dev_id = makeid() + deviceId;
var id = '{"device_id" : "'+dev_id+'"}';
RNFS.writeFile(filePath, id, 'utf8')
.then((success) => {
console.log('FILE WRITTEN!');
navigation.dispatch(resetReachOutPreferences)
})
.catch((err) => {
console.log(err.message);
});
}
}
device_id();
}, []);
console.log("ID: " + device);
I've tried useState(null)
From the React documentation on the State hook:
What does useState return? It returns a pair of values: the current state and a function that updates it.
So in this case, setDevice is a function that can be used to update the value of device (which will be reflected on subsequent renders). Instead of assigning to it, you should call it with the new value as its argument, e.g.:
setDevice(contents);
I'm currently trying to build a discord bot, and I want to use a database for some aspects of it. Currently, I'm trying to add a command that would return the names of all the tables I have in the database, and for the most part I have it down.
The part that I'm struggling with is actually getting the names back out as a var. Every guide and stackoverflow question that I've been able to find on it assume that you just want to get that result and then print it to the console, but I need to return it back to the method that called this.
My previous attempt was setting an outside variable and using a promise to wait for it to change, but I couldn't get that to work, most likely because I don't fully understand how Promises work. My current attempt uses setTimeout() to check, but that just returns the asyncID of either the first or second iteration.
Any help either in making either of these work or completely scrapping them and doing this a different way is very welcome.
Previous code:
function listTables() {
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) throw error;
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
setReturn(temp);
});
let out = checkReturn().then((value) => {
return value();
}).catch((error) => {
console.log(error);
return '';
});
returnValue = null;
return out;
}
var returnValue = null;
function setReturn(value) {
returnValue = value;
}
async function checkReturn() {
console.log('Checking Return: ' + returnValue);
let promise = new Promise((resolve, reject) => {
if(returnValue === null) reject('Var not set');
else resolve(returnValue)
});
return await promise;
}
Current Code:
function listTables() {
setReturn(null);
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) throw error;
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
setReturn(temp);
});
return checkReturn();
}
var returnValue = null;
function setReturn(value) {
returnValue = value;
}
function checkReturn() {
console.log('Checking Return: ' + returnValue);
if(returnValue === null) {
return setTimeout(checkReturn, 50);
} else {
return returnValue;
}
}
You need to modify the listTables function to return a promise.
function listTables() {
return new Promise((resolve, reject) => {
db.query('SELECT table_name FROM information_schema.tables WHERE table_schema=\'' + dbName + '\'', (error, results) => {
if(error) {
reject(error);
return;
}
let temp = '';
results.forEach((item) => {
temp += item.table_name + ', ';
}); temp = temp.slice(0, -2);
resolve(temp);
});
});
}
// Usage of `listTables()`
listTables()
.then(result -> {
// Do process result
});
I have a datastructure in the form of object structure . [![enter image description here][1]][1]
{
Invite1
{
Amount: 10,
PhoneNumber:9876543210,
Status:"Pending"
}
Invite2
{
Amount: 20,
PhoneNumber:1234566789,
Status:"Pending"
}
}
I have a condition when whose Invite(1,2,3) PhoneNumber matches with other document that invitee need to update the field as Status = true
When I try to update a field as Status = true It is updating at the end of the document.
Mycode need to update
var dbref = db1.collection('deyaPayUsers').doc(sendauthid).collection('Split').doc(sendauthid).collection('SentInvitations').doc(senderautoid);
var msg1 = receiverph + "" + status + " to pay $" + document.Amount;
var fulldoc = dbref.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document');
} else {
console.log('Document data :', doc.data());
d1 = doc.data();
console.log("d1 is" + d1);
for (var k in d1) {
var p = d1[k].PhoneNumber;
console.log("ivitees phone" + p);
if (receiverph == p) // Here the condition is true of the invite phoneNumber then need to update
{
console.log("p" + PhoneNumber);
console.log("the phonenumber matches");
var updated = dbref.update({"Status":status});// Here It is updating
at the endof the document
other Method to update
d1.Status = status; // In d1 I have the document data
var setdata = dbref.set(d1);
Please if their is any approach help with me.
Thanks
If I understand correctly that you would like to update each InviteXX item in the document, here is a code that will work (I've kept the main part of your code):
var dbref = db1.collection('deyaPayUsers').doc(sendauthid).collection('Split').doc(sendauthid).collection('SentInvitations').doc(senderautoid);
var msg1 = receiverph +"" + status +" to pay $"+document.Amount;
const fulldoc = dbref.get()
.then(doc => {
if (doc.exists) {
//console.log("Document data:", doc.data());
const inviteUpdate = {}; //An object that we will update by looping over the InviteXX objects of the document
const d1 = doc.data();
//console.log("d1 is" + d1);
for (let key in d1) {
if (d1.hasOwnProperty(key)) {
const p = d1[key].PhoneNumber;
//console.log(key);
//console.log("invitees phone " + p);
if (receiverph === p) // Here the condition is true of the invite phoneNumber then need to update
{
inviteUpdate[key + '.status'] = true;
//The key point is here: we define the object field with a mix of dot notation and []
}
}
}
return dbref.update(inviteUpdate);
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
throw "No such document"
}
})
.catch(function (error) {
console.log("Error:", error);
});
Note that:
You should return a promise in your Cloud Function. I don't have the full code of your function but probably you will return fulldoc. (You may have a look at this video https://www.youtube.com/watch?v=652XeeKNHSk&t=2s)
I don't know how do you get/initialize receiverph
You may use const or let instead of var in a Cloud Function (JavaScript ES6+)
i having Api Call which execute in For Loop some of the value which returns 10 sec itself some may take nearly 60 sec i have to maintain proper Timeout and clear session (i.e if results comes at 15 sec means it should goes to next input values and run the code) but currenly its waiting for 45 sec each single record how to optimize it
here my sample code :
if (selectedrows.length >= 1) {
for (var i = 0; i < selectedrows.length; i++) {
var myVar = setTimeout (function (k) {
var ob = { results: "Appending ..." };
child.update(selectedrows[k][4], selectedrows[k][4], ob);
var fullName = selectedrows[k][1] + ' ' + selectedrows[k][2];
math.ResultCall.async(fullName,function (err, res) {
if (err) throw err;
var returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null)
{
console.log("None found")
}
else{
var obj = { results: “res” };
child.update(selectedrows[k][4], selectedrows[k][4], obj);
}
}
});
}, i * 45000,i);
}
}
Rephrasing your question, you need to return the data when your api gets resolved.
For this please go through https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
JavaScript, by default it work asynchronously because of its event loop.
You have promises and resolve to get notified when your api returns a data
Hope I helped :)
There are several approaches to implement the solution
1. Async-Await: in-case the records-processing order is important
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
await new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
}
**don't forget this means the wrapping function should be async as well (which returns a promise that can be resolved if necessary)
2.Promise.All: if the order is not important
let promArray = [];
for( let i=0; i<selectedrows.length; i++)
{
let ob = { results: "Appending ..." };
child.update(selectedrows[i][4], selectedrows[i][4], ob);
let fullName = selectedrows[i][1] + ' ' + selectedrows[i][2];
promArray.push( new Promise((resolve,reject)=>
{
math.ResultCall.async(fullName,(err, res) => {
if (err) reject(err);
let returnedValue = JSON.parse(res);
console.log(returnedValue);
if(returnedValue.Result == null || returnedValue.Result.FOUND_Result == null) {
console.log("None found")
} else {
let obj = { results: “res” };
child.update(selectedrows[i][4], selectedrows[i][4], obj);
}
resolve();
});
);
}
Promise.all(promArray);
** this will also return a Promise that can be resolved if necessary.
I am trying to iterate through the JSON files generated by the protractor tests. I pull all the file names into an array and call a method that opens and parses through the each file, post the results to the database and pass back a passed/failed flag.
I have tried all the examples here
Make angular.forEach wait for promise after going to next object and still get the same results.
The method is actually called, but the results are not posted to the db. I have tested the parser.parseResults on an individual file and it successfully posted to the db, so it has to have something to do with the promise not resolving correctly.
Is it not possible to do something like this in the jasmine/protractor framework? Or do I have something wrong in the code?
I have included the code for my latest attempt.
Thank You
Christine
matches.reduce(function (p, val) {
console.log('val', val);
return p.then(function () {
return parser.parseResults(val);
});
}, Promise.resolve()).then(function (finalResult) {
console.log('finalResult = ', finalResult);
}, function (err) {
console.log('error in reduce',err);
});
parser.parseResults code
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
try {
if (err != null) {
console.log('error reading file',err);
reject(err);
}
console.log('obj - ',obj);
var results = [];
var Passed = 0;
var Message = '';
var Stack = '';
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
if (specs.length > 0) {
for (var i = 0; i < specs.length; i++) {
var assert = specs[i];
var tcR = new RegExp(/TC[\d]+/);
var tc = assert.description.match(tcR);
if (!assert.failedExpectations.length) {
Passed = 1;
}
else {
assert.failedExpectations.forEach((expectation) => {
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
})
Passed = 0;
}
if (tc != null) {
utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild,
'P', Message, Stack, 0, moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss'), '')
.then(function (resp) {
resolve(Passed);
}, (err) => {
console.log('Posting to Database failed ', err);
reject(err);
});
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
reject(err);
}
}
}
}
}
catch (err) {
console.log('rejecting opening file');
reject(err);
}
});
})
}
If there is not exactly one suite in the obj, with exactly one spec, then your promise is either resolved not at all or multiple times.
Avoid wrapping too many things in the new Promise constructor - always promisify on the smallest possible level, and use promise chaining afterwards.
protractorParser.prototype.parseResults = function (fileName) {
return new Promise((resolve, reject) => {
console.log('In parseresults', fileName);
json.readFile(fileName, function (err, obj) {
if (err != null) {
console.log('error reading file', err);
reject(err);
} else {
resolve(obj);
}
});
}).then(function(obj) {
console.log('obj - ',obj);
var results = [];
for (var suite in obj) {
var specs = obj[suite].specs;
console.log('spec - ', specs);
for (let i = 0; i < specs.length; i++) {
const assert = specs[i];
const tcR = /TC[\d]+/;
const tc = assert.description.match(tcR);
let Passed = 1;
let Message = '';
let Stack = '';
if (assert.failedExpectations.length) {
const expectation = assert.failedExpectations[assert.failedExpectations.length-1];
Passed = 0;
Message = expectation.message;
Stack = expectation.stack.split('\n')[1].trim();
}
if (tc != null) {
const time = moment().utcOffset(config.get('settings.timeOffset')).format('YYYY-MM-DDTHH:mm:ss');
const promise = utility.TestDataManager.insertAutomationResults(tc[0], assert.description, Passed, process.env.testBuild, 'P', Message, Stack, 0, time, '');
results.push(promise.catch(err => {
console.log('Posting to Database failed ', err);
throw err;
}));
} else {
console.log('no test case found for test: ' + assert.description + ' -- skipping');
// I don't think you want to `throw err` here, right?
}
}
}
return Promise.all(results);
});
};