I'm struggling to get the actual text of the text box as I need it as a text to store it in a variable rather than comparing it against a value, because I need to add it to the end of the url to call another page.
I tried using the code suggested by ebeal but it didn't do what I want:
var access_token = driver.findElement(webdriver.By.name("AccToken"))
.getAttribute("value")
.then(console.log);
// This outputs the right result but only to the console as I can't save it to a variable
var access_token = driver.findElement(webdriver.By.name("AccToken"))
.getText();
access_token = access_token.then(function(value){
console.log(value);
});
console.log("the new one : " + access_token);
// this one outputs : the new one: Promise::304 {[[PromiseStatus]]: "pending"}
Any idea?
WebdriverJS is purely asynchronous. Meaning, you need to provide a callback and instantiate your variable inside the callback rather than simply assigning the call the results of the function to your variable.
That's why you will always get a promise everytime you console.log your access_token variable. The webdriverjs docs explain a little about how promises work in selenium-webdriver https://code.google.com/p/selenium/wiki/WebDriverJs#Understanding_the_API
You can do the following to assign the text to a variable:
var access_token;
var promise = driver.findElement(webdriver.By.name("AccToken")).getText();
promise.then(function(text) {
access_token = text;
});
I highly recommend WebdriverIO as it takes away from the pain of having to write your own promises. http://webdriver.io/
So this is one thing that I have had to learn the hard way, so I hope this helps:
var access_token = await driver.findElement(webdriver.By.name("AccToken"))
.getAttribute("value")
.then((value) => { return value; });
I'm not sure which version of Webdriver you are using, but you may have some luck using WebdriverIO. Specifically its getText() function which will return a callback with the text so you can use it elsewhere.
http://webdriver.io/api/property/getText.html
client.getText('#elem').then(function(text) {
console.log(text);
});
This should work just fine if you are looking to just get the value. If you are using the new await ES6 syntax no need to "then" the promise.
const { Builder, By, Key, until } = require('selenium-webdriver');
const assert = require('assert');
let access_token = await driver.findElement(By.name("AccToken")).getAttribute("value");
Then you can even just assert:
assert.equal(access_token, "your token value here");
More information can be found at the documentation for selenium-webdriver. Take a look at the Webdriver instance methods for a closer look. Good luck!
Related
I am new to Adonis JS so extremely sorry for the Stupid Question.
I have the default setup of Adonis JS with Mysql Database and everything working.
I have created a simple usertest route where I am returning JSON of user with ID: 1.
Below is the code for the same
Route.get('/usertest', ({ response }) => {
const User = use('App/Models/User')
let data = User.query().where('id', 1)
.first()
console.log(data)
return response.status(200).json(data)
})
But it is returning and empty object
Raw Response:
{}
Console Log Statement Response:
Promise { <pending> }
I am unable to understand what am I missing here.
Note: I tried let data = User.find(1) but it did not work.
Please help me.
Thanks in advance!!!
Quick note, at least you have to execute the query asynchronously.
I mean, you have to replace:
let data = User.query().where('id', 1)
.first()
by:
let data = await User.query().where('id', 1)
.first()
Of course, this mean you have to precede the function arrow with async:
Route.get('/usertest', async ({ response }) => {
// rest of the code
let data = await User.query().where('id', 1).first()
// rest of the code
})
It is very easy to miss "await" when you start working with async-await frameworks. Just a suggestion on the query whenever you want to find one object it is good practice to use ORM's predefined function. In this case
const user = await User.findBy('id',1)
this will return the first object it finds with the given id. You will find more options and help in knex.js docs http://knexjs.org/#Builder-where
I am building an application customiser in SPFX and I am using pnp/sp to get data from a Sharepoint list - all easy so far. I have figured out the code like this, but it is just returning [object promise] here is my code , any help would be brilliant.
I am calling the function like this :
public emailAddressGetter = this.GetSharePointData();
I am trying to show the output like this :
${escape(this.emailAddressGetter.toString())}
and this is the promise I am executing :
private async GetSharePointData(): Promise<any>
{
let myVar : string;
var resultData: any = await sp.web.lists
.getByTitle('Emails')
.items
.select('EmailAddress')
.getById(99)
.get().then((r => {
myVar = r.EmailAddress;
}));
console.log(myVar);
return myVar;
}
any help would be appreciated, I know I am almost there :) thanks guys
I think your GetSharePointData returns a Promise, because it has async declaration, so you need to execute code asynchronously and wait for the result.
Instead of:
public emailAddressGetter = this.GetSharePointData();
${escape(this.emailAddressGetter.toString())}
Try:
this.GetSharePointData()
.then(res => {
// res here is myVar
${escape(res.toString())};
});
Firstly fix your code's type annotations. You are completely defeating the point of TypeScript by suppressing the errors the language exists to catch by specifying vacuous types instead of leveraging inference. This isn't Java.
async GetSharePointData() { // return type is inferred as `Promise<string>`
const result = await sp.web.lists // the `any` you had here was worse than useless.
.getByTitle('Emails')
.items
.select('EmailAddress')
.getById(99)
.get();
const emailAddress= result.emailAddress;
console.log(emailAddress);
return emailAddress;
}
Now onto async functions and promises. An async function or method always returns a promise. Assigning the result of calling such a function directly to a property or variable will always result in the behavior you described
GetSharePointData().toString() === "[object Promise]"
The correct approach to setting the property emailAddressGetter (BTW that's a terrible name for that property either way) to the email address that the promise eventually resolves with depends on the context, but here is something you might do.
constructor() {
this.emailAddressPromise = this.GetSharePointData();
this.emailAddressPromise.then(emailAddress => this.emailAddress = emailAddress);
}
But that could be awful and unnecessary unpredictable depending on what you are trying to do.
I am trying to make a crawler, and as the data is not showing in the page source, I can only execute the javascript with the web driver and get the response, and then do the data analysis.
The script is simplified, like this, use Promise.
var res = ""
function f1() {
p = window.Promise
a = p.resolve(5).then(function(value) {
console.log(value)
res = value
return res
})
return a
}
console.log(f1()) // Promise object
console.log("result = ", res) // res is empty
My program is like this, writing with c#:
public void GetParameters(string url)
{
IWebDriver driver = new ChromeDriver();
driver.Navigate().GoToUrl(url);
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string script = readFile(#"C:\myscript.js", Encoding.UTF8).TrimEnd(); // The script is a bit long, so I save it to a local file.
var json = js.ExecuteScript(script);
Console.WriteLine("Get the return value");
Console.WriteLine(json);
driver.Close();
}
I want to get the value, and I know then always return Promise object, so I define a variable, and want to store the value to it. But seems that, the Promise is executed asynchronous, so the res always be empty.
OK, I'm writing a crawler, and use Selenium to get the response from the server (Selenium.webdriver can open a web browser, and then execute script), I need get the result, as it will use by another program. So, I can not just add another .then, just output the value. Maybe I can save to a local file, and then read it, but I think it is inefficient.
Anyone can help?
When you try to log the global res, the result hasn't been computed yet. When using Promises, you have to get the result asynchronously, using .then, like this:
f1().then(res => console.log("result =", res));
Try this
You're using promises incorrectly.
f1().then(res => console.log('result=', res)).
I have a function that pulls out from database a random question from Questions collection.
Game_Questions.js - console.log below prints out correct value (string I need), so I thought that return will let yield give me back same value.
exports.random_Question = function *() {
yield Questions.findRandom().limit(1).exec(function(err,question){
console.log("rand q: " + question[0].text);
return question[0].text;
});
}
Game.js:
var Game_Questions = require('./backend/Game_Questions');
And here I want to access question[0].text value from random_Question function from code snippet above (Game_Questions.js). What I've tried so far:
var found_Question = Game_Questions.random_Question();
var found_Question = Game_Questions.random_Question().next().value;
Those two return [Object object] which after using JSON.stringify() shows that the object is:
{"value":{"emitter":{"domain":null,"_events":{}},"emitted":{},"ended":true},"done":false}
I also tried using co(function*()) but it also didn't let me take out the value. Please help how to access it?
The answer by #remus is a callback approach and Koa was designed explicitly to ditch callbacks. So while it's perfectly good code and would fit an Express application it is completely at odds with the design philosophy behind Koa.
From the looks of it you are using Mongoose which has supported promises for async operations since version 4.0 (which was released Apr 2015) which should allow a yield approach to be taken. Note I'm making an assumption you are working with Mongoose - I hope I'm not wrong!
Here is some nice documentation on how Mongoose would fit nicely with koa.
So first of all make sure you are using a version of Mongoose that supports using yield. If not you'll have to use the #remus approach or manually wrap each of your methods so they are yield compatible (i.e. wrapping with promises).
But if you are using a compatible version (4.0 and upwards) then your code would look something like the following:
exports.random_Question = function *() {
var result;
try {
result = yield Questions.findRandom().limit(1).exec();
} catch(e) {
console.log(e.stack);
throw e;
}
console.log("rand q: " + result[0].text);
return result[0].text;
}
Note that I'm assuming the result is an array based on the code you supplied.
The above example doesn't necessarily have to be a generator function. It could also be a normal function that returns a Promise. So alternatively something like this could also be done:
exports.random_Question = function() {
return Questions.findRandom()
.limit(1)
.exec()
.then(function() {
// I'm assuming mongoose assigns the value
// being resolved in exec() to 'this'
var question = this[0];
console.log("rand q: " + question.text);
return question.text;
}).catch(function(e) {
console.log(e.stack);
throw e;
});
}
So for the randomQuestion function all that is important is that it can be yielded by co which handles the Koa application flow control – check tj/co on GitHub for the different objects you can yield.
So finally getting back to the Koa Middleware we can yield either of the above code snippets in the exact same manner. So we'd do:
var koa = require("koa");
var app = module.exports = koa();
var Game_Questions = require('./backend/Game_Questions');
app.use(function*() {
var resultText;
try {
resultText = yield Game_Questions.random_Question();
} catch(e) {
this.throw(500);
}
this.body = resultText;
this.status = 200;
});
app.listen(3000);
Something else to note is that I'm a little unsure of the findRandom method in the mongoose query since I don't know if it plays nicely with the Promise features of mongoose. Personally I'd get a normal mongoose query working using yield before reintroducing findRandom just to make sure it's not causing an issue.
My answer is getting a bit long at this point so I'll leave it at that.
Your syntax is pretty strange, but not sure if that's specific to Koa or not?
Because Node.js is event based, use a callback instead:
exports.random_Question = function(callback) {
Questions.findRandom().limit(1).exec(function(err, question){
callback(err, question);
});
}
And use it:
var Game_Questions = require('./backend/Game_Questions');
Game_Questions.random_Question(function(err, question) {
console.log(question);
});
Of some concern as well is your question states you're trying to reference Game_Questions.randomQuestion() when your function is actually named random_Question.
Please help me with the following.
I have been converting my AngularJS application from localStorage to localForage.
throughout my application I was assigning the localStorage value like this.
window.localStorage.setItem('localSavedValue','SavedValue');
and then I was retrieving the data like this,
var myValue = window.localStorage.getItem('localSavedValue');
So when I console.log(myValue); // it outputted 'SavedValue'
I cannot seem to do this with localForage when I try,
$localForage.setItem('localSavedValue','SavedValue');
var myValue = $localForage.getItem('localSavedValue');
console.log(myValue); // returns an object.
I don't get the value set to myValue.
I am sure this is something do do with promises as when I use the callback I can access the correct 'myValue' however I want to get it out of the call back to use in the rest of the service.
Also to note, I am in a service so can't assign to $scope (unless I don't know how).
Appreciate any help.
Thanks
B
$localForage.setItem('localSavedValue','SavedValue').then(function() {
$localForage.getItem('localSavedValue').then(function(data) {
console.log(data);
});
});
https://github.com/ocombe/angular-localForage#configure-the-provider-
LocalForage is async by design so I would suggest you to use Promises like #RouR suggested.
A minor improvement for code clarity would be to chain-return the promise results, but you still can't avoid the async code consequences.
$localForage.setItem('localSavedValue','SavedValue').then(function() {
return $localForage.getItem('localSavedValue');
}).then(function(data) {
console.log('I\'m printed second', data);
});
console.log('I\'m printed first');
If you are using Babel, a more friendly approach for such migrations would be to configure it to use transform-async-to-generator or preset-es2017 and rewrite such code as
await $localForage.setItem('localSavedValue','SavedValue');
const data = await $localForage.getItem('localSavedValue');
console.log(data);