Synchronous mode of Webdriver.io have problems with Promise - node.js

I write tests on CoffeeScript using Webdriver.io framework (Wdio testrunner) with sync mode enabled. According to the documentation, Webdriver.io commands should be executed in synchronous mode. However, an unexpected problem appears in the process of using the Promise.
We are considering the simplest test that finds an element on a page by selector and displays the text of the found element to the console.
Example 1 – code without promise
browser.url('... URL ...')
a = browser.$('... selector ...').getText()
console.log(a)
In this example commands of the Webdriver.io work correctly.
Example 2 - the code is in the constructor of the Promise
p = new Promise((resolve, reject) ->
browser.url('... URL ...')
a = browser.$('... selector ...').getText()
console.log(a)
resolve()
)
return p
If the commands are contained in the constructor of the Promise, then they are correctly executed too.
Example 3 - the code is in the block .then after returning the Promise
p = new Promise((resolve, reject) ->
resolve()
).then(() ->
browser.url('... URL ...')
a = $('... selector ...').getText()
console.log(a)
)
return p
The next error message shows in display: "$ (...). GetText is not a function" (Example 3). Apparently, the commands of the Webdriver.io begin to work asynchronously. Though I can use await keyword to process those Promises but I want to execute the code equally in the same way (synchronously) regardless of the location of the code (in the Promise or outside it).
Also switching to asynchronous mode occurs when command Await is used.
Example 4 (Example 1 code using the await keyword)
await console.log('123')
browser.url('... URL ...')
a = browser.$('... selector ...').getText()
console.log(a)
In this case for the correctly work of program it will be necessary to redo all the code, taking into account asynchronous processing.
As a solution, I can write all the tests asynchronously, but the code will become more complicated. Can I work with commands of the Webdriver.io synchronously even when using the Promise?

If you want to use Promise in your wdio test script which in sync mode, then you need to use browser.call() of wdio. More details on call: v5 and v4 .
Here you can find the sample code and more details on how a call is used: How to use 3rd party method that takes callback in webdriverio
Thanks,
Naveen

Related

Calling a function that returns a AsyncIterableIterator without using "for await" block

