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

returning a promise in a custom command should throw #435

Closed
brian-mann opened this issue Feb 20, 2017 · 14 comments
Closed

returning a promise in a custom command should throw #435

brian-mann opened this issue Feb 20, 2017 · 14 comments
Assignees
Labels
browser: electron pkg/driver This is due to an issue in the packages/driver directory type: unexpected behavior User expected result, but got another
Milestone

Comments

@brian-mann
Copy link
Member

You cannot return a 3rd party promise from a custom command because this breaks the chaining between cypress commands. This is because the .then methods are not the same.

It is an anti-pattern anyway because all cypress commands are promises.

For instance doing this:

Cypress.addParentCommand('login', function (email, password) {
  return new Cypress.Promise((resolve) => {
    cy.request({
      method: 'POST',
      url: '/login',
      body: {email, password}
    })
    .then(result => {
      resolve(result.body);
    })
  })
})

...can simply be rewritten as:

Cypress.addParentCommand('login', function (email, password) {
  cy.request({
    method: 'POST',
    url: '/login',
    body: {email, password}
  })
  .its("body")
})
@jennifer-shehane jennifer-shehane added pkg/driver This is due to an issue in the packages/driver directory type: unexpected behavior User expected result, but got another labels Feb 23, 2017
@Andrew1431
Copy link

Dual Command

export const createProductWithStock = (context, products) => {
  validate(products);

  return cy.goToInventory({ tab: 'purchases' })
    .get('button.absolute-header-position').click() // Create PO
    .get('div.purchase-order-modal input[name=vendorId]').type('west') // Type vendor name
    .get('a.result.active div.title').click() // Pick vendor from dropdown.
    .then(createProductLineItems(products)) // Add and receive line items.
    .get('div.payment-block a.close-modal').click()
    .then(walkthroughProductCreateModals(products))
    .then(getStockInformation(products));
};

Actual Test

... describe, beforeEach, etc
    it.only('should be able to place an order with all unit types', function() {

      cy.createProductWithStock([{
        type: 'unit',
        name: 'Chicken Butts',
        quantity: 500
      }]).then(result => {
        console.log('Result: ', result);
        expect(result.length).to.equal(1);
      });

    });

All of these actions are promise resolvers etc.

All of this code works up until the assertion. Result is undefined.

const getStockInformation = (products) => {
  return () => {
    // This will jump around the DOM looking for the values it needs for stocks.
    // How can I resolve a certain value? (Will just be a simple array of objects).
    // I'm not even getting the `true` value here.
    return Cypress.Promise.resolve(true);
  };
};

I'm not even getting the 'true' value. How can I achieve this? It's completely necessary. All the stock information is found via the UI so it should be possible, but it appears as though its not.

@Andrew1431
Copy link

I'm very confused as to how all your chaining / sequences work! Would love to know more.

@brian-mann
Copy link
Member Author

We are currently refactoring the custom command interface to make all of this easier. There is a non-documented cy.chain command which will make subjects available outside of the custom command.

Here is a comment where I show this happening. You likely need to add cy.chain to every custom command you write.

#198 (comment)

You'll see in the next couple updates a complete overhaul of the custom command interface + proper docs and examples. You won't have to do the cy.chain either.

@brian-mann
Copy link
Member Author

Also as an aside - you likely don't want to use your UI to build up state. It's totally fine to do these kinds of actions in a single spec file, but we disagree this being the best approach across multiple files. You're essentially trying to replicate the Page Object Pattern which works well for Selenium but is unnecessary (and slow) to do in Cypress.

It's much better to basically issue directly cy.request to your backend to generate the state, and then cy.visit once everything is in place. In other words, when you're testing the feature use the UI, but if its part of normal setup/seeding for use in other features you don't use the UI.

When you approach it like this there's much less need to try to "compose" various commands together and instead you can achieve the same result in 1 or 2 cy.request.

We'll have more opinions and examples of this coming pretty soon. Our docs are being updated pretty regularly now.

@Andrew1431
Copy link

Andrew1431 commented Mar 6, 2017

Those things would be lovely to do if this wasn't Meteor we were developing in ._.

Thank you for the timely response!

WHOAH! Just punched this into my code, and since all the sub-code is promise based, seemed to have worked right out of the box.

export const createProductWithStock = (context, products) => {
  validate(products);

  cy.chain()
    .goToInventory({ tab: 'purchases' })
    .get('button.absolute-header-position').click() // Create PO
    .get('div.purchase-order-modal input[name=vendorId]').type('west') // Type vendor name
    .get('a.result.active div.title').click() // Pick vendor from dropdown.
    .then(createProductLineItems(products)) // Add and receive line items.
    .get('div.payment-block a.close-modal').click()
    .then(walkthroughProductCreateModals(products))
    .then(getStockInformation(products));
};

@Andrew1431
Copy link

Thank you very much! 👍 The whole team is absolutely loving working with Cypress, so thank you for all your guys hard work!

@brian-mann
Copy link
Member Author

brian-mann commented Aug 24, 2017

Going with this as the error message...

screen shot 2017-08-24 at 5 13 57 pm

@brian-mann brian-mann self-assigned this Aug 24, 2017
@brian-mann
Copy link
Member Author

The code for this is done, but this has yet to be released. We'll update the issue and reference the changelog when it's released.

@brian-mann
Copy link
Member Author

Fixed in 0.20.0

@mattblackdev
Copy link

@Andrew1431 I read up above your team is using cypress with a Meteor app. How are you accessing Meteor inside your tests?

import { Meteor } from 'meteor/meteor' fails in the cypress environment because it's not actually a node module.

I've tried importing from all kinds of crazy paths in the .meteor/local directory. When I run meteor normally, in the browser console I can require('meteor/meteor') all day long. But in Cypress's browser require is undefined.

Thanks,
Matt

@Andrew1431
Copy link

Andrew1431 commented Jan 3, 2018 via email

@brian-mann
Copy link
Member Author

brian-mann commented Jan 3, 2018

Browsers have no notion of require. Browsers must have a build process to parse the dependency tree and generate JS files. Cypress does this with browserify or you can swap this out with webpack.

You cannot import Meteor that way because it would create a whole new instance which has nothing to do with the Meteor instance your app is using.

In order to access the Meteor in your application is the same way you'd access it from the dev tools - you just set it on window and then access it with cy.window().then((win) => win.Meteor )

@panneerselvamc
Copy link

panneerselvamc commented Feb 6, 2019

This Function returns nothing when i call this function kindly help me to overcome this

const search=()=>{
  cy.get('body').then(async ($body)=>{
    let flag =$body.text().includes("LOGIN")
    
    if (flag) {
      cy.log("in if")
      return(false)
    } else {
      cy.wait(4000)
      cy.log("else")
      return(true)
    }
  })
}

@jennifer-shehane
Copy link
Member

@panneerselvamc Can you include the test code you've written where you call the function?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
browser: electron pkg/driver This is due to an issue in the packages/driver directory type: unexpected behavior User expected result, but got another
Projects
None yet
Development

No branches or pull requests

5 participants