How to retrieve the text using protractor's getText API? - javascript

I am using protractor for my test framework and I need to get the value by using the getText method and store it in another value. I have problem in extracting the value from getText method. I do understand that I need to resolve the promise but it didn't work for me.
I have the page object like this. (Emp.js)
this.getID = async()=>{
await empID.getText();
}
and in the test.spec.js. This is how I have my test to retrieve the file.
var emp = new emp();
let empID = await emp.getID();
//When I do console.log(empID) it returns undefined. not sure why ?

Please try this:
this.getID = async() => {
return await empID.getText();
}

Related

Returning the value of an async axios API call to a variable [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I do apologise in advance for what seems like a stupid question that has been answered so many times before, however I just can't get my head around exactly how to accomplish what I'm trying to do and I've been going round and around in circles for hours now re-writing the same bit of code over and over again.
I am very much a beginner at any kind of programming (bar some SQL wrangling and a bit of dodgy VBA stuff) and find it difficult to learn without a specific problem I want to solve. I have done some basic javascript course stuff so I know the basic syntax.
What I am trying to do is make a GET request using axios to get some data from an api and use the data it responds with to set the value of a variable that I'm then using to display on the screen.
Essentially what I want to do is this (within a nodejs .js script):
Get data from a GET api call
Get a value from that data to make a second GET API call
Use the data from that second call to place into variables that I can use within a function
At the moment I'm stuck at the first hurdle, this is what I have so far (that works):
const queryData = '123456';
const getLink = async () => {
try {
const resp = await axios.get(`https://www.apisite.com/${queryData}`);
return resp.data;
} catch (err) {
console.error(err);
}
};
getLink().then(console.log);
And this does actually do something, the console is populated with the object returned by the API
Where I am stumped is how to get that data into my variable to use on screen.
Essentially what I want to do here is
let myObject = getLink();
From there I would then want to use the rest of the object so I could have:
let title = myObject.title;
let desc = myObject.description;
let user = myObject.user;
etc.
And this is where I am stuck because I can't seem to find a way to "get the data out" so to speak. I've tried suggestions about adding a new async function, about wrapping it as an IIFE and I just can't figure out what the answer is.
Any help at all (using as basic a concept as possible) would be much appreciated here.
#Bergi - the function I'm trying to call this is here. However I haven't actually been using this function to test, I've just been doing it from an empty project to just see if I can get the basics to work so I don't have to worry about other things obfuscating the issue. I'm trying to test it outside of any function at the moment just trying to see exactly how to get the data out to implement it. The below is the fabricated version of what I would be trying if I could get this to work but it is likely it is full of errors because I haven't actually tried to run this, I made it purely to show what I'm trying to do:
testing = function(tokens, idx, options, env, self) {
const token = tokens[idx];
if (token.info !== 'isbn') return defaultRender(tokens, idx, options, env, self); //checks for 'isbn' code fence token
const elementId = 'isbn_target_' + Math.random() + '_' + Date.now();
const element = document.createElement('div');
let html = '';
try {
element.setAttribute('id', elementId);
element.style.display = 'none';
document.body.appendChild(element);
//let queryData = token.content.trim();
const queryData = '123456';
const getLink = async () => {
try {
const resp = await axios.get(`https://www.apisite.com/${queryData}`);
return resp.data;
} catch (err) {
console.error(err);
}
};
let queryResponse = getLink();
let title = queryResponse.title;
html = '<div style="background-color: white;">' + title + '</div>';
} catch (error) {
console.error(error);
return '<div style="border: 1px solid red; padding: 10px;">Could not render preview: ' + htmlentities(error.message) + '</div>';
} finally {
document.body.removeChild(element);
}
return html;
};
Because getLink() is async, it returns a Promise.
In Node v14.18.0 and later, you can simply await it:
let myObject = await getLink();
You can wrap your code in an anonymous async function if you're running a prior version of Node:
(async () => {
let myObject = await getLink();
let title = myObject.title;
let desc = myObject.description;
let user = myObject.user;
})();
While outside the scope of the question as you've asked it here, you might also consider decreasing the verbosity of your code by using Destructuring assignment to assign your values:
let myObject = await getLink();
let {title, 'description': desc, user} = myObject;

MongoDB Realm Functions: How to query the document count of a collection

I tried implementing using this:
const mongodb = context.services.get("mongodb-atlas");
const itemsCollection = mongodb.db("natcocuDB").collection("members");
And I tried to put it inside an object
let memberToInsert = arg;
memberToInsert.memberID = itemsCollection.count({}) + 1;
Then the result is this:
memberID : [object Promise]1"
So the count function is a Promise. I tried to "await" the count but the function editor of realm produces an error.
The error says it's missing some ";".
So I tried so separate it by creating an async function for the count.
async function getDocumentCount(collection) {
return await collection.count({}) + 1;
}
But the result is the same only an object:
memberID : Object
Do you have any idea how can I get the document count? Thanks!
Solved it already. I just made my parent function async. And the 'await' worked. Thanks.
use await
Db query is an async operation that returns a promise. So in order to get a response from it use await or a callback.
let memberToInsert = arg;
const count = await itemsCollection.count({});
memberToInsert.memberID = count + 1;
https://docs.mongodb.com/realm/functions/#behavior

async function has old state React-Redux

I am working on a React project where user can upload and remove photos in projects. After Uploading new image it should be visible to user only if corresponding projectis selected. The solution is fairly simple to check
if
(selectedProject.projectID=== imageMetadata.projectID)
where
selectedProject.projectID: Id of currently selected project( Comming from
Redux Store )
imageMetadata.projectID: Id of project to which uploaded image belongs.
All of this is being done inside an async function and the problem we are facing is that even after selectedAlbum.albumID is changed everywhere else, this function still has its old value. Is it because the function is async?
This is my code:
let projectId = selectedProject.projectID;
const responses = await Promise.all(
filesToUpload.map( async (file) => {
let res = await imageStoreApiHandler.uploadPhoto(file, projectId);
notifyUploadProgress(count++, total, notifcationKey);
if (res.status === 200) {
let imageMetadata: any = res.data[0];
if (selectedProject.projectID === imageMetadata.projectID) {
addImage(imageMetadata);
}
}
return res;
}));
It's probably a closure problem where the uploadhandler keeps caching the first function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
Maybe write a function which will return a promise all array based on the parameters current project id.

How to use async call inside forEach when using firebase calls

the question that I have is that I can't figure out how to make this code work properly using Firestore (not sure if this is irrelevant).
The actual code is the following:
prestamoItems() {
var myarray = [];
var myobject = {};
//here comes the first async method (works OK)
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
//here comes forEach
val.docs.forEach(doc => {
myobject = doc.data();
myobject.id = doc.id;
console.log("The doc id is " +myobject.id)
//here comes second async call inside the forEach loop, but it doesnt wait for this
//to be finished, and immediately goes to the other step
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
})
myarray.push(myobject)
console.log("myobject pushed to myarray")
});
}
});
}
Please note that I'm calling an async method inside a forEach loop that comes from another async method. In every variation of the code, the output that I'm getting (the console logs) are the following:
11:13:14.999 Prestamos.vue?18d2:71 The doc id is 1yTCUKwBvlopXX2suvVu
11:13:14.999 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is Z5TE15Fj3HFrn1zvceGe
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is JNN9aN65XE1tUTmlzkoJ
11:13:15.000 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.000 Prestamos.vue?18d2:71 The doc id is NF2hHCpM8leZezHbmnJx
11:13:15.001 Prestamos.vue?18d2:78 myobject pushed to myarray
11:13:15.364 Prestamos.vue?18d2:74 The doc id from the other collection is 1yTCUKwBvlopXX2suvVu
11:13:15.368 Prestamos.vue?18d2:74 The doc id from the other collection is Z5TE15Fj3HFrn1zvceGe
11:13:15.374 Prestamos.vue?18d2:74 The doc id from the other collection is JNN9aN65XE1tUTmlzkoJ
11:13:15.379 Prestamos.vue?18d2:74 The doc id from the other collection is NF2hHCpM8leZezHbmnJx
So, the forEach loop is not waiting to the async function inside it (which actually is the expected behavior, AFAIK).
The question is how can I make it wait for the inner call to be finished before adding the obect to the array? Thanks in advance.
either you nest code, which depends on previous results into then() callbacks or you wrap the loop (forEach does not support async) in async block to make use of await inside. eg.:
fb.prestamosCollection
.orderBy("fechaPrestamo", "desc")
.get()
.then(val => {
if (!val.empty) {
// wrap loop in async function call iife so we can use await inside
(async () => {
for (var i = 0; i < val.docs.length; i++) {
const doc = val.docs[i];
myobject = doc.data();
myobject.id = doc.id;
// this will be synchronous now
let eqp = await fb.equiposCollection.doc(myobject.id).get();
console.log(eqp.id);
myarray.push(myobject)
}
})();
}
});
The root of the problem is that you're trying to turn an asychronous operation (waiting for Firestore to return values) into a synchronous one. This isn't really possible in a meaningful way in JavaScript without causing lots of issues!
You'll need to populate your array inside of the .then() callback and return the promise as a result of the function. Any caller that calls your prestamoItems() function will also have to use .then() callbacks to access the underlying myarray value:
const _ = {
async prestamoItems() {
const val = await fb.prestamosCollection.orderBy("fechaPrestamo", "desc").get();
if (val.empty) {
return myarray
}
// Promise.all() will take a list of promises and will return their results once they have all finished.
return await Promise.all(
// Array.prototype.map() will take an existing array and, for each item, call the given function and return a new array with the return value of each function in that array.
// This is functionally equivalent to making a new array and push()ing to it, but it reads a lot nicer!
val.docs.map(async doc => {
const myobject = doc.data();
const eqp = await fp.equiposCollection.doc(myobject.id).get()
// I presume you want to do something with eqp here
return myobject
})
);
}
}
The above code sample uses Array.prototype.map() to do away with myarray as it's not necessary.
A caller would have to use this code like this:
_.prestamoItems().then((myarray) => {
...
})
Promises are a way of saying that a value may be avaliable at some point in the future. Because of this, you have to make sure that any interaction you have with a promise is written in such a way that assumes the value is not avaliable immediately. The easiest way to do this is by using async/await and ensuring that you return promise objects.
just move the push inside then like this
fb.equiposCollection.doc(myobject.id).get().then(eqp => {
console.log("The doc id from the other collection is " +eqp.id)
myarray.push(myobject)
console.log("myobject pushed to myarray")
})

