diff --git a/cypress.config.ts b/cypress.config.ts index 3e70e41de48..c830b6718e3 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ bundler: 'vite', }, experimentalRunAllSpecs: true, - excludeSpecPattern: ['**/e2e/**', ...(process.env.CI ? ['**/SelectDialog/**'] : [])], + excludeSpecPattern: ['**/e2e/**'], }, includeShadowDom: true, viewportWidth: 1920, diff --git a/packages/main/src/components/SelectDialog/SelectDialog.cy.tsx b/packages/main/src/components/SelectDialog/SelectDialog.cy.tsx deleted file mode 100644 index 9cc3e392946..00000000000 --- a/packages/main/src/components/SelectDialog/SelectDialog.cy.tsx +++ /dev/null @@ -1,306 +0,0 @@ -import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js'; -import ListSelectionMode from '@ui5/webcomponents/dist/types/ListSelectionMode.js'; -import { useState } from 'react'; -import type { ListPropTypes, SelectDialogPropTypes } from '../..'; -import { Button, SelectDialog, ListItemStandard } from '../..'; - -const listItems = new Array(5) - .fill('o_O') - .map((_, index) => ( - - )); - -describe('SelectDialog', () => { - it('Basic', () => { - cy.mount({listItems}); - cy.get('[ui5-dialog]').should('be.visible'); - cy.findByPlaceholderText('Search'); - cy.findByText('Cancel').click(); - cy.get('[ui5-dialog]').should('not.be.visible'); - }); - - it('with headerText', () => { - cy.mount( - - {listItems} - , - ); - cy.findByText('Select Dialog') - .should('have.css', 'grid-column-start', 'titleStart') - .and('have.css', 'grid-column-end', 'titleCenter') - .and('have.attr', 'level', 'H1'); - cy.mount( - - {listItems} - , - ); - cy.findByText('Select Dialog').should('have.css', 'grid-area', 'titleCenter').and('have.attr', 'level', 'H1'); - cy.mount( - - {listItems} - , - ); - cy.findByText('Select Dialog').should('have.attr', 'level', 'H2'); - }); - - it('selection', () => { - const close = cy.spy().as('close'); - const change = cy.spy().as('change'); - const confirm = cy.spy().as('confirm'); - const TestComp = ({ - close, - change, - confirm, - rememberSelections, - mode, - }: { - close: SelectDialogPropTypes['onClose']; - change: ListPropTypes['onSelectionChange']; - confirm: SelectDialogPropTypes['onConfirm']; - rememberSelections?: SelectDialogPropTypes['rememberSelections']; - mode?: SelectDialogPropTypes['selectionMode']; - }) => { - const [open, setOpen] = useState(true); - const [items, setItems] = useState(undefined); - return ( - <> - - { - setItems(e.detail.selectedItems.map((item) => item.text)); - confirm(e); - }} - onClose={(e) => { - setOpen(false); - close(e); - }} - listProps={{ onSelectionChange: change }} - > - {listItems} - - Last Selected Item: {items} - - ); - }; - cy.mount(); - cy.get('[ui5-dialog]').should('be.visible'); - cy.clickUi5ListItemByText('Product1'); - cy.get('[ui5-dialog]').should('not.be.visible'); - cy.findByText('Last Selected Item: Product1').should('be.visible'); - cy.findByText('Open').click(); - cy.get('[ui5-li]').each(($li) => { - cy.wrap($li).should('not.have.attr', 'selected'); - }); - - cy.mount(); - cy.get('[ui5-dialog]').should('be.visible'); - cy.clickUi5ListItemByText('Product1'); - cy.get('[ui5-dialog]').should('not.be.visible'); - cy.findByText('Last Selected Item: Product1').should('be.visible'); - cy.findByText('Open').click(); - cy.get('[ui5-li]').each(($li) => { - if ($li.attr('text') === 'Product1') { - cy.wrap($li).should('have.attr', 'selected'); - } else { - cy.wrap($li).should('not.have.attr', 'selected'); - } - }); - - cy.get('@close').should('have.callCount', 2); - cy.get('@confirm').should('have.callCount', 2); - cy.get('@change').should('have.callCount', 2); - - cy.mount(); - cy.findByText('Cancel').click(); - cy.findByText('Open').click(); - cy.closeUi5PopupWithEsc(); - - cy.get('@close').should('have.callCount', 4); - cy.get('@confirm').should('have.callCount', 2); - cy.get('@change').should('have.callCount', 2); - - cy.mount(); - cy.clickUi5ListItemByText('Product1'); - cy.clickUi5ListItemByText('Product3'); - cy.get('[ui5-dialog]').should('be.visible'); - cy.findByText('Select').click(); - cy.findByText('Last Selected Item: Product1Product3').should('be.visible'); - - cy.findByText('Open').click(); - cy.get('[ui5-li]').each(($li) => { - cy.wrap($li).should('not.have.attr', 'selected'); - }); - - cy.mount( - , - ); - cy.clickUi5ListItemByText('Product1'); - cy.clickUi5ListItemByText('Product3'); - cy.get('[ui5-dialog]').should('be.visible'); - cy.findByText('Select').click(); - cy.findByText('Last Selected Item: Product1Product3').should('be.visible'); - cy.get('[ui5-li]').each(($li) => { - if ($li.attr('text') === 'Product1' || $li.attr('text') === 'Product3') { - cy.wrap($li).should('have.attr', 'selected'); - } else { - cy.wrap($li).should('not.have.attr', 'selected'); - } - }); - - cy.get('@close').should('have.callCount', 6); - cy.get('@confirm').should('have.callCount', 4); - cy.get('@change').should('have.callCount', 6); - }); - - it('Search', () => { - const search = cy.spy().as('search'); - const input = cy.spy().as('input'); - const reset = cy.spy().as('reset'); - const TestComp = ({ - search, - input, - reset, - }: { - search: SelectDialogPropTypes['onSearch']; - input: SelectDialogPropTypes['onSearchInput']; - reset: SelectDialogPropTypes['onSearchReset']; - }) => { - const [inputVal, setInputVal] = useState(''); - const [searchVal, setSearchVal] = useState(''); - return ( - <> - { - setSearchVal(e.detail.value); - search(e); - }} - onSearchInput={(e) => { - setInputVal(e.detail.value); - input(e); - }} - onSearchReset={reset} - open - > - {listItems} - -
- input: {inputVal} -
- search: {searchVal} - - ); - }; - cy.mount(); - cy.get('[accessible-name="Reset"][ui5-icon]').should('not.exist'); - cy.get('[ui5-input]').typeIntoUi5Input('Test'); - cy.findByTestId('inputVal').should('have.text', 'input: Test'); - cy.get('@search').should('have.callCount', 0); - cy.get('@input').should('have.callCount', 4); - cy.get('@reset').should('have.callCount', 0); - cy.get('[ui5-input]').typeIntoUi5Input('{enter}'); - cy.findByTestId('searchVal').should('have.text', 'search: Test'); - cy.get('@search').should('have.callCount', 1); - cy.get('@input').should('have.callCount', 4); - cy.get('@reset').should('have.callCount', 0); - cy.get('[accessible-name="Search"][ui5-icon]').click(); - cy.get('@search').should('have.callCount', 2); - cy.get('@input').should('have.callCount', 4); - cy.get('@reset').should('have.callCount', 0); - cy.get('[part="clear-icon"][ui5-icon]').click(); - cy.get('@search').should('have.callCount', 2); - // clearing the input via clear button fires input event as well - cy.get('@input').should('have.callCount', 5); - cy.get('@reset').should('have.callCount', 1); - cy.get('[accessible-name="Reset"][ui5-icon]').should('not.exist'); - }); - - it('confirmButtonText', () => { - const confirm = cy.spy().as('confirm'); - cy.mount( - , - ); - cy.get('[ui5-dialog]').should('be.visible'); - cy.findByText('Exterminate').click(); - cy.get('@confirm').should('have.been.calledOnce'); - cy.get('[ui5-dialog]').should('not.be.visible'); - }); - - it('numberOfSelectedItems', () => { - cy.mount(); - cy.findByText('Selected: 1337').should('be.visible'); - }); - - it('onCancel', () => { - const cancel = cy.spy().as('cancel'); - const TestComp = ({ - cancel, - mode, - }: { - cancel: SelectDialogPropTypes['onCancel']; - mode: SelectDialogPropTypes['selectionMode']; - }) => { - const [open, setOpen] = useState(false); - return ( - <> - - { - setOpen(false); - }} - selectionMode={mode} - > - {listItems} - - - ); - }; - let callCount = 1; - [ListSelectionMode.Single, ListSelectionMode.Multiple].forEach((mode) => { - cy.mount(); - cy.findByText('Open').click(); - cy.findByText('Cancel').click(); - cy.get('@cancel').should('have.callCount', callCount); - callCount++; - - cy.findByText('Open').click(); - cy.realPress('Escape'); - cy.get('@cancel').should('have.callCount', callCount); - callCount++; - }); - }); - - it('confirmButtonProps', () => { - cy.mount( - , - ); - cy.findByTestId('confirmBtn').should('be.visible').and('have.attr', 'disabled'); - cy.findByTestId('confirmBtn').should('have.attr', 'design', 'Emphasized'); - }); -}); diff --git a/packages/main/src/components/SelectDialog/SelectDialog.stories.tsx b/packages/main/src/components/SelectDialog/SelectDialog.stories.tsx index 0879b7570d3..6a08e2bd927 100644 --- a/packages/main/src/components/SelectDialog/SelectDialog.stories.tsx +++ b/packages/main/src/components/SelectDialog/SelectDialog.stories.tsx @@ -16,7 +16,11 @@ import { SelectDialog } from './index.js'; const meta = { title: 'Modals & Popovers / SelectDialog', component: SelectDialog, - argTypes: { children: { control: { disable: true } } }, + argTypes: { + children: { control: { disable: true } }, + onSearch: { control: { disable: true } }, + onCancel: { control: { disable: true } }, + }, args: { headerText: 'Select Product', open: isChromatic }, parameters: { chromatic: { delay: 1000 }, diff --git a/packages/main/src/components/SelectDialog/index.tsx b/packages/main/src/components/SelectDialog/index.tsx index aa779f16e10..833d0badbd8 100644 --- a/packages/main/src/components/SelectDialog/index.tsx +++ b/packages/main/src/components/SelectDialog/index.tsx @@ -118,6 +118,13 @@ export interface SelectDialogPropTypes * @since 1.25.0 */ confirmButtonProps?: Omit; + /** + * + * Allows overriding the SearchField's default placeholder text. If not set, the word "Search" in the current local language or English will be used as a placeholder. + * + * __Note:__ The placeholder is used as accessible-name of the input for screen reader support. + */ + searchPlaceholder?: string; /** * This event will be fired when the value of the search field is changed by a user - e.g. at each key press */ @@ -169,6 +176,7 @@ const SelectDialog = forwardRef((props, ref selectionMode = ListSelectionMode.Single, numberOfSelectedItems, rememberSelections, + searchPlaceholder, showClearButton, onClose, onClear, @@ -341,9 +349,9 @@ const SelectDialog = forwardRef((props, ref )} { await expect(page.locator('[accessible-name="Reset"][ui5-icon]')).not.toBeVisible(); const input = page.locator('[ui5-input]'); + await expect(input).toHaveAttribute('placeholder', 'Search'); + await expect(input).toHaveAttribute('accessible-name', 'Search'); await ui5wc.typeIntoInput(input, 'Test'); await expect(page.getByTestId('input-val')).toHaveText('input: Test'); await expect(page.getByTestId('search-count')).toHaveText('0'); @@ -152,6 +154,12 @@ test.describe('SelectDialog', () => { await expect(page.getByTestId('input-count')).toHaveText('2'); await expect(page.getByTestId('reset-count')).toHaveText('1'); await expect(page.locator('[accessible-name="Reset"][ui5-icon]')).not.toBeVisible(); + + await ui5wc.closePopupWithEsc(); + await page.getByTestId('set-placeholder').click(); + await page.getByTestId('open-btn').click(); + await expect(input).toHaveAttribute('placeholder', 'Hello'); + await expect(input).toHaveAttribute('accessible-name', 'Hello'); }); test('confirmButtonText', async ({ mount, page }) => { diff --git a/packages/main/src/components/SelectDialog/test/SelectDialogTestComponents.tsx b/packages/main/src/components/SelectDialog/test/SelectDialogTestComponents.tsx index 3aa2b5c20e1..8a4fb279794 100644 --- a/packages/main/src/components/SelectDialog/test/SelectDialogTestComponents.tsx +++ b/packages/main/src/components/SelectDialog/test/SelectDialogTestComponents.tsx @@ -109,15 +109,24 @@ export const SelectDialogSelectionWithToggleTestComp = () => { // Tracks search/input/reset values and counts via DOM export const SelectDialogSearchTestComp = () => { + const [open, setOpen] = useState(true); const [inputVal, setInputVal] = useState(''); const [searchVal, setSearchVal] = useState(''); const [searchCount, setSearchCount] = useState(0); const [inputCount, setInputCount] = useState(0); const [resetCount, setResetCount] = useState(0); + const [searchPlaceholder, setSearchPlaceholder] = useState(undefined); return ( <> + + { setSearchVal(e.detail.value); setSearchCount((c) => c + 1); @@ -127,7 +136,8 @@ export const SelectDialogSearchTestComp = () => { setInputCount((c) => c + 1); }} onSearchReset={() => setResetCount((c) => c + 1)} - open + onClose={() => setOpen(false)} + open={open} > {listItems}