Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request cy.all to work with multiple commands in parallel #8719

Open
valoricDe opened this issue Oct 1, 2020 · 8 comments
Open

Feature Request cy.all to work with multiple commands in parallel #8719

valoricDe opened this issue Oct 1, 2020 · 8 comments
Labels
pkg/driver This is due to an issue in the packages/driver directory stage: proposal 💡 No work has been done of this issue type: enhancement Requested enhancement of existing feature

Comments

@valoricDe
Copy link

valoricDe commented Oct 1, 2020

Summary

Sometimes you want to work with multiple cypress commands but want to wait for all comands to finish before proceeding with another task

Current behavior

currently you have to chain these commands and pass the fetched data from promiselike to promiselike.

cy.fixture('filea.json').then((fileAContents) => {
  cy.fixture('fileb.json').then((fileBContents => {
    ....
    cy.request... with fileAContents, fileBContents, fileCContents ...
  }
}

Desired behavior

like Bluebirds props method or my favorite

import { zipObject } from 'lodash'

export async function makePromiseFromObject(obj: { [key: string]: Promise<any> }) {
  return zipObject(Object.keys(obj), await Promise.all(Object.values(obj)))
}

we could aggregate all comand responses into one object with cy.all

cy.all({
  fileAContents: cy.fixture('filea.json'),
  fileBContents: cy.fixture('fileb.json'),
  ...
).then(props => cy.request( with ...props))

Relates to: #915

@valoricDe
Copy link
Author

Hi Jessica sry it could be that I've choosen the wrong issue template. Could you reassign and delete labels as you see fit?

@JessicaSachs JessicaSachs removed their assignment Oct 9, 2020
@JessicaSachs JessicaSachs added stage: needs investigating Someone from Cypress needs to look at this type: enhancement Requested enhancement of existing feature and removed experiment: component testing labels Oct 9, 2020
@jennifer-shehane jennifer-shehane added stage: proposal 💡 No work has been done of this issue pkg/driver This is due to an issue in the packages/driver directory and removed stage: needs investigating Someone from Cypress needs to look at this labels Oct 15, 2020
@jayarjo
Copy link

jayarjo commented Nov 13, 2020

Absolutely required I'd say.

I stumbled on this repo. However it doesn't work when I try it with fixtures.

@MCFreddie777
Copy link

Whats the status on this task? This would be great! Can't wait to see this in changelog!

@Xapuu
Copy link

Xapuu commented Feb 19, 2021

Any updates here.

@manuscriptmastr
Copy link

manuscriptmastr commented Dec 30, 2021

Just wanted to leave this solution here for anyone interested (mixture of a few ideas). I have a use case where I needed to assert that subtotal + tip + tax = order total. The two challenges for testing here are:

  1. I can't reasonably assert on exact values because the price of items are generally data driven.
  2. I also can't dynamically look up these 4 items via something like cy.get(... all table rows) because other items like discounts/rewards/fees also match.

To assert that these values add up, I need all 4 Cypress results present. This normally forces me to nest 4 levels of cy.get(...).then(...) to have access to all 4 values, but it's fairly easy to create a custom Cypress command like this:

// cypress/support/commands.js

/**
 * @param cypressCommandFns An array of functions that return Cypress commands
 * @returns A Cypress chainable whose `.then()` passes an array of jQuery-wrapped DOM nodes
 */
Cypress.Commands.add('all', (cypressCommandsFns) =>
  cypressCommandsFns.reduce(
    (results, command) =>
      results.then((bucket) => command().then((res) => [...bucket, res])),
    cy.wrap([])
  )
)

// my-test.spec.js
cy.all([
  // Testing Library syntax
  () => cy.findByRole('row', { name: /sub-total/i }),
  () => cy.findByRole('row', { name: /estimated tax/i }),
  () => cy.findByRole('row', { name: /tip/i }),
  () => cy.findByRole('row', { name: /order total/i }),
]).then(([$subtotal, $tax, $tip, $total]) => {
  ... make sure values add up
})

Something to note: this strategy requires passing in functions that return Cypress commands.

Hopefully this helps anyone struggling with this kind of testing challenge!

@bahmutov
Copy link
Contributor

@manuscriptmastr you probably can write the above test using the following solution https://cypresstips.substack.com/p/use-aliases-to-avoid-pyramid-of-callbacks

@manuscriptmastr
Copy link

manuscriptmastr commented Jan 21, 2022

@bahmutov Thanks for posting! Definitely see this working (and I love that it's the same use case 😃 ). TBH I don't love this.[property] even though I think that would be "standard" Cypress, but I'm glad there's an alternative solution to the problem!

@xeger
Copy link

xeger commented Dec 6, 2022

Just to confirm, @bahmutov had the ideal answer. As long as we can predict the aliases we will bind, there is no need to wait for all promises; just let Cypress fulfill them serially, and then "remember" all predicted aliases inside a then(function() {}).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg/driver This is due to an issue in the packages/driver directory stage: proposal 💡 No work has been done of this issue type: enhancement Requested enhancement of existing feature
Projects
None yet
Development

No branches or pull requests

9 participants