0

I just tried to use await with promisify library. I put my code below.

import promisify from 'cypress-promise';

describe('My First Test', () => {
  it('Does not do much!', async() => {
    const url = "https://rahulshettyacademy.com/seleniumPractise/#/";
    cy.visit(url);
    cy.get(".search-keyword").type("ca");
    cy.wait(2000);
    cy.get(".products").find(".product").should("have.length", 4);
    cy.get(".products").find(".product").each(async($el, index, list) => {
      const element = cy.wrap($el);
      const txtElement = await promisify(element.find(".product-name"));
    });
  })
})

On this line const txtElement = await promisify(element.find(".product-name")); my code gives below error.

`CypressError: cy.each() timed out after waiting 4000ms.

Your callback function returned a promise that never resolved.

The callback function was:

() => {
          const ret = fn.call(ctx, el, index, subject); // if the return value is false then return early

          if (ret === false) {
            endEarly = true;
          }

          return ret;
        }

    at <unknown> (https://rahulshettyacademy.com/__cypress/runner/cypress_runner.js:139277:83)
From previous event:
    at thenFn (https://rahulshettyacademy.com/__cypress/runner/cypress_runner.js:139276:13)
    at yieldItem (https://rahulshettyacademy.com/__cypress/runner/cypress_runner.js:139662:16)
From previous event:
    at Context.each (https://rahulshettyacademy.com/__cypress/runner/cypress_runner.js:139667:62)
    at wrapped (https://rahulshettyacademy.com/__cypress/runner/cypress_runner.js:157859:19)
From Your Spec Code:
    at eval (webpack:///./cypress/integration/examples/Test1.spec.ts:14:41)
    at step (https://rahulshettyacademy.com/__cypress/tests?p=cypress\integration\examples\Test1.spec.ts:129:23)
    at Object.eval [as next] (https://rahulshettyacademy.com/__cypress/tests?p=cypress\integration\examples\Test1.spec.ts:110:53)
    at eval (https://rahulshettyacademy.com/__cypress/tests?p=cypress\integration\examples\Test1.spec.ts:104:71)
at new Promise (<anonymous>)
    at ./cypress/integration/examples/Test1.spec.ts.__awaiter (https://rahulshettyacademy.com/__cypress/tests?p=cypress\integration\examples\Test1.spec.ts:100:12)
    at Context.eval (webpack:///./cypress/integration/examples/Test1.spec.ts:4:26)`

Cypress Version 11.2.0

cypress-promise version ^1.1.0

Node version 18.12.1

Operating System Windows 10 Pro - 21H2 - OS Build 19044.2311

Paolo
  • 3,530
  • 7
  • 21
AMendis
  • 1,346
  • 4
  • 18
  • 34
  • 1
    Is there a particular reason you need to use the promisify library? From what I can gather, what you're trying to achieve can be done without it. – DJSDev Dec 06 '22 at 05:43
  • I agree with DJSDev - why not just use `cy.wrap($el).find('.product-name');`? – agoff Dec 06 '22 at 15:28
  • @DJSDev we can store the element as a variable using await – AMendis Dec 07 '22 at 07:32

2 Answers2

3

cypress-promise was last updated nearly 3 years ago, and there's been some major changes to core Cypress since. Even when it was current, there were caveats from the author about it's use.

There is a simpler way to do what you want, since jQuery .find() will work in the same way as promisify in your code

cy.get(".products").find(".product").each(($el, index) => {
  
  // jQuery version of find(), which will not throw an error
  const $productName = $el.find(".product-name")

  // to see if the find() succeeded, check the length of the jQuery result object
  if ($productName.length) {
    const txtElement = $productName[0]   // presume you want the raw element?
    ...                                  // test it here
  } else {
    cy.log('No product name for product' + index)
  }
});

It seems unlikely that a product would not have a product name, so I disagree with the theory that the .find() is failing.

Note, you should be careful about what you do at the line // test it here. It is possible for the .each() command to loop too quickly, and also for for the .products list to become "detached" and cause an error.

To work around any problems in the loop, take a look at the article A Better cy.each Iteration


Also, adding .product-name to the .product selector should yield the same result.

cy.get(".products").find(".product .product-name")
  .each($txtElement => {
    ...
Paolo
  • 3,530
  • 7
  • 21
0

The true error is obfuscated because Cypress is displaying the error about the promise and not the reason the promise didn't resolve.

The promise isn't resolving because it's likely not finding the element. Whatever reason it's not finding element is for you to figure out, but this error message isn't showing you the underlying reason why the promise isn't resolving.

To verify, if you switch to using a .then() callback instead, you should see the actual error underneath the promise issue.

cy.get(".products").find(".product").each(($el, index, list) => {
  const element = cy.wrap($el);
  // const txtElement = await promisify(element.find(".product-name"));
  element.find(".product-name").then(textElement => {
    // Do something with textElement
  });
});

FWIW, my experience with using async/await with Cypress has been mixed at best. Syntactically it looks nice, but mixing async promises with Cypress slightly different async nature causes more problems than it fixes.

DJSDev
  • 812
  • 9
  • 18