Skip to content

Commit b80b36e

Browse files
authored
feat(cypress-commands): add commands for dropdown menus (#5756)
Adds: - `clickDropdownMenuItemByText` - `clickDropdownMenuItem` - `openDropDownByClick`
1 parent 75c78ed commit b80b36e

File tree

2 files changed

+156
-1
lines changed

2 files changed

+156
-1
lines changed

packages/cypress-commands/src/commands.ts

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,11 @@ declare global {
7272
* __Note:__ The select popover must be visible, otherwise it can lead to unwanted side effects.
7373
*
7474
* @param text text of the ui5-option that should be clicked
75-
* @example cy.get('[ui5-select]').clickUi5SelectOptionByText('Option2');
75+
* @param options ClickOptions
7676
*
77+
* @deprecated: This command is deprecated. Please use `clickDropdownMenuItemByText` instead.
78+
*
79+
* @example cy.get('[ui5-select]').clickUi5SelectOptionByText('Option2');*
7780
*/
7881
clickUi5SelectOptionByText(text: string, options?: Partial<ClickOptions>): Chainable<Element>;
7982

@@ -82,9 +85,39 @@ declare global {
8285
*
8386
* __Note:__ The select popover must be visible, otherwise it can lead to unwanted side effects.
8487
*
88+
* @deprecated: This command is deprecated. Please use `clickDropdownMenuItem` instead.
89+
*
8590
* @example cy.get('[ui5-option]').clickUi5SelectOption();
8691
*/
8792
clickUi5SelectOption(options?: Partial<ClickOptions>): Chainable<Element>;
93+
94+
/**
95+
* Click on an option of "select-like" components by text. Currently supported components are `ui5-select`, `ui5-combobox` and `ui5-multi-combobox`.
96+
*
97+
* __Note:__ The popover must be visible, otherwise it can lead to unwanted side effects.
98+
*
99+
* @param text text of the item inside the popover that should be clicked
100+
* @param options Cypress.ClickOptions
101+
* @example cy.get('[ui5-select]').clickDropdownMenuItemByText('Option2');
102+
*
103+
*/
104+
clickDropdownMenuItemByText(text: string, options?: Partial<ClickOptions>): Chainable<Element>;
105+
106+
/**
107+
* Click on a chained option of "select-like" components. Currently supported components are `ui5-option`, `ui5-mcb-item` and `ui5-cb-item` (since v1.24.3 of `@ui5/webcomponents`).
108+
*
109+
* __Note:__ The popover must be visible, otherwise it can lead to unwanted side effects.
110+
*
111+
* @example cy.get('[ui5-option]').clickDropdownMenuItem();
112+
*/
113+
clickDropdownMenuItem(options?: Partial<ClickOptions>): Chainable<Element>;
114+
115+
/**
116+
* Click on the open button in "select-like" components to open the popover. Currently supported components are `ui5-select`, `ui5-combobox` and `ui5-multi-combobox`.
117+
*
118+
* @example cy.get('[ui5-select]').openDropDownByClick();
119+
*/
120+
openDropDownByClick(options?: Partial<ClickOptions>): Chainable<Element>;
88121
}
89122
}
90123
}
@@ -155,4 +188,40 @@ Cypress.Commands.add('clickUi5SelectOption', { prevSubject: 'element' }, (subjec
155188
});
156189
});
157190

191+
Cypress.Commands.add('clickDropdownMenuItemByText', { prevSubject: 'element' }, (subject, text, options = {}) => {
192+
cy.wrap(subject).then(async ($dropdown) => {
193+
// @ts-expect-error: ui5-webcomponent types are not bundled in
194+
const staticArea = await $dropdown.get(0).getStaticAreaItemDomRef();
195+
cy.wrap(staticArea).find('[ui5-responsive-popover][open]').should('be.visible');
196+
// necessary as otherwise focusing the ui5-li is flaky
197+
cy.wait(300);
198+
cy.wrap(staticArea)
199+
.contains(text)
200+
.then(async ($li) => {
201+
await $li.get(0).focus();
202+
cy.wrap($li)
203+
.find('li')
204+
.click({ force: true, ...options });
205+
});
206+
});
207+
});
208+
209+
Cypress.Commands.add('clickDropdownMenuItem', { prevSubject: 'element' }, (subject, options = {}) => {
210+
cy.wrap(subject).then(($option) => {
211+
// @ts-expect-error: ui5-webcomponent types are not bundled in
212+
const domRef = $option.get(0).getDomRef();
213+
cy.wrap(domRef)
214+
.find('li')
215+
.click({ force: true, ...options });
216+
});
217+
});
218+
219+
Cypress.Commands.add('openDropDownByClick', { prevSubject: 'element' }, (subject, options = {}) => {
220+
if (subject.get(0).hasAttribute('ui5-multi-combobox')) {
221+
// mcb needs a lot of calculation time to make the popover available
222+
cy.wait(500);
223+
}
224+
cy.wrap(subject).shadow().find('[input-icon]').click(options);
225+
});
226+
158227
export {};

packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,90 @@ describe('UI5 Web Components - Child Commands', () => {
191191
// the web component doesn't fire the event if the popover is not opened
192192
cy.get('@select').should('have.been.calledTwice');
193193
});
194+
195+
it('clickDropdownMenuItemByText', () => {
196+
const selectItemText =
197+
'This very long item should be selected by first focusing it and then pressing it. A focus is applied first, because otherwise it wouldnt be visible. Strangely, longer items tend to result in occasional test failures compared to smaller ones, which is why this item has this text.';
198+
const changeSpy = cy.spy().as('change');
199+
let callCounter = 1;
200+
const components = [
201+
<ComboBox key="ui5-combobox" onSelectionChange={changeSpy}>
202+
{...new Array(30).fill(<ComboBoxItem text="Item" />)}
203+
<ComboBoxItem text={selectItemText} />
204+
</ComboBox>,
205+
<MultiComboBox key="ui5-multi-combobox" onSelectionChange={changeSpy}>
206+
{...new Array(30).fill(<MultiComboBoxItem text="Item" />)}
207+
<MultiComboBoxItem text={selectItemText} />
208+
</MultiComboBox>,
209+
<Select key="ui5-select" onChange={changeSpy}>
210+
{...new Array(30).fill(<Option>Item</Option>)}
211+
<Option>{selectItemText}</Option>
212+
</Select>
213+
];
214+
215+
components.forEach((component) => {
216+
cy.mount(component);
217+
cy.get(`[${component.key}]`).openDropDownByClick();
218+
cy.get(`[${component.key}]`).clickDropdownMenuItemByText(selectItemText);
219+
220+
switch (component.key) {
221+
case 'ui5-combobox':
222+
cy.get(`[${component.key}]`).should('have.value', selectItemText);
223+
break;
224+
case 'ui5-multi-combobox':
225+
cy.get(`[${component.key}]`).find('[ui5-token]').contains(selectItemText);
226+
break;
227+
case 'ui5-select':
228+
cy.get(`[${component.key}]`).should('have.value', selectItemText);
229+
break;
230+
}
231+
232+
cy.get('@change').should('have.callCount', callCounter);
233+
callCounter++;
234+
cy.wait(200);
235+
});
236+
});
237+
238+
it('clickDropDownMenuItem', () => {
239+
const selectItemText = 'Select me';
240+
const changeSpy = cy.spy().as('change');
241+
let callCounter = 1;
242+
const components = [
243+
<ComboBox key="ui5-combobox" onSelectionChange={changeSpy}>
244+
{...new Array(5).fill(<ComboBoxItem text="Item" />)}
245+
<ComboBoxItem text={selectItemText} data-testid="selectItem" />
246+
</ComboBox>,
247+
<MultiComboBox key="ui5-multi-combobox" onSelectionChange={changeSpy}>
248+
{...new Array(5).fill(<MultiComboBoxItem text="Item" />)}
249+
<MultiComboBoxItem text={selectItemText} data-testid="selectItem" />
250+
</MultiComboBox>,
251+
<Select key="ui5-select" onChange={changeSpy}>
252+
{...new Array(5).fill(<Option>Item</Option>)}
253+
<Option data-testid="selectItem">{selectItemText}</Option>
254+
</Select>
255+
];
256+
257+
components.forEach((component) => {
258+
cy.mount(component);
259+
cy.get(`[${component.key}]`).openDropDownByClick();
260+
cy.get('[ui5-responsive-popover][open]').should('be.visible');
261+
cy.get(`[data-testid="selectItem"]`).clickDropdownMenuItem();
262+
263+
switch (component.key) {
264+
case 'ui5-combobox':
265+
cy.get(`[${component.key}]`).should('have.value', selectItemText);
266+
break;
267+
case 'ui5-multi-combobox':
268+
cy.get(`[${component.key}]`).find('[ui5-token]').contains(selectItemText);
269+
break;
270+
case 'ui5-select':
271+
cy.get(`[${component.key}]`).should('have.value', selectItemText);
272+
break;
273+
}
274+
275+
cy.get('@change').should('have.callCount', callCounter);
276+
callCounter++;
277+
cy.wait(200);
278+
});
279+
});
194280
});

0 commit comments

Comments
 (0)