@sapudex/web-components 2.62.0 → 2.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cypress/specs/FilterMenu.cy.tsx +43 -22
- package/cypress/specs/FilterMenuAccessibility.cy.tsx +1017 -0
- package/cypress/specs/ListItem.cy.tsx +234 -6
- package/cypress/specs/MastheadCountrySelector.cy.tsx +177 -0
- package/cypress/specs/SelectBox.cy.tsx +7 -2
- package/cypress/specs/SelectBoxAccessibility.cy.tsx +5 -5
- package/cypress/specs/SideNavigation.cy.tsx +49 -0
- package/cypress/specs/SideNavigationMobile.cy.tsx +69 -0
- package/cypress/support/component-imports.instrumented.ts +4 -0
- package/cypress/support/component-imports.src.ts +4 -0
- package/dist/AccordionItemTemplate.js +1 -1
- package/dist/AccordionItemTemplate.js.map +1 -1
- package/dist/FilterMenu.d.ts +2 -2
- package/dist/FilterMenu.js +6 -4
- package/dist/FilterMenu.js.map +1 -1
- package/dist/FilterMenuTemplate.js +2 -2
- package/dist/FilterMenuTemplate.js.map +1 -1
- package/dist/List.d.ts +1 -8
- package/dist/List.js +4 -12
- package/dist/List.js.map +1 -1
- package/dist/ListGroupHeaderTemplate.js +8 -7
- package/dist/ListGroupHeaderTemplate.js.map +1 -1
- package/dist/ListItem.js +12 -1
- package/dist/ListItem.js.map +1 -1
- package/dist/ListItemBase.d.ts +5 -0
- package/dist/ListItemBase.js +3 -0
- package/dist/ListItemBase.js.map +1 -1
- package/dist/ListItemTemplate.js +2 -2
- package/dist/ListItemTemplate.js.map +1 -1
- package/dist/ListSelectAllTemplate.js +1 -1
- package/dist/ListSelectAllTemplate.js.map +1 -1
- package/dist/MastheadCountrySelector.d.ts +14 -0
- package/dist/MastheadCountrySelector.js +6 -0
- package/dist/MastheadCountrySelector.js.map +1 -1
- package/dist/MastheadCountrySelectorTemplate.js +1 -1
- package/dist/MastheadCountrySelectorTemplate.js.map +1 -1
- package/dist/MessageStrip.d.ts +1 -0
- package/dist/MessageStrip.js +6 -0
- package/dist/MessageStrip.js.map +1 -1
- package/dist/SearchTemplate.js +1 -1
- package/dist/SearchTemplate.js.map +1 -1
- package/dist/SearchableListBaseTemplate.js +8 -10
- package/dist/SearchableListBaseTemplate.js.map +1 -1
- package/dist/SideNavigation.d.ts +9 -0
- package/dist/SideNavigation.js +9 -0
- package/dist/SideNavigation.js.map +1 -1
- package/dist/SideNavigationMobile.d.ts +19 -0
- package/dist/SideNavigationMobile.js +32 -1
- package/dist/SideNavigationMobile.js.map +1 -1
- package/dist/SideNavigationMobileTemplate.js +1 -2
- package/dist/SideNavigationMobileTemplate.js.map +1 -1
- package/dist/SideNavigationSubItem.d.ts +4 -1
- package/dist/SideNavigationSubItem.js +20 -9
- package/dist/SideNavigationSubItem.js.map +1 -1
- package/dist/SideNavigationSubItemTemplate.js +1 -1
- package/dist/SideNavigationSubItemTemplate.js.map +1 -1
- package/dist/SideNavigationTemplate.d.ts +2 -0
- package/dist/SideNavigationTemplate.js +6 -0
- package/dist/SideNavigationTemplate.js.map +1 -0
- package/dist/assets/{InputSuggestions-BPKrPqPb.js → InputSuggestions-DSPGFWZq.js} +2 -2
- package/dist/assets/{ListItemStandardExpandableTextTemplate-DkdOcCxC.js → ListItemStandardExpandableTextTemplate-hSNo3Xyr.js} +2 -2
- package/dist/assets/{bundle.esm-17Yt5gDr.js → bundle.esm-qSu0eWiH.js} +237 -238
- package/dist/assets/messagebundle_ar-22dGHdkl.js +1 -0
- package/dist/assets/messagebundle_ar-DbxuUDUB.js +1 -0
- package/dist/assets/messagebundle_bg-CaaOz5e4.js +1 -0
- package/dist/assets/messagebundle_bg-QOUvq6-8.js +1 -0
- package/dist/assets/messagebundle_ca-D-8eSg1w.js +1 -0
- package/dist/assets/messagebundle_ca-jsUpFfNJ.js +1 -0
- package/dist/assets/messagebundle_cnr-BdSolJRo.js +1 -0
- package/dist/assets/messagebundle_cnr-rtr9Ox4O.js +1 -0
- package/dist/assets/messagebundle_cs-CbM7zJ23.js +1 -0
- package/dist/assets/messagebundle_cy-D5E7e9o1.js +1 -0
- package/dist/assets/messagebundle_cy-hajQLyoj.js +1 -0
- package/dist/assets/messagebundle_da-C3PD-hWQ.js +1 -0
- package/dist/assets/messagebundle_da-DFzvQYW2.js +1 -0
- package/dist/assets/messagebundle_de-C106E9io.js +1 -0
- package/dist/assets/messagebundle_de-C36z5lgV.js +1 -0
- package/dist/assets/messagebundle_el-BLHqa1_J.js +1 -0
- package/dist/assets/messagebundle_el-k8W9FVQI.js +1 -0
- package/dist/assets/messagebundle_en-ClXds397.js +1 -0
- package/dist/assets/messagebundle_en-DgPtAFO8.js +1 -0
- package/dist/assets/messagebundle_en_GB-DxulA9qE.js +1 -0
- package/dist/assets/messagebundle_en_GB-LxAIZigF.js +1 -0
- package/dist/assets/{messagebundle_en_US_sappsd-Se8GgI58.js → messagebundle_en_US_sappsd-TZz2y4pV.js} +1 -1
- package/dist/assets/messagebundle_en_US_sappsd-oE0A2op2.js +1 -0
- package/dist/assets/messagebundle_en_US_saprigi-C6FsbpF8.js +1 -0
- package/dist/assets/{messagebundle_en_US_saprigi-CbfvaHUL.js → messagebundle_en_US_saprigi-CkPhuOLS.js} +1 -1
- package/dist/assets/messagebundle_en_US_saptrc-CFSYKuS7.js +1 -0
- package/dist/assets/messagebundle_en_US_saptrc-CNZe1wPP.js +1 -0
- package/dist/assets/messagebundle_es-C3ijAvKG.js +1 -0
- package/dist/assets/messagebundle_es-wi4P-8Bo.js +1 -0
- package/dist/assets/messagebundle_es_MX-JEoOD2AD.js +1 -0
- package/dist/assets/messagebundle_es_MX-qDQ65ei9.js +1 -0
- package/dist/assets/messagebundle_et-C3wgDmm9.js +1 -0
- package/dist/assets/messagebundle_et-D4r4iubd.js +1 -0
- package/dist/assets/messagebundle_fi-BjyQcbRb.js +1 -0
- package/dist/assets/messagebundle_fi-CivJKH9k.js +1 -0
- package/dist/assets/messagebundle_fr-BxDSBfD5.js +1 -0
- package/dist/assets/messagebundle_fr-JN2VAe-b.js +1 -0
- package/dist/assets/messagebundle_fr_CA-FkrcsWH5.js +1 -0
- package/dist/assets/messagebundle_fr_CA-phd0XOeR.js +1 -0
- package/dist/assets/messagebundle_hi-B_pehoTp.js +1 -0
- package/dist/assets/messagebundle_hi-CVOoC3dA.js +1 -0
- package/dist/assets/messagebundle_hr-BYS-ya62.js +1 -0
- package/dist/assets/messagebundle_hr-DHuCJjK8.js +1 -0
- package/dist/assets/messagebundle_hu-Crn0Y1hl.js +1 -0
- package/dist/assets/messagebundle_hu-DJL3QHT4.js +1 -0
- package/dist/assets/messagebundle_id-BJEG-7Up.js +1 -0
- package/dist/assets/messagebundle_id-CgbG2IVb.js +1 -0
- package/dist/assets/messagebundle_it-B-E3gO1k.js +1 -0
- package/dist/assets/messagebundle_it-DHwy0JuE.js +1 -0
- package/dist/assets/messagebundle_iw-BFfL9nZy.js +1 -0
- package/dist/assets/messagebundle_iw-BgyHu_0a.js +1 -0
- package/dist/assets/messagebundle_ja-BDNEwBMO.js +1 -0
- package/dist/assets/messagebundle_ja-eyoqeb4r.js +1 -0
- package/dist/assets/messagebundle_kk-BA_1qhYv.js +1 -0
- package/dist/assets/messagebundle_kk-CTAXqbPN.js +1 -0
- package/dist/assets/messagebundle_ko-C1tsjQMn.js +1 -0
- package/dist/assets/messagebundle_ko-CkiNi7iV.js +1 -0
- package/dist/assets/messagebundle_lt-Dp0c8r7p.js +1 -0
- package/dist/assets/{messagebundle_lt-BGK5mpcm.js → messagebundle_lt-bNum-ekg.js} +1 -1
- package/dist/assets/messagebundle_lv-B9UWTGX9.js +1 -0
- package/dist/assets/messagebundle_lv-D02PBhtR.js +1 -0
- package/dist/assets/messagebundle_mk--Xt_Ciey.js +1 -0
- package/dist/assets/messagebundle_mk-D6s2Tr95.js +1 -0
- package/dist/assets/messagebundle_ms-BAqsvtp5.js +1 -0
- package/dist/assets/messagebundle_ms-BobJaFPp.js +1 -0
- package/dist/assets/messagebundle_nl-BJCykHj1.js +1 -0
- package/dist/assets/messagebundle_nl-Dj7LaMyb.js +1 -0
- package/dist/assets/messagebundle_no-CR_uQXUz.js +1 -0
- package/dist/assets/messagebundle_no-CnwJbEW8.js +1 -0
- package/dist/assets/messagebundle_pl-D6FQ-6EC.js +1 -0
- package/dist/assets/messagebundle_pl-eJC2NE6N.js +1 -0
- package/dist/assets/messagebundle_pt-CbdPbTKR.js +1 -0
- package/dist/assets/messagebundle_pt-n8LcOyWG.js +1 -0
- package/dist/assets/messagebundle_pt_PT-B17ziKL9.js +1 -0
- package/dist/assets/messagebundle_pt_PT-BVpS4lrC.js +1 -0
- package/dist/assets/messagebundle_ro-C0jrNva4.js +1 -0
- package/dist/assets/messagebundle_ro-ixITTbJt.js +1 -0
- package/dist/assets/messagebundle_ru-Bh6RMNe2.js +1 -0
- package/dist/assets/messagebundle_ru-Dbxms1Xm.js +1 -0
- package/dist/assets/messagebundle_sh-CMDXUWge.js +1 -0
- package/dist/assets/messagebundle_sh-Cb-sVI_0.js +1 -0
- package/dist/assets/messagebundle_sk-DZkkgRSd.js +1 -0
- package/dist/assets/{messagebundle_sk-CXOF1RuF.js → messagebundle_sk-Dqb_XwMg.js} +1 -1
- package/dist/assets/messagebundle_sl-DIl-2Lb1.js +1 -0
- package/dist/assets/messagebundle_sl-Dx6UWXni.js +1 -0
- package/dist/assets/messagebundle_sr-DstlyDjZ.js +1 -0
- package/dist/assets/messagebundle_sr-yQWBd9jR.js +1 -0
- package/dist/assets/messagebundle_sv-Dr2hDyEO.js +1 -0
- package/dist/assets/messagebundle_sv-iHKWgaRg.js +1 -0
- package/dist/assets/messagebundle_th-DbWfCb5y.js +1 -0
- package/dist/assets/messagebundle_th-yLU2SE6L.js +1 -0
- package/dist/assets/messagebundle_tr-CIoGg6uY.js +1 -0
- package/dist/assets/messagebundle_tr-lAQvvdUi.js +1 -0
- package/dist/assets/messagebundle_uk-DIBItAKu.js +1 -0
- package/dist/assets/messagebundle_uk-j_sqGY4D.js +1 -0
- package/dist/assets/messagebundle_vi-C40OW2eC.js +1 -0
- package/dist/assets/messagebundle_vi-xWTpoKPI.js +1 -0
- package/dist/assets/messagebundle_zh_CN-CmeOlVfl.js +1 -0
- package/dist/assets/messagebundle_zh_CN-U8Z0kuQb.js +1 -0
- package/dist/assets/messagebundle_zh_TW-B_1_vc8O.js +1 -0
- package/dist/assets/messagebundle_zh_TW-hwHN6ElU.js +1 -0
- package/dist/assets/{parameters-bundle.css-Cv89y49I.js → parameters-bundle.css-2ZsUlBNO.js} +299 -151
- package/dist/assets/parameters-bundle.css-31Bw5XOG.js +2 -0
- package/dist/assets/parameters-bundle.css-BJp4ZvSQ.js +2 -0
- package/dist/assets/{parameters-bundle.css-vNsSPPU5.js → parameters-bundle.css-BKlkVfkE.js} +742 -494
- package/dist/assets/parameters-bundle.css-BMOU75LU.js +2 -0
- package/dist/assets/parameters-bundle.css-BZF5sWSb.js +1 -0
- package/dist/assets/{parameters-bundle.css-DmEWEk0u.js → parameters-bundle.css-Bf1GOISM.js} +786 -513
- package/dist/assets/parameters-bundle.css-BpWLGMCI.js +2 -0
- package/dist/assets/parameters-bundle.css-BsoxE2UF.js +2 -0
- package/dist/assets/parameters-bundle.css-CAhrGUcA.js +2 -0
- package/dist/assets/{parameters-bundle.css-C3eDVARm.js → parameters-bundle.css-CDJt5bvS.js} +176 -89
- package/dist/assets/parameters-bundle.css-CIr3BQBD.js +2 -0
- package/dist/assets/parameters-bundle.css-CVUmNgQM.js +2 -0
- package/dist/assets/parameters-bundle.css-C_pu3Dce.js +2 -0
- package/dist/assets/parameters-bundle.css-ChtqHIDX.js +2 -0
- package/dist/assets/parameters-bundle.css-CvaMQVtq.js +1 -0
- package/dist/assets/parameters-bundle.css-Cwz89dEH.js +2 -0
- package/dist/assets/parameters-bundle.css-CyCovTbK.js +2 -0
- package/dist/assets/parameters-bundle.css-Cyf5K2-Q.js +2 -0
- package/dist/assets/parameters-bundle.css-DdDLbfHl.js +2 -0
- package/dist/assets/{parameters-bundle.css-C5V2Zp_F.js → parameters-bundle.css-Dfz9lgd6.js} +131 -95
- package/dist/assets/{parameters-bundle.css-K-MvKimD.js → parameters-bundle.css-DjW0INFD.js} +139 -88
- package/dist/assets/parameters-bundle.css-JyFiyY-_.js +2 -0
- package/dist/assets/parameters-bundle.css-tf-z7jv9.js +2 -0
- package/dist/css/themes/MastheadShell.css +1 -1
- package/dist/css/themes/PromoTile.css +1 -1
- package/dist/css/themes/SideNavigation.css +1 -1
- package/dist/css/themes/SideNavigationMobile.css +1 -1
- package/dist/css/themes/Slider.css +1 -1
- package/dist/css/themes/sap_fiori_3/parameters-bundle.css +0 -1
- package/dist/css/themes/sap_glow/parameters-bundle.css +0 -1
- package/dist/css/themes/sap_horizon/parameters-bundle.css +0 -1
- package/dist/custom-elements-internal.json +1436 -0
- package/dist/custom-elements.json +1490 -21
- package/dist/generated/assets/themes/sap_fiori_3/parameters-bundle.css.json +1 -1
- package/dist/generated/assets/themes/sap_glow/parameters-bundle.css.json +1 -1
- package/dist/generated/assets/themes/sap_horizon/parameters-bundle.css.json +1 -1
- package/dist/generated/themes/MastheadShell.css.d.ts +1 -1
- package/dist/generated/themes/MastheadShell.css.js +1 -1
- package/dist/generated/themes/MastheadShell.css.js.map +1 -1
- package/dist/generated/themes/PromoTile.css.d.ts +1 -1
- package/dist/generated/themes/PromoTile.css.js +1 -1
- package/dist/generated/themes/PromoTile.css.js.map +1 -1
- package/dist/generated/themes/SideNavigation.css.d.ts +1 -1
- package/dist/generated/themes/SideNavigation.css.js +1 -1
- package/dist/generated/themes/SideNavigation.css.js.map +1 -1
- package/dist/generated/themes/SideNavigationMobile.css.d.ts +1 -1
- package/dist/generated/themes/SideNavigationMobile.css.js +1 -1
- package/dist/generated/themes/SideNavigationMobile.css.js.map +1 -1
- package/dist/generated/themes/Slider.css.d.ts +1 -1
- package/dist/generated/themes/Slider.css.js +1 -1
- package/dist/generated/themes/Slider.css.js.map +1 -1
- package/dist/generated/themes/sap_fiori_3/parameters-bundle.css.d.ts +1 -1
- package/dist/generated/themes/sap_fiori_3/parameters-bundle.css.js +1 -1
- package/dist/generated/themes/sap_fiori_3/parameters-bundle.css.js.map +1 -1
- package/dist/generated/themes/sap_glow/parameters-bundle.css.d.ts +1 -1
- package/dist/generated/themes/sap_glow/parameters-bundle.css.js +1 -1
- package/dist/generated/themes/sap_glow/parameters-bundle.css.js.map +1 -1
- package/dist/generated/themes/sap_horizon/parameters-bundle.css.d.ts +1 -1
- package/dist/generated/themes/sap_horizon/parameters-bundle.css.js +1 -1
- package/dist/generated/themes/sap_horizon/parameters-bundle.css.js.map +1 -1
- package/dist/vscode.html-custom-data.json +12 -2
- package/dist/web-types.json +33 -3
- package/package.json +8 -8
- package/src/AccordionItemTemplate.tsx +1 -0
- package/src/FilterMenu.ts +6 -4
- package/src/FilterMenuTemplate.tsx +12 -8
- package/src/List.ts +4 -12
- package/src/ListGroupHeaderTemplate.tsx +9 -3
- package/src/ListItem.ts +12 -1
- package/src/ListItemBase.ts +7 -0
- package/src/ListItemTemplate.tsx +6 -1
- package/src/ListSelectAllTemplate.tsx +11 -12
- package/src/MastheadCountrySelector.ts +18 -0
- package/src/MastheadCountrySelectorTemplate.tsx +2 -0
- package/src/MessageStrip.ts +7 -0
- package/src/SearchTemplate.tsx +3 -1
- package/src/SearchableListBaseTemplate.tsx +12 -12
- package/src/SideNavigation.ts +17 -0
- package/src/SideNavigationMobile.ts +52 -0
- package/src/SideNavigationMobileTemplate.tsx +3 -5
- package/src/SideNavigationSubItem.ts +17 -5
- package/src/SideNavigationSubItemTemplate.tsx +3 -1
- package/src/SideNavigationTemplate.tsx +17 -0
- package/src/generated/themes/MastheadShell.css.ts +1 -1
- package/src/generated/themes/PromoTile.css.ts +1 -1
- package/src/generated/themes/SideNavigation.css.ts +1 -1
- package/src/generated/themes/SideNavigationMobile.css.ts +1 -1
- package/src/generated/themes/Slider.css.ts +1 -1
- package/src/generated/themes/sap_fiori_3/parameters-bundle.css.ts +1 -1
- package/src/generated/themes/sap_glow/parameters-bundle.css.ts +1 -1
- package/src/generated/themes/sap_horizon/parameters-bundle.css.ts +1 -1
- package/src/themes/MastheadShell.css +14 -2
- package/src/themes/PromoTile.css +5 -0
- package/src/themes/SideNavigation.css +43 -8
- package/src/themes/SideNavigationMobile.css +1 -0
- package/src/themes/Slider.css +25 -11
- package/dist/assets/messagebundle_ar-C3EXytoC.js +0 -1
- package/dist/assets/messagebundle_ar-DmZrrjEF.js +0 -1
- package/dist/assets/messagebundle_bg-BaZ97Q_b.js +0 -1
- package/dist/assets/messagebundle_bg-CgU7GPvK.js +0 -1
- package/dist/assets/messagebundle_ca-BwjVUbUA.js +0 -1
- package/dist/assets/messagebundle_ca-YiUGbO_8.js +0 -1
- package/dist/assets/messagebundle_cnr-CN2hPZIN.js +0 -1
- package/dist/assets/messagebundle_cnr-zdEdPJvc.js +0 -1
- package/dist/assets/messagebundle_cs-CGbnEjza.js +0 -1
- package/dist/assets/messagebundle_cy-BF0YH9Iz.js +0 -1
- package/dist/assets/messagebundle_cy-CUiGsjO6.js +0 -1
- package/dist/assets/messagebundle_da-CWKLQJiq.js +0 -1
- package/dist/assets/messagebundle_da-bTkr4pUc.js +0 -1
- package/dist/assets/messagebundle_de-BmnClk4G.js +0 -1
- package/dist/assets/messagebundle_de-vB6qhgvG.js +0 -1
- package/dist/assets/messagebundle_el-DKdItEgW.js +0 -1
- package/dist/assets/messagebundle_el-Gv1Ly8aj.js +0 -1
- package/dist/assets/messagebundle_en-DbKo-Dkl.js +0 -1
- package/dist/assets/messagebundle_en-DcV886MF.js +0 -1
- package/dist/assets/messagebundle_en_GB-Be93_Z4H.js +0 -1
- package/dist/assets/messagebundle_en_GB-CFh7e8hQ.js +0 -1
- package/dist/assets/messagebundle_en_US_sappsd-HCarC-Yr.js +0 -1
- package/dist/assets/messagebundle_en_US_saprigi-CCHFk7YZ.js +0 -1
- package/dist/assets/messagebundle_en_US_saptrc-B8AIRzlo.js +0 -1
- package/dist/assets/messagebundle_en_US_saptrc-yJ3PcdEm.js +0 -1
- package/dist/assets/messagebundle_es-BH-a8BxO.js +0 -1
- package/dist/assets/messagebundle_es-Dt93wbGV.js +0 -1
- package/dist/assets/messagebundle_es_MX-BedlYlF3.js +0 -1
- package/dist/assets/messagebundle_es_MX-COPqooo9.js +0 -1
- package/dist/assets/messagebundle_et-BsYgDw46.js +0 -1
- package/dist/assets/messagebundle_et-UwpqUE-p.js +0 -1
- package/dist/assets/messagebundle_fi-BN3UWEz0.js +0 -1
- package/dist/assets/messagebundle_fi-Cwf7Puui.js +0 -1
- package/dist/assets/messagebundle_fr-43w09LAE.js +0 -1
- package/dist/assets/messagebundle_fr-CVRaf9_H.js +0 -1
- package/dist/assets/messagebundle_fr_CA-BM04X6xU.js +0 -1
- package/dist/assets/messagebundle_fr_CA-CdnVYumi.js +0 -1
- package/dist/assets/messagebundle_hi-DfeonbAH.js +0 -1
- package/dist/assets/messagebundle_hi-JRJlP9Uh.js +0 -1
- package/dist/assets/messagebundle_hr-CKOnn34q.js +0 -1
- package/dist/assets/messagebundle_hr-CbyIBlH3.js +0 -1
- package/dist/assets/messagebundle_hu-DF1gQudE.js +0 -1
- package/dist/assets/messagebundle_hu-D_IQ9kTy.js +0 -1
- package/dist/assets/messagebundle_id-B0K1usj4.js +0 -1
- package/dist/assets/messagebundle_id-gDJYoaGq.js +0 -1
- package/dist/assets/messagebundle_it-B80_R2Ih.js +0 -1
- package/dist/assets/messagebundle_it-CVqU4g6t.js +0 -1
- package/dist/assets/messagebundle_iw-BoelOIS4.js +0 -1
- package/dist/assets/messagebundle_iw-iMDtLxaa.js +0 -1
- package/dist/assets/messagebundle_ja-BlRbv4vb.js +0 -1
- package/dist/assets/messagebundle_ja-BrDH-19-.js +0 -1
- package/dist/assets/messagebundle_kk-C7VPek1-.js +0 -1
- package/dist/assets/messagebundle_kk-DhAT_bim.js +0 -1
- package/dist/assets/messagebundle_ko-CIqP8x6n.js +0 -1
- package/dist/assets/messagebundle_ko-DgD6uyZ5.js +0 -1
- package/dist/assets/messagebundle_lt-BV0kKrY0.js +0 -1
- package/dist/assets/messagebundle_lv-5IcjoxWD.js +0 -1
- package/dist/assets/messagebundle_lv-DDBi7iKe.js +0 -1
- package/dist/assets/messagebundle_mk-BUrn04sZ.js +0 -1
- package/dist/assets/messagebundle_mk-P5veRdg2.js +0 -1
- package/dist/assets/messagebundle_ms-9VDLR5en.js +0 -1
- package/dist/assets/messagebundle_ms-CB8sQUg2.js +0 -1
- package/dist/assets/messagebundle_nl-BaAgPO7h.js +0 -1
- package/dist/assets/messagebundle_nl-f1Up3dB9.js +0 -1
- package/dist/assets/messagebundle_no-C-_ldp7o.js +0 -1
- package/dist/assets/messagebundle_no-DRSqWQ-C.js +0 -1
- package/dist/assets/messagebundle_pl-BQoPaokq.js +0 -1
- package/dist/assets/messagebundle_pl-DBO1atMe.js +0 -1
- package/dist/assets/messagebundle_pt-BNEglYxa.js +0 -1
- package/dist/assets/messagebundle_pt-DgAMHmW-.js +0 -1
- package/dist/assets/messagebundle_pt_PT-BtYzp9KB.js +0 -1
- package/dist/assets/messagebundle_pt_PT-D1Ef8kUU.js +0 -1
- package/dist/assets/messagebundle_ro-CuDPp2fe.js +0 -1
- package/dist/assets/messagebundle_ro-D591wJ6f.js +0 -1
- package/dist/assets/messagebundle_ru-D0NridWi.js +0 -1
- package/dist/assets/messagebundle_ru-I8YLCfrn.js +0 -1
- package/dist/assets/messagebundle_sh-BswdbSRi.js +0 -1
- package/dist/assets/messagebundle_sh-Dw2y_oct.js +0 -1
- package/dist/assets/messagebundle_sk-BG4S4ZVk.js +0 -1
- package/dist/assets/messagebundle_sl-CAnJO_8X.js +0 -1
- package/dist/assets/messagebundle_sl-kpVWxIp_.js +0 -1
- package/dist/assets/messagebundle_sr-BTWvO8VQ.js +0 -1
- package/dist/assets/messagebundle_sr-VJmRSdj4.js +0 -1
- package/dist/assets/messagebundle_sv-B-RCgnW_.js +0 -1
- package/dist/assets/messagebundle_sv-Bd4wCcDb.js +0 -1
- package/dist/assets/messagebundle_th-CMHmLdI3.js +0 -1
- package/dist/assets/messagebundle_th-CZ1imsCy.js +0 -1
- package/dist/assets/messagebundle_tr-BfWAYIdW.js +0 -1
- package/dist/assets/messagebundle_tr-D-BnBirv.js +0 -1
- package/dist/assets/messagebundle_uk-DhxIThVl.js +0 -1
- package/dist/assets/messagebundle_uk-HU8hI0yj.js +0 -1
- package/dist/assets/messagebundle_vi-BUTqUKd4.js +0 -1
- package/dist/assets/messagebundle_vi-D1El4_Wj.js +0 -1
- package/dist/assets/messagebundle_zh_CN-Dt0azUea.js +0 -1
- package/dist/assets/messagebundle_zh_CN-Ofgx2uXY.js +0 -1
- package/dist/assets/messagebundle_zh_TW-5lv7yYS1.js +0 -1
- package/dist/assets/messagebundle_zh_TW-LSErOAsd.js +0 -1
- package/dist/assets/parameters-bundle.css-B68EyCuR.js +0 -278
- package/dist/assets/parameters-bundle.css-BkJSEiFx.js +0 -278
- package/dist/assets/parameters-bundle.css-CI4HNvFw.js +0 -1
- package/dist/assets/parameters-bundle.css-COeynv6D.js +0 -277
- package/dist/assets/parameters-bundle.css-CRa5DITh.js +0 -1
- package/dist/assets/parameters-bundle.css-CnIzAMdG.js +0 -3
- package/dist/assets/parameters-bundle.css-CsV5qbZp.js +0 -3
- package/dist/assets/parameters-bundle.css-DCvHNL3s.js +0 -3
- package/dist/assets/parameters-bundle.css-DK40uKOQ.js +0 -3
- package/dist/assets/parameters-bundle.css-DMfTAqMv.js +0 -2
- package/dist/assets/parameters-bundle.css-DO35k9r0.js +0 -2
- package/dist/assets/parameters-bundle.css-Df7wtRW4.js +0 -2
- package/dist/assets/parameters-bundle.css-DvAfqdlT.js +0 -3
- package/dist/assets/parameters-bundle.css-KoXGNyLG.js +0 -3
- package/dist/assets/parameters-bundle.css-P_M_rm9z.js +0 -3
- package/dist/assets/parameters-bundle.css-UJIxXHL5.js +0 -2
- package/dist/assets/parameters-bundle.css-co26r5Nz.js +0 -3
- package/dist/assets/parameters-bundle.css-uT62L0va.js +0 -3
|
@@ -0,0 +1,1017 @@
|
|
|
1
|
+
import { renderFinished } from "@ui5/webcomponents-base/dist/Render.js";
|
|
2
|
+
import {
|
|
3
|
+
UDExFilterMenu, UDExFilterMenuGroupHeader, UDExFilterMenuItem, UDExFilterMenuSelectAll, UDExListItem,
|
|
4
|
+
} from "../support/component-imports.js";
|
|
5
|
+
import { UDExListMode } from "../../src/types/List.js";
|
|
6
|
+
import type UDExFilterMenuElement from "../../src/FilterMenu.js";
|
|
7
|
+
import type UDExFilterMenuGroupHeaderElement from "../../src/FilterMenuGroupHeader.js";
|
|
8
|
+
import type UDExCheckboxElement from "../../src/Checkbox.js";
|
|
9
|
+
import type { UDExSearchableListBaseSelectionChangeEventDetail } from "../../src/SearchableListBase.js";
|
|
10
|
+
|
|
11
|
+
const UDExMenu = () => cy.get("[udex-filter-menu]");
|
|
12
|
+
const UDExTrigger = () => UDExMenu().shadow().find("#filterMenuTrigger");
|
|
13
|
+
const UDExPopover = () => UDExMenu().shadow().find("[ui5-popover]");
|
|
14
|
+
const UDExList = () => UDExMenu().shadow().find("[udex-list]");
|
|
15
|
+
const UDExGroup = () => UDExList().find("[udex-list-group-header]");
|
|
16
|
+
const UDExHeaderItem = () => UDExGroup().shadow().find("[udex-list-item]#group-heading");
|
|
17
|
+
const UDExHeaderRow = () => UDExHeaderItem().shadow().find('[part="item"]');
|
|
18
|
+
const UDExLeaf = (UDExIndex: number) => UDExList().find("[udex-list-item]").eq(UDExIndex);
|
|
19
|
+
const UDExLeafRow = (UDExIndex: number) => UDExLeaf(UDExIndex).shadow().find('[part="item"]');
|
|
20
|
+
const UDExNormalize = (UDExText: string | null) => (UDExText || "").replace(/\s+/g, " ").trim();
|
|
21
|
+
const UDExGroupName = "Programming Languages Digital Builders";
|
|
22
|
+
const UDExChildName = "JavaScript Frontend web development";
|
|
23
|
+
type UDExCheckedState = "false" | "true" | "mixed";
|
|
24
|
+
|
|
25
|
+
function UDExOpenMenu(UDExKey: "Enter" | "Space" = "Enter") {
|
|
26
|
+
UDExPopover().then($popover => {
|
|
27
|
+
$popover[0].addEventListener("ui5-open", cy.stub().as("popoverOpened"), { once: true });
|
|
28
|
+
});
|
|
29
|
+
// Reach the native trigger through the normal tab order, not a programmatic row focus.
|
|
30
|
+
cy.get("#before-filter-menu").click();
|
|
31
|
+
cy.realPress("Tab");
|
|
32
|
+
UDExTrigger().should("be.focused");
|
|
33
|
+
cy.realPress(UDExKey);
|
|
34
|
+
cy.get("@popoverOpened").should("have.been.calledOnce");
|
|
35
|
+
cy.then(() => renderFinished());
|
|
36
|
+
UDExTrigger().should("have.attr", "aria-expanded", "true");
|
|
37
|
+
UDExPopover().should($popover => {
|
|
38
|
+
expect($popover).to.have.attr("open");
|
|
39
|
+
expect($popover).not.to.have.class("ui5-popup-opening");
|
|
40
|
+
expect($popover[0].shadowRoot!.getAnimations().filter(UDExAnimation =>
|
|
41
|
+
UDExAnimation.pending || UDExAnimation.playState === "running")).to.have.length(0);
|
|
42
|
+
});
|
|
43
|
+
UDExList().then($list => {
|
|
44
|
+
// Flat menus legitimately have no groups; do not make group existence a retry prerequisite.
|
|
45
|
+
$list.find("[udex-list-group-header][collapsible]").toArray().forEach(UDExGroupElement => {
|
|
46
|
+
cy.wrap(UDExGroupElement).shadow().find(".udex-list__group-list__content").should($content => {
|
|
47
|
+
expect($content[0].getAnimations().filter(UDExAnimation =>
|
|
48
|
+
UDExAnimation.pending || UDExAnimation.playState === "running")).to.have.length(0);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function UDExMountGrouped(UDExState: UDExCheckedState = "false", UDExCollapsible = true, UDExRated = false) {
|
|
55
|
+
cy.mount(
|
|
56
|
+
<div id="filter-menu-a11y-fixture">
|
|
57
|
+
<button id="before-filter-menu">Previous</button>
|
|
58
|
+
<UDExFilterMenu filterName="Languages" mode={UDExListMode.MultiSelect} hideResultBtn hideResetBtn>
|
|
59
|
+
<UDExFilterMenuGroupHeader id="source-group" label="<b>Programming</b> Languages"
|
|
60
|
+
supportingText="Digital Builders" collapsible={UDExCollapsible}
|
|
61
|
+
selected={UDExState !== "false"} indeterminate={UDExState === "mixed"}>
|
|
62
|
+
<UDExFilterMenuItem id="source-javascript" label="<b>Java</b>Script"
|
|
63
|
+
supportingText="Frontend web development" selected={UDExState !== "false"}
|
|
64
|
+
rating={UDExRated ? "4" : undefined} ratingCount={UDExRated ? "4.0" : undefined}
|
|
65
|
+
totalCount={UDExRated ? "20" : undefined}></UDExFilterMenuItem>
|
|
66
|
+
<UDExFilterMenuItem id="source-python" label="Python" supportingText="Data analysis"
|
|
67
|
+
selected={UDExState === "true"}></UDExFilterMenuItem>
|
|
68
|
+
</UDExFilterMenuGroupHeader>
|
|
69
|
+
</UDExFilterMenu>
|
|
70
|
+
<button id="after-filter-menu">Next</button>
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
cy.get("#filter-menu-a11y-fixture").then($fixture => {
|
|
74
|
+
$fixture[0].addEventListener("selection-change", cy.stub().as("selectionChange"));
|
|
75
|
+
});
|
|
76
|
+
UDExOpenMenu();
|
|
77
|
+
UDExHeaderRow().should("be.focused");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function UDExAssertDecorativeCheckbox(UDExItem: Cypress.Chainable<JQuery<HTMLElement>>,
|
|
81
|
+
UDExSelected: boolean, UDExIndeterminate = false) {
|
|
82
|
+
UDExItem.shadow().find("[udex-checkbox]").should($checkbox => {
|
|
83
|
+
expect($checkbox).to.have.attr("aria-hidden", "true");
|
|
84
|
+
expect($checkbox).to.have.attr("tabindex", "-1");
|
|
85
|
+
expect($checkbox).not.to.have.attr("accessible-name");
|
|
86
|
+
expect($checkbox).not.to.have.attr("aria-label");
|
|
87
|
+
expect($checkbox).not.to.have.attr("aria-labelledby");
|
|
88
|
+
const UDExCheckbox = $checkbox[0] as UDExCheckboxElement;
|
|
89
|
+
expect(UDExCheckbox.accessibleName || "").to.equal("");
|
|
90
|
+
expect(UDExCheckbox.checked).to.equal(UDExSelected);
|
|
91
|
+
expect(Boolean(UDExCheckbox.indeterminate)).to.equal(UDExIndeterminate);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function UDExAssertTreeRow(UDExRow: Cypress.Chainable<JQuery<HTMLElement>>, UDExName: string,
|
|
96
|
+
UDExState: UDExCheckedState) {
|
|
97
|
+
UDExRow.should($row => {
|
|
98
|
+
expect($row).to.have.attr("role", "treeitem");
|
|
99
|
+
expect($row).to.have.attr("aria-label", UDExName);
|
|
100
|
+
expect($row).to.have.attr("aria-checked", UDExState);
|
|
101
|
+
expect($row).not.to.have.attr("aria-selected");
|
|
102
|
+
expect($row).not.to.have.attr("aria-hidden");
|
|
103
|
+
expect($row.attr("aria-label")).not.to.match(/checkbox|selected|unselected|expand|collapse/i);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function assertRawRowName(item: Cypress.Chainable<JQuery<HTMLElement>>, expected: string, expectedHolder = expected) {
|
|
108
|
+
item.shadow().find(".udex-list__content-wrap").should($wrapper => {
|
|
109
|
+
const wrapper = $wrapper[0];
|
|
110
|
+
const root = wrapper.getRootNode() as ShadowRoot;
|
|
111
|
+
const row = root.querySelector('[part="item"]')!;
|
|
112
|
+
const content = wrapper.querySelector(".udex-list__content")!;
|
|
113
|
+
const textHolder = content.querySelector(".udex-list__text-holder")!;
|
|
114
|
+
const normalize = (text: string | null) => (text || "").replace(/\s+/g, " ").trim();
|
|
115
|
+
// Read the shared containers, not a space-joined reconstruction of their spans.
|
|
116
|
+
expect(normalize(textHolder.textContent)).to.equal(expectedHolder);
|
|
117
|
+
expect(normalize(content.textContent)).to.equal(expected);
|
|
118
|
+
expect(row).to.have.attr("aria-label", normalize(content.textContent));
|
|
119
|
+
expect(wrapper).to.have.attr("aria-label", expected);
|
|
120
|
+
const nameId = wrapper.getAttribute("aria-labelledby")!;
|
|
121
|
+
expect(nameId).to.equal(`${wrapper.getAttribute("_id")}-invisibleText`);
|
|
122
|
+
const source = root.getElementById(nameId);
|
|
123
|
+
expect(source, "hidden name source resolves in the row's own shadow root").not.to.equal(null);
|
|
124
|
+
expect(source!.getRootNode()).to.equal(root);
|
|
125
|
+
expect(source).to.have.class("hidden");
|
|
126
|
+
expect(normalize(source!.textContent)).to.equal(expected);
|
|
127
|
+
expect(normalize(source!.textContent)).to.equal(normalize(content.textContent));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function UDExAssertSelectionEvent(UDExSourceId: string, UDExSelectedIds: string[], UDExCallCount: number) {
|
|
132
|
+
UDExMenu().then($menu => {
|
|
133
|
+
const UDExSource = (UDExId: string) => $menu[0].querySelector(`#${UDExId}`);
|
|
134
|
+
const UDExExpectedItems = UDExSelectedIds.map(UDExSource);
|
|
135
|
+
expect(UDExExpectedItems.every(Boolean), "expected source nodes exist").to.equal(true);
|
|
136
|
+
cy.get("@selectionChange").should("have.callCount", UDExCallCount).its("lastCall.args.0.detail")
|
|
137
|
+
.should((UDExDetail: UDExSearchableListBaseSelectionChangeEventDetail) => {
|
|
138
|
+
expect(UDExDetail.item, "event identifies the original source, not its popup clone").to.equal(UDExSource(UDExSourceId));
|
|
139
|
+
expect(UDExDetail.selectedItems).to.have.length(UDExExpectedItems.length);
|
|
140
|
+
UDExDetail.selectedItems.forEach((UDExItem, UDExIndex) => {
|
|
141
|
+
expect(UDExItem).to.equal(UDExExpectedItems[UDExIndex]);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
UDExMenu().should($current => {
|
|
145
|
+
const UDExSelected = ($current[0] as UDExFilterMenuElement).selectedItems;
|
|
146
|
+
expect(UDExSelected).to.have.length(UDExExpectedItems.length);
|
|
147
|
+
UDExSelected.forEach((UDExItem, UDExIndex) => expect(UDExItem).to.equal(UDExExpectedItems[UDExIndex]));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function UDExAssertLocalGroupName(UDExElement: Cypress.Chainable<JQuery<HTMLElement>>, UDExExpected: string) {
|
|
153
|
+
UDExElement.should($element => {
|
|
154
|
+
const UDExRoot = $element[0].getRootNode() as ShadowRoot;
|
|
155
|
+
expect($element).to.have.attr("aria-labelledby", "group-heading group-supporting-text");
|
|
156
|
+
const UDExIds = $element.attr("aria-labelledby")!.split(/\s+/);
|
|
157
|
+
const UDExName = UDExIds.map(UDExId => {
|
|
158
|
+
const UDExLabel = UDExRoot.getElementById(UDExId);
|
|
159
|
+
expect(UDExLabel, `${UDExId} resolves in the row's own shadow root`).not.to.equal(null);
|
|
160
|
+
expect(UDExLabel!.getRootNode()).to.equal(UDExRoot);
|
|
161
|
+
return UDExNormalize(UDExLabel!.textContent);
|
|
162
|
+
}).join(" ");
|
|
163
|
+
expect(UDExName).to.equal(UDExExpected);
|
|
164
|
+
expect(UDExNormalize(UDExRoot.querySelector(".udex-list__header")!.textContent)).to.equal(UDExName);
|
|
165
|
+
expect($element).not.to.have.attr("aria-describedby");
|
|
166
|
+
expect($element).not.to.have.attr("aria-description");
|
|
167
|
+
expect(UDExName).not.to.match(/expand|collapse|checkbox/i);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
describe("FilterMenu accessibility regressions", () => {
|
|
172
|
+
describe("Trigger label in name", () => {
|
|
173
|
+
const UDExWindow = window as Window & { "udex-config"?: { translations?: Record<string, string> } };
|
|
174
|
+
let UDExOriginalConfig: typeof UDExWindow["udex-config"];
|
|
175
|
+
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
UDExOriginalConfig = UDExWindow["udex-config"];
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
afterEach(() => {
|
|
181
|
+
if (UDExOriginalConfig === undefined) {
|
|
182
|
+
delete UDExWindow["udex-config"];
|
|
183
|
+
} else {
|
|
184
|
+
UDExWindow["udex-config"] = UDExOriginalConfig;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const UDExAssertTriggerName = (UDExExpected: string) => UDExTrigger().should($trigger => {
|
|
189
|
+
expect($trigger).to.have.attr("role", "button");
|
|
190
|
+
expect($trigger).to.have.attr("aria-label", UDExExpected);
|
|
191
|
+
const UDExVisibleText = UDExNormalize($trigger[0].textContent);
|
|
192
|
+
expect(UDExVisibleText).to.equal(UDExExpected);
|
|
193
|
+
expect($trigger.attr("aria-label")).to.contain(UDExVisibleText);
|
|
194
|
+
expect($trigger.attr("aria-label")).not.to.match(/select options/i);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
[
|
|
198
|
+
{ name: "filter name", prefix: "", label: "Languages", badge: undefined, expected: "Languages" },
|
|
199
|
+
{ name: "prefix, name and numeric badge", prefix: "Filter by:", label: "Languages", badge: 3, expected: "Filter by: Languages 3" },
|
|
200
|
+
{ name: "prefix only without a zero badge", prefix: "Filter by:", label: "", badge: 0, expected: "Filter by:" },
|
|
201
|
+
{ name: "numeric badge only", prefix: "", label: "", badge: 7, expected: "7" },
|
|
202
|
+
].forEach(UDExCase => {
|
|
203
|
+
it(`uses the exact visible ${UDExCase.name}, with literal word boundaries`, () => {
|
|
204
|
+
cy.mount(<UDExFilterMenu filterNamePrefix={UDExCase.prefix} filterName={UDExCase.label} badgeValue={UDExCase.badge} />);
|
|
205
|
+
UDExAssertTriggerName(UDExCase.expected);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("reacts to prefix, name and badge changes, omitting a badge when it becomes zero", () => {
|
|
210
|
+
cy.mount(<UDExFilterMenu filterNamePrefix="Filter by:" filterName="Languages" badgeValue={2} />);
|
|
211
|
+
UDExAssertTriggerName("Filter by: Languages 2");
|
|
212
|
+
UDExMenu().then($menu => {
|
|
213
|
+
const UDExElement = $menu[0] as UDExFilterMenuElement;
|
|
214
|
+
UDExElement.filterNamePrefix = "Show:";
|
|
215
|
+
UDExElement.filterName = "Platforms";
|
|
216
|
+
UDExElement.badgeValue = 5;
|
|
217
|
+
});
|
|
218
|
+
UDExAssertTriggerName("Show: Platforms 5");
|
|
219
|
+
UDExMenu().invoke("prop", "badgeValue", 0);
|
|
220
|
+
UDExAssertTriggerName("Show: Platforms");
|
|
221
|
+
UDExTrigger().find("[udex-badge]").should("not.exist");
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it("preserves an explicit accessibleName until cleared, then restores the visible name", () => {
|
|
225
|
+
cy.mount(<UDExFilterMenu filterName="Languages" badgeValue={2} accessibleName="Choose programming languages" />);
|
|
226
|
+
UDExTrigger().should("have.attr", "aria-label", "Choose programming languages");
|
|
227
|
+
UDExMenu().invoke("prop", "badgeValue", 4);
|
|
228
|
+
UDExTrigger().find("[udex-badge]").should("have.text", "4");
|
|
229
|
+
UDExTrigger().should("have.attr", "aria-label", "Choose programming languages");
|
|
230
|
+
UDExMenu().invoke("prop", "accessibleName", "");
|
|
231
|
+
UDExAssertTriggerName("Languages 4");
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("forwards accessibleNameRef unchanged to local aria-labelledby targets without replacing the explicit aria-label", () => {
|
|
235
|
+
cy.mount(
|
|
236
|
+
<div>
|
|
237
|
+
<span id="outside-filter-label">Outside label</span>
|
|
238
|
+
<UDExFilterMenu filterName="Languages" accessibleName="Explicit language menu"
|
|
239
|
+
accessibleNameRef="local-filter-label local-filter-context" />
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
UDExMenu().then($menu => {
|
|
243
|
+
// The API forwards IDREFs; it does not bridge light-DOM labels across the shadow boundary.
|
|
244
|
+
const UDExRoot = $menu[0].shadowRoot!;
|
|
245
|
+
[["local-filter-label", "Language filters"], ["local-filter-context", "Available choices"]].forEach(([UDExId, UDExText]) => {
|
|
246
|
+
const UDExLabel = $menu[0].ownerDocument.createElement("span");
|
|
247
|
+
UDExLabel.id = UDExId;
|
|
248
|
+
UDExLabel.textContent = UDExText;
|
|
249
|
+
UDExRoot.append(UDExLabel);
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
UDExTrigger().should($trigger => {
|
|
253
|
+
expect($trigger).to.have.attr("aria-label", "Explicit language menu");
|
|
254
|
+
expect($trigger).to.have.attr("aria-labelledby", "local-filter-label local-filter-context");
|
|
255
|
+
const UDExRoot = $trigger[0].getRootNode() as ShadowRoot;
|
|
256
|
+
const UDExName = $trigger.attr("aria-labelledby")!.split(" ")
|
|
257
|
+
.map(UDExId => UDExRoot.getElementById(UDExId)!.textContent).join(" ");
|
|
258
|
+
expect(UDExName).to.equal("Language filters Available choices");
|
|
259
|
+
expect(UDExRoot.getElementById("outside-filter-label")).to.equal(null);
|
|
260
|
+
});
|
|
261
|
+
UDExMenu().invoke("prop", "accessibleNameRef", "");
|
|
262
|
+
UDExTrigger().should($trigger => {
|
|
263
|
+
expect($trigger.attr("aria-labelledby") || "").to.equal("");
|
|
264
|
+
expect($trigger).to.have.attr("aria-label", "Explicit language menu");
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("uses the localized SELECT_OPTIONS fallback only when no visible label or nonzero badge exists", () => {
|
|
269
|
+
UDExWindow["udex-config"] = {
|
|
270
|
+
...UDExOriginalConfig,
|
|
271
|
+
translations: { ...UDExOriginalConfig?.translations, SELECT_OPTIONS: "Optionen auswählen" },
|
|
272
|
+
};
|
|
273
|
+
cy.mount(<UDExFilterMenu badgeValue={0} />);
|
|
274
|
+
UDExTrigger().should($trigger => {
|
|
275
|
+
expect(UDExNormalize($trigger[0].textContent)).to.equal("");
|
|
276
|
+
expect($trigger).to.have.attr("aria-label", "Optionen auswählen");
|
|
277
|
+
});
|
|
278
|
+
UDExMenu().invoke("prop", "filterName", "Languages");
|
|
279
|
+
UDExAssertTriggerName("Languages");
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
describe("Real-focus row names and native selection", () => {
|
|
284
|
+
[false, true].forEach(UDExCollapsible => {
|
|
285
|
+
// Updated: raw shared-container text must retain the same literal word boundaries as both name sources.
|
|
286
|
+
it(`names ${UDExCollapsible ? "collapsible" : "noncollapsible"} MultiSelect headers and children completely without decorative state words`, () => {
|
|
287
|
+
UDExMountGrouped("false", UDExCollapsible);
|
|
288
|
+
UDExAssertTreeRow(UDExHeaderRow(), UDExGroupName, "false");
|
|
289
|
+
UDExAssertTreeRow(UDExLeafRow(0), UDExChildName, "false");
|
|
290
|
+
assertRawRowName(UDExHeaderItem(), UDExGroupName);
|
|
291
|
+
assertRawRowName(UDExLeaf(0), UDExChildName);
|
|
292
|
+
UDExAssertDecorativeCheckbox(UDExHeaderItem(), false);
|
|
293
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), false);
|
|
294
|
+
UDExHeaderItem().shadow().find('[part="title"]').should("have.text", "Programming Languages");
|
|
295
|
+
UDExHeaderItem().shadow().find('[part="supporting"]').should("have.text", "Digital Builders");
|
|
296
|
+
UDExLeaf(0).shadow().find('[part="title"]').should("have.text", "JavaScript");
|
|
297
|
+
cy.realPress("ArrowDown");
|
|
298
|
+
UDExLeafRow(0).should("be.focused");
|
|
299
|
+
assertRawRowName(UDExLeaf(0), UDExChildName);
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it("keeps literal label/support boundaries in nonInteractive noncollapsible and collapsible headers", () => {
|
|
304
|
+
[false, true].forEach(collapsible => {
|
|
305
|
+
cy.mount(
|
|
306
|
+
<div>
|
|
307
|
+
<button id="before-filter-menu">Previous</button>
|
|
308
|
+
<UDExFilterMenu filterName="Languages" mode={UDExListMode.MultiSelect} hideResultBtn hideResetBtn>
|
|
309
|
+
<UDExFilterMenuGroupHeader nonInteractive collapsible={collapsible}
|
|
310
|
+
label="<b>Programming</b> Languages" supportingText="Digital Builders">
|
|
311
|
+
<UDExFilterMenuItem label="JavaScript" supportingText="Frontend web development" />
|
|
312
|
+
</UDExFilterMenuGroupHeader>
|
|
313
|
+
</UDExFilterMenu>
|
|
314
|
+
</div>
|
|
315
|
+
);
|
|
316
|
+
UDExOpenMenu();
|
|
317
|
+
UDExGroup().shadow().find(".udex-list__inactive-header-content").should($content => {
|
|
318
|
+
const normalize = (text: string | null) => (text || "").replace(/\s+/g, " ").trim();
|
|
319
|
+
expect(normalize($content[0].textContent)).to.equal(UDExGroupName);
|
|
320
|
+
expect($content[0].querySelector(".udex-list__header-title")!.textContent)
|
|
321
|
+
.to.equal("Programming Languages");
|
|
322
|
+
expect(normalize($content[0].parentElement!.textContent)).to.equal(UDExGroupName);
|
|
323
|
+
});
|
|
324
|
+
UDExGroup().shadow().find("[udex-list-item]#group-heading").should("not.exist");
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("includes rating metadata after the grouped child's label and supporting text", () => {
|
|
329
|
+
UDExMountGrouped("false", true, true);
|
|
330
|
+
UDExAssertTreeRow(UDExLeafRow(0), `${UDExChildName} Rating 4.0, Total 20, Rating Indicator 4 of 5`, "false");
|
|
331
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), false);
|
|
332
|
+
UDExLeaf(0).shadow().find("[udex-rating-indicator]")
|
|
333
|
+
.should("have.attr", "aria-label", "Rating 4.0, Total 20, Rating Indicator 4 of 5");
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
["pointer", "Enter", "Space"].forEach(UDExActivation => {
|
|
337
|
+
it(`preserves real-focus row identity and exact source event payloads through false → true → mixed via ${UDExActivation}`, () => {
|
|
338
|
+
UDExMountGrouped();
|
|
339
|
+
const UDExIdentities = new Map<string, HTMLElement>();
|
|
340
|
+
const UDExNodeQueries = [UDExGroup, UDExHeaderItem, UDExHeaderRow, () => UDExLeaf(0), () => UDExLeafRow(0)];
|
|
341
|
+
UDExNodeQueries.forEach((UDExQuery, UDExIndex) => {
|
|
342
|
+
UDExQuery().then($node => { UDExIdentities.set(String(UDExIndex), $node[0]); });
|
|
343
|
+
});
|
|
344
|
+
const UDExAssertIdentities = () => UDExNodeQueries.forEach((UDExQuery, UDExIndex) => {
|
|
345
|
+
UDExQuery().should($node => expect($node[0]).to.equal(UDExIdentities.get(String(UDExIndex))));
|
|
346
|
+
});
|
|
347
|
+
UDExAssertTreeRow(UDExHeaderRow(), UDExGroupName, "false");
|
|
348
|
+
if (UDExActivation === "pointer") {
|
|
349
|
+
UDExHeaderRow().click();
|
|
350
|
+
} else {
|
|
351
|
+
cy.realPress(UDExActivation);
|
|
352
|
+
}
|
|
353
|
+
UDExHeaderRow().should("be.focused");
|
|
354
|
+
UDExAssertTreeRow(UDExHeaderRow(), UDExGroupName, "true");
|
|
355
|
+
UDExAssertTreeRow(UDExLeafRow(0), UDExChildName, "true");
|
|
356
|
+
UDExAssertDecorativeCheckbox(UDExHeaderItem(), true);
|
|
357
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), true);
|
|
358
|
+
UDExAssertSelectionEvent("source-group", ["source-group", "source-javascript", "source-python"], 1);
|
|
359
|
+
UDExAssertIdentities();
|
|
360
|
+
|
|
361
|
+
cy.realPress("ArrowDown");
|
|
362
|
+
UDExLeafRow(0).should("be.focused");
|
|
363
|
+
if (UDExActivation === "pointer") {
|
|
364
|
+
UDExLeafRow(0).click();
|
|
365
|
+
} else {
|
|
366
|
+
cy.realPress(UDExActivation);
|
|
367
|
+
}
|
|
368
|
+
UDExLeafRow(0).should("be.focused");
|
|
369
|
+
UDExAssertTreeRow(UDExLeafRow(0), UDExChildName, "false");
|
|
370
|
+
UDExAssertTreeRow(UDExHeaderRow(), UDExGroupName, "mixed");
|
|
371
|
+
UDExAssertDecorativeCheckbox(UDExHeaderItem(), true, true);
|
|
372
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), false);
|
|
373
|
+
UDExAssertSelectionEvent("source-javascript", ["source-group", "source-python"], 2);
|
|
374
|
+
UDExAssertIdentities();
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
[UDExListMode.SingleSelect, UDExListMode.MultiSelect].forEach(UDExMode => {
|
|
379
|
+
// Updated: include the raw additional-text boundary and the same-shadow hidden name source.
|
|
380
|
+
it(`gives flat ${UDExMode} options complete label/support/additional names and native aria-selected`, () => {
|
|
381
|
+
cy.mount(
|
|
382
|
+
<div id="filter-menu-a11y-fixture">
|
|
383
|
+
<button id="before-filter-menu">Previous</button>
|
|
384
|
+
<UDExFilterMenu filterName="Languages" mode={UDExMode} hideResultBtn hideResetBtn>
|
|
385
|
+
{/* FilterMenu accepts HTMLElement sources; ListItem exposes additionalText, unlike FilterMenuItem. */}
|
|
386
|
+
<UDExListItem id="source-flat" label="<b>Java</b>Script" supportingText="Frontend web development"
|
|
387
|
+
additionalText="Code JS"></UDExListItem>
|
|
388
|
+
</UDExFilterMenu>
|
|
389
|
+
</div>
|
|
390
|
+
);
|
|
391
|
+
cy.get("#filter-menu-a11y-fixture").then($fixture => {
|
|
392
|
+
$fixture[0].addEventListener("selection-change", cy.stub().as("selectionChange"));
|
|
393
|
+
});
|
|
394
|
+
UDExOpenMenu("Space");
|
|
395
|
+
const UDExName = `${UDExChildName} Code JS`;
|
|
396
|
+
assertRawRowName(UDExLeaf(0), UDExName, UDExChildName);
|
|
397
|
+
UDExLeaf(0).shadow().find('[part="title"]').should("have.text", "JavaScript");
|
|
398
|
+
UDExLeafRow(0).should($row => {
|
|
399
|
+
expect($row).to.have.attr("role", "option");
|
|
400
|
+
expect($row).to.have.attr("aria-label", UDExName);
|
|
401
|
+
expect($row).to.have.attr("aria-selected", "false");
|
|
402
|
+
expect($row).not.to.have.attr("aria-checked");
|
|
403
|
+
});
|
|
404
|
+
if (UDExMode === UDExListMode.MultiSelect) {
|
|
405
|
+
UDExLeafRow(0).should("be.focused");
|
|
406
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), false);
|
|
407
|
+
}
|
|
408
|
+
UDExLeafRow(0).click();
|
|
409
|
+
UDExLeafRow(0).should($row => {
|
|
410
|
+
expect($row).to.have.attr("aria-label", UDExName);
|
|
411
|
+
expect($row).to.have.attr("aria-selected", "true");
|
|
412
|
+
expect($row).not.to.have.attr("aria-checked");
|
|
413
|
+
});
|
|
414
|
+
UDExAssertSelectionEvent("source-flat", ["source-flat"], 1);
|
|
415
|
+
if (UDExMode === UDExListMode.MultiSelect) {
|
|
416
|
+
UDExLeafRow(0).should("be.focused");
|
|
417
|
+
UDExAssertDecorativeCheckbox(UDExLeaf(0), true);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
describe("Select All has its own root count in a real-focus tree", () => {
|
|
424
|
+
const UDExSelectAll = () => UDExList().find("[udex-list-select-all]");
|
|
425
|
+
const UDExSelectAllItem = () => UDExSelectAll().shadow().find('[udex-list-item][part="group-item"]');
|
|
426
|
+
const UDExSelectAllRow = () => UDExSelectAllItem().shadow().find('[part="item"]');
|
|
427
|
+
const UDExChildren = () => UDExSelectAll().children("[udex-list-item]");
|
|
428
|
+
const UDExChild = (UDExIndex: number) => UDExChildren().eq(UDExIndex);
|
|
429
|
+
const UDExChildRow = (UDExIndex: number) => UDExChild(UDExIndex).shadow().find('[part="item"]');
|
|
430
|
+
const UDExSupport = "Available languages";
|
|
431
|
+
const UDExHeaderName = `Select All ${UDExSupport}`;
|
|
432
|
+
const UDExChoices = [
|
|
433
|
+
{ id: "source-javascript", label: "JavaScript", support: "Frontend development" },
|
|
434
|
+
{ id: "source-java", label: "Java", support: "Application development" },
|
|
435
|
+
{ id: "source-python", label: "Python", support: "Data analysis" },
|
|
436
|
+
];
|
|
437
|
+
|
|
438
|
+
function UDExMountSelectAll({ UDExDisabledChild = false, UDExSearch = false, UDExRootLeaf = false } = {}) {
|
|
439
|
+
cy.mount(
|
|
440
|
+
<div id="filter-menu-a11y-fixture">
|
|
441
|
+
<button id="before-filter-menu">Previous</button>
|
|
442
|
+
<UDExFilterMenu filterName="Languages" mode={UDExListMode.MultiSelect}
|
|
443
|
+
showSearchInput={UDExSearch} hideResultBtn hideResetBtn>
|
|
444
|
+
<UDExFilterMenuSelectAll id="source-select-all" supportingText={UDExSupport}>
|
|
445
|
+
{UDExChoices.map((UDExChoice, UDExIndex) => (
|
|
446
|
+
<UDExFilterMenuItem id={UDExChoice.id} label={UDExChoice.label} supportingText={UDExChoice.support}
|
|
447
|
+
disabled={UDExDisabledChild && UDExIndex === 1}></UDExFilterMenuItem>
|
|
448
|
+
))}
|
|
449
|
+
</UDExFilterMenuSelectAll>
|
|
450
|
+
{UDExRootLeaf && <UDExFilterMenuItem id="source-root-leaf" label="Other language"></UDExFilterMenuItem>}
|
|
451
|
+
</UDExFilterMenu>
|
|
452
|
+
<button id="after-filter-menu">Next</button>
|
|
453
|
+
</div>
|
|
454
|
+
);
|
|
455
|
+
cy.get("#filter-menu-a11y-fixture").then($fixture => {
|
|
456
|
+
$fixture[0].addEventListener("selection-change", cy.stub().as("selectionChange"));
|
|
457
|
+
$fixture[0].addEventListener("select-all", cy.stub().as("selectAll"));
|
|
458
|
+
});
|
|
459
|
+
UDExOpenMenu();
|
|
460
|
+
if (UDExSearch) {
|
|
461
|
+
UDExMenu().shadow().find("[udex-search]").shadow().find("#search-input").should("be.focused");
|
|
462
|
+
} else {
|
|
463
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function UDExAssertFocusedRow(UDExRow: Cypress.Chainable<JQuery<HTMLElement>>) {
|
|
468
|
+
UDExRow.should("be.focused").should($row => {
|
|
469
|
+
let UDExActive = $row[0].ownerDocument.activeElement;
|
|
470
|
+
while (UDExActive?.shadowRoot?.activeElement) {
|
|
471
|
+
UDExActive = UDExActive.shadowRoot.activeElement;
|
|
472
|
+
}
|
|
473
|
+
expect(UDExActive, "deep DOM focus is the native row, not its transparent host").to.equal($row[0]);
|
|
474
|
+
expect(($row[0].getRootNode() as ShadowRoot).activeElement).to.equal($row[0]);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function UDExAllElements(UDExRoot: Element | ShadowRoot): Element[] {
|
|
479
|
+
return Array.from(UDExRoot.querySelectorAll("*")).flatMap(UDExElement => [
|
|
480
|
+
UDExElement, ...(UDExElement.shadowRoot ? UDExAllElements(UDExElement.shadowRoot) : []),
|
|
481
|
+
]);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function UDExAssertTransparentHosts(UDExHosts: Cypress.Chainable<JQuery<HTMLElement>>) {
|
|
485
|
+
UDExHosts.should($hosts => {
|
|
486
|
+
$hosts.toArray().forEach(UDExHost => {
|
|
487
|
+
expect(UDExHost).to.have.attr("role", "none");
|
|
488
|
+
["aria-current", "aria-checked", "aria-selected", "aria-level", "aria-posinset", "aria-setsize"].forEach(UDExAttr => {
|
|
489
|
+
expect(UDExHost, `transparent host omits ${UDExAttr}`).not.to.have.attr(UDExAttr);
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function UDExAssertHierarchy(UDExExpectedChildren = UDExChoices, UDExRootCount = 1) {
|
|
496
|
+
UDExList().should("have.attr", "aria-multiselectable", "true");
|
|
497
|
+
UDExList().shadow().find("#udex-list").should("have.attr", "role", "tree");
|
|
498
|
+
[UDExList, UDExSelectAll, UDExSelectAllItem, UDExChildren].forEach(UDExQuery => UDExAssertTransparentHosts(UDExQuery()));
|
|
499
|
+
UDExSelectAllItem().should("have.attr", "accessible-role", "treeitem");
|
|
500
|
+
UDExSelectAllRow().should($row => {
|
|
501
|
+
expect($row).to.have.attr("role", "treeitem");
|
|
502
|
+
expect($row).to.have.attr("aria-level", "1");
|
|
503
|
+
expect($row).to.have.attr("aria-posinset", "1");
|
|
504
|
+
expect($row).to.have.attr("aria-setsize", String(UDExRootCount));
|
|
505
|
+
expect($row).not.to.have.attr("aria-expanded");
|
|
506
|
+
});
|
|
507
|
+
UDExChildren().should("have.length", UDExExpectedChildren.length);
|
|
508
|
+
UDExExpectedChildren.forEach((UDExChoice, UDExIndex) => {
|
|
509
|
+
UDExChild(UDExIndex).should("have.attr", "accessible-role", "treeitem");
|
|
510
|
+
UDExChildRow(UDExIndex).should($row => {
|
|
511
|
+
expect($row).to.have.attr("role", "treeitem");
|
|
512
|
+
expect($row).to.have.attr("aria-label", `${UDExChoice.label} ${UDExChoice.support}`);
|
|
513
|
+
expect($row).to.have.attr("aria-level", "2");
|
|
514
|
+
expect($row).to.have.attr("aria-posinset", String(UDExIndex + 1));
|
|
515
|
+
expect($row).to.have.attr("aria-setsize", String(UDExExpectedChildren.length));
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
UDExSelectAll().shadow().find(".udex-list__group, .udex-list__group-list").should($wrappers => {
|
|
519
|
+
expect($wrappers).to.have.length(2);
|
|
520
|
+
$wrappers.toArray().forEach(UDExWrapper => expect(UDExWrapper).to.have.attr("role", "none"));
|
|
521
|
+
});
|
|
522
|
+
// Like GroupHeader, the child group is a same-shadow sibling of the header host.
|
|
523
|
+
// Explicit native levels/counts are checked; this is not proof of spoken AT hierarchy.
|
|
524
|
+
UDExSelectAllItem().should($item => {
|
|
525
|
+
const UDExGroup = $item[0].nextElementSibling!;
|
|
526
|
+
expect(UDExGroup).to.have.attr("role", "group");
|
|
527
|
+
expect(UDExGroup.getRootNode()).to.equal($item[0].getRootNode());
|
|
528
|
+
expect(UDExGroup.querySelector("slot")!.assignedElements()).to.have.length(UDExExpectedChildren.length);
|
|
529
|
+
});
|
|
530
|
+
UDExList().should($list => {
|
|
531
|
+
const UDExElements = UDExAllElements($list[0]);
|
|
532
|
+
expect(UDExElements.filter(UDExElement => UDExElement.matches('[role="option"], [role="listbox"]')),
|
|
533
|
+
"no options or nested listboxes across any popup list shadow root").to.have.length(0);
|
|
534
|
+
expect(UDExElements.filter(UDExElement => UDExElement.matches('[role="treeitem"]')))
|
|
535
|
+
.to.have.length(UDExExpectedChildren.length + UDExRootCount);
|
|
536
|
+
expect(UDExElements.filter(UDExElement => UDExElement.matches(
|
|
537
|
+
'[aria-live], [role="status"], [id$="-treeposition"], [aria-activedescendant], [aria-current]'
|
|
538
|
+
)), "no scripted navigation speech or current-item surrogate").to.have.length(0);
|
|
539
|
+
UDExElements.filter(UDExElement => UDExElement.matches('[role="treeitem"]')).forEach(UDExRow => {
|
|
540
|
+
["aria-selected", "aria-describedby", "aria-description"].forEach(UDExAttr => {
|
|
541
|
+
expect(UDExRow).not.to.have.attr(UDExAttr);
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function UDExTrackSelectAllNodes() {
|
|
548
|
+
const UDExQueries = [UDExSelectAll, UDExSelectAllItem, UDExSelectAllRow,
|
|
549
|
+
...Array.from(UDExChoices.keys()).flatMap(UDExIndex => [() => UDExChild(UDExIndex), () => UDExChildRow(UDExIndex)])];
|
|
550
|
+
const UDExOriginals: HTMLElement[] = [];
|
|
551
|
+
UDExQueries.forEach(UDExQuery => UDExQuery().then($node => { UDExOriginals.push($node[0]); }));
|
|
552
|
+
return () => UDExQueries.forEach((UDExQuery, UDExIndex) => {
|
|
553
|
+
UDExQuery().should($node => expect($node[0], "rendered node identity survives navigation/selection")
|
|
554
|
+
.to.equal(UDExOriginals[UDExIndex]));
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function UDExAssertSourceSelection(UDExSelectedIds: string[]) {
|
|
559
|
+
UDExMenu().should($menu => {
|
|
560
|
+
const UDExExpected = UDExSelectedIds.map(UDExId => $menu[0].querySelector(`#${UDExId}`));
|
|
561
|
+
expect(UDExExpected.every(Boolean)).to.equal(true);
|
|
562
|
+
const UDExSelected = ($menu[0] as UDExFilterMenuElement).selectedItems;
|
|
563
|
+
expect(UDExSelected).to.have.length(UDExExpected.length);
|
|
564
|
+
UDExSelected.forEach((UDExItem, UDExIndex) => expect(UDExItem).to.equal(UDExExpected[UDExIndex]));
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function UDExAssertBulkEvent(UDExCount: number, UDExSelectionCount: number, UDExSelectedIds: string[]) {
|
|
569
|
+
UDExMenu().then($menu => {
|
|
570
|
+
cy.get("@selectAll").should("have.callCount", UDExCount).its("lastCall.args.0").should((UDExEvent: CustomEvent) => {
|
|
571
|
+
expect(UDExEvent.target, "public event comes from FilterMenu, not its internal Select All clone").to.equal($menu[0]);
|
|
572
|
+
expect(UDExEvent.bubbles).to.equal(true);
|
|
573
|
+
expect(UDExEvent.detail, "select-all is payloadless, unlike selection-change").to.be.oneOf([null, undefined]);
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
cy.get("@selectionChange").should("have.callCount", UDExSelectionCount);
|
|
577
|
+
UDExAssertSourceSelection(UDExSelectedIds);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function UDExAssertSelectAllState(UDExState: UDExCheckedState, UDExStates: UDExCheckedState[]) {
|
|
581
|
+
UDExAssertHierarchy();
|
|
582
|
+
UDExAssertTreeRow(UDExSelectAllRow(), UDExHeaderName, UDExState);
|
|
583
|
+
UDExAssertDecorativeCheckbox(UDExSelectAllItem(), UDExState !== "false", UDExState === "mixed");
|
|
584
|
+
UDExChoices.forEach((UDExChoice, UDExIndex) => {
|
|
585
|
+
UDExAssertTreeRow(UDExChildRow(UDExIndex), `${UDExChoice.label} ${UDExChoice.support}`, UDExStates[UDExIndex]);
|
|
586
|
+
UDExAssertDecorativeCheckbox(UDExChild(UDExIndex), UDExStates[UDExIndex] === "true");
|
|
587
|
+
});
|
|
588
|
+
UDExMenu().shadow().find("[aria-live]").should("not.exist");
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
it("separates the default/custom named root (level 1, 1 of 1) from three children and returns native focus to the same header", () => {
|
|
592
|
+
UDExMountSelectAll();
|
|
593
|
+
const UDExAssertIdentities = UDExTrackSelectAllNodes();
|
|
594
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
595
|
+
UDExSelectAllItem().shadow().find('[part="title"]').should("have.text", "Select All");
|
|
596
|
+
UDExSelectAllItem().shadow().find('[part="supporting"]').should("have.text", UDExSupport);
|
|
597
|
+
|
|
598
|
+
cy.realPress("ArrowDown");
|
|
599
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
600
|
+
cy.realPress("ArrowUp");
|
|
601
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
602
|
+
UDExAssertIdentities();
|
|
603
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
604
|
+
|
|
605
|
+
cy.get("#source-select-all").invoke("prop", "label", "Choose all languages");
|
|
606
|
+
UDExAssertTreeRow(UDExSelectAllRow(), `Choose all languages ${UDExSupport}`, "false");
|
|
607
|
+
UDExSelectAllItem().shadow().find('[part="title"]').should("have.text", "Choose all languages");
|
|
608
|
+
UDExAssertHierarchy();
|
|
609
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
610
|
+
UDExAssertIdentities();
|
|
611
|
+
cy.get("@selectAll").should("not.have.been.called");
|
|
612
|
+
cy.get("@selectionChange").should("not.have.been.called");
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
it("clears and restores Select All tree semantics through MultiSelect → SingleSelect → MultiSelect while open", () => {
|
|
616
|
+
UDExMountSelectAll();
|
|
617
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
618
|
+
UDExSelectAllRow().realClick();
|
|
619
|
+
UDExAssertSelectAllState("true", ["true", "true", "true"]);
|
|
620
|
+
const UDExSelectedIds = ["source-select-all", ...UDExChoices.map(UDExChoice => UDExChoice.id)];
|
|
621
|
+
UDExAssertBulkEvent(1, 0, UDExSelectedIds);
|
|
622
|
+
|
|
623
|
+
UDExMenu().invoke("prop", "mode", UDExListMode.SingleSelect);
|
|
624
|
+
cy.then(() => renderFinished());
|
|
625
|
+
UDExPopover().should("have.attr", "open");
|
|
626
|
+
UDExTrigger().should("have.attr", "aria-expanded", "true");
|
|
627
|
+
UDExList().should("not.have.attr", "aria-multiselectable");
|
|
628
|
+
UDExList().shadow().find("#udex-list").should($list => {
|
|
629
|
+
expect($list).to.have.attr("role", "presentation");
|
|
630
|
+
expect($list).not.to.have.attr("aria-multiselectable");
|
|
631
|
+
});
|
|
632
|
+
[UDExList, UDExSelectAll, UDExSelectAllItem, UDExChildren].forEach(UDExQuery => UDExAssertTransparentHosts(UDExQuery()));
|
|
633
|
+
UDExSelectAll().should("have.prop", "mode", UDExListMode.SingleSelect);
|
|
634
|
+
// Select All keeps its decorative checkbox: only its native row role/state changes.
|
|
635
|
+
UDExSelectAllItem().should("have.prop", "mode", UDExListMode.MultiSelect);
|
|
636
|
+
UDExSelectAllItem().should("have.attr", "accessible-role", "option");
|
|
637
|
+
UDExSelectAllRow().should($row => {
|
|
638
|
+
expect($row).to.have.attr("role", "option");
|
|
639
|
+
expect($row).to.have.attr("aria-label", UDExHeaderName);
|
|
640
|
+
expect($row).to.have.attr("aria-selected", "true");
|
|
641
|
+
["aria-checked", "aria-level", "aria-posinset", "aria-setsize", "aria-expanded"].forEach(UDExAttr => {
|
|
642
|
+
expect($row).not.to.have.attr(UDExAttr);
|
|
643
|
+
});
|
|
644
|
+
});
|
|
645
|
+
UDExAssertDecorativeCheckbox(UDExSelectAllItem(), true);
|
|
646
|
+
UDExSelectAll().shadow().find(".udex-list__group-list").should("have.attr", "role", "listbox");
|
|
647
|
+
UDExChoices.forEach((UDExChoice, UDExIndex) => {
|
|
648
|
+
UDExChild(UDExIndex).should("have.prop", "mode", UDExListMode.SingleSelect);
|
|
649
|
+
UDExChildRow(UDExIndex).should($row => {
|
|
650
|
+
expect($row).to.have.attr("role", "option");
|
|
651
|
+
expect($row).to.have.attr("aria-label", `${UDExChoice.label} ${UDExChoice.support}`);
|
|
652
|
+
expect($row).to.have.attr("aria-selected", "true");
|
|
653
|
+
["aria-checked", "aria-level", "aria-expanded"].forEach(UDExAttr => {
|
|
654
|
+
expect($row).not.to.have.attr(UDExAttr);
|
|
655
|
+
});
|
|
656
|
+
// Grouped option positions remain valid outside tree mode; only their level is removed.
|
|
657
|
+
expect($row).to.have.attr("aria-posinset", String(UDExIndex + 1));
|
|
658
|
+
expect($row).to.have.attr("aria-setsize", String(UDExChoices.length));
|
|
659
|
+
});
|
|
660
|
+
UDExChild(UDExIndex).shadow().find("[udex-checkbox]").should("not.exist");
|
|
661
|
+
});
|
|
662
|
+
UDExList().should($list => {
|
|
663
|
+
expect(UDExAllElements($list[0]).filter(UDExElement => UDExElement.matches('[role="tree"], [role="treeitem"]')))
|
|
664
|
+
.to.have.length(0);
|
|
665
|
+
});
|
|
666
|
+
UDExAssertBulkEvent(1, 0, UDExSelectedIds);
|
|
667
|
+
|
|
668
|
+
UDExMenu().invoke("prop", "mode", UDExListMode.MultiSelect);
|
|
669
|
+
cy.then(() => renderFinished());
|
|
670
|
+
UDExPopover().should("have.attr", "open");
|
|
671
|
+
UDExTrigger().should("have.attr", "aria-expanded", "true");
|
|
672
|
+
UDExSelectAll().should("have.prop", "mode", UDExListMode.MultiSelect);
|
|
673
|
+
UDExSelectAllItem().should("have.prop", "mode", UDExListMode.MultiSelect);
|
|
674
|
+
UDExAssertSelectAllState("true", ["true", "true", "true"]);
|
|
675
|
+
UDExAssertBulkEvent(1, 0, UDExSelectedIds);
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
["Enter", "Space", "pointer"].forEach(UDExActivation => {
|
|
679
|
+
it(`keeps counts and native row identity through bulk true/false and partial selection via ${UDExActivation}, preserving distinct public events`, () => {
|
|
680
|
+
UDExMountSelectAll();
|
|
681
|
+
const UDExAssertIdentities = UDExTrackSelectAllNodes();
|
|
682
|
+
const UDExActivate = (UDExRow: Cypress.Chainable<JQuery<HTMLElement>>) => {
|
|
683
|
+
if (UDExActivation === "pointer") {
|
|
684
|
+
UDExRow.realClick();
|
|
685
|
+
} else {
|
|
686
|
+
UDExAssertFocusedRow(UDExRow);
|
|
687
|
+
cy.realPress(UDExActivation);
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
const UDExAllSourceIds = ["source-select-all", ...UDExChoices.map(UDExChoice => UDExChoice.id)];
|
|
691
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
692
|
+
|
|
693
|
+
UDExActivate(UDExSelectAllRow());
|
|
694
|
+
UDExAssertSelectAllState("true", ["true", "true", "true"]);
|
|
695
|
+
UDExAssertBulkEvent(1, 0, UDExAllSourceIds);
|
|
696
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
697
|
+
UDExAssertIdentities();
|
|
698
|
+
|
|
699
|
+
UDExActivate(UDExSelectAllRow());
|
|
700
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
701
|
+
UDExAssertBulkEvent(2, 0, []);
|
|
702
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
703
|
+
UDExAssertIdentities();
|
|
704
|
+
|
|
705
|
+
cy.realPress("ArrowDown");
|
|
706
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
707
|
+
UDExActivate(UDExChildRow(0));
|
|
708
|
+
UDExAssertSelectAllState("mixed", ["true", "false", "false"]);
|
|
709
|
+
UDExAssertSelectionEvent("source-javascript", ["source-select-all", "source-javascript"], 1);
|
|
710
|
+
cy.get("@selectAll").should("have.callCount", 2);
|
|
711
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
712
|
+
UDExAssertIdentities();
|
|
713
|
+
|
|
714
|
+
cy.realPress("ArrowUp");
|
|
715
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
716
|
+
UDExActivate(UDExSelectAllRow());
|
|
717
|
+
UDExAssertSelectAllState("true", ["true", "true", "true"]);
|
|
718
|
+
UDExAssertBulkEvent(3, 1, UDExAllSourceIds);
|
|
719
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
720
|
+
UDExAssertIdentities();
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
it("counts the disabled child but skips it in keyboard navigation and keeps bulk selection mixed while it remains unchecked", () => {
|
|
725
|
+
UDExMountSelectAll({ UDExDisabledChild: true });
|
|
726
|
+
const UDExAssertIdentities = UDExTrackSelectAllNodes();
|
|
727
|
+
UDExChildRow(1).should($row => {
|
|
728
|
+
expect($row).to.have.attr("aria-disabled", "true");
|
|
729
|
+
expect($row).to.have.attr("tabindex", "-1");
|
|
730
|
+
});
|
|
731
|
+
cy.realPress("Space");
|
|
732
|
+
UDExAssertSelectAllState("mixed", ["true", "false", "true"]);
|
|
733
|
+
UDExAssertBulkEvent(1, 0, ["source-select-all", "source-javascript", "source-python"]);
|
|
734
|
+
|
|
735
|
+
cy.realPress("ArrowDown");
|
|
736
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
737
|
+
cy.realPress("ArrowDown");
|
|
738
|
+
UDExAssertFocusedRow(UDExChildRow(2));
|
|
739
|
+
cy.realPress("ArrowUp");
|
|
740
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
741
|
+
cy.realPress("Enter");
|
|
742
|
+
UDExAssertSelectAllState("mixed", ["false", "false", "true"]);
|
|
743
|
+
UDExAssertSelectionEvent("source-javascript", ["source-select-all", "source-python"], 1);
|
|
744
|
+
cy.get("@selectAll").should("have.callCount", 1);
|
|
745
|
+
|
|
746
|
+
cy.realPress("ArrowUp");
|
|
747
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
748
|
+
cy.realPress("Space");
|
|
749
|
+
UDExAssertSelectAllState("mixed", ["true", "false", "true"]);
|
|
750
|
+
UDExAssertBulkEvent(2, 1, ["source-select-all", "source-javascript", "source-python"]);
|
|
751
|
+
cy.realPress("Space");
|
|
752
|
+
UDExAssertSelectAllState("false", ["false", "false", "false"]);
|
|
753
|
+
UDExAssertBulkEvent(3, 1, []);
|
|
754
|
+
cy.get("#source-java").should("have.prop", "selected", false);
|
|
755
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
756
|
+
UDExAssertIdentities();
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
it("recounts filtered children independently of the single root and preserves result-only live text during real-focus navigation", () => {
|
|
760
|
+
UDExMountSelectAll({ UDExSearch: true });
|
|
761
|
+
const UDExSearchInput = () => UDExMenu().shadow().find("[udex-search]").shadow().find("#search-input");
|
|
762
|
+
const UDExSearchReset = () => UDExMenu().shadow().find("[udex-search]").shadow()
|
|
763
|
+
.find("[udex-control-button]#reset-button").shadow().find("button");
|
|
764
|
+
const UDExResults = () => UDExMenu().shadow().find('[aria-live="polite"]');
|
|
765
|
+
UDExAssertHierarchy();
|
|
766
|
+
// Search owns initial focus; Tab must enter the real header, not a host/active descendant.
|
|
767
|
+
cy.realPress("Tab");
|
|
768
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
769
|
+
cy.realPress(["Shift", "Tab"]);
|
|
770
|
+
UDExSearchInput().should("be.focused").type("Java");
|
|
771
|
+
UDExAssertHierarchy([UDExChoices[0], UDExChoices[1]]);
|
|
772
|
+
|
|
773
|
+
const UDExAssertResultOnlyNavigation = () => {
|
|
774
|
+
UDExResults().should("have.length", 1).should("have.attr", "aria-atomic", "true");
|
|
775
|
+
UDExResults().invoke("text").then(UDExResultText => {
|
|
776
|
+
expect(UDExResultText).not.to.equal("");
|
|
777
|
+
expect(UDExResultText).not.to.match(/Select All|Java|Python|Available languages|level|\d+ of \d+/i);
|
|
778
|
+
// A nonempty search adds a real reset-button tab stop before the list.
|
|
779
|
+
cy.realPress("Tab");
|
|
780
|
+
UDExSearchReset().should("be.focused");
|
|
781
|
+
cy.realPress("Tab");
|
|
782
|
+
UDExSelectAllRow().then($row => {
|
|
783
|
+
const UDExOriginalHeader = $row[0];
|
|
784
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
785
|
+
cy.realPress("ArrowDown");
|
|
786
|
+
UDExAssertFocusedRow(UDExChildRow(0));
|
|
787
|
+
cy.realPress("ArrowUp");
|
|
788
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
789
|
+
UDExSelectAllRow().should($current => expect($current[0]).to.equal(UDExOriginalHeader));
|
|
790
|
+
});
|
|
791
|
+
UDExResults().should("have.text", UDExResultText);
|
|
792
|
+
cy.realPress(["Shift", "Tab"]);
|
|
793
|
+
UDExSearchReset().should("be.focused");
|
|
794
|
+
cy.realPress(["Shift", "Tab"]);
|
|
795
|
+
UDExSearchInput().should("be.focused");
|
|
796
|
+
});
|
|
797
|
+
};
|
|
798
|
+
UDExAssertResultOnlyNavigation();
|
|
799
|
+
UDExSearchInput().clear().type("JavaScript");
|
|
800
|
+
UDExAssertHierarchy([UDExChoices[0]]);
|
|
801
|
+
UDExAssertResultOnlyNavigation();
|
|
802
|
+
UDExSearchInput().clear();
|
|
803
|
+
UDExAssertHierarchy(UDExChoices);
|
|
804
|
+
cy.get("@selectionChange").should("not.have.been.called");
|
|
805
|
+
cy.get("@selectAll").should("not.have.been.called");
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
it("counts Select All as root 1 of 2 beside an ordinary leaf without adding either root to its three-child set", () => {
|
|
809
|
+
UDExMountSelectAll({ UDExRootLeaf: true });
|
|
810
|
+
UDExAssertHierarchy(UDExChoices, 2);
|
|
811
|
+
UDExAssertTreeRow(UDExSelectAllRow(), UDExHeaderName, "false");
|
|
812
|
+
const UDExRootLeaf = () => UDExList().children("[udex-list-item]");
|
|
813
|
+
UDExRootLeaf().should("have.length", 1);
|
|
814
|
+
UDExAssertTransparentHosts(UDExRootLeaf());
|
|
815
|
+
UDExAssertTreeRow(UDExRootLeaf().shadow().find('[part="item"]'), "Other language", "false");
|
|
816
|
+
UDExRootLeaf().shadow().find('[part="item"]').should($row => {
|
|
817
|
+
expect($row).to.have.attr("aria-level", "1");
|
|
818
|
+
expect($row).to.have.attr("aria-posinset", "2");
|
|
819
|
+
expect($row).to.have.attr("aria-setsize", "2");
|
|
820
|
+
});
|
|
821
|
+
cy.realPress("End");
|
|
822
|
+
UDExAssertFocusedRow(UDExRootLeaf().shadow().find('[part="item"]'));
|
|
823
|
+
cy.realPress("Home");
|
|
824
|
+
UDExAssertFocusedRow(UDExSelectAllRow());
|
|
825
|
+
cy.realPress("Enter");
|
|
826
|
+
UDExAssertHierarchy(UDExChoices, 2);
|
|
827
|
+
UDExAssertTreeRow(UDExSelectAllRow(), UDExHeaderName, "true");
|
|
828
|
+
UDExChoices.forEach((UDExChoice, UDExIndex) => {
|
|
829
|
+
UDExAssertTreeRow(UDExChildRow(UDExIndex), `${UDExChoice.label} ${UDExChoice.support}`, "true");
|
|
830
|
+
});
|
|
831
|
+
UDExAssertTreeRow(UDExRootLeaf().shadow().find('[part="item"]'), "Other language", "false");
|
|
832
|
+
UDExAssertBulkEvent(1, 0, ["source-select-all", ...UDExChoices.map(UDExChoice => UDExChoice.id)]);
|
|
833
|
+
UDExMenu().shadow().find("[aria-live]").should("not.exist");
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
describe("Expansion changes only expansion, never selection or focus", () => {
|
|
838
|
+
let UDExObserver: MutationObserver | undefined;
|
|
839
|
+
|
|
840
|
+
afterEach(() => {
|
|
841
|
+
UDExObserver?.disconnect();
|
|
842
|
+
UDExObserver = undefined;
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
(["false", "true", "mixed"] as const).forEach(UDExState => {
|
|
846
|
+
it(`keeps ${UDExState === "false" ? "unchecked" : UDExState === "true" ? "fully checked" : "partially checked"} header state and identities stable through Left/Right and source rerender`, () => {
|
|
847
|
+
UDExMountGrouped(UDExState);
|
|
848
|
+
const UDExRecords: MutationRecord[] = [];
|
|
849
|
+
const UDExKeyEvents: { key: string; prevented: boolean }[] = [];
|
|
850
|
+
const UDExOriginalNodes: HTMLElement[] = [];
|
|
851
|
+
let UDExSelectedSources: Element[];
|
|
852
|
+
const UDExNodeQueries = [UDExGroup, UDExHeaderItem, UDExHeaderRow, () => UDExLeaf(0), () => UDExLeafRow(0)];
|
|
853
|
+
UDExNodeQueries.forEach(UDExQuery => UDExQuery().then($node => { UDExOriginalNodes.push($node[0]); }));
|
|
854
|
+
UDExMenu().then($menu => {
|
|
855
|
+
UDExSelectedSources = [...($menu[0] as UDExFilterMenuElement).selectedItems];
|
|
856
|
+
$menu[0].addEventListener("keydown", UDExEvent => {
|
|
857
|
+
if (["ArrowLeft", "ArrowRight"].includes(UDExEvent.key)) {
|
|
858
|
+
UDExKeyEvents.push({ key: UDExEvent.key, prevented: UDExEvent.defaultPrevented });
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
});
|
|
862
|
+
UDExGroup().then($group => {
|
|
863
|
+
$group[0].addEventListener("header-press", cy.stub().as("headerPress"));
|
|
864
|
+
$group[0].addEventListener("accordion-icon-click", cy.stub().as("accordionToggle"));
|
|
865
|
+
$group[0].addEventListener("ui5-accordion-icon-click", cy.stub().as("prefixedAccordionToggle"));
|
|
866
|
+
});
|
|
867
|
+
UDExHeaderRow().then($row => {
|
|
868
|
+
$row[0].addEventListener("blur", cy.stub().as("headerBlur"));
|
|
869
|
+
cy.spy($row[0], "focus").as("headerRefocus");
|
|
870
|
+
UDExObserver = new MutationObserver(UDExChanges => UDExRecords.push(...UDExChanges));
|
|
871
|
+
UDExObserver.observe($row[0], {
|
|
872
|
+
attributes: true,
|
|
873
|
+
attributeOldValue: true,
|
|
874
|
+
attributeFilter: ["aria-expanded", "aria-checked", "aria-selected", "aria-label", "aria-hidden",
|
|
875
|
+
"aria-labelledby", "aria-description", "aria-describedby", "role", "tabindex"],
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
const UDExAssertStableState = (UDExCollapsed: boolean, UDExToggleCount: number) => {
|
|
880
|
+
cy.then(() => renderFinished());
|
|
881
|
+
UDExAssertTreeRow(UDExHeaderRow(), UDExGroupName, UDExState);
|
|
882
|
+
UDExAssertTreeRow(UDExLeafRow(0), UDExChildName, UDExState !== "false" ? "true" : "false");
|
|
883
|
+
UDExAssertTreeRow(UDExLeafRow(1), "Python Data analysis", UDExState === "true" ? "true" : "false");
|
|
884
|
+
UDExHeaderRow().should("be.focused").should($row => {
|
|
885
|
+
expect($row).to.have.attr("aria-expanded", String(!UDExCollapsed));
|
|
886
|
+
expect(($row[0].getRootNode() as ShadowRoot).activeElement).to.equal(UDExOriginalNodes[2]);
|
|
887
|
+
});
|
|
888
|
+
UDExNodeQueries.forEach((UDExQuery, UDExIndex) => {
|
|
889
|
+
UDExQuery().should($node => expect($node[0]).to.equal(UDExOriginalNodes[UDExIndex]));
|
|
890
|
+
});
|
|
891
|
+
cy.get("#source-group").should($source => {
|
|
892
|
+
expect($source[0]).to.have.property("collapsed", UDExCollapsed);
|
|
893
|
+
expect($source[0]).to.have.property("selected", UDExState !== "false");
|
|
894
|
+
expect(Boolean(($source[0] as UDExFilterMenuGroupHeaderElement).indeterminate)).to.equal(UDExState === "mixed");
|
|
895
|
+
});
|
|
896
|
+
UDExMenu().should($menu => {
|
|
897
|
+
const UDExSelected = ($menu[0] as UDExFilterMenuElement).selectedItems;
|
|
898
|
+
expect(UDExSelected).to.have.length(UDExSelectedSources.length);
|
|
899
|
+
UDExSelected.forEach((UDExItem, UDExIndex) => expect(UDExItem).to.equal(UDExSelectedSources[UDExIndex]));
|
|
900
|
+
});
|
|
901
|
+
UDExAssertDecorativeCheckbox(UDExHeaderItem(), UDExState !== "false", UDExState === "mixed");
|
|
902
|
+
cy.get("@headerBlur").should("not.have.been.called");
|
|
903
|
+
cy.get("@headerRefocus").should("not.have.been.called");
|
|
904
|
+
cy.get("@selectionChange").should("not.have.been.called");
|
|
905
|
+
cy.get("@headerPress").should("not.have.been.called");
|
|
906
|
+
["@accordionToggle", "@prefixedAccordionToggle"].forEach(UDExAlias => {
|
|
907
|
+
cy.get(UDExAlias).should("have.callCount", UDExToggleCount).its("lastCall.args.0.detail")
|
|
908
|
+
.should("deep.equal", { collapsed: UDExCollapsed });
|
|
909
|
+
});
|
|
910
|
+
UDExMenu().shadow().find("[aria-live]").should("not.exist");
|
|
911
|
+
cy.then(() => {
|
|
912
|
+
UDExRecords.push(...UDExObserver!.takeRecords());
|
|
913
|
+
expect(UDExRecords.map(UDExRecord => UDExRecord.attributeName)).to.deep.equal(
|
|
914
|
+
Array(UDExToggleCount).fill("aria-expanded"));
|
|
915
|
+
expect(UDExRecords.map(UDExRecord => UDExRecord.oldValue)).to.deep.equal(
|
|
916
|
+
UDExToggleCount === 1 ? ["true"] : ["true", "false"]);
|
|
917
|
+
});
|
|
918
|
+
};
|
|
919
|
+
|
|
920
|
+
cy.realPress("ArrowLeft");
|
|
921
|
+
UDExAssertStableState(true, 1);
|
|
922
|
+
cy.realPress("ArrowLeft");
|
|
923
|
+
cy.realPress("ArrowLeft");
|
|
924
|
+
UDExAssertStableState(true, 1);
|
|
925
|
+
|
|
926
|
+
// A parent rerender must use the synchronized source collapsed state, not reopen the group.
|
|
927
|
+
UDExMenu().invoke("prop", "filterName", "Updated languages");
|
|
928
|
+
UDExTrigger().should("have.attr", "aria-label", "Updated languages");
|
|
929
|
+
UDExAssertStableState(true, 1);
|
|
930
|
+
|
|
931
|
+
cy.realPress("ArrowRight");
|
|
932
|
+
UDExAssertStableState(false, 2);
|
|
933
|
+
cy.realPress("ArrowRight");
|
|
934
|
+
cy.realPress("ArrowRight");
|
|
935
|
+
UDExAssertStableState(false, 2);
|
|
936
|
+
cy.then(() => {
|
|
937
|
+
expect(UDExKeyEvents).to.deep.equal([
|
|
938
|
+
{ key: "ArrowLeft", prevented: true },
|
|
939
|
+
{ key: "ArrowLeft", prevented: false },
|
|
940
|
+
{ key: "ArrowLeft", prevented: false },
|
|
941
|
+
{ key: "ArrowRight", prevented: true },
|
|
942
|
+
{ key: "ArrowRight", prevented: false },
|
|
943
|
+
{ key: "ArrowRight", prevented: false },
|
|
944
|
+
]);
|
|
945
|
+
});
|
|
946
|
+
});
|
|
947
|
+
});
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
describe("SingleSelect group supporting names", () => {
|
|
951
|
+
[false, true].forEach(UDExPerGroupListbox => {
|
|
952
|
+
it(`resolves heading and support locally for each noncollapsible ${UDExPerGroupListbox ? "per-group listbox" : "group wrapper"}`, () => {
|
|
953
|
+
cy.mount(
|
|
954
|
+
<div>
|
|
955
|
+
<button id="before-filter-menu">Previous</button>
|
|
956
|
+
<UDExFilterMenu filterName="Languages" mode={UDExListMode.SingleSelect}>
|
|
957
|
+
{["Frontend", "Backend"].map(UDExLabel => (
|
|
958
|
+
<UDExFilterMenuGroupHeader label={`<b>${UDExLabel}</b> languages`} supportingText={`${UDExLabel} support`}>
|
|
959
|
+
<UDExFilterMenuItem label={`${UDExLabel} choice`} supportingText="Option support"></UDExFilterMenuItem>
|
|
960
|
+
</UDExFilterMenuGroupHeader>
|
|
961
|
+
))}
|
|
962
|
+
{!UDExPerGroupListbox && <UDExFilterMenuItem label="Other language"></UDExFilterMenuItem>}
|
|
963
|
+
</UDExFilterMenu>
|
|
964
|
+
</div>
|
|
965
|
+
);
|
|
966
|
+
UDExOpenMenu();
|
|
967
|
+
["Frontend", "Backend"].forEach((UDExLabel, UDExIndex) => {
|
|
968
|
+
const UDExTarget = UDExGroup().eq(UDExIndex).shadow()
|
|
969
|
+
.find(UDExPerGroupListbox ? '[role="listbox"]' : '.udex-list__group[role="group"]');
|
|
970
|
+
UDExAssertLocalGroupName(UDExTarget, `${UDExLabel} languages ${UDExLabel} support`);
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
});
|
|
974
|
+
|
|
975
|
+
it("names a collapsible SingleSelect heading from label and support exactly once, excluding its chevron and children", () => {
|
|
976
|
+
cy.mount(
|
|
977
|
+
<div>
|
|
978
|
+
<button id="before-filter-menu">Previous</button>
|
|
979
|
+
<UDExFilterMenu filterName="Languages" mode={UDExListMode.SingleSelect}>
|
|
980
|
+
<UDExFilterMenuGroupHeader collapsible label="<b>Programming</b> Languages" supportingText="Digital Builders">
|
|
981
|
+
<UDExFilterMenuItem label="JavaScript" supportingText="Frontend web development"></UDExFilterMenuItem>
|
|
982
|
+
</UDExFilterMenuGroupHeader>
|
|
983
|
+
</UDExFilterMenu>
|
|
984
|
+
</div>
|
|
985
|
+
);
|
|
986
|
+
UDExOpenMenu();
|
|
987
|
+
const UDExHeading = () => UDExGroup().shadow().find('[part="group-item"][role="treeitem"]');
|
|
988
|
+
UDExAssertLocalGroupName(UDExHeading(), UDExGroupName);
|
|
989
|
+
UDExHeading().should($heading => {
|
|
990
|
+
expect($heading).to.have.attr("aria-expanded", "true");
|
|
991
|
+
expect($heading).not.to.have.attr("aria-checked");
|
|
992
|
+
expect($heading).not.to.have.attr("aria-selected");
|
|
993
|
+
});
|
|
994
|
+
UDExGroup().shadow().find(".udex-list__group-heading__icon").should("have.attr", "tabindex", "-1");
|
|
995
|
+
});
|
|
996
|
+
});
|
|
997
|
+
|
|
998
|
+
it("returns focus to the same trigger on Escape and permits Tab to leave the closed menu", () => {
|
|
999
|
+
UDExMountGrouped();
|
|
1000
|
+
UDExMenu().then($menu => {
|
|
1001
|
+
$menu[0].addEventListener("after-close", cy.stub().as("menuClosed"), { once: true });
|
|
1002
|
+
});
|
|
1003
|
+
UDExTrigger().then($trigger => {
|
|
1004
|
+
const UDExOriginalTrigger = $trigger[0];
|
|
1005
|
+
cy.realPress("Escape");
|
|
1006
|
+
cy.get("@menuClosed").should("have.been.calledOnce");
|
|
1007
|
+
UDExPopover().should("not.have.attr", "open");
|
|
1008
|
+
UDExTrigger().should("be.focused").should($current => {
|
|
1009
|
+
expect($current[0]).to.equal(UDExOriginalTrigger);
|
|
1010
|
+
expect($current).to.have.attr("aria-expanded", "false");
|
|
1011
|
+
});
|
|
1012
|
+
cy.realPress("Tab");
|
|
1013
|
+
cy.get("#after-filter-menu").should("be.focused");
|
|
1014
|
+
cy.get("@selectionChange").should("not.have.been.called");
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
});
|