1

I am facing a issue that sometimes the promise code is executed and some time it just skip it the statements handling promise i.e using then statement, I have tried two approaches still having the issue.

few confusing points:

  • should I do not use await with line of code handling promise like using then
  • should I use async keyword in then function like

Example:

 await item.element(by.css("h4 a")).getText().then(async(text)=> {
            if (text == product) {
                await item.element(by.css("button[class*='btn-info']")).click();
            }

Working result:

enter image description here

In above image the results of variable printed like 80000 etc

My code is as below:

First approach:

I have replace every function keyword and put async with fat function, I also added the await where ever it allows me. also, I have use await and then together

import { Given, When, Then } from "cucumber";
import { browser, element, by } from "protractor";
import { async } from "q";
import chai from "chai"

let assert = chai.assert;
async function selectItems(product) {
    //take 4 cards into list
    //go through each index in the list - and get the title= if title =desired title then in that index i will select add button
    await element.all(by.tagName("app-card")).each(async(item) => {

      await item.element(by.css("h4 a")).getText().then(async(text)=> {
            if (text == product) {
                await item.element(by.css("button[class*='btn-info']")).click();
            }
        })
    })
}
Given(':I will navigate to qaacamedy site', async () => {
   await browser.get("https://qaclickacademy.github.io/protocommerce/");
   await console.log("browser lunched");
  });

  When(': click on the shop and add all products in cart', async () => {
    await element(by.linkText("Shop")).click();
    await selectItems("Samsung Note 8");
    await selectItems("iphone X");

    await element(by.partialLinkText("Checkout")).getText().then(function(text) {
        let res = text.split("(");
        let x = res[1].trim().charAt(0);
        let y = x;
        console.log(y);
        assert.equal(res[1].trim().charAt(0),x);
    })
  });

  When(': I calculate all price', async () => {
    let value;
    let amount=new Array() ;
    let set= new Set();
    await element(by.partialLinkText("Checkout")).click();
    await element.all(by.css("td[class*='text-center']")).each(function(item){
          item.element(by.css("strong")).getText().then(function(text) {
               console.log(text);
               let res =text.split('.');
               value=Number(res[1].trim());
               amount.push(value);
               set.add(value);
               console.log("my value ="+value);
               console.log("my amounts"+amount);
        }) 
    })
        let add=0;
            // for (let i = 0; i < amount.length; i++) {
            //     await console.log("array value = "+amount[i]);
            //     add=add+amount[i];
            //  }
             for (let num of set) {

              await console.log("iterbale value of set = "+num);     //1 2 3 4 5 6
               add=add+num;
            }


             await console.log("total calculate value ="+add);
             await console.log("my amounts final"+amount);
  });

  Then(': some should be shown', async () =>  {
    await console.log("Then Statement");
  });

enter image description here

As shown in above result the statements are not printed now, but sometimes I get results

Second approach:

I have tried to put promise function as async as well:

import { Given, When, Then } from "cucumber";
import { browser, element, by } from "protractor";
import { async } from "q";
import chai from "chai"

let assert = chai.assert;
async function selectItems(product) {
    //take 4 cards into list
    //go through each index in the list - and get the title= if title =desired title then in that index i will select add button
    await element.all(by.tagName("app-card")).each(async(item) => {

      await item.element(by.css("h4 a")).getText().then(async(text)=> {
            if (text == product) {
                await item.element(by.css("button[class*='btn-info']")).click();
            }
        })
    })
}
Given(':I will navigate to qaacamedy site', async () => {
   await browser.get("https://qaclickacademy.github.io/protocommerce/");
   await console.log("browser lunched");
  });

  When(': click on the shop and add all products in cart', async () => {
    await element(by.linkText("Shop")).click();
    await selectItems("Samsung Note 8");
    await selectItems("iphone X");

    await element(by.partialLinkText("Checkout")).getText().then(async(text)=> {
        let res = text.split("(");
        let x = res[1].trim().charAt(0);
        let y = x;
        await console.log(y);
        await assert.equal(res[1].trim().charAt(0),x);
    })
  });

  When(': I calculate all price', async () => {
    let value;
    let amount=new Array() ;
    let set= new Set();
    await element(by.partialLinkText("Checkout")).click();
    await element.all(by.css("td[class*='text-center']")).each(async(item)=>{
          item.element(by.css("strong")).getText().then(async(text)=> {
               await console.log(text);
               let res =text.split('.');
               value=Number(res[1].trim());
               amount.push(value);
               set.add(value);
               await console.log("my value ="+value);
               await console.log("my amounts"+amount);
        }) 
    })
        let add=0;
            // for (let i = 0; i < amount.length; i++) {
            //     await console.log("array value = "+amount[i]);
            //     add=add+amount[i];
            //  }
             for (let num of set) {

              await console.log("iterbale value of set = "+num);     //1 2 3 4 5 6
               add=add+num;
            }


             await console.log("total calculate value ="+add);
             await console.log("my amounts final"+amount);
  });

  Then(': sum should be shown', async () =>  {
    await console.log("Then Statement");
  });

Here in second approach also I am getting the same issue.

Also suggest, Is it a good practice to handle the promise function as well as below:

await element(by.partialLinkText("Checkout")).getText().then(async(text)=> {

In both above approach I have use below flag:

SELENIUM_PROMISE_MANAGER: false,

This problem always occur specially after If I use debug mode using launch.json

My feature file looks like below:

Feature: I am going to validate the qaacamedy site

Scenario: practice assignment

    Given :I will navigate to qaacamedy site
    When : click on the shop and add all products in cart 
    When : I calculate all price 
    Then : sum should be shown

have also tried to delete the async , async kit and protractor package and install it again, once it worked but after sometime again it start showing me issue. not understanding why the same code behavior differently, I don't getting the main cause of issue, stucking from many days on same

Please look into it, that the last heavy issue I am stucking with protractor

Shubham Jain
  • 16,610
  • 15
  • 78
  • 125
  • 1
    Yes, you should not [use `then` chaining in an `await` expression](https://stackoverflow.com/a/54387912/1048572). – Bergi May 07 '19 at 20:58
  • Does `.each()` support asynchronous callbacks? – Bergi May 07 '19 at 20:58
  • @Bergi - thanks for your response, my code is executing successfully with await and .each together, so I assume it support asynchronous callbacks. – Shubham Jain May 07 '19 at 21:00
  • 1
    Yes, it will run them, but will it actually wait for the promises that they return? – Bergi May 07 '19 at 21:02
  • You may want to narrow down your question a bit; as written it is pretty wide ranging and contains enough material for multiple questions. See https://stackoverflow.com/help/how-to-ask – Will May 07 '19 at 21:05
  • @Bergi - I am not sure as I am a new one with protractor and I just put what ever permitted to make my script run. My code is skipped by debug what I observe with having promises, how I can check same? any way around – Shubham Jain May 07 '19 at 21:08
  • @WillCain - Yes, I do understand, I just put all necessary information which may require to understand the issue, i will narrow down it as per the stack guidelines .. thanks – Shubham Jain May 07 '19 at 21:09

1 Answers1

2

Since you are using async/await you should avoid traditional promise handling (e.g. then). It also looks like you are awaiting methods that do not return a promise, which is essentially pointless. Declaring async on callback does not make the calling method asynchronous.

A proper implementation of selectItems would look something like this:

async function selectItems(product) {
    // async functions return a promise, use 'map' so we can wait for the promises to resolve using Promise.all
    const promises = element.all(by.tagName("app-card")).map(async (item) => {
        // use await on getText() since it returns a promise
        const text = await item.element(by.css("h4 a")).getText();
        if (text == product) {
            // return the promise produced by 'click'
            return item.element(by.css("button[class*='btn-info']")).click();
        }
    });
    return Promise.all(promises);
}

The tests should also be updated to avoid mixing async/await syntax with traditional promise handling.

Jake Holzinger
  • 5,783
  • 2
  • 19
  • 33
  • 2
    Click actually [does](https://www.protractortest.org/#/api?view=webdriver.WebElement.prototype.click) return a promise. But in general good advice here. – Will May 07 '19 at 21:03
  • 1
    @WillCain thanks for clarifying, updated answer accordingly. – Jake Holzinger May 07 '19 at 21:05
  • @JakeHolzinger - what actually return Promise.all(promises); does? .... should i avoid using then completely now it seems is a old mechanism?, and if I shoud use then which places – Shubham Jain May 07 '19 at 21:12
  • @ShubhamJain `Promise.all(promises)` is how you wait for all of the "clicking" to finish, without this you will have your problem of the promise being "skipped." You are free to use `then` it's just bad practice to mix it with `async/await` since the new syntax is built to avoid traditional promise handling. – Jake Holzinger May 07 '19 at 21:16
  • async function selectItems(product) { // async functions return a promise, use 'map' so we can wait for the promises to resolve using Promise.all const promises = element.all(by.tagName("app-card")).map(async (item) => { // use await on getText() since it returns a promise const text = await item.element(by.css("h4 a")).getText(); if (text == product) { // return the promise produced by 'click' return item.element(by.css("button[class*='btn-info']")).click(); } return Promise.all(promises); }); } – Shubham Jain May 07 '19 at 21:24
  • .(node:16772) UnhandledPromiseRejectionWarning: TypeError: # is not iterable UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 6) – Shubham Jain May 07 '19 at 21:25
  • getting error like it after adding the promise.all , may be because I have put it inside but , if I copy code as you have shared, i got error: Argument of type 'Promise<{}[]>' is not assignable to parameter of type 'Iterable<{} | PromiseLike<{}>>'. Property '[Symbol.iterator]' is missing in type 'Promise<{}[]>' but required in type 'Iterable<{} | PromiseLike<{}>>'.ts(2345) – Shubham Jain May 07 '19 at 21:27
  • I have regret for my so many questions, just If I understand same then my it resolve my issue, as you new syntax to avoid traditional promise, did you mean that now I can use sttaement as below: var text=await element(by.partialLinkText("Checkout")).getText(); – Shubham Jain May 07 '19 at 21:32
  • Why does `});` follow `return Promise.all(promises)`? Seems to me you're not copying the code as is. I don't know why you're getting rejections, you should use `try/catch` to handle errors. The typescript issues are a completely separate issue, not related to your original issue. You can try `async function selectItems(product): Promise`, but that is outside of the scope of this answer. – Jake Holzinger May 07 '19 at 21:34
  • I am getting error async function selectItems(product): Promise. thanks for your help. i will try more my own, your answer and other comment helps me that I am missing many thing regarding promises, if you have any link where from learn all that promise thing then please share. it will help.. thanks – Shubham Jain May 07 '19 at 21:45