diff --git a/packages/cypress-commands/src/commands.ts b/packages/cypress-commands/src/commands.ts index 419af3ccbca..091a929164c 100644 --- a/packages/cypress-commands/src/commands.ts +++ b/packages/cypress-commands/src/commands.ts @@ -72,8 +72,11 @@ declare global { * __Note:__ The select popover must be visible, otherwise it can lead to unwanted side effects. * * @param text text of the ui5-option that should be clicked - * @example cy.get('[ui5-select]').clickUi5SelectOptionByText('Option2'); + * @param options ClickOptions * + * @deprecated: This command is deprecated. Please use `clickDropdownMenuItemByText` instead. + * + * @example cy.get('[ui5-select]').clickUi5SelectOptionByText('Option2');* */ clickUi5SelectOptionByText(text: string, options?: Partial): Chainable; @@ -82,9 +85,39 @@ declare global { * * __Note:__ The select popover must be visible, otherwise it can lead to unwanted side effects. * + * @deprecated: This command is deprecated. Please use `clickDropdownMenuItem` instead. + * * @example cy.get('[ui5-option]').clickUi5SelectOption(); */ clickUi5SelectOption(options?: Partial): Chainable; + + /** + * Click on an option of "select-like" components by text. Currently supported components are `ui5-select`, `ui5-combobox` and `ui5-multi-combobox`. + * + * __Note:__ The popover must be visible, otherwise it can lead to unwanted side effects. + * + * @param text text of the item inside the popover that should be clicked + * @param options Cypress.ClickOptions + * @example cy.get('[ui5-select]').clickDropdownMenuItemByText('Option2'); + * + */ + clickDropdownMenuItemByText(text: string, options?: Partial): Chainable; + + /** + * 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`). + * + * __Note:__ The popover must be visible, otherwise it can lead to unwanted side effects. + * + * @example cy.get('[ui5-option]').clickDropdownMenuItem(); + */ + clickDropdownMenuItem(options?: Partial): Chainable; + + /** + * 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`. + * + * @example cy.get('[ui5-select]').openDropDownByClick(); + */ + openDropDownByClick(options?: Partial): Chainable; } } } @@ -155,4 +188,40 @@ Cypress.Commands.add('clickUi5SelectOption', { prevSubject: 'element' }, (subjec }); }); +Cypress.Commands.add('clickDropdownMenuItemByText', { prevSubject: 'element' }, (subject, text, options = {}) => { + cy.wrap(subject).then(async ($dropdown) => { + // @ts-expect-error: ui5-webcomponent types are not bundled in + const staticArea = await $dropdown.get(0).getStaticAreaItemDomRef(); + cy.wrap(staticArea).find('[ui5-responsive-popover][open]').should('be.visible'); + // necessary as otherwise focusing the ui5-li is flaky + cy.wait(300); + cy.wrap(staticArea) + .contains(text) + .then(async ($li) => { + await $li.get(0).focus(); + cy.wrap($li) + .find('li') + .click({ force: true, ...options }); + }); + }); +}); + +Cypress.Commands.add('clickDropdownMenuItem', { prevSubject: 'element' }, (subject, options = {}) => { + cy.wrap(subject).then(($option) => { + // @ts-expect-error: ui5-webcomponent types are not bundled in + const domRef = $option.get(0).getDomRef(); + cy.wrap(domRef) + .find('li') + .click({ force: true, ...options }); + }); +}); + +Cypress.Commands.add('openDropDownByClick', { prevSubject: 'element' }, (subject, options = {}) => { + if (subject.get(0).hasAttribute('ui5-multi-combobox')) { + // mcb needs a lot of calculation time to make the popover available + cy.wait(500); + } + cy.wrap(subject).shadow().find('[input-icon]').click(options); +}); + export {}; diff --git a/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx b/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx index 442c7fdabdd..fb369fa826b 100644 --- a/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx +++ b/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx @@ -191,4 +191,90 @@ describe('UI5 Web Components - Child Commands', () => { // the web component doesn't fire the event if the popover is not opened cy.get('@select').should('have.been.calledTwice'); }); + + it('clickDropdownMenuItemByText', () => { + const selectItemText = + '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.'; + const changeSpy = cy.spy().as('change'); + let callCounter = 1; + const components = [ + + {...new Array(30).fill()} + + , + + {...new Array(30).fill()} + + , + + ]; + + components.forEach((component) => { + cy.mount(component); + cy.get(`[${component.key}]`).openDropDownByClick(); + cy.get(`[${component.key}]`).clickDropdownMenuItemByText(selectItemText); + + switch (component.key) { + case 'ui5-combobox': + cy.get(`[${component.key}]`).should('have.value', selectItemText); + break; + case 'ui5-multi-combobox': + cy.get(`[${component.key}]`).find('[ui5-token]').contains(selectItemText); + break; + case 'ui5-select': + cy.get(`[${component.key}]`).should('have.value', selectItemText); + break; + } + + cy.get('@change').should('have.callCount', callCounter); + callCounter++; + cy.wait(200); + }); + }); + + it('clickDropDownMenuItem', () => { + const selectItemText = 'Select me'; + const changeSpy = cy.spy().as('change'); + let callCounter = 1; + const components = [ + + {...new Array(5).fill()} + + , + + {...new Array(5).fill()} + + , + + ]; + + components.forEach((component) => { + cy.mount(component); + cy.get(`[${component.key}]`).openDropDownByClick(); + cy.get('[ui5-responsive-popover][open]').should('be.visible'); + cy.get(`[data-testid="selectItem"]`).clickDropdownMenuItem(); + + switch (component.key) { + case 'ui5-combobox': + cy.get(`[${component.key}]`).should('have.value', selectItemText); + break; + case 'ui5-multi-combobox': + cy.get(`[${component.key}]`).find('[ui5-token]').contains(selectItemText); + break; + case 'ui5-select': + cy.get(`[${component.key}]`).should('have.value', selectItemText); + break; + } + + cy.get('@change').should('have.callCount', callCounter); + callCounter++; + cy.wait(200); + }); + }); });