Skip to content

Commit ef8fb4c

Browse files
authored
Merge pull request #9522 from asirvadAbrahamVarghese/add-cypress-command-select-accordion-item
Add cypress command select accordion item
2 parents 7f79b24 + a0a7779 commit ef8fb4c

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* eslint-disable no-undef */
2+
3+
describe('Validate clickItem', () => {
4+
beforeEach(() => {
5+
cy.login();
6+
cy.menu('Settings', 'Application Settings');
7+
});
8+
9+
it('should fail when an invalid node label is passed', (done) => {
10+
cy.accordion('Access Control');
11+
12+
cy.on('fail', (err) => {
13+
expect(err.message).to.include('not found');
14+
done();
15+
});
16+
17+
cy.selectAccordionItem([
18+
'ManageIQ Region: Region 0 [0]',
19+
'Tenants',
20+
'No Company', // This label does not exist
21+
]);
22+
});
23+
24+
it('should support path arrays containing both exact strings and regex patterns', () => {
25+
cy.accordion('Settings');
26+
cy.selectAccordionItem([
27+
/^ManageIQ Region/,
28+
'Zones',
29+
/^Zone: Default/,
30+
'Server: EVM [1] (current)',
31+
]);
32+
});
33+
34+
it('should not collapse already expanded node', () => {
35+
cy.accordion('Settings');
36+
cy.selectAccordionItem([
37+
/^ManageIQ Region/,
38+
'Zones',
39+
/^Zone: Default/,
40+
'Server: EVM [1] (current)',
41+
]);
42+
// Above path is already expanded, so this should not collapse it
43+
cy.selectAccordionItem([
44+
/^ManageIQ Region/,
45+
'Zones',
46+
/^Zone: Default/,
47+
'Server: EVM [1] (current)',
48+
]);
49+
});
50+
});

cypress/support/commands/explorer.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,93 @@ Cypress.Commands.add('accordionItem', (name) => {
2424

2525
cy.get('.list-group-item').contains(name).click();
2626
});
27+
28+
/**
29+
* Selects an accordion item based on a path of labels.
30+
* @param accordionPath: The path can be a mix of strings and regular expressions.
31+
* For example, `[/^ManageIQ Region/, 'Zone', 'Server']`
32+
* will expand the accordion until it finds the item with the label 'Server' under 'Zone' under 'ManageIQ Region'.
33+
* If the path is not found, it will throw an error.
34+
*/
35+
Cypress.Commands.add('selectAccordionItem', (accordionPath) => {
36+
cy.get('li.list-group-item').then(($items) => {
37+
// Converting jQuery collection to an array for easier manipulation
38+
const listItems = [...$items];
39+
40+
/**
41+
* Function to recursively expand the accordion and click the target item.
42+
* @param {number} accordionPathIndex: The current index in the accordionPath array.
43+
* @param {number} searchStartIndex: The index in the listItems array to start searching from,
44+
* once the first label is matched, it is not required to start iterating from the beginning.
45+
* @returns {void}
46+
*/
47+
const expandAndClickPath = (accordionPathIndex, searchStartIndex) => {
48+
const accordionLabel = accordionPath[accordionPathIndex];
49+
const isClickableNode = accordionPathIndex === accordionPath.length - 1;
50+
51+
for (let i = searchStartIndex; i < listItems.length; i++) {
52+
/* To remove */
53+
Cypress.log({
54+
name: 'selectAccordionItem',
55+
message: `Loop index: ${i} & Searching for label: ${accordionLabel}`,
56+
});
57+
58+
const liText = listItems[i].textContent.trim();
59+
// Check if the current item matches the label
60+
// Use either string match or regex match based on the type of accordionLabel
61+
let isMatch = false;
62+
if (typeof accordionLabel === 'string') {
63+
isMatch = liText === accordionLabel;
64+
} else if (accordionLabel instanceof RegExp) {
65+
isMatch = accordionLabel.test(liText);
66+
}
67+
68+
if (isMatch) {
69+
/* To remove */
70+
Cypress.log({
71+
name: 'selectAccordionItem',
72+
message: `Matched "${liText}" at index ${i}`,
73+
});
74+
75+
// Wrap the current li element in a jQuery object to use jQuery methods
76+
const currentLiElement = Cypress.$(listItems[i]);
77+
// If it's the last label in the path, then that is the desired item to click
78+
if (isClickableNode) {
79+
// Click the node corresponding to the last label in the given path and terminate
80+
cy.wrap(currentLiElement).click();
81+
return;
82+
}
83+
84+
const isExpandable =
85+
currentLiElement.find('span.fa-angle-right').length > 0;
86+
87+
// If it's not the last label in the path, either expand the node
88+
// or move to the next label in the given path
89+
if (isExpandable) {
90+
// Expand the node
91+
cy.wrap(currentLiElement)
92+
.find('span.fa-angle-right')
93+
.click()
94+
.then(() => {
95+
// Recurse to the next label in the given path array and
96+
// start iteration from the current index
97+
expandAndClickPath(accordionPathIndex + 1, i + 1);
98+
});
99+
} else {
100+
// If it's already expanded, continue to the next label
101+
// start iteration from the current index
102+
expandAndClickPath(accordionPathIndex + 1, i + 1);
103+
}
104+
// Exit the current function scope
105+
return;
106+
}
107+
}
108+
// If we reach here, it means the label was not found
109+
throw new Error(`Accordion item: "${accordionLabel}" not found`);
110+
};
111+
112+
// Start the recursive call from the first label in the given path
113+
// and from the beginning of the accordion items in the panel
114+
expandAndClickPath(0, 0);
115+
});
116+
});

0 commit comments

Comments
 (0)