Cypress is an exceptional tool for end-to-end testing, providing a robust environment for automating complex interactions within web applications. One such challenging scenario involves automating tests within SAP Hybris, mainly when dealing with a list of promotions presented in a table format. This article delves into a specific issue encountered during this process and explores the solution, providing a comprehensive guide for others facing similar challenges.
The Scenario
Imagine you are tasked with automating the process of finding and clicking a specific promotion in SAP Hybris. The promotions are listed in a table, and each promotion is uniquely identified by four values: promotionCode
, promotionName
, websiteEnv
,
and promotionStatus
.
However, multiple variations of the same promotion exist, with identical promotionCode
, promotionName
, and websiteEnv
values but differing promotionStatus
values. The unique identifier, in this case, is the Published
status.
Here’s the problem: the promotionStatus
value is not initially visible in the viewport, making it challenging for Cypress to interact with it directly.
The Initial Approach
The initial code aimed to locate the promotion by iterating through each row in the table and checking if all four criteria matched. If found, it would click on the row. The code snippet used was:
cy.get('tr.yw-coll-browser-hyperlink').each(($row) => {
cy.wrap($row).within(() => {
const promotionCode = 'CR_PMI_MGM_Godfather_Discount_01_More';
const promotionName = 'MGM GODFATHER Reward';
const websiteEnv = 'Costa Rica_Promotion_Group';
const promotionStatus = 'Published';
cy.get('.yw-listview-cell-label.z-label').contains(promotionCode).should('exist')
.then(() => {
cy.get('.yw-listview-cell-label.z-label').contains(promotionName).should('exist')
.then(() => {
cy.get('.yw-listview-cell-label.z-label').contains(websiteEnv).should('exist')
.then(() => {
cy.get('div.z-listbox-body').should('exist').scrollTo('right', { ensureScrollable: true }).wait(500);
cy.get('.yw-listview-cell-label.z-label')
.contains(promotionStatus).should('be.visible')
.then(($status) => {
cy.log('Found status: ', $status.text());
cy.wrap($row).click({ force: true });
});
});
});
});
});
});
The Problem
The code successfully found the promotion code, name, and environment values but failed to locate the Published
status. This happened because the Published
status was not in the viewport and Cypress could not scroll the table horizontally as intended. This limitation caused Cypress to throw an error: expected div. list box.z-flex-item to exist in the DOM
.
The Solution
The core of the issue lies in the incorrect scope of the search for the z-listbox-body
element. The cy.get('div.z-listbox-body')
command was inside the cy.wrap($row).within(() => {})
block, restricting the search scope to the row, whereas z-listbox-body
was outside this row.
To resolve this, we need to specify the withinSubject
option to expand the search scope. The corrected approach is:
cy.get('tr.yw-coll-browser-hyperlink').each(($row) => {
cy.wrap($row).within(() => {
const promotionCode = 'CR_PMI_MGM_Godfather_Discount_01_More';
const promotionName = 'MGM GODFATHER Reward';
const websiteEnv = 'Costa Rica_Promotion_Group';
const promotionStatus = 'Published';
cy.get('.yw-listview-cell-label.z-label').contains(promotionCode).should('exist')
.then(() => {
cy.get('.yw-listview-cell-label.z-label').contains(promotionName).should('exist')
.then(() => {
cy.get('.yw-listview-cell-label.z-label').contains(websiteEnv).should('exist')
.then(() => {
cy.get('div.z-listbox-body', { withinSubject: Cypress.$('body')[0] }).scrollTo('right', { ensureScrollable: true }).wait(500);
cy.get('.yw-listview-cell-label.z-label')
.contains(promotionStatus).should('be.visible')
.then(($status) => {
cy.log('Found status: ', $status.text());
cy.wrap($row).click({ force: true });
});
});
});
});
});
});
Beside this command:{ withinSubject: Cypress.$('body')[0] }
I’ve also tried using the next one and it worked as well:
{withinSubject:null}
Key Insights and Best Practices
- Understanding Scope with
withinSubject
: ThewithinSubject
option is crucial when you need to search outside the initially scoped element. This approach allows Cypress to locate elements beyond the immediate context, enabling more flexible interactions. - Scrolling and Visibility: While Cypress can interact with elements outside the viewport using
.scrollIntoView()
or.click({ force: true })
, understanding when and how to use these commands effectively can simplify your test scripts and improve reliability. - Debugging Tips: When Cypress cannot find an element, verify the element’s presence in the DOM and check the scope of your search commands. Using
.should('exist')
is a good practice to ensure the element is loaded before interacting with it.