Phantomjs with node gives "Promise pending" - javascript

When I run the script below from the command line node script.js, the result is:
success
Promise { <pending> }
The page never gets opened in console.log, can anyone explain why?
var phantom = require('phantom');
phantom.create().then(function (ph) {
ph.createPage().then(function (page) {
page.open('https://stackoverflow.com/').then(function (status) {
console.log(status);
var p = page.evaluate(function () {
return document.getElementsByTagName('html')[0].innerHTML
});
console.log(p);
});
});
});

as displayed, page.evaluate returns a promise.
try the folowing code :
var phantom = require('phantom');
phantom.create().then(function(ph) {
ph.createPage().then(function(page) {
page.open('https://stackoverflow.com/').then(function(status) {
console.log('test'+status);
var p = page.evaluate(function () {
return document.getElementsByTagName('html')[0].innerHTML
});
p.then(function(pagecontent) {
console.log(pagecontent);
process.exit()
});
});
});
});

That's because you're assigning Promise to a variable, and it's result is not returned immediately. You should rather:
page.evaluate(function () {
return document.getElementsByTagName('html')[0].innerHTML;
}).then(function (html) {
console.log(html);
});
Also, to not get lost in callback hell you might try to use async/await approach:
(async () => {
const instance = await phantom.create();
const page = await instance.createPage();
const status = await page.open('https://stackoverflow.com/');
const html = await page.evaluate(function () {
return document.getElementsByTagName('html')[0].innerHTML;
});
console.log(html);
})();
Which is kind of preferred way according to phantom maintainers guide.

Related

async api call function seems to work until test