I'm writing an AWS Lambda function in TypeScript using the Node.js runtime. I'm using a "batchDelete" function from a DynamoDB ORM library which returns an AsyncIterableIterator type.
According to the documentation here https://github.com/awslabs/dynamodb-data-mapper-js#batchDelete, I should invoke the method with a for await loop like this:
for await (const found of mapper.batchDelete(toRemove)) {
// items will be yielded as they are successfully removed
}
This all works great but the problem comes in where if I enable ESLint on my project. The default rules throw an error because the for await block is empty. I also get a warning because the found constant is never used. I have no use for the found constant and don't want to log it. I was wondering if there was another way to call an AsyncIterableIterator function where we disregard what is returned and don't have the empty block?
If you don't care about the results of the iteration, then you should probably just do something like this:
await Promise.all(toRemove.map(item => mapper.delete(item));
To use the mapper.batchDelete(toRemove) result more directly, you have to allow for multiple levels of promises. Perhaps you could do this:
await Promise.all(await mapper.batchDelete(toRemove)[Symbol.asyncIterator]());
In doing this, await mapper.batchDelete(toRemove)[Symbol.asyncIterator](), that would get you the default async Iterator and then passing it to Promise.all() would iterate it to get an iterable of promises. Unfortunately, in building it to make this easier:
for await (const found of mapper.batchDelete(toRemove))
they made it a bit more difficult to just get an array of promises out of it.
FYI, here's a link to the code for the .batchDelete() method if you want to look at how it's implemented.

Adding a value from Mongoose DB into a variable in Node.js

I am still quite new to Node.js and can't seem to find anything to help me around this.
I am having an issue of getting the query from my last record and adding it to my variable.
If I do it like below: -
let lastRecord = Application.find().sort({$natural:-1}).limit(1).then((result) => { result });
Then I get the value of the variable showing in console.log as : -
Promise { <pending> }
What would I need to do to output this correctly to my full data?
Here is it fixed:
Application.findOne().sort({$natural:-1}).exec().then((lastRecord) => {
console.log(lastRecord); // "lastRecord" is the result. You must use it here.
}, (err) => {
console.log(err); // This only runs if there was an error. "err" contains the data about the error.
});
Several things:
You are only getting one record, not many records, so you just use findOne instead of find. As a result you also don't need limit(1) anymore.
You need to call .exec() to actually run the query.
The result is returned to you inside the callback function, it must be used here.
exec() returns a Promise. A promise in JavaScript is basically just a container that holds a task that will be completed at some point in the future. It has the method then, which allows you to bind functions for it to call when it is complete.
Any time you go out to another server to get some data using JavaScript, the code does not stop and wait for the data. It actually continues executing onward without waiting. This is called "asynchronisity". Then it comes back to run the functions given by then when the data comes back.
Asynchronous is simply a word used to describe a function that will BEGIN executing when you call it, but the code will continue running onward without waiting for it to complete. This is why we need to provide some kind of function for it to come back and execute later when the data is back. This is called a "callback function".
This is a lot to explain from here, but please go do some research on JavaScript Promises and asynchronisity and this will make a lot more sense.
Edit:
If this is inside a function you can do this:
async function someFunc() {
let lastRecord = await Application.findOne().sort({$natural:-1}).exec();
}
Note the word async before the function. This must me there in order for await to work. However this method is a bit tricky to understand if you don't understand promises already. I'd recommend you start with my first suggestion and work your way up to the async/await syntax once you fully understand promises.
Instead of using .then(), you'll want to await the record. For example:
let lastRecord = await Application.find().sort({$natural:-1}).limit(1);
You can learn more about awaiting promises in the MDN entry for await, but the basics are that to use a response from a promise, you either use await or you put your logic into the .then statement.

how to run foreach in synchronous way in nodejs

I am running email alert sending job in nodejs, due to asyncronous, hits are too many. Even elastic search throwing timeout exception.
Along with node i am using Q promise.
Please tell me how to fix this issue.
If you can use new Node, google how to use async/await, then you can for-cycle all requests and await them.
If you cant, you can do it recursively:
function processAllOneByOne(fns, i){
if (i >= fns.length) { return Promise.resolve({done:true}) }
fns[i]().then(() => processAll(fns, i+1));
}
And call it with
processAllOneByOne(fns, 0)
Please note that once you create promise you CANT handle how it is executed "inside". So you need to have fns which is array of function, calling that function creates and return Promise you want to wait to finish.
So push there something like fns.push(() => sendAlert(some, paramaters)), where sendAlert is creating the Promise you need.

using promises in node.js to create and compare two arrays

I needed to compare two arrays the first one a couple of filenames from a database, the second one a list of files I already downloaded to my client. The Idea was to load whatever files are missing on the client.
As the reading via fswas two slow, I tried using Promises to wait for one function to finish before the next starts. But somehow I got lost...
My code so far:
let filesIneed = [];
let filesIhave = [];
let filesToFetch = [];
getLocalFiles().then(getFilesIneed).then(getfilesToRetreive);
function getLocalFiles() {
fs.readdir(localPath, (err, files) => {
files.forEach(file => {
filesIhave.push(file)
});
})
return Promise.all(filesIhave);
}
function getFilesIneed () {
for (let x of docs) {//this is my JSON
filesIneed.push(y.NameOfFileIShouldHave);
}
}
return Promise.all(filesIneed);
}
function getfilesToRetreive() {
filesToFetch = _.difference(filesIneed, filesIhave);
return Promise.all(filesToFetch);
}
console.log(filesToFetch);
I do get the first and second array ("filesIneed" and "filesIhave"), but difference is always empty. So maybe I just mangled up the Promises, as this concept is completely new to me and I'm aware I only understood half of it.
This is completely wrong. You cannot run Promise.all on an array of filenames. You can only run it on an array of promises.
There is also no need to push every element of an array one at a time to an empty array just to return that array when you already have that array in the first place.
You cannot use promises to compare two arrays. You can use lodash to compare two arrays in a then handler of a promise, that resolves to an array.
If you want to get a promise of file names from the fs.readdir then use one of the following modules:
https://www.npmjs.com/package/mz
http://bluebirdjs.com/docs/api/promise.promisifyall.html
https://www.npmjs.com/package/fs-promise
https://www.npmjs.com/package/fs-promised
Also don't use global variables for everything because you will have problems with any concurrency.
Also, read about promises. Without understanding how promises work you will not be able to guess a correct way of using them. Even looking at some working code examples can help a lot and there are a lot of questions and answers on stack Overflow about promises:
promise call separate from promise-resolution
Q Promise delay
Return Promise result instead of Promise
Exporting module from promise result
What is wrong with promise resolving?
Return value in function from a promise block
How can i return status inside the promise?
Should I refrain from handling Promise rejection asynchronously?
Is the deferred/promise concept in JavaScript a new one or is it a traditional part of functional programming?
How can I chain these functions together with promises?
Promise.all in JavaScript: How to get resolve value for all promises?
Why Promise.all is undefined
function will return null from javascript post/get
Use cancel() inside a then-chain created by promisifyAll
Why is it possible to pass in a non-function parameter to Promise.then() without causing an error?
Implement promises pattern
Promises and performance
Trouble scraping two URLs with promises
http.request not returning data even after specifying return on the 'end' event
async.each not iterating when using promises
jQuery jqXHR - cancel chained calls, trigger error chain
Correct way of handling promisses and server response
Return a value from a function call before completing all operations within the function itself?
Resolving a setTimeout inside API endpoint
Async wait for a function
JavaScript function that returns AJAX call data
try/catch blocks with async/await
jQuery Deferred not calling the resolve/done callbacks in order
Returning data from ajax results in strange object
javascript - Why is there a spec for sync and async modules?
Return data after ajax call success