How to use node sqlite3 with q (promise)

I'm trying to use the promise with sqlite3. Here is a part of my source code:
this.deleteTag = function(tag, project){
var db = this.db;
if (project){
return q.nfcall(db.run, "DELETE FROM tag2project WHERE tag = ? AND project = ?",
[tag.id, project.id]);
}else{
return q.all([
q.nfcall(db.run, "DELETE FROM tag2project WHERE tag = ?", [tag.id]),
q.nfcall(db.run, "DELETE FROM tags WHERE id = ?", [tag.id])
]);
}
};
But those promises only enter in .fail where error is:
[TypeError: Database object expected]
Searching for this error only got me to the sourcecode of sqlite itself https://github.com/joyent/smartos-live/blob/master/src/node-sqlite3/src/statement.cc#L91
The old version using simple callback is working so there is not error in this.db or the sql query.
I think db.run is not function but method. from Q doc:
If you are working with methods, instead of simple functions, you can
easily run in to the usual problems where passing a method to another
function—like Q.nfcall—"un-binds" the method from its owner. To avoid
this, you can either use Function.prototype.bind or some nice
shortcut methods we provide:
return Q.ninvoke(redisClient, "get", "user:1:id");
return Q.npost(redisClient, "get", ["user:1:id"]);
But I always use Q.denodeify or Q.nbind. it is cleaner.
You can also create reusable wrappers with Q.denodeify or Q.nbind:
var readFile = Q.denodeify(FS.readFile);
return readFile("foo.txt", "utf-8");
var redisClientGet = Q.nbind(redisClient.get, redisClient);
return redisClientGet("user:1:id");
You could bind the object that you created when you promisify the function.
Example
const { promisify } = require('util');
const db = new lib_sqlite3.Database(_dirname + '/your-db-path');
const runAsync = promisify(db.run.bind(db));

Categories

Resources