I am trying to get some exchange data and use it for some logic. I thought the most straight forward idea would be to use a function where I could pass the different pairs I may want, there are many per exchange. If I console log inside the function when the data ends everything works find. When i try and get the response when it is ready I get undefined, please see the commented console log and my last line.
I understand that I am missing something with async and the way it works.
const https = require('https');
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
return (binanceBookTickerJson)
});
});
};
binancePairPrice('BTCUSDT').then(console.log);
day one javascript coming from python. This is quite a step from what I am used to writing. Any docs or links would be appreciated too.
thansk
https.get doesn't return something that can be promisified, so you can't await it.
You can do something else which is wrapping the https.get call within a Promise and then await it when calling binancePairPrice.
const https = require('https')
async function binancePairPrice (binancePair) {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol='
return new Promise((resolve) => {
https.get(url, res => {
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
resolve() = >
{
binanceBookTickerJson = JSON.parse(binanceBookTicker);
return (binanceBookTickerJson)
}
});
})
})
}
(async () => await binancePairPrice('BTCUSDT))()
Your binancePairPrice function doesn't wait for the end callback to happen and therefore just carries on and returns undefined.
You need to return a Promise and then resolve the promise with the value you want to return from the function.
Promise basics
Using the Promise() constructor
async function binancePairPrice (binancePair) {
return new Promise((resolve, reject) => {
let url = 'https://api.binance.com/api/v3/ticker/bookTicker';
let queryString = '?symbol=';
https.get(url+queryString+binancePair,(res) => {
console.log(res.statusCode);
let binanceBookTicker = '';
let binanceBookTickerJson =
res.on('data', data => {
binanceBookTicker += data;
});
res.on('end', () => {
binanceBookTickerJson = JSON.parse(binanceBookTicker);
//console.log(binanceBookTickerJson);
resolve(binanceBookTickerJson)
});
});
});
}

How to write a unit test for a function with Promise

I am a complete beginner with Node.JS and Mocha and was tasked to write unit test's for a group project. My problem is that i do not even know where to start since the return value is a promise.
Watching a lot of guides i have learned how to check return values for common functions but it wouldn't help me with a real world example.
If any expierienced developer could help me with a guide and code example specific to the function i listed i could hack and understand it and apply to other functions as well.
Here is a code example that get's statistics from a CSV File
function getStatistics() {
return new Promise((resolve, reject)=>{
try {
let readStatistics = [];
const statisticsReadStream = fs.createReadStream(statisticsFileName);
csv.fromStream(statisticsReadStream, {headers: true})
.transform(function (data) {
data.avgDuration = parseFloat(data.avgDuration);
data.avgPassed = parseFloat(data.avgPassed);
data.avgReachedPoints = parseFloat(data.avgReachedPoints);
data.minReachedPoints = parseInt(data.minReachedPoints);
data.maxReachedPoints = parseInt(data.maxReachedPoints);
return data;
})
.on("data", function (data) {
readStatistics.push(data);
})
.on("end", function () {
resolve(readStatistics);
statisticsReadStream.close();
});
}catch(err){
reject();
}
});
}
In mocha, you can return the promise from the test function to indicate that the test (it) has completed.
describe('My Test', function () {
it('should do something cool', function () {
return getStatistics().then(readStatistics => {
// Assert whatever you want here
});
});
});
Any error that gets thrown from your getStatistics function or any assertion error will cause the test to fail.
If you are specifically looking to see if something throws an error, you can catch the error (reject()) in a test too.
describe('My Test', function () {
it('should do something cool', function () {
return getStatistics().catch(error => {
// Assert whatever you want here about the error
});
});
});
https://mochajs.org/#asynchronous-code
Here is the code:
`describe('Statistic', function(){
it('should transform data into strings', function () {
return statGet().then(readStatistics => {
let maybe = statGet();
var csv = maybe.csv;
let dat = function (data) {
data.avgDuration = "1,2";
data.avgPassed = "2,3";
data.avgReachedPoints ="3,4";
data.minReachedPoints = "4";
data.maxReachedPoints = "5";
return data;
}
assert.typeOf(csv.transform(dat, 'string'));
});
});
});`
on the other hand, i have liuttle idea of what i shold be testing in the first place.
I feel hopelessly lost. I want to go back to hello world =(

How to access site JavaScript functions using webdriverIO

I have a problem with accessing code that I am able to use through browser console.
In my case it is a Tawk_Api function Tawk_API.hideWidget();
I tried to use browser execute and call but the output saying that Tawk.Api is not defined
Code example
var expect = require('chai').expect;
function HideTawk (){
Tawk_API.hideWidget();
}
describe('', function() {
it('should be able to filter for commands', function () {
browser.url('https://arutech.ee/en/windows-price-request');
$('#uheosaline').click();
browser.execute(HideTawk());
var results = $$('.commands.property a').filter(function (link) {
return link.isVisible();
});
expect(results.length).to.be.equal(3);
results[1].click();
expect($('#getText').getText()).to.be.equal('GETTEXT');
});
});
Working fixed function:
function HideTawk (){
return new Promise(function(resolve, reject) {
Tawk_API.hideWidget();
})
}
And browser.execute(HideTawk()) is a mistake it should be browser.call(HideTawk());
docs: http://webdriver.io/api/utility/call.html
I have a below code in my application base object it can help you to understand call api:
_callClientAPI(func, args) {
let trial = 1;
return new Promise(async(res, rej) => {
while (true) {
if (trial > this._pollTrials) {
rej(`Could not retrieve the element in this method * this._pollTimeout} seconds.`);
break;
}
let result;
try {
result = await func.call(this.client, args, false);
} catch (e) { }
if (result && result !== '') {
res(result);
break;
}
await this.wait();
trial++;
}
});
}

What's wrong with this async function?

async lsEntered(){
if(this.service.wd == '')
{
await basic((this.service.wd));
}
else
{
await basic(('/'+this.service.wd));
}
this.files = await JSON.parse(localStorage.getItem('FILENAMES'));
var filesList = document.getElementById(this.trackLine.toString());
var li;
for (var i = 0; i < this.files.length; i++) {
li = document.createElement('li');
li.appendChild(document.createTextNode(this.files[i].name));
filesList.appendChild(li);
}
localStorage.clear();
}
I want to wait until basic is finished and JSON.parse finishes before displaying the values in the DOM. I'm getting the values of the previous call every time which is tell me the async is no working. To be fair I don't have tons of TS experience.
Edit: This is basic I was hoping not to have to deal with it as it's a javascript function and fragily integrated into this app.
var basic = function (path) {
var ACCESS_TOKEN = '';
var dbx = new Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesListFolder({ path: path })
.then(function (response) {
localStorage.setItem('FILENAMES',JSON.stringify(response.entries));
console.log(response);
})
.catch(function (error) {
console.error(error);
});
return false;
}
let myPromise = new Promise((resolve, reject) => {
// Work you want to execute
resolve("I am done");
});
myPromise.then((successMessage) => {
// successMessage is whatever we passed in the resolve(...) function above.
console.log("Yay! " + successMessage);
});
You can only await promises1 and basic is not returning a promise. You need to do
return dbx.filesListfolder(...)...
Also consider what Bergi said in their comment.
1: Actually, you can await any value, but there is no point in awaiting something that is not a promise. By not returning the promise from basic, lsEntered won't wait for the local storage to be set.

How to get Protractor deferred Promise to work?

Scenario 1) Stale Element Reference error
it("should have all elements", function (done) {
var def = protractor.promise.defer();
var prm = browser.findElements(by.css("jive")).then((elements) => {
elements.forEach((ele) => {
var id = ele.getId();
var loc = ele.getLocation();
var inner = ele.getInnerHtml();
var text = ele.getText();
var tag = ele.getTagName();
});
def.then((wtf) => {
debugger;
});
});
done();
});
I thought that the code above would have a ton of promises on the queue after running through the iteration on all elements. But when the def.then statement runs Selenium is telling me I have Stale Elements. The iteration is running through the elements for that css.
I was hoping to get an array of resolved promises for everything the iteration requested...
Scenario 2) Gives Stale Element Reference
var promises = Array<webdriver.promise.Promise<any>>();
var allElements: webdriver.IWebElement[] = [];
it("should have all elements", function (done) {
var alllinks: webdriver.WebElement[];
browser.controlFlow().execute(() => {
browser.findElements(by.tagName("a")).then((works) => {
alllinks = works;
alllinks.forEach((ele) => {
promises.push(ele.getAttribute("href"));
promises.push(ele.getId());
promises.push(ele.getInnerHtml());
promises.push(ele.getLocation());
});
//getting stale reference here...
protractor.promise.all(promises).then((wtf) => {
debugger;
});
debugger;
});
});
Please advise.
I think you need the map():
var links = element.all(by.tagName("a")).map(function (link) {
return {
href: link.getAttribute("href"),
id: link.getId(),
innerHTML: link.getInnerHtml(),
location: link.getLocation()
}
});
Now the links would contain a promise resolving into an array of objects.
My tiny example might be helpful for you:
viewBookingDetailsPage.roomtypeAttributeForParticularDay = function (day, roomTypeNumber, selector) {
var deferred = protractor.promise.defer();
element.all(by.repeater(viewBookingDetailsPage.guestroomInfo.allDays)).then(function (days) {
days[day].all(by.repeater(viewBookingDetailsPage.guestroomInfo.roomTypesInDay)).then(function (roomTypes) {
deferred.fulfill(roomTypes[roomTypeNumber].$(selector));
});
});
return deferred.promise;
};
You need to use fulFill to return result after promise will be successfully resolved.

Categories