diff --git a/packages/cypress-commands/src/queries.ts b/packages/cypress-commands/src/queries.ts index 653dd5b08dc..dc5124da3b5 100644 --- a/packages/cypress-commands/src/queries.ts +++ b/packages/cypress-commands/src/queries.ts @@ -1,3 +1,7 @@ +interface FindToolbarButtonByTextOptions { + queryShadowButton?: boolean; +} + declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace Cypress { @@ -23,7 +27,24 @@ declare global { * @example cy.get('[ui5-tab-container]').findUi5TabOpenPopoverButtonByText('Tab 1.1'); * @param {string} text The text of the sub-tab that should be queried. */ - findUi5TabOpenPopoverButtonByText(text: string, options?: Partial): Chainable; + findUi5TabOpenPopoverButtonByText(text: string): Chainable; + + /** + * Returns the element that represents the `ui5-toolbar-button`. + * When `options.queryShadowButton` is `true`, the internal `button` element is returned, otherwise the `ui5-button` element. + * + * __Note:__ This query can either be chained to a `ui5-toolbar` or not be chained at all. + * + * __Note:__ The `text` next needs to be unique in the respective scope. + * + * @example cy.findToolbarButtonByText("Button Text") + * @example cy.get('[ui5-toolbar]').findToolbarButtonByText("Button Text") + * + * @param {string} text - The text of the button to search for. This text should be unique within the toolbar to ensure a single button is returned. + * @param {FindToolbarButtonByTextOptions} [options] - An optional object containing configuration options for the query. + * @param {boolean} [options.queryShadowButton=false] - If set to `true`, the internal `button` element will be returned instead of the `ui5-button` element. + */ + findToolbarButtonByText(text: string, options?: FindToolbarButtonByTextOptions): Chainable; // private /** * Returns the internal input element inside the shadow-root. @@ -36,6 +57,41 @@ declare global { } } +Cypress.Commands.addQuery('findToolbarButtonByText', function (text, options) { + return (subject) => { + if (subject !== undefined && !subject?.[0]?.hasAttribute('ui5-toolbar')) { + const err = `findToolbarButtonByText() needs to be chained to a \`ui5-toolbar\`, or not be chained at all.`; + throw new TypeError(err); + } + const container = subject ? [subject[0]] : document.querySelectorAll('[ui5-toolbar]'); + + const toolbarBtns: HTMLElement[] = []; + container.forEach((el) => { + if (el) { + const toolbarDom = el.getDomRef(); + const buttons = Cypress.$(toolbarDom).find('[ui5-button]'); + const matchingButtons = buttons.filter(function () { + return Cypress.$(this).text() === text; + }); + + toolbarBtns.push(...matchingButtons); + } + }); + + if (toolbarBtns.length > 1) { + const err = `Multiple ui5-toolbar-button elements with the same text ("${text}") were found.`; + throw new TypeError(err); + } + + let toolbarBtn = toolbarBtns[0]; + if (options?.queryShadowButton) { + toolbarBtn = toolbarBtn.shadowRoot!.querySelector('button')!; + } + + return Cypress.$(toolbarBtn); + }; +}); + Cypress.Commands.addQuery('findShadowInput', function () { const getShadow = cy.now('shadow'); const getInput = cy.now('find', 'input'); diff --git a/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx b/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx index 699346f5dc3..5605f4c3a76 100644 --- a/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx +++ b/packages/cypress-commands/test/UI5WebComponentsChild.cy.tsx @@ -16,7 +16,9 @@ import { Switch, Tab, TabContainer, - TextArea + TextArea, + Toolbar, + ToolbarButton } from '@ui5/webcomponents-react'; describe('UI5 Web Components - Child Commands', () => { @@ -260,4 +262,26 @@ describe('UI5 Web Components - Child Commands', () => { cy.wait(200); }); }); + + it('findToolbarButtonByText', () => { + cy.mount( + <> + + + + + + + + + + + + ); + + cy.findToolbarButtonByText('TBB1').should('be.visible'); + cy.findToolbarButtonByText('TBB2').should('be.visible'); + cy.findToolbarButtonByText('TBB3').should('be.visible'); + cy.findToolbarButtonByText('TBB3').should('exist').not('be.visible'); + }); }); diff --git a/packages/main/src/components/FilterBar/FilterBar.cy.tsx b/packages/main/src/components/FilterBar/FilterBar.cy.tsx index 7092bbeccab..fd113ff3b46 100644 --- a/packages/main/src/components/FilterBar/FilterBar.cy.tsx +++ b/packages/main/src/components/FilterBar/FilterBar.cy.tsx @@ -358,12 +358,12 @@ describe('FilterBar.cy.tsx', () => { ); - cy.get('[text="Go"]'); - cy.get('[text="Filters"]'); - cy.get('[text="Adapt Filters"]').should('not.exist'); - cy.get('[text="Hide Filter Bar"]'); - cy.findByTestId('variantManagement'); - cy.findByTestId('SELECT'); + cy.findToolbarButtonByText('Go').should('be.visible'); + cy.findToolbarButtonByText('Filters').should('be.visible'); + cy.findToolbarButtonByText('Adapt Filters').should('not.exist'); + cy.findToolbarButtonByText('Hide Filter Bar').should('be.visible'); + cy.findByTestId('variantManagement').should('be.visible'); + cy.findByTestId('SELECT').should('be.visible'); cy.mount( @@ -378,13 +378,18 @@ describe('FilterBar.cy.tsx', () => { ); - cy.get('[text="Go"]'); - cy.get('[text="Filters"]').should('not.exist'); - cy.get('[text="Adapt Filters"]'); - cy.get('[text="Hide Filter Bar"]').should('not.exist'); + cy.findByText('Go').should('be.visible'); + cy.findByText('Filters').should('not.exist'); + cy.findByText('Adapt Filters').should('be.visible'); + cy.findByText('Hide Filter Bar').should('not.exist'); cy.findByPlaceholderText('Search').should('not.exist'); cy.findByTestId('variantManagement').should('not.exist'); - cy.findByTestId('SELECT'); + cy.findByTestId('SELECT').should('be.visible'); + + cy.findToolbarButtonByText('Go').should('not.exist'); + cy.findToolbarButtonByText('Filters"]').should('not.exist'); + cy.findToolbarButtonByText('Adapt Filters"]').should('not.exist'); + cy.findToolbarButtonByText('Hide Filter Bar"]').should('not.exist'); }); it('addCustomCSS', () => { diff --git a/packages/main/src/components/FilterBar/index.tsx b/packages/main/src/components/FilterBar/index.tsx index c9b59edb936..1a247f26a0c 100644 --- a/packages/main/src/components/FilterBar/index.tsx +++ b/packages/main/src/components/FilterBar/index.tsx @@ -19,8 +19,8 @@ import { SEARCH, SHOW_FILTER_BAR } from '../../i18n/i18n-defaults.js'; -import type { DialogDomRef, ToolbarButtonDomRef } from '../../webComponents/index.js'; -import { Icon, Toolbar, ToolbarButton } from '../../webComponents/index.js'; +import type { ButtonDomRef, DialogDomRef, ToolbarButtonDomRef } from '../../webComponents/index.js'; +import { Button, Icon, Toolbar, ToolbarButton } from '../../webComponents/index.js'; import { FilterGroupItem } from '../FilterGroupItem/index.js'; import type { FilterGroupItemInternalProps } from '../FilterGroupItem/types.js'; import { FlexBox } from '../FlexBox/index.js'; @@ -99,7 +99,7 @@ const FilterBar = forwardRef((props, ref) => const dialogRef = useRef(null); const filterBarButtonsRef = useRef(null); const filterAreaRef = useRef(null); - const filterBtnRef = useRef(null); + const filterBtnRef = useRef(null); const i18nBundle = useI18nBundle('@ui5/webcomponents-react'); const uniqueId = useId(); @@ -217,9 +217,21 @@ const FilterBar = forwardRef((props, ref) => const cssClasses = clsx(classNames.outerContainer, className, !hideToolbar && classNames.outerContainerWithToolbar); - const ToolbarButtons = ( + const FBButtonComponent = hideToolbar ? Button : ToolbarButton; + const filtersButtonText = `${filtersText}${ + activeFiltersCount && parseInt(activeFiltersCount as string, 10) ? ` (${activeFiltersCount})` : '' + }`; + const FBButtons = ( <> - {showGoOnFB && } + {showGoOnFB && ( + + {hideToolbar ? goText : undefined} + + )} {!hideToggleFiltersButton && !hideToolbar && !isPhone && ( ((props, ref) => aria-live="polite" /> )} - {showClearOnFB && } + {showClearOnFB && ( + + {hideToolbar ? clearText : undefined} + + )} {showRestoreOnFB && ( - + + {hideToolbar ? restoreText : undefined} + )} {!hideFilterConfiguration && ( - 0 ? ` (${activeFiltersCount})` : '' - }`} + + > + {hideToolbar ? filtersButtonText : undefined} + )} ); @@ -338,7 +365,7 @@ const FilterBar = forwardRef((props, ref) => {header} - {ToolbarButtons} + {FBButtons} )} @@ -373,7 +400,7 @@ const FilterBar = forwardRef((props, ref) => className={classNames.lastSpacer} >
- {ToolbarButtons} + {FBButtons}