6

I'm new to cypress and I just hit this problem I seem unable to solve.

What I'm trying to do is this: on an eshop page, there's this "Show More Products" button (sorry for the language :)):

enter image description here

If I click it, I'll see more products on the page. I need to be able to click this button for as long as I can see it on the page. The reason is there might be many products and clicking the button just once will not get me to the end of the list, so I still might not be able to see all the products.

The way I see it, this is a simple while loop with a condition.

And now comes cypress and its asynchronous nature and the page on Conditional Testing I've skimmed through the page, looked for information here and on stackoverflow, tried out some code, but the result is still the same, I have not solved this simple problem. How would you go about this?

Well, now after I've written all this, there might be one option... I have information about how many pages there're (on the right side in the pic). But it just feels like a horrible solution anyway.

8
  • Did you look more closely at the Element-existence and Dynamic-text sections on that page? They might point you in the right direction.
    – c32hedge
    Commented Nov 4, 2019 at 19:36
  • I'm playing around with it right now, I just tried the code from the first link you've mentioned. But again, this return statement is unable to return anything beyond the context of the cy.get()... so I'm again at square one. It seems too overwhelming to do all this just to do such a simple thing that just about every tester has to do like 30 times a day. And they build this crazy stuff you can't even query for one simple piece of information.
    – pavelsaman
    Commented Nov 4, 2019 at 19:53
  • The key there is that if you return something from cy.get, and then chain .then after the .get, you can use that return value in the body of the .then.
    – c32hedge
    Commented Nov 4, 2019 at 19:56
  • And how do you do it if you want to use page object pattern? So you have this code in a class, in a function in that class. And you want to call it from your test that's in a different file and just includes the first file with your page object. If I'm not mistaken, I need a return value from the function.
    – pavelsaman
    Commented Nov 4, 2019 at 19:58
  • It depends on how you're structuring your page objects. You could potentially have a high-level tryShowMoreProducts function that would check for the button and click it if it's present, thereby visiting the next page. In that case you're not explicitly returning anything. I've gotten some code to work in our tests that involve returning a Promise, then using cy.wrap and other similar features to get the code that uses the return value to run at the right time, but I'm far from an expert. It's still a "throw code at the wall until something sticks" exercise, for the most part.
    – c32hedge
    Commented Nov 4, 2019 at 20:04

3 Answers 3

4

Ok so there is a way, but I am not sure if this is "the" way when it comes to Cypress. You can write a recursive function that will call itself when the button is present. I have used a site which has a similar button and got it to work, the code would look something like this:

function loadMoreProducts() {
    cy.get('body').then((body) => {
        if (body.find('.more_products').length > 0) {
            body.find('.more_products').click()
            cy.wait('@getProducts')
            loadMoreProducts()
        }
    })
}

it('will load all products', () => {
    cy.server()
    cy.route('products*').as('getProducts')
    loadMoreProducts()
})

This code is waiting for a route matching a specified url, then calls the loadMoreProducts() function recursively as long as element with '.more_products' class can be found within body of the document. In your case you would have to create a specific route to wait for (which is basically a get request url, captured from 'f12' network tab when you press the 'dalsi produkty' button).

1
  • 1
    Wonderful, this is a working solution, just tested it with my example. My route looks like this: cy.route('POST', '/Common/GetMoreProducts**').as('getProducts') and the function is basically the same, just using a variable instead od '.more_products'. Thank you. I guess I need to learn more about these routes, that was the missing part.
    – pavelsaman
    Commented Nov 5, 2019 at 14:09
0

I'm not familiar with the cypress but the logic I would implement would be as following that you can use as pseudo code.

    while(button.exists) {
     click(button)
     executeJavaScript("return document.readyState").toString().equals("complete")
}
  • So first need to check if element exists in the while statement.
  • Then you click to it.
  • Then you need to execute jScript that waits until document state is complete.

I found link below for executing java script in the cypress.

https://github.com/cypress-io/cypress/issues/897

Edit: code above taken from groovy.

3
  • That's exactly the problem, I don't see this option "return True when the button exists" in cypress. It works with chainables, and they don't return value in this way.
    – pavelsaman
    Commented Nov 4, 2019 at 19:10
  • I've run into this kind of issue frequently in Cypress and it usually comes down to how Cypress commands are enqueued. It's very easy to write code that ends up running way too early, so while the pseudocode logic above makes sense, I suspect the OP's problem is more about getting the conditional logic to execute at the right time (after the DOM is loaded).
    – c32hedge
    Commented Nov 4, 2019 at 19:41
  • @c32hedge: would you have a working solution? Because I'm going crazy with this thing here :D I've tried just about every possible horrible workaround I could think of and nothing came out of it.
    – pavelsaman
    Commented Nov 4, 2019 at 19:56
0

You can implement a logic by using if statement. It is better to reach body tag than write your if expression because it is always be present. In the if statement by using find method, you can add the locator. If it is exists it is going to execute the code under if not will execute the code under else.

cy.get('body').then($body => {
            if($body.find('add the specific locator').length){
                cy.log('x')
            }else{
                cy.log('y')
            }
        })

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.