Cypress Test Automation Issue: Trouble with Button Visibility States in Bubble.io App

I’m wondering if anyone has come across this issue.

We are using Cypress/JavaScript for our test automation of our Bubble app. We are facing difficulty with some button/states. For context, we have a dashboard with 9 Lesson cards in a 3x3 format. On the cards, there is a Start OR a Continue button (User has never clicked/started a lesson before, the button is Start) and if the user has started the lesson but NOT completed the lesson, the button will be the Continue button.

Each lesson is of its own category and the IDs are specific to the state of the button and the category, for example:

If a user has never started ANY lessons and they are ALL new, the lesson button IDs on the DOM will be as follows:

  • card 1: start-lesson-spirituality (exists & visible)
  • card 2: start-lesson-recovery (exists & visible)
  • card 3: start-lesson-relationships (exists & visible)
  • card 4: start-lesson-life-skills (exists & visible)
  • card 5: start-lesson-nutrition (exists & visible)
  • card 6: start-lesson-health (exists & visible)
  • card 7: start-lesson-sleep (exists & visible)
  • card 8: start-lesson-exercise (exists & visible)
  • card 9: start-lesson-emotions (exists & visible)

Where the issue arises, and I’m not sure if this is a Bubble issue or how we built it:

If the user clicks the Start lesson button and goes through the process but does not COMPLETE a specific lesson, the state of the buttons on the DOM will be:

  • card 1: start-lesson-spirituality (exists & NOT visible)
  • card 1: continue-lesson-spirituality (exists & visible)
  • card 2: start-lesson-recovery (exists & visible)
  • card 3: start-lesson-relationships (exists & visible)
  • card 4: start-lesson-life-skills (exists & visible)
  • card 5: start-lesson-nutrition (exists & visible)
  • card 6: start-lesson-health (exists & visible)
  • card 7: start-lesson-sleep (exists & visible)
  • card 8: start-lesson-exercise (exists & visible)
  • card 9: start-lesson-emotions (exists & visible)

So when writing the tests, I need to be able to click ANY lesson, as once they are complete, the next run the lesson will be replaced with a new lesson card of the completed category. I can’t hard code to hit the same lesson every test run.

Below is the method I am using in the test to find the buttons and filter between only the “visible” buttons to click. The problem seems that they are always visible on the DOM, and the display: none/visibility is not really working.

static clickStartOrContinueLessonButton() {
  const lessonButtons = [
    "spirituality",
    "recovery",
    "relationships",
    "life-skills",
    "nutrition",
    "health",
    "sleep",
    "exercise",
    "emotions",
  ];

  // Function to check visibility of buttons with given selector prefix
  const checkVisibility = (selectorPrefix) => {
    let visibleButtons = [ ];

    return cy.wrap(lessonButtons).each((lesson) => {
      const selector = `#${selectorPrefix}-lesson-${lesson}`;
      cy.get('body').find(selector).then(($elements) => {
        if ($elements.length > 0) {
          cy.get(selector).should('be.visible').then(($element) => {
            visibleButtons.push($element);
          });
        }
      }).catch(() => {
        // Ignore errors if element is not found
      });
    }).then(() => visibleButtons);
  };

  // Function to click a random button from the visible buttons list
  const clickRandomButton = (visibleButtons) => {
    if (visibleButtons.length > 0) {
      const randomIndex = Math.floor(Math.random() * visibleButtons.length);
      const randomButton = visibleButtons[randomIndex];
      cy.wrap(randomButton).scrollIntoView().should("be.visible").click();

      cy.get('.lesson-title-selector') // Adjust this selector as per your application
        .invoke("text")
        .then((text) => {
          cy.wrap(text.trim()).as("lessonTitle");
        });
    } else {
      throw new Error("No visible buttons found.");
    }
  };

  // Check for visible "Continue Lesson" buttons first
  checkVisibility('continue').then((continueButtons) => {
    if (continueButtons.length > 0) {
      clickRandomButton(continueButtons);
    } else {
      // If no "Continue Lesson" buttons are visible, check for "Start Lesson" buttons
      checkVisibility('start').then((startButtons) => {
        clickRandomButton(startButtons);
      });
    }
  });
}

The issue I am running into is that because ALL the Start buttons STILL exist on the DOM even though they are not supposed to be visible. So no matter how I write the test it can still locate them

I would appreciate any insights or recommendations on how to handle this issue.

Thank you!

Hey @it-admin :wave:

If you hide the elements with the workflow action Hide, it doesn’t remove them from the DOM tree as far as I see. Therefore, cypress be.visible might interpret it still visible (not sure).

However, you can change the following lines in the code to get the elements without the visibility attribute or focus on this.

Instead of:

cy.get(selector).should('be.visible').then(($element) => {
            visibleButtons.push($element);
          });

Try this to get the not visibility: hidden elements:

cy.get(selector).should('not.have.css', 'visibility', 'hidden').then(($element) => {
            visibleButtons.push($element);
          });

I hope this gives you a starting point.

bdk_512x512 @Huseyin from Flusk | Discover the #1 Security and Monitoring Tool for Bubble

1 Like

This topic was automatically closed after 70 days. New replies are no longer allowed.