Node's del command - callback not firing

I'm working through a pluralsight course on gulp. John Papa is demonstrating how to inject a function that deletes existing css files, into the routine that compiles the new ones.
The callback on the del function is not firing. The del function is running, file are deleted, I see no error messages. If I call the callback manually it executes, so looks like the function is in tact. So I am wondering what would cause del not to want to execute the callback.
delete routine:
function clean(path, done) {
log('cleaning ' + path);
del(path, done); // problem call
}
The 'done' function is not firing, but it does if I change the code to this:
function clean(path, done) {
log('cleaning ' + path);
del(path);
done();
}
Which, of course, defeats the intended purpose of waiting until del is done before continuing on.
Any ideas at to what's going on would be appreciated.
for reference (in case relevant):
compile css function:
gulp.task('styles', ['clean-styles'], function(){
log('compiling less');
return gulp
.src(config.less)
.pipe($.less())
.pipe($.autoprefixer({browsers:['last 2 versions', '> 5%']}))
.pipe(gulp.dest(config.temp));
});
injected clean function:
gulp.task('clean-styles', function(done){
var files = config.temp + '/**/*.css';
clean(files, done);
});
UPDATE
If anyone else runs into this, re-watched the training video and it was using v1.1 of del. I checked and I was using 2.x. After installing v 1.1 all works.
del isn't a Node's command, it's probably this npm package. If that's the case it doesn't receive a callback as second parameter, instead it returns a promise and you should call .then(done) to get it called after the del finishes.
Update
A better solution is to embrace the Gulp's promise nature:
Change your clean function to:
function clean(path) {
return del(path); // returns a promise
}
And your clean-styles task to:
gulp.task('clean-styles', function(){
var files = config.temp + '/**/*.css';
return clean(files);
});
As of version 2.0, del's API changed to use promises.
Thus to specify callback you should use .then():
del('unicorn.png').then(callback);
In case you need to call it from a gulp task - just return a promise from the task:
gulp.task('clean', function () {
return del('unicorn.png');
});
Checking the docs for the del package it looks like you're getting mixed up between node's standard callback mechanism and del's, which is using a promise.
You'll want to use the promise API, with .then(done) in order to execute the callback parameter.
Node and javascript in general is currently in a bit of a state of flux for design patterns to handle async code, with most of the browser community and standards folks leaning towards promises, whereas the Node community tends towards the callback style and a library such as async.
With ES6 standardizing promises, I suspect we're going to see more of these kinds of incompatibilities in node as the folks who are passionate about that API start incorporating into node code more and more.

Resources